diff --git a/.ameba.yml b/.ameba.yml index 47647e8e1..0e5043707 100644 --- a/.ameba.yml +++ b/.ameba.yml @@ -3,3 +3,9 @@ Metrics/CyclomaticComplexity: Lint/NotNil: Enabled: false + +Documentation/DocumentationAdmonition: + Enabled: false + +Lint/UselessAssign: + ExcludeTypeDeclarations: true diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 56ec93981..2e69dfeb3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,7 +9,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-13, macos-latest] runs-on: ${{ matrix.os }} steps: @@ -31,11 +31,11 @@ jobs: mkdir build docker-compose run --rm app crystal build src/mint.cr -o build/mint-${GITHUB_REF_SLUG}-linux --static --no-debug --release - - if: matrix.os == 'macos-latest' + - if: startsWith(matrix.os, 'macos') name: Build binary (macOS) run: | mkdir build - crystal build src/mint.cr -o build/mint-${GITHUB_REF_SLUG}-osx --release + crystal build src/mint.cr -o build/mint-${GITHUB_REF_SLUG}-${{ matrix.os }} --release - name: Upload artifacts uses: actions/upload-artifact@v3 @@ -50,8 +50,8 @@ jobs: aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws_bucket: ${{ secrets.AWS_BUCKET }} aws_key_id: ${{ secrets.AWS_KEY }} - source_dir: build destination_dir: "" + source_dir: build - if: startsWith(github.ref, 'refs/tags/') name: Upload to GitHub Releases @@ -59,6 +59,6 @@ jobs: with: repo_token: ${{ secrets.GITHUB_TOKEN }} tag: ${{ github.ref }} - file: build/* overwrite: true file_glob: true + file: build/* diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 2cc00a9da..38ed9b0b9 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -39,9 +39,9 @@ jobs: - name: Log into ${{ env.REGISTRY }} registry uses: docker/login-action@v3 with: + password: ${{ secrets.GITHUB_TOKEN }} registry: ${{ env.REGISTRY }} username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} # Extract metadata (tags, labels) for Docker # https://github.com/docker/metadata-action @@ -52,12 +52,12 @@ jobs: images: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | - type=ref,event=tag + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{version}} type=ref,event=branch - type=ref,event=pr type=sha,format=long - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} + type=ref,event=tag + type=ref,event=pr # Build and push Docker image with Buildx # https://github.com/docker/build-push-action @@ -67,10 +67,10 @@ jobs: with: context: . push: true - cache-from: type=gha cache-to: type=gha,mode=max + cache-from: type=gha + labels: ${{ steps.meta.outputs.labels }} + tags: ${{ steps.meta.outputs.tags }} platforms: | linux/amd64 linux/arm64 - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/ci-base.yml b/.github/workflows/ci-base.yml new file mode 100644 index 000000000..706d49497 --- /dev/null +++ b/.github/workflows/ci-base.yml @@ -0,0 +1,57 @@ +name: CI + +on: + workflow_call: + inputs: + crystal-version: + required: true + type: string + +jobs: + test: + name: Test + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-13] + runs-on: ${{ matrix.os }} + + steps: + - name: Install Crystal + uses: crystal-lang/install-crystal@v1 + with: + crystal: ${{ inputs.crystal-version }} + + - name: Download source + uses: actions/checkout@v4 + + - name: Install dependencies + run: shards install + + - name: Run specs + run: crystal spec --error-on-warnings --error-trace + + - name: Build the binary + run: shards build --error-on-warnings --error-trace + + - name: Run core specs (Firefox) + working-directory: ./core/tests + run: ../../bin/mint test -b firefox + + - name: Run core specs (Google Chrome) + working-directory: ./core/tests + run: ../../bin/mint test -b chrome + + - name: Check formatting (Mint) + working-directory: ./core + run: ../bin/mint format --check + + - name: Check formatting (Mint tests) + working-directory: ./core/tests + run: ../../bin/mint format --check + + - name: Check formatting (Crystal) + run: crystal tool format --check + + - name: Run ameba + run: bin/ameba diff --git a/.github/workflows/ci-nightly.yml b/.github/workflows/ci-nightly.yml index 99dc0555c..a477e2d50 100644 --- a/.github/workflows/ci-nightly.yml +++ b/.github/workflows/ci-nightly.yml @@ -7,49 +7,6 @@ on: jobs: test: - name: Test - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, macos-latest] - runs-on: ${{ matrix.os }} - - steps: - - name: Install Crystal - uses: crystal-lang/install-crystal@v1 - with: - crystal: nightly - - - name: Download source - uses: actions/checkout@v4 - - - name: Install dependencies - run: shards install - - - name: Run specs - run: crystal spec --error-on-warnings --error-trace - - - name: Build the binary - run: shards build --error-on-warnings --error-trace - - - name: Run core specs (Firefox) - working-directory: ./core/tests - run: ../../bin/mint test -b firefox - - - name: Run core specs (Google Chrome) - working-directory: ./core/tests - run: ../../bin/mint test -b chrome - - - name: Check formatting (Mint) - working-directory: ./core - run: ../bin/mint format --check - - - name: Check formatting (Mint tests) - working-directory: ./core/tests - run: ../../bin/mint format --check - - - name: Check formatting (Crystal) - run: crystal tool format --check - - - name: Run ameba - run: bin/ameba + uses: ./.github/workflows/ci-base.yml + with: + crystal-version: nightly diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d0cb766df..04ac421b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,49 +11,6 @@ on: jobs: test: - name: Test - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, macos-latest] - runs-on: ${{ matrix.os }} - - steps: - - name: Install Crystal - uses: crystal-lang/install-crystal@v1 - with: - crystal: latest - - - name: Download source - uses: actions/checkout@v4 - - - name: Install dependencies - run: shards install - - - name: Run specs - run: crystal spec --error-on-warnings --error-trace - - - name: Build the binary - run: shards build --error-on-warnings --error-trace - - - name: Run core specs (Firefox) - working-directory: ./core/tests - run: ../../bin/mint test -b firefox - - - name: Run core specs (Google Chrome) - working-directory: ./core/tests - run: ../../bin/mint test -b chrome - - - name: Check formatting (Mint) - working-directory: ./core - run: ../bin/mint format --check - - - name: Check formatting (Mint tests) - working-directory: ./core/tests - run: ../../bin/mint format --check - - - name: Check formatting (Crystal) - run: crystal tool format --check - - - name: Run ameba - run: bin/ameba + uses: ./.github/workflows/ci-base.yml + with: + crystal-version: latest diff --git a/.gitignore b/.gitignore index c284ca24b..6f8bafc5f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ /lib/ /bin/ /.shards/ -.vscode \ No newline at end of file +.vscode +node_modules +coverage diff --git a/.tool-versions b/.tool-versions index 1868f63d6..7b43fac36 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,4 @@ -crystal 1.9.1 +crystal 1.10.1 mint 0.19.0 +nodejs 20.10.0 +yarn 1.22.19 diff --git a/Makefile b/Makefile index e04ddb5ef..29f8ae433 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ test: spec ameba .PHONY: test-core test-core: build - cd core/tests && ../../bin/mint test -b firefox + cd core/tests && ../../bin/mint test -b chrome .PHONY: development development: build @@ -37,6 +37,17 @@ local: build documentation: rm -rf docs && crystal docs -# This builds the binary and depends on files in "src" and "core" directories. -bin/mint: $(shell find src -type f) $(shell find core/source -type f) +src/assets/runtime.js: $(shell find runtime/src -type f) + cd runtime && make index + +src/assets/runtime_test.js: $(shell find runtime/src -type f) + cd runtime && make index_testing + +# This builds the binary and depends on files in some directories. +bin/mint: \ + $(shell find core/source -type f) \ + $(shell find runtime/src -type f) \ + $(shell find src -type f) \ + src/assets/runtime_test.js \ + src/assets/runtime.js shards build --error-on-warnings --error-trace --progress diff --git a/core/source/Array.mint b/core/source/Array.mint index 3d44fbd7d..c5c5807db 100644 --- a/core/source/Array.mint +++ b/core/source/Array.mint @@ -8,10 +8,7 @@ module Array { Array.any([1, 3], (number : Number) : Bool { number % 2 == 0 }) == false */ fun any (array : Array(item), function : Function(item, Bool)) : Bool { - case Array.find(array, function) { - Maybe.Nothing => false - Maybe.Just => true - } + Array.find(array, function) != Maybe.Nothing } /* @@ -20,14 +17,14 @@ module Array { Array.append([1, 1, 2] [3, 5, 8]) == [1, 1, 2, 3, 5, 8] */ fun append (array1 : Array(item), array2 : Array(item)) : Array(item) { - `[].concat(#{array1}).concat(#{array2})` + `[...#{array1}, ...#{array2}]` } /* Returns the element at the given index as a `Maybe(item)`. - Array.at([0], 0) == Maybe::Just(0) - Array.at([0], 1) == Maybe::Nothing() + Array.at([0], 0) == Maybe.Just(0) + Array.at([0], 1) == Maybe.Nothing() */ fun at (array : Array(item), index : Number) : Maybe(item) { array[index] @@ -35,9 +32,9 @@ module Array { /* Flattens an `Array(Maybe(item))` into an `Array(item)`, by unwrapping the - items and skipping all elements of `Maybe::Nothing`. + items and skipping all elements of `Maybe.Nothing`. - Array.compact([Maybe::Just("A"), Maybe::Nothing()]) == ["A"] + Array.compact([Maybe.Just("A"), Maybe.Nothing()]) == ["A"] */ fun compact (array : Array(Maybe(item))) : Array(item) { Array.reduce( @@ -45,8 +42,8 @@ module Array { [], (memo : Array(item), item : Maybe(item)) : Array(item) { case item { - Maybe.Just(value) => Array.push(memo, value) - Maybe.Nothing => memo + Just(value) => Array.push(memo, value) + Nothing => memo } }) } @@ -70,7 +67,7 @@ module Array { ` (() => { for (let item of #{array}) { - if (_compare(#{other}, item)) { + if (#{%compare%}(#{other}, item)) { return true } } @@ -98,7 +95,7 @@ module Array { ` (() => { if (#{index} < 0 || #{index} >= #{array}.length) { return #{array} } - const result = Array.from(#{array}) + const result = [...#{array}] result.splice(#{index}, 1) return result })() @@ -131,15 +128,14 @@ module Array { /* Finds the first element in the array that matches the predicate function. - Array.find([1, 2, 3, 4], (number : Number) { number % 2 == 0 }) == Maybe::Just(2) + Array.find([1, 2, 3, 4], (number : Number) { number % 2 == 0 }) == Maybe.Just(2) */ fun find (array : Array(item), function : Function(item, Bool)) : Maybe(item) { - Array.first( - for item of array { - item - } when { - function(item) - }) + for item of array { + item + } when { + function(item) + }[0] } /* @@ -149,7 +145,7 @@ module Array { Array.findByAndMap( [1, 2, 3, 4], (number : Number) : (Bool, value) { {number % 2 == 0, "Two"} } - ) == Maybe::Just("Two") + ) == Maybe.Just("Two") */ fun findByAndMap ( array : Array(item), @@ -161,21 +157,21 @@ module Array { const [found, value] = #{function}(item) if (found) { - return #{Maybe::Just(`value`)} + return #{Maybe.Just(`value`)} } } - return #{Maybe::Nothing} + return #{Maybe.Nothing} })() ` } /* - Returns the first element of the array as `Maybe::Just(item)` or - `Maybe::Nothing`. + Returns the first element of the array as `Maybe.Just(item)` or + `Maybe.Nothing`. - Array.first(["a", "x"]) == Maybe::Just("a") - Array.first([]) == Maybe::Nothing + Array.first(["a", "x"]) == Maybe.Just("a") + Array.first([]) == Maybe.Nothing */ fun first (array : Array(item)) : Maybe(item) { array[0] @@ -247,7 +243,7 @@ module Array { let lowerLimit = 0 #{array} = - Array.from(#{array}).reverse() + [...#{array}].reverse() for (var $0 = 0; $0 < groups; $0++) { lowerLimit = $0 * #{size}; @@ -273,7 +269,7 @@ module Array { ` (() => { for (let index = 0; index < #{array}.length; index++) { - if (_compare(#{value}, #{method}(#{array}[index]))) { + if (#{%compare%}(#{value}, #{method}(#{array}[index]))) { return index } } @@ -306,7 +302,7 @@ module Array { fun insertAt (array : Array(item), item : item, position : Number) : Array(item) { ` (() => { - const result = Array.from(#{array}) + const result = [...#{array}] if (#{position} <= 0) { result.unshift(#{item}) @@ -339,19 +335,20 @@ module Array { } /* - Returns the last element of the array as `Maybe::Just(a)` or `Maybe::Nothing`. + Returns the last element of the array as `Maybe.Just(a)` or `Maybe.Nothing`. - Array.last(["x", "a"]) == Maybe::Just("a") - Array.last([]) == Maybe::Nothing + Array.last(["x", "a"]) == Maybe.Just("a") + Array.last([]) == Maybe.Nothing */ fun last (array : Array(item)) : Maybe(item) { ` (() => { - let last = #{array}[#{array}.length - 1] + let last = #{array}[#{array}.length - 1]; + if (last !== undefined) { - return #{Maybe::Just(`last`)} + return #{Maybe.Just(`last`)} } else { - return #{Maybe::Nothing} + return #{Maybe.Nothing} } })() ` @@ -401,8 +398,8 @@ module Array { Returns the maximum value of an array of numbers. It's a maybe because the array might not have items in it. - Array.max([0, 1, 2, 3, 4]) == Maybe::Just(4) - Array.max([]) == Maybe::Nothing + Array.max([0, 1, 2, 3, 4]) == Maybe.Just(4) + Array.max([]) == Maybe.Nothing */ fun max (array : Array(Number)) : Maybe(Number) { if Array.size(array) > 0 { @@ -416,8 +413,8 @@ module Array { Returns the minimum value of an array of numbers. It's a maybe because the array might not have items in it. - Array.min([0, 1, 2, 3, 4]) == Maybe::Just(0) - Array.min([]) == Maybe::Nothing + Array.min([0, 1, 2, 3, 4]) == Maybe.Just(0) + Array.min([]) == Maybe.Nothing */ fun min (array : Array(Number)) : Maybe(Number) { if Array.size(array) > 0 { @@ -452,7 +449,7 @@ module Array { fun move (array : Array(item), from : Number, to : Number) : Array(item) { ` (() => { - const result = Array.from(#{array}) + const result = [...#{array}] if (#{from} == #{to} || #{from} < 0 || #{from} >= result.length) { return result @@ -562,8 +559,8 @@ module Array { /* Returns a random element from the array. - Array.sample(["a"]) == Maybe::Just("a") - Array.sample() == Maybe::Nothing() + Array.sample(["a"]) == Maybe.Just("a") + Array.sample() == Maybe.Nothing() */ fun sample (array : Array(item)) : Maybe(item) { ` @@ -571,9 +568,9 @@ module Array { if (#{array}.length) { const item = #{array}[Math.floor(Math.random() * #{array}.length)] - return #{Maybe::Just(`item`)} + return #{Maybe.Just(`item`)} } else { - return #{Maybe::Nothing} + return #{Maybe.Nothing} } })() ` @@ -598,7 +595,7 @@ module Array { ` (() => { if (#{index} < 0 || #{index} >= #{array}.length) { return #{array} } - const result = Array.from(#{array}) + const result = [...#{array}] result[#{index}] = #{item} return result })() @@ -712,7 +709,7 @@ module Array { return #{array} } - const result = Array.from(#{array}) + const result = [...#{array}] const saved = result[#{index1}] result[#{index1}] = result[#{index2}] result[#{index2}] = saved; @@ -760,7 +757,7 @@ module Array { fun unshift (array : Array(item), item : item) : Array(item) { ` (() => { - const result = Array.from(#{array}) + const result = [...#{array}] result.unshift(#{item}) return result })() diff --git a/core/source/Base64.mint b/core/source/Base64.mint index f2610b137..f72157608 100644 --- a/core/source/Base64.mint +++ b/core/source/Base64.mint @@ -4,9 +4,9 @@ module Base64 { ` (() => { try { - return #{Result::Ok(`atob(#{value})`)}; + return #{Result.Ok(`atob(#{value})`)}; } catch (error) { - return #{Result::Err(`error.toString()`)}; + return #{Result.Err(`error.toString()`)}; } })() ` diff --git a/core/source/Clipboard.mint b/core/source/Clipboard.mint index f038becf4..659ec28fb 100644 --- a/core/source/Clipboard.mint +++ b/core/source/Clipboard.mint @@ -29,12 +29,17 @@ module Clipboard { // Get selection and replace current selection const selection = window.getSelection() - const lastRanges = Array.from({length: selection.rangeCount}, (_, i) => selection.getRangeAt(i)) + + const lastRanges = + Array.from( + { length: selection.rangeCount }, + (_, i) => selection.getRangeAt(i)) + selection.removeAllRanges() selection.addRange(range) // Select all the text - textarea.setSelectionRange(0, 999999) + textarea.setSelectionRange(0, Number.MAX_SAFE_INTEGER) // Copy to clipboard document.execCommand("copy") diff --git a/core/source/Console.mint b/core/source/Console.mint index 11194cfb8..e8b8fe389 100644 --- a/core/source/Console.mint +++ b/core/source/Console.mint @@ -30,8 +30,7 @@ module Console { */ fun assert (assertion : Bool, value : a, values : Array(b) = []) : Tuple(Bool, a, Array(b)) { `console.assert(#{assertion}, #{value}, ...#{values})` - - #(assertion, value, values) + {assertion, value, values} } /* @@ -53,7 +52,7 @@ module Console { `console.count(#{label})` Console.Counter.increment(label) - #(label, Console.Counter.get(label)) + {label, Console.Counter.get(label)} } /* @@ -66,7 +65,7 @@ module Console { `console.countReset(#{label})` Console.Counter.clear(label) - #(label, Console.Counter.get(label)) + {label, Console.Counter.get(label)} } /* @@ -78,8 +77,7 @@ module Console { */ fun debug (value : a, values : Array(b) = []) : Tuple(a, Array(b)) { `console.debug(#{value}, ...#{values})` - - #(value, values) + {value, values} } /* @@ -89,7 +87,6 @@ module Console { */ fun dir (value : a) : a { `console.dir(#{value})` - value } @@ -101,7 +98,6 @@ module Console { */ fun dirxml (value : a) : a { `console.dirxml(#{value})` - value } @@ -112,8 +108,7 @@ module Console { */ fun error (value : a, values : Array(b) = []) : Tuple(a, Array(b)) { `console.error(#{value}, ...#{values})` - - #(value, values) + {value, values} } /* @@ -123,7 +118,6 @@ module Console { */ fun group (label : String = "Default") : String { `console.group(#{label})` - label } @@ -134,7 +128,6 @@ module Console { */ fun groupCollapsed (label : String = "Default") : String { `console.groupCollapsed(#{label})` - label } @@ -145,7 +138,6 @@ module Console { */ fun groupEnd (label : String = "Default") : String { `console.groupEnd(#{label})` - label } @@ -156,8 +148,7 @@ module Console { */ fun info (value : a, values : Array(b) = []) : Tuple(a, Array(b)) { `console.info(#{value}, ...#{values})` - - #(value, values) + {value, values} } /* @@ -169,8 +160,7 @@ module Console { */ fun log (value : a, values : Array(b) = []) : Tuple(a, Array(b)) { `console.log(#{value}, ...#{values})` - - #(value, values) + {value, values} } /* @@ -219,7 +209,7 @@ module Console { `console.table(#{data})` } - #(data, columns) + {data, columns} } /* @@ -229,7 +219,6 @@ module Console { */ fun time (label : String = "Default") : String { `console.time(#{label})` - label } @@ -240,7 +229,6 @@ module Console { */ fun timeEnd (label : String = "Default") : String { `console.timeEnd(#{label})` - label } @@ -251,8 +239,7 @@ module Console { */ fun timeLog (label : String = "Default", values : Array(a) = []) : Tuple(String, Array(a)) { `console.timeLog(#{label}, ...#{values})` - - #(label, values) + {label, values} } /* @@ -279,8 +266,7 @@ module Console { */ fun trace (value : a, values : Array(b)) : Tuple(a, Array(b)) { `console.trace(#{value}, ...#{values})` - - #(value, values) + {value, values} } /* @@ -290,7 +276,6 @@ module Console { */ fun warn (value : a, values : Array(b) = []) : Tuple(a, Array(b)) { `console.warn(#{value}, ...#{values})` - - #(value, values) + {value, values} } } diff --git a/core/source/Dom.mint b/core/source/Dom.mint index 5bfb7aaab..bad3ffaac 100644 --- a/core/source/Dom.mint +++ b/core/source/Dom.mint @@ -56,14 +56,9 @@ module Dom { |> Dom.getElementById() */ fun focus (maybeElement : Maybe(Dom.Element)) : Promise(Void) { - case maybeElement { - Maybe.Just(element) => - { - focusWhenVisible(element) - Promise.resolve(void) - } - - Maybe.Nothing => Promise.resolve(void) + if let Maybe.Just(element) = maybeElement { + focusWhenVisible(element) + Promise.resolve(void) } } @@ -89,7 +84,7 @@ module Dom { let focus = () => { if (counter > 15) { - resolve(#{Result::Err("Could not focus the element in 150ms. Is it visible?")}) + resolve(#{Result.Err("Could not focus the element in 150ms. Is it visible?")}) } #{element}.focus() @@ -98,7 +93,7 @@ module Dom { counter++ setTimeout(focus, 10) } else { - resolve(#{Result::Ok(void)}) + resolve(#{Result.Ok(void)}) } } @@ -116,9 +111,9 @@ module Dom { ` (() => { if (document.activeElement) { - return #{Maybe::Just(`document.activeElement`)} + return #{Maybe.Just(`document.activeElement`)} } else { - return #{Maybe::Nothing} + return #{Maybe.Nothing} } })() ` @@ -131,8 +126,8 @@ module Dom { Dom.getElementById("my-div") case (outcome) { - Maybe::Just(element) => Dom.getAttribute(element, "id") == "my-div" - Maybe::Nothing => false + Maybe.Just(element) => Dom.getAttribute(element, "id") == "my-div" + Maybe.Nothing => false } */ fun getAttribute (element : Dom.Element, name : String) : Maybe(String) { @@ -141,9 +136,9 @@ module Dom { const value = #{element}.getAttribute(#{name}) if (value === "") { - return #{Maybe::Nothing} + return #{Maybe.Nothing} } else { - return #{Maybe::Just(`value`)} + return #{Maybe.Just(`value`)} } })() ` @@ -155,7 +150,7 @@ module Dom { Dom.getChildren()) */ fun getChildren (element : Dom.Element) : Array(Dom.Element) { - `Array.from(#{element}.children)` + `[...#{element}.children]` } /* @@ -220,9 +215,9 @@ module Dom { let element = document.getElementById(#{id}) if (element) { - return #{Maybe::Just(`element`)} + return #{Maybe.Just(`element`)} } else { - return #{Maybe::Nothing} + return #{Maybe.Nothing} } })() ` @@ -240,12 +235,12 @@ module Dom { let element = document.querySelector(#{selector}) if (element) { - return #{Maybe::Just(`element`)} + return #{Maybe.Just(`element`)} } else { - return #{Maybe::Nothing} + return #{Maybe.Nothing} } } catch (error) { - return #{Maybe::Nothing} + return #{Maybe.Nothing} } })() ` @@ -262,9 +257,9 @@ module Dom { const element = document.elementFromPoint(#{left}, #{top}) if (element) { - return #{Maybe::Just(`element`)} + return #{Maybe.Just(`element`)} } else { - return #{Maybe::Nothing} + return #{Maybe.Nothing} } })() ` @@ -284,16 +279,16 @@ module Dom { fun getFocusableElements (element : Dom.Element) : Array(Dom.Element) { ` (() => { - /* Save focused element. */ + // Save focused element. const focused = document.activeElement - /* Save scroll position. */ + // Save scroll position. const scrollX = window.scrollX const scrollY = window.scrollY - /* Save the scroll position of each element. */ + // Save the scroll position of each element. const scrollPositions = - Array.from(document.querySelectorAll("*")).reduce((memo, element) => { + [...document.querySelectorAll("*")].reduce((memo, element) => { if (element.scrollHeight > 0 || element.scrollWidth > 0) { memo.set(element, [element.scrollLeft, element.scrollTop]) } @@ -301,11 +296,12 @@ module Dom { return memo }, new Map) - /* Gather the focusable elements by focusing them and comparing it - with the focused element. */ + // Gather the focusable elements by focusing them and comparing it + // with the focused element. const foundElements = - Array.from(#{element}.querySelectorAll("*")).reduce((memo ,element) => { + [...#{element}.querySelectorAll("*")].reduce((memo ,element) => { element.focus() + if (document.activeElement == element && element.tabIndex !== -1) { memo.push(element) } @@ -313,7 +309,7 @@ module Dom { return memo }, []) - /* Restore scroll positions and focus. */ + // Restore scroll positions and focus. for (let element in scrollPositions) { const [x, y] = scrollPositions[element] element.scrollTo(x, y) @@ -388,7 +384,7 @@ module Dom { let hash = String.parameterize(text) - #(tag, text, hash) + {tag, text, hash} }) } @@ -477,10 +473,7 @@ module Dom { Dom.scrollTo(element, 10, 10) */ fun scrollTo (element : Dom.Element, left : Number, top : Number) : Promise(Void) { - `#{element}.scrollTo({ - left: #{left}, - top: #{top} - })` + `#{element}.scrollTo({ left: #{left}, top: #{top} })` } /* @@ -521,8 +514,13 @@ module Dom { It is used to set the value of `input` fields programmatically. */ - fun setValue (dom : Dom.Element, value : String) : Dom.Element { - `(#{dom}.value = #{value}) && #{dom}` + fun setValue (element : Dom.Element, value : String) : Dom.Element { + ` + (() => { + #{element}.value = #{value} + return #{element} + })() + ` } /* @@ -531,10 +529,6 @@ module Dom { Dom.smoothScrollTo(element, 10, 10) */ fun smoothScrollTo (element : Dom.Element, left : Number, top : Number) : Promise(Void) { - `#{element}.scrollTo({ - behavior: 'smooth', - left: #{left}, - top: #{top} - })` + `#{element}.scrollTo({ behavior: 'smooth', left: #{left}, top: #{top} })` } } diff --git a/core/source/File.mint b/core/source/File.mint index 337068622..da6e6727a 100644 --- a/core/source/File.mint +++ b/core/source/File.mint @@ -3,7 +3,8 @@ module File { /* Prompts a dialog for the saving the given file. - file = await File.select(*) + let file = + await File.select("*") File.download(file) */ @@ -55,7 +56,7 @@ module File { /* Reads the contents of the given file as a String. - file = + let file = File.create("Some content...", "test.txt", "text/plain") File.readAsArrayBuffer(file) @@ -76,11 +77,11 @@ module File { /* Reads the contents of the given file as a Data URL. - files = + let files = await File.select("text/plain") - url = - File.readAsDataURL(file) + let url = + await File.readAsDataURL(file) url == "data:text/plain;...." */ @@ -100,10 +101,10 @@ module File { /* Reads the contents of the given file as a String. - file = + let file = File.create("Some content...", "test.txt", "text/plain") - url = + let url = await File.readAsString(file) url == "Some content..." @@ -127,7 +128,7 @@ module File { * The mime type can be restricted to the given one. * It might not resolve if the user cancels the dialog. - file = + let file = await File.select("application/json") Debug.log(file) @@ -165,7 +166,7 @@ module File { * The mime type can be restricted to the given one. * It might not resolve if the user cancels the dialog. - files = + let files = await File.selectMultiple("application/json") Debug.log(files) diff --git a/core/source/FileSize.mint b/core/source/FileSize.mint index b9af09faa..566a8fa89 100644 --- a/core/source/FileSize.mint +++ b/core/source/FileSize.mint @@ -8,16 +8,23 @@ module FileSize { FileSize.format(1073741824) == "1 GB" */ fun format (size : Number) : String { - ` - (() => { - if (#{size} == 0){ - return "0 B" - } else { - const index = Math.floor(Math.log(#{size}) / Math.log(1024)); - const affix = ['B', 'kB', 'MB', 'GB', 'TB'][index] - return (#{size} / Math.pow(1024, index)).toFixed(2) * 1 + ' ' + affix; - } - })() - ` + if size == 0 { + "0 B" + } else { + let index = + Math.floor(Math.log(size) / Math.log(1024)) + + let affix = + ["B", "kB", "MB", "GB", "TB"][index] or "" + + // We calculate the number, then convert it to String + // with 2 decimals and then parse it again. + let number = + (size / Math.pow(1024, index) + |> Number.toFixed(2) + |> Number.fromString()) or 0 + + "#{number} #{affix}" + } } } diff --git a/core/source/Html.Event.mint b/core/source/Html.Event.mint index df154af1b..4b4974f6c 100644 --- a/core/source/Html.Event.mint +++ b/core/source/Html.Event.mint @@ -1,46 +1,54 @@ /* Represents an HTML event. */ type Html.Event { - bubbles : Bool, - cancelable : Bool, + event : Html.NativeEvent, + + clipboardData : Html.DataTransfer, + dataTransfer : Html.DataTransfer, + currentTarget : Dom.Element, + target : Dom.Element, + defaultPrevented : Bool, - dataTransfer : Html.DataTransfer, - clipboardData : Html.DataTransfer, - eventPhase : Number, + cancelable : Bool, isTrusted : Bool, - target : Dom.Element, - timeStamp : Number, + bubbles : Bool, + repeat : Bool, + + shiftKey : Bool, + metaKey : Bool, + ctrlKey : Bool, + altKey : Bool, + + animationName : String, + pseudoElement : String, + propertyName : String, + locale : String, type : String, data : String, - altKey : Bool, - charCode : Number, - ctrlKey : Bool, key : String, - keyCode : Number, - locale : String, + + elapsedTime : Number, + eventPhase : Number, + timeStamp : Number, + charCode : Number, location : Number, - metaKey : Bool, - repeat : Bool, - shiftKey : Bool, - which : Number, - button : Number, + keyCode : Number, buttons : Number, + button : Number, + detail : Number, + which : Number, + clientX : Number, clientY : Number, - pageX : Number, - pageY : Number, screenX : Number, screenY : Number, - detail : Number, + pageX : Number, + pageY : Number, + deltaMode : Number, deltaX : Number, deltaY : Number, - deltaZ : Number, - animationName : String, - pseudoElement : String, - propertyName : String, - elapsedTime : Number, - event : Html.NativeEvent + deltaZ : Number } /* Utility functions for `Html.Event` */ @@ -145,53 +153,6 @@ module Html.Event { const Y = 89 const Z = 90 - /* Converts a native event into a Mint one. */ - fun fromEvent (event : Html.NativeEvent) : Html.Event { - { - bubbles: `#{event}.bubbles`, - cancelable: `#{event}.cancelable`, - currentTarget: `#{event}.currentTarget`, - defaultPrevented: `#{event}.defaultPrevented`, - dataTransfer: `#{event}.dataTransfer`, - clipboardData: `#{event}.clipboardData`, - eventPhase: `#{event}.eventPhase`, - isTrusted: `#{event}.isTrusted`, - target: `#{event}.target`, - timeStamp: `#{event}.timeStamp`, - type: `#{event}.type`, - data: `#{event}.data`, - altKey: `#{event}.altKey`, - charCode: `#{event}.charCode`, - ctrlKey: `#{event}.ctrlKey`, - key: `#{event}.key`, - keyCode: `#{event}.keyCode`, - locale: `#{event}.locale`, - location: `#{event}.location`, - metaKey: `#{event}.metaKey`, - repeat: `#{event}.repeat`, - shiftKey: `#{event}.shiftKey`, - which: `#{event}.which`, - button: `#{event}.button`, - buttons: `#{event}.buttons`, - clientX: `#{event}.clientX`, - clientY: `#{event}.clientY`, - pageX: `#{event}.pageX`, - pageY: `#{event}.pageY`, - screenX: `#{event}.screenX`, - screenY: `#{event}.screenY`, - detail: `#{event}.detail`, - deltaMode: `#{event}.deltaMode`, - deltaX: `#{event}.deltaX`, - deltaY: `#{event}.deltaY`, - deltaZ: `#{event}.deltaZ`, - animationName: `#{event}.animationName`, - pseudoElement: `#{event}.pseudoElement`, - propertyName: `#{event}.propertyName`, - elapsedTime: `#{event}.elapsedTime`, - event: event - } - } - /* Returns whether or not the events propagation is stopped or not. diff --git a/core/source/Html.Portals.Body.mint b/core/source/Html.Portals.Body.mint index 0ce197ad6..65399eaa2 100644 --- a/core/source/Html.Portals.Body.mint +++ b/core/source/Html.Portals.Body.mint @@ -5,6 +5,6 @@ component Html.Portals.Body { /* Renders the children into the document's body. */ fun render : Html { - `_createPortal(#{children}, document.body)` + `#{%createPortal%}(#{children}, document.body)` } } diff --git a/core/source/Html.Portals.Head.mint b/core/source/Html.Portals.Head.mint index 478bfdedb..c3e427a05 100644 --- a/core/source/Html.Portals.Head.mint +++ b/core/source/Html.Portals.Head.mint @@ -5,6 +5,6 @@ component Html.Portals.Head { /* Renders the children into the document's head. */ fun render : Html { - `_createPortal(#{children}, document.head)` + `#{%createPortal%}(#{children}, document.head)` } } diff --git a/core/source/Html.mint b/core/source/Html.mint index fce170fb7..5745b12d8 100644 --- a/core/source/Html.mint +++ b/core/source/Html.mint @@ -7,7 +7,7 @@ module Html { Html.empty() } else {
- <{ items }> + items
} */ diff --git a/core/source/Http.mint b/core/source/Http.mint index 45a23cf80..c0a95439e 100644 --- a/core/source/Http.mint +++ b/core/source/Http.mint @@ -63,15 +63,17 @@ request = await |> Http.send() case (request) { - Result::Ok(response) => + Result.Ok(response) => Debug.log(response) - Result::Err(error) => + Result.Err(error) => Debug.log(error) } ``` */ module Http { + const REQUESTS = `{}` + /* Aborts all running requests. @@ -79,9 +81,9 @@ module Http { */ fun abortAll : Void { ` - this._requests && Object.keys(this._requests).forEach((uid) => { - this._requests[uid].abort() - delete this._requests[uid] + #{REQUESTS} && Object.keys(#{REQUESTS}).forEach((uid) => { + #{REQUESTS}[uid].abort() + delete #{REQUESTS}[uid] }) ` } @@ -245,11 +247,6 @@ module Http { |> url(urlValue) } - /* Returns all running requests. */ - fun requests : Map(String, Http.NativeRequest) { - `this._requests` - } - /* Sends the request with a unique ID (generated by default) so it could be aborted later. @@ -263,11 +260,9 @@ module Http { ) : Promise(Result(Http.ErrorResponse, Http.Response)) { ` new Promise((resolve, reject) => { - if (!this._requests) { this._requests = {} } - let xhr = new XMLHttpRequest() - this._requests[#{uid}] = xhr + #{REQUESTS}[#{uid}] = xhr xhr.withCredentials = #{request.withCredentials} xhr.responseType = "blob" @@ -286,11 +281,11 @@ module Http { try { xhr.open(#{request.method}.toUpperCase(), #{request.url}, true) } catch (error) { - delete this._requests[#{uid}] + delete #{REQUESTS}[#{uid}] - resolve(#{Result::Err({ + resolve(#{Result.Err({ headers: `getResponseHeaders()`, - type: Http.Error::BadUrl, + type: Http.Error.BadUrl, status: `xhr.status`, url: request.url })}) @@ -301,29 +296,29 @@ module Http { }) xhr.addEventListener('error', (event) => { - delete this._requests[#{uid}] + delete #{REQUESTS}[#{uid}] - resolve(#{Result::Err({ + resolve(#{Result.Err({ headers: `getResponseHeaders()`, - type: Http.Error::NetworkError, + type: Http.Error.NetworkError, status: `xhr.status`, url: request.url })}) }) xhr.addEventListener('timeout', (event) => { - delete this._requests[#{uid}] + delete #{REQUESTS}[#{uid}] - resolve(#{Result::Err({ + resolve(#{Result.Err({ headers: `getResponseHeaders()`, - type: Http.Error::Timeout, + type: Http.Error.Timeout, status: `xhr.status`, url: request.url })}) }) xhr.addEventListener('load', async (event) => { - delete this._requests[#{uid}] + delete #{REQUESTS}[#{uid}] let contentType = xhr.getResponseHeader("Content-Type"); let responseText = await xhr.response.text(); @@ -337,9 +332,9 @@ module Http { object.querySelector("parsererror"); if (errorNode) { - body = #{Http.ResponseBody::Text(`responseText`)}; + body = #{Http.ResponseBody.Text(`responseText`)}; } else { - body = #{Http.ResponseBody::HTML(`object`)}; + body = #{Http.ResponseBody.HTML(`object`)}; } } else if (contentType.startsWith("application/xml")) { const object = @@ -349,26 +344,26 @@ module Http { object.querySelector("parsererror"); if (errorNode) { - body = #{Http.ResponseBody::Text(`responseText`)}; + body = #{Http.ResponseBody.Text(`responseText`)}; } else { - body = #{Http.ResponseBody::XML(`object`)}; + body = #{Http.ResponseBody.XML(`object`)}; } } else if (contentType.startsWith("application/json")) { try { - body = #{Http.ResponseBody::JSON(`JSON.parse(responseText)`)}; + body = #{Http.ResponseBody.JSON(`JSON.parse(responseText)`)}; } catch (e) { - body = #{Http.ResponseBody::Text(`responseText`)}; + body = #{Http.ResponseBody.Text(`responseText`)}; } } else if (contentType.startsWith("text/")) { - body = #{Http.ResponseBody::Text(`responseText`)}; + body = #{Http.ResponseBody.Text(`responseText`)}; } if (!body) { const parts = #{Url.parse(request.url).path}.split('/'); - body = #{Http.ResponseBody::File(`new File([xhr.response], parts[parts.length - 1], { type: contentType })`)}; + body = #{Http.ResponseBody.File(`new File([xhr.response], parts[parts.length - 1], { type: contentType })`)}; } - resolve(#{Result::Ok({ + resolve(#{Result.Ok({ headers: `getResponseHeaders()`, bodyString: `responseText`, status: `xhr.status`, @@ -377,11 +372,11 @@ module Http { }) xhr.addEventListener('abort', (event) => { - delete this._requests[#{uid}] + delete #{REQUESTS}[#{uid}] - resolve(#{Result::Err({ + resolve(#{Result.Err({ headers: `getResponseHeaders()`, - type: Http.Error::Aborted, + type: Http.Error.Aborted, status: `xhr.status`, url: request.url })}) diff --git a/core/source/Json.mint b/core/source/Json.mint index 632b6375e..5aeff88fc 100644 --- a/core/source/Json.mint +++ b/core/source/Json.mint @@ -11,9 +11,9 @@ module Json { ` (() => { try { - return #{Result::Ok(`JSON.parse(#{input})`)} + return #{Result.Ok(`JSON.parse(#{input})`)} } catch (error) { - return #{Result::Err(`error.message`)} + return #{Result.Err(`error.message`)} } })() ` diff --git a/core/source/Locale.mint b/core/source/Locale.mint index 4942067ab..ad1de429c 100644 --- a/core/source/Locale.mint +++ b/core/source/Locale.mint @@ -1,17 +1,17 @@ module Locale { /* Sets the current locale. */ fun set (locale : String) : Bool { - `_L.set(#{locale})` + `#{%setLocale%}(#{locale})` } /* Returns the current locale. */ fun get : Maybe(String) { ` (() => { - if (_L.locale) { - return #{Maybe::Just(`_L.locale`)} + if (#{%locale%}) { + return #{Maybe.Just(`#{%locale%}`)} } else { - return #{Maybe::Nothing} + return #{Maybe.Nothing} } })() ` diff --git a/core/source/Map.mint b/core/source/Map.mint index b036341b2..5d7980d5e 100644 --- a/core/source/Map.mint +++ b/core/source/Map.mint @@ -15,7 +15,7 @@ module Map { fun delete (map : Map(key, value), keyToDelete : key) : Map(key, value) { Map.fromArray( for key, value of map { - #(key, value) + {key, value} } when { key != keyToDelete }) @@ -32,7 +32,7 @@ module Map { fun deleteValues (map : Map(key, value), valueToDelete : value) : Map(key, value) { Map.fromArray( for key, value of map { - #(key, value) + {key, value} } when { value != valueToDelete }) @@ -178,7 +178,7 @@ module Map { ) : Map(key, result) { Map.fromArray( for key, value of map { - (#(key, function(key, value))) + {key, function(key, value)} }) } @@ -194,7 +194,7 @@ module Map { |> Map.set("a", "y") (Map.merge(a, b) - |> Map.get("a")) == Maybe::Just("y") + |> Map.get("a")) == Maybe.Just("y") */ fun merge (map1 : Map(key, value), map2 : Map(key, value)) : Map(key, value) { Map.reduce( @@ -248,7 +248,7 @@ module Map { let set = false for (let item of #{map}) { - if (_compare(item[0], #{key})) { + if (#{%compare%}(item[0], #{key})) { set = true result.push([#{key}, #{value}]) } else { @@ -292,7 +292,7 @@ module Map { method : Function(key, value, result) ) : Map(key, value) { ` - Array.from(#{map}).sort((a, b) => { + [...#{map}].sort((a, b) => { let aVal = #{method}(a[0], a[1]) let bVal = #{method}(b[0], b[1]) diff --git a/core/source/Math.mint b/core/source/Math.mint index 899e2476f..b8f25833f 100644 --- a/core/source/Math.mint +++ b/core/source/Math.mint @@ -118,13 +118,13 @@ module Math { `Math.cosh(#{number})` } - /* Returns the value of `Math:E` raised to the power x, where x is the given number */ + /* Returns the value of `Math.E` raised to the power x, where x is the given number */ fun exp (x : Number) : Number { `Math.exp(#{x})` } /* - Returns the value of `Math:E` to the power x, minus 1 + Returns the value of `Math.E` to the power x, minus 1 Math.exp(2) == 7.38905609893065 Math.expm1(2) == 6.38905609893065 diff --git a/core/source/Maybe.mint b/core/source/Maybe.mint index d530f505a..0eef179a2 100644 --- a/core/source/Maybe.mint +++ b/core/source/Maybe.mint @@ -8,12 +8,12 @@ module Maybe { /* Maps the value of a maybe with a possibility to discard it. - Maybe::Just(4) + Maybe.Just(4) |> Maybe.andThen((num : Number) : Maybe(String) { if (num > 4) { - Maybe::Just(Number.toString(num)) + Maybe.Just(Number.toString(num)) } else { - Maybe::Nothing + Maybe.Nothing } }) */ @@ -22,30 +22,30 @@ module Maybe { transform : Function(value, Maybe(result)) ) : Maybe(result) { case maybe { - Maybe.Just(value) => transform(value) - Maybe.Nothing => Maybe.Nothing + Just(value) => transform(value) + Nothing => Maybe.Nothing } } /* Flattens a nested maybe. - (Maybe.just("A") - |> Maybe.just() - |> Maybe.flatten()) == Maybe.just("A") + (Maybe.Just("A") + |> Maybe.Just() + |> Maybe.flatten()) == Maybe.Just("A") */ fun flatten (maybe : Maybe(Maybe(value))) : Maybe(value) { case maybe { - Maybe.Nothing => Maybe.Nothing - Maybe.Just(value) => value + Nothing => Maybe.Nothing + Just(value) => value } } /* Returns whether or not the maybe is just a value or not. - Maybe.isJust(Maybe.just("A")) == true - Maybe.isJust(Maybe.nothing()) == false + Maybe.isJust(Maybe.Just("A")) == true + Maybe.isJust(Maybe.Nothing) == false */ fun isJust (maybe : Maybe(value)) : Bool { maybe != Maybe.Nothing @@ -54,8 +54,8 @@ module Maybe { /* Returns whether or not the maybe is just nothing or not. - Maybe.isNothing(Maybe.just("A")) == false - Maybe.isNothing(Maybe.nothing("A")) == false + Maybe.isNothing(Maybe.Just("A")) == false + Maybe.isNothing(Maybe.Nothing("A")) == false */ fun isNothing (maybe : Maybe(value)) : Bool { maybe == Maybe.Nothing @@ -69,13 +69,13 @@ module Maybe { /* Maps the value of a maybe. - (Maybe.just(1) + (Maybe.Just(1) |> Maybe.map((number : Number) : Number { number + 2 })) == 3 */ fun map (maybe : Maybe(value), func : Function(value, result)) : Maybe(result) { case maybe { - Maybe.Just(value) => Maybe.Just(func(value)) - Maybe.Nothing => Maybe.Nothing + Just(value) => Maybe.Just(func(value)) + Nothing => Maybe.Nothing } } @@ -87,32 +87,32 @@ module Maybe { /* Returns the first maybe with value of the array or nothing if all are nothing. - Maybe.oneOf([Maybe.just("A"), Maybe.nothing()]) == Maybe.just("A") + Maybe.oneOf([Maybe.Just("A"), Maybe.Nothing]) == Maybe.just("A") */ fun oneOf (array : Array(Maybe(value))) : Maybe(value) { array - |> Array.find((item : Maybe(value)) : Bool { Maybe.isJust(item) }) + |> Array.find(Maybe.isJust) |> flatten() } /* Converts the maybe to a result using the given value as the error. - Maybe.toResult(Maybe.nothing(), "Error") == Result.error("Error") - Maybe.toResult(Maybe.just("A"), "Error") == Result.ok("A") + Maybe.toResult(Maybe.Nothing, "Error") == Result.Error("Error") + Maybe.toResult(Maybe.Just("A"), "Error") == Result.Ok("A") */ fun toResult (maybe : Maybe(value), error : error) : Result(error, value) { case maybe { - Maybe.Just(value) => Result.Ok(value) - Maybe.Nothing => Result.Err(error) + Just(value) => Result.Ok(value) + Nothing => Result.Err(error) } } /* Returns the value of a maybe or the given value if it's nothing. - Maybe.withDefault(Maybe.nothing(), "A") == "A" - Maybe.withDefault(Maybe.just("B"), "A") == "B" + Maybe.withDefault(Maybe.Nothing, "A") == "A" + Maybe.withDefault(Maybe.Just("B"), "A") == "B" */ fun withDefault (maybe : Maybe(value), defaultValue : value) : value { maybe or defaultValue @@ -126,8 +126,8 @@ module Maybe { */ fun withLazyDefault (maybe : Maybe(value), func : Function(value)) : value { case maybe { - Maybe.Nothing => func() - Maybe.Just(value) => value + Just(value) => value + Nothing => func() } } } diff --git a/core/source/Number.mint b/core/source/Number.mint index 5131a5632..183eddd99 100644 --- a/core/source/Number.mint +++ b/core/source/Number.mint @@ -43,16 +43,16 @@ module Number { ` (() => { if (#{input}.trim() === '') { - return #{Maybe::Nothing} + return #{Maybe.Nothing} } let value = Number(#{input}) if (Number.isNaN(value)) { - return #{Maybe::Nothing} + return #{Maybe.Nothing} } - return #{Maybe::Just(`value`)} + return #{Maybe.Just(`value`)} })() ` } diff --git a/core/source/Object/Decode.mint b/core/source/Object/Decode.mint index 85649fcf2..11158da8b 100644 --- a/core/source/Object/Decode.mint +++ b/core/source/Object/Decode.mint @@ -3,67 +3,67 @@ module Object.Decode { /* Decodes the object as an `Array` using the given decoder. - Object.Decode.array(`["A", "B"]`, Object.Decode.string) == Result::Ok(["a", "b"]) + Object.Decode.array(`["A", "B"]`, Object.Decode.string) == Result.Ok(["a", "b"]) */ fun array ( input : Object, decoder : Function(Object, Result(Object.Error, a)) ) : Result(Object.Error, Array(a)) { - `Decoder.array(#{decoder})(#{input})` + `#{%decodeArray%}(#{decoder}, #{%ok%}, #{%err%})(#{input})` } /* Decodes the object as a `Bool` - Object.Decode.boolean(`true`) == Result::Ok(true) + Object.Decode.boolean(`true`) == Result.Ok(true) */ fun boolean (input : Object) : Result(Object.Error, Bool) { - `Decoder.boolean(#{input})` + `#{%decodeBoolean%}(#{%ok%}, #{%err%})(#{input})` } /* Decodes a field from an object using the given decoder. Object.Decode.field( - `{field: "Value"}`, "field", Object.Decode.string) == Result::Ok("Value") + `{field: "Value"}`, "field", Object.Decode.string) == Result.Ok("Value") */ fun field ( input : Object, key : String, decoder : Function(Object, Result(Object.Error, a)) ) : Result(Object.Error, a) { - `Decoder.field(#{key}, #{decoder})(#{input})` + `#{%decodeField%}(#{key}, #{decoder}, #{%err%})(#{input})` } /* Decodes the object as a `Maybe(a)` using the given decoder. - Object.Decode.maybe(`"A"`, Object.Decode.String) == Result::Ok(Maybe::Just("A")) - Object.Decode.maybe(`null`, Object.Decode.String) == Result::Ok(Maybe::Nothing) + Object.Decode.maybe(`"A"`, Object.Decode.String) == Result.Ok(Maybe.Just("A")) + Object.Decode.maybe(`null`, Object.Decode.String) == Result.Ok(Maybe.Nothing) */ fun maybe ( input : Object, decoder : Function(Object, Result(Object.Error, a)) ) : Result(Object.Error, Maybe(a)) { - `Decoder.maybe(#{decoder})(#{input})` + `#{%decodeMaybe%}(#{decoder}, #{%ok%}, #{%err%}, #{%just%}, #{%nothing%})(#{input})` } /* Decodes the object as a `Number` - Object.Decode.number(`0`) == Result::Ok(0) + Object.Decode.number(`0`) == Result.Ok(0) */ fun number (input : Object) : Result(Object.Error, Number) { - `Decoder.number(#{input})` + `#{%decodeNumber%}(#{%ok%}, #{%err%})(#{input})` } /* Decodes the object as a `String` - Object.Decode.string(`"A"`) == Result::Ok("A") + Object.Decode.string(`"A"`) == Result.Ok("A") */ fun string (input : Object) : Result(Object.Error, String) { - `Decoder.string(#{input})` + `#{%decodeString%}(#{%ok%}, #{%err%})(#{input})` } /* @@ -72,6 +72,6 @@ module Object.Decode { Object.Decode.time(`"new Date()"`) */ fun time (input : Object) : Result(Object.Error, Time) { - `Decoder.time(#{input})` + `#{%decodeTime%}(#{%ok%}, #{%err%})(#{input})` } } diff --git a/core/source/Provider/ElementSize.mint b/core/source/Provider/ElementSize.mint index 0eaf8eb03..d51d124ff 100644 --- a/core/source/Provider/ElementSize.mint +++ b/core/source/Provider/ElementSize.mint @@ -32,14 +32,9 @@ provider Provider.ElementSize : Provider.ElementSize.Subscription { } for subscription of subscriptions { - case subscription.element { - Maybe.Just(element) => - { - ResizeObserver.observe(observer, element) - void - } - - Maybe.Nothing => void + if let Maybe.Just(element) = subscription.element { + ResizeObserver.observe(observer, element) + void } } diff --git a/core/source/Provider/Intersection.mint b/core/source/Provider/Intersection.mint index 89141dc26..49ded2784 100644 --- a/core/source/Provider/Intersection.mint +++ b/core/source/Provider/Intersection.mint @@ -19,20 +19,15 @@ provider Provider.Intersection : Provider.Intersection.Subscription { */ let currentObservers = for item of observers { - let #(subscription, observer) = + let {subscription, observer} = item if Array.contains(subscriptions, subscription) { - Maybe.Just(#(subscription, observer)) + Maybe.Just({subscription, observer}) } else { - case subscription.element { - Maybe.Just(observed) => - { - IntersectionObserver.unobserve(observer, observed) - Maybe.Nothing - } - - => Maybe.Nothing + if let Maybe.Just(observed) = subscription.element { + IntersectionObserver.unobserve(observer, observed) + Maybe.Nothing } } } @@ -41,32 +36,24 @@ provider Provider.Intersection : Provider.Intersection.Subscription { /* Create new observers. */ let newObservers = for subscription of subscriptions { - case subscription.element { - Maybe.Just(observed) => - Maybe.Just( - #( - subscription, - IntersectionObserver.new( - subscription.rootMargin, - subscription.threshold, - subscription.callback) - |> IntersectionObserver.observe(observed) - )) - - => Maybe.Nothing + if let Maybe.Just(observed) = subscription.element { + Maybe.Just( + { + subscription, + IntersectionObserver.new( + subscription.rootMargin, + subscription.threshold, + subscription.callback) + |> IntersectionObserver.observe(observed) + }) } } when { - let size = - observers - |> Array.select( - ( - item : Tuple(Provider.Intersection.Subscription, IntersectionObserver) - ) { - item[0] == subscription - }) - |> Array.size() - - (size == 0) + Array.size( + for item of observers { + item + } when { + item[0] == subscription + }) == 0 } |> Array.compact() diff --git a/core/source/Provider/Keyboard.mint b/core/source/Provider/Keyboard.mint index bfc3d2097..6acf0ff7c 100644 --- a/core/source/Provider/Keyboard.mint +++ b/core/source/Provider/Keyboard.mint @@ -15,7 +15,7 @@ provider Provider.Keyboard : Provider.Keyboard.Subscription { Maybe.map( listeners, (methods : Tuple(Function(Void), Function(Void))) { - let #(keydownListener, keyupListener) = + let {keydownListener, keyupListener} = methods keydownListener() @@ -24,33 +24,30 @@ provider Provider.Keyboard : Provider.Keyboard.Subscription { next { listeners: Maybe.Nothing } } else { - case listeners { - Maybe.Nothing => - next - { - listeners: - Maybe.Just( - #( - Window.addEventListener( - "keydown", - true, - (event : Html.Event) { - for subscription of subscriptions { - subscription.downs(event) - } - }), - Window.addEventListener( - "keyup", - true, - (event : Html.Event) { - for subscription of subscriptions { - subscription.ups(event) - } - }) - )) - } - - => next { } + if listeners == Maybe.Nothing { + next + { + listeners: + Maybe.Just( + { + Window.addEventListener( + "keydown", + true, + (event : Html.Event) { + for subscription of subscriptions { + subscription.downs(event) + } + }), + Window.addEventListener( + "keyup", + true, + (event : Html.Event) { + for subscription of subscriptions { + subscription.ups(event) + } + }) + }) + } } } } diff --git a/core/source/Provider/MediaQuery.mint b/core/source/Provider/MediaQuery.mint index 3f2bc463d..6284b5f49 100644 --- a/core/source/Provider/MediaQuery.mint +++ b/core/source/Provider/MediaQuery.mint @@ -21,22 +21,21 @@ provider Provider.MediaQuery : Provider.MediaQuery.Subscription { memo : Map(String, Function(Void)), subscription : Provider.MediaQuery.Subscription ) { - case Map.get(listeners, subscription.query) { - Maybe.Nothing => - Map.set( - memo, + if Map.get(listeners, subscription.query) == Maybe.Nothing { + Map.set( + memo, + subscription.query, + Window.addMediaQueryListener( subscription.query, - Window.addMediaQueryListener( - subscription.query, - (active : Bool) { - for item of subscriptions { - subscription.changes(active) - } when { - item.query == subscription.query - } - })) - - Maybe.Just => memo + (active : Bool) { + for item of subscriptions { + subscription.changes(active) + } when { + item.query == subscription.query + } + })) + } else { + memo } }) @@ -54,14 +53,12 @@ provider Provider.MediaQuery : Provider.MediaQuery.Subscription { |> Array.find( (item : Provider.MediaQuery.Subscription) { item.query == query }) - case subscription { - Maybe.Just => memo - - Maybe.Nothing => - { - listener() - Map.delete(memo, query) - } + if subscription == Maybe.Nothing { + // Unsubscribe + listener() + Map.delete(memo, query) + } else { + memo } }) diff --git a/core/source/Provider/Mouse.mint b/core/source/Provider/Mouse.mint index 88821337f..45c7330d8 100644 --- a/core/source/Provider/Mouse.mint +++ b/core/source/Provider/Mouse.mint @@ -21,7 +21,7 @@ provider Provider.Mouse : Provider.Mouse.Subscription { ( methods : Tuple(Function(Void), Function(Void), Function(Void)) ) { - let #(clickListener, moveListener, upListener) = + let {clickListener, moveListener, upListener} = methods clickListener() @@ -31,50 +31,47 @@ provider Provider.Mouse : Provider.Mouse.Subscription { next { listeners: Maybe.Nothing } } else { - case listeners { - Maybe.Nothing => - next - { - listeners: - Maybe.Just( - #( - Window.addEventListener( - "click", - true, - (event : Html.Event) { - for subscription of subscriptions { - subscription.clicks(event) - } - }), - Window.addEventListener( - "mousemove", - false, - (event : Html.Event) { - AnimationFrame.cancel(id) + if listeners == Maybe.Nothing { + next + { + listeners: + Maybe.Just( + { + Window.addEventListener( + "click", + true, + (event : Html.Event) { + for subscription of subscriptions { + subscription.clicks(event) + } + }), + Window.addEventListener( + "mousemove", + false, + (event : Html.Event) { + AnimationFrame.cancel(id) - next - { - id: - AnimationFrame.request( - (timestamp : Number) { - for subscription of subscriptions { - subscription.moves(event) - } - }) - } - }), - Window.addEventListener( - "mouseup", - false, - (event : Html.Event) { - for subscription of subscriptions { - subscription.ups(event) + next + { + id: + AnimationFrame.request( + (timestamp : Number) { + for subscription of subscriptions { + subscription.moves(event) + } + }) } - }) - )) - } - - => next { } + }), + Window.addEventListener( + "mouseup", + false, + (event : Html.Event) { + for subscription of subscriptions { + subscription.ups(event) + } + }) + }) + } } } } diff --git a/core/source/Provider/Mutation.mint b/core/source/Provider/Mutation.mint index 3e9cb72de..b262b1b3e 100644 --- a/core/source/Provider/Mutation.mint +++ b/core/source/Provider/Mutation.mint @@ -19,15 +19,10 @@ provider Provider.Mutation : Provider.Mutation.Subscription { fun notify (entries : Array(MutationObserver.Entry)) : Array(Array(Promise(Void))) { for entry of entries { for subscription of subscriptions { - case subscription.element { - Maybe.Just(element) => - if Dom.contains(element, entry.target) { - subscription.changes() - } else { - next { } - } - - Maybe.Nothing => next { } + if let Maybe.Just(element) = subscription.element { + if Dom.contains(element, entry.target) { + subscription.changes() + } } } } @@ -42,14 +37,9 @@ provider Provider.Mutation : Provider.Mutation.Subscription { /* For each subscription observe the given elements. */ for subscription of subscriptions { - case subscription.element { - Maybe.Just(element) => - { - MutationObserver.observe(observer, element, true, true) - subscription.changes() - } - - Maybe.Nothing => next { } + if let Maybe.Just(element) = subscription.element { + MutationObserver.observe(observer, element, true, true) + subscription.changes() } } diff --git a/core/source/Provider/OutsideClick.mint b/core/source/Provider/OutsideClick.mint index b6efe9ecd..4d92f2fae 100644 --- a/core/source/Provider/OutsideClick.mint +++ b/core/source/Provider/OutsideClick.mint @@ -31,11 +31,8 @@ provider Provider.OutsideClick : Provider.OutsideClick.Subscription { Maybe.map(listener, (unsubscribe : Function(Void)) { unsubscribe() }) next { listener: Maybe.Nothing } } else { - case listener { - Maybe.Nothing => - next { listener: Maybe.Just(Window.addEventListener("mouseup", true, handle)) } - - => next { } + if listener == Maybe.Nothing { + next { listener: Maybe.Just(Window.addEventListener("mouseup", true, handle)) } } } } diff --git a/core/source/Provider/Pointer.mint b/core/source/Provider/Pointer.mint index 6aa71c90a..a798a5766 100644 --- a/core/source/Provider/Pointer.mint +++ b/core/source/Provider/Pointer.mint @@ -21,7 +21,7 @@ provider Provider.Pointer : Provider.Pointer.Subscription { ( methods : Tuple(Function(Void), Function(Void), Function(Void)) ) { - let #(downListener, moveListener, upListener) = + let {downListener, moveListener, upListener} = methods downListener() @@ -31,50 +31,47 @@ provider Provider.Pointer : Provider.Pointer.Subscription { next { listeners: Maybe.Nothing } } else { - case listeners { - Maybe.Nothing => - next - { - listeners: - Maybe.Just( - #( - Window.addEventListener( - "pointerdown", - true, - (event : Html.Event) { - for subscription of subscriptions { - subscription.downs(event) - } - }), - Window.addEventListener( - "pointermove", - false, - (event : Html.Event) { - AnimationFrame.cancel(id) + if listeners == Maybe.Nothing { + next + { + listeners: + Maybe.Just( + { + Window.addEventListener( + "pointerdown", + true, + (event : Html.Event) { + for subscription of subscriptions { + subscription.downs(event) + } + }), + Window.addEventListener( + "pointermove", + false, + (event : Html.Event) { + AnimationFrame.cancel(id) - next - { - id: - AnimationFrame.request( - (timestamp : Number) { - for subscription of subscriptions { - subscription.moves(event) - } - }) - } - }), - Window.addEventListener( - "pointerup", - false, - (event : Html.Event) { - for subscription of subscriptions { - subscription.ups(event) + next + { + id: + AnimationFrame.request( + (timestamp : Number) { + for subscription of subscriptions { + subscription.moves(event) + } + }) } - }) - )) - } - - => next { } + }), + Window.addEventListener( + "pointerup", + false, + (event : Html.Event) { + for subscription of subscriptions { + subscription.ups(event) + } + }) + }) + } } } } diff --git a/core/source/Provider/Resize.mint b/core/source/Provider/Resize.mint index f34a04dd6..9389241de 100644 --- a/core/source/Provider/Resize.mint +++ b/core/source/Provider/Resize.mint @@ -21,11 +21,8 @@ provider Provider.Resize : Provider.Resize.Subscription { Maybe.map(listener, (unsubscribe : Function(Void)) { unsubscribe() }) next { listener: Maybe.Nothing } } else { - case listener { - Maybe.Nothing => - next { listener: Maybe.Just(Window.addEventListener("resize", true, handle)) } - - => next { } + if listener == Maybe.Nothing { + next { listener: Maybe.Just(Window.addEventListener("resize", true, handle)) } } } } diff --git a/core/source/Provider/Scroll.mint b/core/source/Provider/Scroll.mint index ee8368eee..1a19de4b8 100644 --- a/core/source/Provider/Scroll.mint +++ b/core/source/Provider/Scroll.mint @@ -21,11 +21,8 @@ provider Provider.Scroll : Provider.Scroll.Subscription { Maybe.map(listener, (unsubscribe : Function(Void)) { unsubscribe() }) next { listener: Maybe.Nothing } } else { - case listener { - Maybe.Nothing => - next { listener: Maybe.Just(Window.addEventListener("scroll", false, handle)) } - - => next { } + if listener == Maybe.Nothing { + next { listener: Maybe.Just(Window.addEventListener("scroll", false, handle)) } } } } diff --git a/core/source/Provider/Shortcuts.mint b/core/source/Provider/Shortcuts.mint index 23569da8e..aa956a93d 100644 --- a/core/source/Provider/Shortcuts.mint +++ b/core/source/Provider/Shortcuts.mint @@ -28,15 +28,11 @@ provider Provider.Shortcuts : Provider.Shortcuts.Subscription { let control = if event.ctrlKey && event.keyCode != 17 { Maybe.Just(17) - } else { - Maybe.Nothing } let shift = if event.shiftKey && event.keyCode != 16 { Maybe.Just(16) - } else { - Maybe.Nothing } let combo = @@ -68,11 +64,8 @@ provider Provider.Shortcuts : Provider.Shortcuts.Subscription { Maybe.map(listener, (unsubscribe : Function(Void)) { unsubscribe() }) next { listener: Maybe.Nothing } } else { - case listener { - Maybe.Nothing => - next { listener: Maybe.Just(Window.addEventListener("keydown", true, handle)) } - - => next { } + if listener == Maybe.Nothing { + next { listener: Maybe.Just(Window.addEventListener("keydown", true, handle)) } } } } diff --git a/core/source/Provider/TabFocus.mint b/core/source/Provider/TabFocus.mint index 9e7a96749..7099552fc 100644 --- a/core/source/Provider/TabFocus.mint +++ b/core/source/Provider/TabFocus.mint @@ -21,8 +21,6 @@ provider Providers.TabFocus : Provider.TabFocus.Subscription { } when { subscription.element == activeElement } - } else { - [] } } @@ -37,8 +35,6 @@ provider Providers.TabFocus : Provider.TabFocus.Subscription { } when { subscription.element == target } - } else { - [] } } @@ -48,7 +44,7 @@ provider Providers.TabFocus : Provider.TabFocus.Subscription { Maybe.map( listeners, (methods : Tuple(Function(Void), Function(Void))) { - let #(keyDownListener, keyUpListener) = + let {keyDownListener, keyUpListener} = methods keyDownListener() @@ -57,19 +53,16 @@ provider Providers.TabFocus : Provider.TabFocus.Subscription { next { listeners: Maybe.Nothing } } else { - case listeners { - Maybe.Nothing => - next - { - listeners: - Maybe.Just( - #( - Window.addEventListener("keydown", true, handleKeyDown), - Window.addEventListener("keyup", true, handleKeyUp) - )) - } - - => next { } + if listeners == Maybe.Nothing { + next + { + listeners: + Maybe.Just( + { + Window.addEventListener("keydown", true, handleKeyDown), + Window.addEventListener("keyup", true, handleKeyUp) + }) + } } } } diff --git a/core/source/Provider/Url.mint b/core/source/Provider/Url.mint index 4b2bb2a71..91bff28ef 100644 --- a/core/source/Provider/Url.mint +++ b/core/source/Provider/Url.mint @@ -24,11 +24,8 @@ provider Provider.Url : Provider.Url.Subscription { Maybe.map(listener, (unsubscribe : Function(Void)) { unsubscribe() }) next { listener: Maybe.Nothing } } else { - case listener { - Maybe.Nothing => - next { listener: Maybe.Just(Window.addEventListener("popstate", false, handle)) } - - => next { } + if listener == Maybe.Nothing { + next { listener: Maybe.Just(Window.addEventListener("popstate", false, handle)) } } } } diff --git a/core/source/Provider/Websocket.mint b/core/source/Provider/Websocket.mint index 3b229d4f2..9f7f8d789 100644 --- a/core/source/Provider/Websocket.mint +++ b/core/source/Provider/Websocket.mint @@ -57,22 +57,21 @@ provider Provider.WebSocket : WebSocket.Config { memo : Map(String, WebSocket), config : WebSocket.Config ) { - case Map.get(connections, config.url) { - Maybe.Nothing => - Map.set( - memo, - config.url, - WebSocket.open( - { - onMessage: (message : String) { onMessage(config.url, message) }, - onOpen: (socket : WebSocket) { onOpen(config.url, socket) }, - onClose: () { onClose(config.url) }, - onError: () { onError(config.url) }, - reconnectOnClose: config.reconnectOnClose, - url: config.url - })) - - Maybe.Just => memo + if Map.get(connections, config.url) == Maybe.Nothing { + Map.set( + memo, + config.url, + WebSocket.open( + { + onMessage: (message : String) { onMessage(config.url, message) }, + onOpen: (socket : WebSocket) { onOpen(config.url, socket) }, + onClose: () { onClose(config.url) }, + onError: () { onError(config.url) }, + reconnectOnClose: config.reconnectOnClose, + url: config.url + })) + } else { + memo } }) @@ -86,18 +85,13 @@ provider Provider.WebSocket : WebSocket.Config { socket : WebSocket ) { let subscription = - subscriptions - |> Array.find( - (config : WebSocket.Config) { config.url == url }) - - case subscription { - Maybe.Nothing => - { - WebSocket.closeWithoutReconnecting(socket) - Map.delete(memo, url) - } + Array.find(subscriptions, (config : WebSocket.Config) { config.url == url }) - Maybe.Just => memo + if subscription == Maybe.Nothing { + WebSocket.closeWithoutReconnecting(socket) + Map.delete(memo, url) + } else { + memo } }) diff --git a/core/source/Result.mint b/core/source/Result.mint index 02c3356de..5c8e6c664 100644 --- a/core/source/Result.mint +++ b/core/source/Result.mint @@ -18,95 +18,96 @@ module Result { /* Maps over the value of the result to an other result and flattens it. - (Result.error("error") - |> Result.flatMap(\item : String => Result::Ok(item + "1"))) == Result.error("error") + (Result.Err("error") + |> Result.flatMap(\item : String => Result.Ok(item + "1"))) == Result.error("error") - (Result.ok("ok") - |> Result.map(\item : String => Result::Ok(item + "1"))) == Result.ok("ok1") + (Result.Ok("ok") + |> Result.map(\item : String => Result.Ok(item + "1"))) == Result.ok("ok1") */ fun flatMap ( input : Result(error, a), func : Function(a, Result(error, b)) ) : Result(error, b) { - Result.map(input, func) + input + |> Result.map(func) |> Result.join() } /* Returns true if the result is an error. - (Result.error("error") + (Result.Err("error") |> Result.isError()) == true */ fun isError (input : Result(a, b)) : Bool { case input { - Result.Err => true - Result.Ok => false + Err => true + Ok => false } } /* Returns true if the result is ok. - (Result.ok("ok") + (Result.Ok("ok") |> Result.isOk()) == true */ fun isOk (input : Result(a, b)) : Bool { case input { - Result.Err => false - Result.Ok => true + Err => false + Ok => true } } /* Joins two results together. - Result.join(Result::Ok(Result::Ok("Hello"))) == Result::Ok("Hello") - Result.join(Result::Err("Error") == Result::Err("Error") + Result.join(Result.Ok(Result.Ok("Hello"))) == Result.Ok("Hello") + Result.join(Result.Err("Error") == Result.Err("Error") */ fun join (input : Result(error, Result(error, value))) : Result(error, value) { case input { - Result.Err(error) => Result.Err(error) - Result.Ok(value) => value + Err(error) => Result.Err(error) + Ok(value) => value } } /* Maps over the value of the result. - (Result.error("error") - |> Result.map(\item : String => item + "1")) == Result.error("error") + (Result.Err("error") + |> Result.map(\item : String => item + "1")) == Result.Err("error") - (Result.ok("ok") - |> Result.map(\item : String => item + "1")) == Result.ok("ok1") + (Result.Ok("ok") + |> Result.map(\item : String => item + "1")) == Result.Ok("ok1") */ fun map (input : Result(a, b), func : Function(b, c)) : Result(a, c) { case input { - Result.Ok(value) => Result.Ok(func(value)) - Result.Err => input + Ok(value) => Result.Ok(func(value)) + Err => input } } /* Maps over the error of the result. - (Result.error("error") + (Result.Err("error") |> Result.mapError(\item : String => item + "1")) == Result.error("error1") - (Result.ok("ok") + (Result.Ok("ok") |> Result.mapError(\item : String => item + "1")) == Result.ok("ok") */ fun mapError (input : Result(a, b), func : Function(a, c)) : Result(c, b) { case input { - Result.Err(value) => Result.Err(func(value)) - Result.Ok => input + Err(value) => Result.Err(func(value)) + Ok => input } } /* Returns a new ok result. - (Result.ok("ok") + (Result.Ok("ok") |> Result.isOk()) == true */ fun ok (input : a) : Result(b, a) { @@ -116,48 +117,48 @@ module Result { /* Converts the result into a maybe. - (Result.ok("blah") - |> Result.toMaybe()) == Maybe.just("blah") + (Result.Ok("blah") + |> Result.toMaybe()) == Maybe.Just("blah") - (Result.error("blah") - |> Result.toMaybe()) == Maybe.nothing() + (Result.Err("blah") + |> Result.toMaybe()) == Maybe.Nothing */ fun toMaybe (result : Result(a, b)) : Maybe(b) { case result { - Result.Ok(value) => Maybe.Just(value) - Result.Err => Maybe.Nothing + Ok(value) => Maybe.Just(value) + Err => Maybe.Nothing } } /* Returns the value of the result or the default value if it's an error. - (Result.error("error") + (Result.Err("error") |> Result.withDefault("a")) == "a" - (Result.ok("ok") + (Result.Ok("ok") |> Result.withDefault("a")) == "ok" */ fun withDefault (input : Result(a, b), defaultValue : b) : b { case input { - Result.Ok(value) => value - Result.Err => defaultValue + Ok(value) => value + Err => defaultValue } } /* Returns the error of the result or the default value if it's an ok. - (Result.error("error") + (Result.Err("error") |> Result.withError("a")) == "error" - (Result.ok("ok") + (Result.Ok("ok") |> Result.withError("a")) == "a" */ fun withError (input : Result(a, b), defaultError : a) : a { case input { - Result.Err(value) => value - Result.Ok => defaultError + Err(value) => value + Ok => defaultError } } } diff --git a/core/source/SearchParams.mint b/core/source/SearchParams.mint index f81ebec95..d67217da0 100644 --- a/core/source/SearchParams.mint +++ b/core/source/SearchParams.mint @@ -73,9 +73,9 @@ module SearchParams { let value = #{params}.get(#{key}) if (value === null) { - return #{Maybe::Nothing} + return #{Maybe.Nothing} } else { - return #{Maybe::Just(`value`)} + return #{Maybe.Just(`value`)} } })() ` diff --git a/core/source/Set.mint b/core/source/Set.mint index b450435c4..d18e02285 100644 --- a/core/source/Set.mint +++ b/core/source/Set.mint @@ -32,7 +32,7 @@ module Set { const newSet = [] #{set}.forEach((item) => { - if (_compare(item, #{value})) { return } + if (#{%compare%}(item, #{value})) { return } newSet.push(item) }) @@ -67,7 +67,7 @@ module Set { ` (() => { for (let item of #{set}) { - if (_compare(item, #{value})) { + if (#{%compare%}(item, #{value})) { return true } } diff --git a/core/source/Storage/Common.mint b/core/source/Storage/Common.mint index ccbdfe96e..117f2155b 100644 --- a/core/source/Storage/Common.mint +++ b/core/source/Storage/Common.mint @@ -21,13 +21,13 @@ module Storage.Common { (() => { try { #{storage}.clear() - return #{Result::Ok(void)} + return #{Result.Ok(void)} } catch (error) { switch(error.name) { case 'SecurityError': - return #{Result::Err(Storage.Error::SecurityError)} + return #{Result.Err(Storage.Error.SecurityError)} default: - return #{Result::Err(Storage.Error::Unknown)} + return #{Result.Err(Storage.Error.Unknown)} } } })() @@ -40,13 +40,13 @@ module Storage.Common { (() => { try { #{storage}.removeItem(#{key}) - return #{Result::Ok(void)} + return #{Result.Ok(void)} } catch (error) { switch(error.name) { case 'SecurityError': - return #{Result::Err(Storage.Error::SecurityError)} + return #{Result.Err(Storage.Error.SecurityError)} default: - return #{Result::Err(Storage.Error::Unknown)} + return #{Result.Err(Storage.Error.Unknown)} } } })() @@ -61,16 +61,16 @@ module Storage.Common { let value = #{storage}.getItem(#{key}) if (typeof value === "string") { - return #{Result::Ok(`value`)} + return #{Result.Ok(`value`)} } else { - return #{Result::Err(Storage.Error::NotFound)} + return #{Result.Err(Storage.Error.NotFound)} } } catch (error) { switch(error.name) { case 'SecurityError': - return #{Result::Err(Storage.Error::SecurityError)} + return #{Result.Err(Storage.Error.SecurityError)} default: - return #{Result::Err(Storage.Error::Unknown)} + return #{Result.Err(Storage.Error.Unknown)} } } })() @@ -82,13 +82,13 @@ module Storage.Common { ` (() => { try { - return #{Result::Ok(`Object.keys(#{storage}).sort()`)} + return #{Result.Ok(`Object.keys(#{storage}).sort()`)} } catch (error) { switch(error.name) { case 'SecurityError': - return #{Result::Err(Storage.Error::SecurityError)} + return #{Result.Err(Storage.Error.SecurityError)} default: - return #{Result::Err(Storage.Error::Unknown)} + return #{Result.Err(Storage.Error.Unknown)} } } })() @@ -101,19 +101,19 @@ module Storage.Common { (() => { try { #{storage}.setItem(#{key}, #{value}) - return #{Result::Ok(void)} + return #{Result.Ok(void)} } catch (error) { switch(error.name) { case 'SecurityError': - return #{Result::Err(Storage.Error::SecurityError)} + return #{Result.Err(Storage.Error.SecurityError)} case 'QUOTA_EXCEEDED_ERR': - return #{Result::Err(Storage.Error::QuotaExceeded)} + return #{Result.Err(Storage.Error.QuotaExceeded)} case 'QuotaExceededError': - return #{Result::Err(Storage.Error::QuotaExceeded)} + return #{Result.Err(Storage.Error.QuotaExceeded)} case 'NS_ERROR_DOM_QUOTA_REACHED': - return #{Result::Err(Storage.Error::QuotaExceeded)} + return #{Result.Err(Storage.Error.QuotaExceeded)} default: - return #{Result::Err(Storage.Error::Unknown)} + return #{Result.Err(Storage.Error.Unknown)} } } })() @@ -125,13 +125,13 @@ module Storage.Common { ` (() => { try { - return #{Result::Ok(`#{storage}.length`)} + return #{Result.Ok(`#{storage}.length`)} } catch (error) { switch(error.name) { case 'SecurityError': - return #{Result::Err(Storage.Error::SecurityError)} + return #{Result.Err(Storage.Error.SecurityError)} default: - return #{Result::Err(Storage.Error::Unknown)} + return #{Result.Err(Storage.Error.Unknown)} } } })() diff --git a/core/source/String.mint b/core/source/String.mint index e4191dcff..5387eb4ac 100644 --- a/core/source/String.mint +++ b/core/source/String.mint @@ -23,7 +23,7 @@ module String { Returns an integer between 0 and 65535 representing the UTF-16 code unit at the given index. - String.charCodeAt("The quick brown fox jumps over the lazy dog.", 4) == Maybe::Just(113) + String.charCodeAt("The quick brown fox jumps over the lazy dog.", 4) == Maybe.Just(113) */ fun charCodeAt (string : String, index : Number) : Maybe(Number) { ` @@ -31,9 +31,9 @@ module String { const result = #{string}.charCodeAt(#{index}); if (isNaN(result)) { - return #{Maybe::Nothing} + return #{Maybe.Nothing} } else { - return #{Maybe::Just(`result`)} + return #{Maybe.Just(`result`)} } })() ` @@ -78,12 +78,12 @@ module String { /* Returns a non-negative integer that is the UTF-16 code point value. - * If there is no element at pos, returns `Maybe::Nothing`. + * If there is no element at pos, returns `Maybe.Nothing`. * If the element at pos is a UTF-16 high surrogate, returns the code point of the surrogate pair. * If the element at pos is a UTF-16 low surrogate, returns only the low surrogate code point. - String.codePointAt("☃★♲", 1) == Maybe::Just(9733) + String.codePointAt("☃★♲", 1) == Maybe.Just(9733) */ fun codePointAt (string : String, index : Number) : Maybe(Number) { ` @@ -91,9 +91,9 @@ module String { const result = #{string}.codePointAt(#{index}); if (result === undefined) { - return #{Maybe::Nothing} + return #{Maybe.Nothing} } else { - return #{Maybe::Just(`result`)} + return #{Maybe.Just(`result`)} } })() ` @@ -183,10 +183,10 @@ module String { /* Returns the index within the calling String object of the first occurrence of - the specified value, returns `Maybe::Nothing` if the value is not found. + the specified value, returns `Maybe.Nothing` if the value is not found. - String.indexOf("The quick brown fox jumps over the lazy dog.", "whale") == Maybe::Nothing - String.indexOf("The quick brown fox jumps over the lazy dog.", "fox") == Maybe::Just(16) + String.indexOf("The quick brown fox jumps over the lazy dog.", "whale") == Maybe.Nothing + String.indexOf("The quick brown fox jumps over the lazy dog.", "fox") == Maybe.Just(16) */ fun indexOf (string : String, search : String) : Maybe(Number) { ` @@ -194,9 +194,9 @@ module String { const result = #{string}.indexOf(#{search}); if (result == -1) { - return #{Maybe::Nothing} + return #{Maybe.Nothing} } else { - return #{Maybe::Just(`result`)} + return #{Maybe.Just(`result`)} } })() ` @@ -277,10 +277,10 @@ module String { /* Returns the index within the calling String object of the last occurrence of - the specified value, returns `Maybe::Nothing` if the value is not found. + the specified value, returns `Maybe.Nothing` if the value is not found. - String.lastIndexOf("The quick brown fox jumps over the lazy dog.", "whale") == Maybe::Nothing - String.lastIndexOf("The quick brown fox jumps over the lazy dog.", "the") == Maybe::Just(31) + String.lastIndexOf("The quick brown fox jumps over the lazy dog.", "whale") == Maybe.Nothing + String.lastIndexOf("The quick brown fox jumps over the lazy dog.", "the") == Maybe.Just(31) */ fun lastIndexOf (string : String, search : String) : Maybe(Number) { ` @@ -288,9 +288,9 @@ module String { const result = #{string}.lastIndexOf(#{search}); if (result == -1) { - return #{Maybe::Nothing} + return #{Maybe.Nothing} } else { - return #{Maybe::Just(`result`)} + return #{Maybe.Just(`result`)} } })() ` diff --git a/core/source/Test/Context.mint b/core/source/Test/Context.mint index 9be664d8e..3f8537d97 100644 --- a/core/source/Test/Context.mint +++ b/core/source/Test/Context.mint @@ -11,7 +11,7 @@ module Test.Context { fun assertEqual (context : Test.Context(a), value : a) : Test.Context(a) { ` #{context}.step((subject) => { - if (!_compare(#{value}, subject)) { + if (!#{%compare%}(#{value}, subject)) { throw \`Assertion failed: ${#{value}} === ${subject}\` } return subject @@ -61,7 +61,7 @@ module Test.Context { #{context}.step((subject) => { const actual = #{method}(subject) - if (!_compare(#{value}, actual)) { + if (!#{%compare%}(#{value}, actual)) { throw \`Assertion failed: ${actual} === ${#{value}}\` } return subject @@ -69,6 +69,29 @@ module Test.Context { ` } + /* + Asserts if the given value equals of the returned value from the given + function. + + test { + Test.Context.of(5) + |> Test.Context.assert((value : Number) { value == 5 }) + } + */ + fun assert ( + context : Test.Context(a), + method : Function(a, bool) + ) : Test.Context(a) { + ` + #{context}.step((subject) => { + if (!#{method}(subject)) { + throw \`Assertion failed!\` + } + return subject + }) + ` + } + /* Maps the given subject to a new subject. @@ -90,7 +113,7 @@ module Test.Context { } */ fun of (a : a) : Test.Context(a) { - `new TestContext(#{a})` + `new #{%testContext%}(#{a})` } /* Spies on the given entity if it's a function. */ diff --git a/core/source/Test/Html.mint b/core/source/Test/Html.mint index 6dff3b299..bdd831661 100644 --- a/core/source/Test/Html.mint +++ b/core/source/Test/Html.mint @@ -3,20 +3,20 @@ module Test.Html { /* Starts a test of an `Html` node. - Test.Html.start(
<{ "Content" }>
) + Test.Html.start(
"Content"
) */ fun start (node : Html) : Test.Context(Dom.Element) { - ` + (` (() => { const root = document.createElement("div") document.body.appendChild(root) - ReactDOM.render(#{node}, root) - return new TestContext(root, () => { - ReactDOM.unmountComponentAtNode(root) + #{%testRender%}(#{node}, root) + return new #{%testContext%}(root, () => { document.body.removeChild(root) }) })() - ` + ` as Test.Context(Dom.Element)) + |> Test.Context.timeout(0) } fun find ( diff --git a/core/source/Time.mint b/core/source/Time.mint index d171538e8..fcf67c633 100644 --- a/core/source/Time.mint +++ b/core/source/Time.mint @@ -28,9 +28,9 @@ module Time { ` (() => { try { - return #{Maybe::Just(`new Date(#{raw})`)} + return #{Maybe.Just(`new Date(#{raw})`)} } catch (error) { - return #{Maybe::Nothing} + return #{Maybe.Nothing} } })() ` @@ -164,7 +164,7 @@ module Time { /* Returns the month of the given time (as a `Month`). - Time.month(Time.utcDate(2018, 4, 5)) == Month::April + Time.month(Time.utcDate(2018, 4, 5)) == Month.April */ fun month (time : Time) : Month { case monthNumber(time) { @@ -267,7 +267,7 @@ module Time { /* Returns the day of week of the given time. - Time.dayOfWeek(Time.utcDate(2018, 4, 5)) == Weekday::Thursday + Time.dayOfWeek(Time.utcDate(2018, 4, 5)) == Weekday.Thursday */ fun dayOfWeek (time : Time) : Weekday { case dayOfWeekNumber(time) { @@ -370,7 +370,7 @@ module Time { /* Shifts the given time using the given time span. - Time.shift(Time.utcDate(2018, 4, 5), Time.Span::Days(2)) == + Time.shift(Time.utcDate(2018, 4, 5), Time.Span.Days(2)) == Time.utcDate(2018, 4, 7) */ fun shift (time : Time, delta : Time.Span) : Time { @@ -380,28 +380,28 @@ module Time { #{ case (delta) { - Time.Span::Milliseconds(amount) => + Time.Span.Milliseconds(amount) => `time.setUTCMilliseconds(time.getUTCMilliseconds() + #{amount})` - Time.Span::Seconds(amount) => + Time.Span.Seconds(amount) => `time.setUTCSeconds(time.getUTCSeconds() + #{amount})` - Time.Span::Minutes(amount) => + Time.Span.Minutes(amount) => `time.setUTCMinutes(time.getUTCMinutes() + #{amount})` - Time.Span::Hours(amount) => + Time.Span.Hours(amount) => `time.setUTCHours(time.getUTCHours() + #{amount})` - Time.Span::Days(amount) => + Time.Span.Days(amount) => `time.setUTCDate(time.getUTCDate() + #{amount})` - Time.Span::Weeks(amount) => + Time.Span.Weeks(amount) => `time.setUTCDate(time.getUTCDate() + (7 * #{amount}))` - Time.Span::Months(amount) => + Time.Span.Months(amount) => `time.setUTCMonth(time.getUTCMonth() + #{amount})` - Time.Span::Years(amount) => + Time.Span.Years(amount) => `time.setUTCFullYear(time.getUTCFullYear() + #{amount})` } } @@ -629,7 +629,7 @@ module Time { conversion this function can fail. Time.inZone("America/New_York", Time.utc(2019, 1, 1, 7, 12, 35, 200)) == - Maybe::Just(Time.utc(2019, 1, 1, 2, 12, 35, 200)) + Maybe.Just(Time.utc(2019, 1, 1, 2, 12, 35, 200)) */ fun inZone (timeZone : String, time : Time) : Maybe(Time) { ` @@ -643,9 +643,9 @@ module Time { // Shift the resulting time by the local time-zone offset. time.setUTCMinutes(time.getUTCMinutes() - time.getTimezoneOffset()) - return #{Maybe::Just(`time`)}; + return #{Maybe.Just(`time`)}; } catch { - return #{Maybe::Nothing} + return #{Maybe.Nothing} } })() ` diff --git a/core/source/Time/Format.mint b/core/source/Time/Format.mint index a41d14e3d..d827fa875 100644 --- a/core/source/Time/Format.mint +++ b/core/source/Time/Format.mint @@ -7,9 +7,9 @@ module Time { Time.utc(2016, 1, 2, 12, 34, 50, 200) time = - Time.shift(Time.Span::Hours(4), time) + Time.shift(Time.Span.Hours(4), time) - Time.distanceOfTimeInWords(time, now, Time.Format::English)) == "in 4 hours" + Time.distanceOfTimeInWords(time, now, Time.Format.English)) == "in 4 hours" */ fun distanceOfTimeInWords ( from : Time, diff --git a/core/source/Time/Languages/English.mint b/core/source/Time/Languages/English.mint index 4e03e9a56..54c482d34 100644 --- a/core/source/Time/Languages/English.mint +++ b/core/source/Time/Languages/English.mint @@ -5,59 +5,59 @@ module Time.Format { toMonthAbbreviation: (month : Month) { case month { - Month.January => "Jan" - Month.February => "Feb" - Month.March => "Mar" - Month.April => "Apr" - Month.May => "May" - Month.June => "Jun" - Month.July => "Jul" - Month.August => "Aug" - Month.September => "Sep" - Month.October => "Oct" - Month.November => "Nov" - Month.December => "Dec" + January => "Jan" + February => "Feb" + March => "Mar" + April => "Apr" + May => "May" + June => "Jun" + July => "Jul" + August => "Aug" + September => "Sep" + October => "Oct" + November => "Nov" + December => "Dec" } }, toMonthName: (month : Month) { case month { - Month.January => "January" - Month.February => "February" - Month.March => "March" - Month.April => "April" - Month.May => "May" - Month.June => "June" - Month.July => "July" - Month.August => "August" - Month.September => "September" - Month.October => "October" - Month.November => "November" - Month.December => "December" + January => "January" + February => "February" + March => "March" + April => "April" + May => "May" + June => "June" + July => "July" + August => "August" + September => "September" + October => "October" + November => "November" + December => "December" } }, toWeekdayName: (weekday : Weekday) { case weekday { - Weekday.Monday => "Monday" - Weekday.Tuesday => "Tuesday" - Weekday.Wednesday => "Wednesday" - Weekday.Thursday => "Thursday" - Weekday.Friday => "Friday" - Weekday.Saturday => "Saturday" - Weekday.Sunday => "Sunday" + Monday => "Monday" + Tuesday => "Tuesday" + Wednesday => "Wednesday" + Thursday => "Thursday" + Friday => "Friday" + Saturday => "Saturday" + Sunday => "Sunday" } }, toWeekdayAbbreviation: (weekday : Weekday) { case weekday { - Weekday.Monday => "Mon" - Weekday.Tuesday => "Tue" - Weekday.Wednesday => "Wed" - Weekday.Thursday => "Thu" - Weekday.Friday => "Fri" - Weekday.Saturday => "Sat" - Weekday.Sunday => "Sun" + Monday => "Mon" + Tuesday => "Tue" + Wednesday => "Wed" + Thursday => "Thu" + Friday => "Fri" + Saturday => "Sat" + Sunday => "Sun" } }, toOrdinalSuffix: diff --git a/core/source/Time/Languages/Hungarian.mint b/core/source/Time/Languages/Hungarian.mint index b63d80f53..675a372ec 100644 --- a/core/source/Time/Languages/Hungarian.mint +++ b/core/source/Time/Languages/Hungarian.mint @@ -5,59 +5,59 @@ module Time.Format { toMonthAbbreviation: (month : Month) { case month { - Month.January => "jan." - Month.February => "febr." - Month.March => "márc." - Month.April => "ápr." - Month.May => "máj." - Month.June => "jún." - Month.July => "júl." - Month.August => "aug." - Month.September => "szept." - Month.October => "okt." - Month.November => "nov." - Month.December => "dec." + January => "jan." + February => "febr." + March => "márc." + April => "ápr." + May => "máj." + June => "jún." + July => "júl." + August => "aug." + September => "szept." + October => "okt." + November => "nov." + December => "dec." } }, toMonthName: (month : Month) { case month { - Month.January => "janár" - Month.February => "február" - Month.March => "március" - Month.April => "április" - Month.May => "május" - Month.June => "június" - Month.July => "július" - Month.August => "augusztus" - Month.September => "szeptember" - Month.October => "október" - Month.November => "november" - Month.December => "december" + January => "janár" + February => "február" + March => "március" + April => "április" + May => "május" + June => "június" + July => "július" + August => "augusztus" + September => "szeptember" + October => "október" + November => "november" + December => "december" } }, toWeekdayName: (weekday : Weekday) { case weekday { - Weekday.Monday => "hétfő" - Weekday.Tuesday => "kedd" - Weekday.Wednesday => "szerda" - Weekday.Thursday => "csütörtök" - Weekday.Friday => "péntek" - Weekday.Saturday => "szombat" - Weekday.Sunday => "vasárnap" + Monday => "hétfő" + Tuesday => "kedd" + Wednesday => "szerda" + Thursday => "csütörtök" + Friday => "péntek" + Saturday => "szombat" + Sunday => "vasárnap" } }, toWeekdayAbbreviation: (weekday : Weekday) { case weekday { - Weekday.Monday => "hé" - Weekday.Tuesday => "ke" - Weekday.Wednesday => "sze." - Weekday.Thursday => "csü." - Weekday.Friday => "pé." - Weekday.Saturday => "szo." - Weekday.Sunday => "va." + Monday => "hé" + Tuesday => "ke" + Wednesday => "sze." + Thursday => "csü." + Friday => "pé." + Saturday => "szo." + Sunday => "va." } }, toOrdinalSuffix: diff --git a/core/source/Url.mint b/core/source/Url.mint index d0fdb2bad..782ac386c 100644 --- a/core/source/Url.mint +++ b/core/source/Url.mint @@ -44,23 +44,22 @@ module Url { Url.parse("https://www.example.com").host == "www.example.com" */ fun parse (url : String) : Url { + let anchor = + Dom.createElement("a") + ` (() => { - if (!this._a) { - this._a = document.createElement('a') - } - - this._a.href = #{url} + #{anchor}.href = #{url} return #{{ - hostname: `this._a.hostname || ""`, - protocol: `this._a.protocol || ""`, - origin: `this._a.origin || ""`, - path: `this._a.pathname || ""`, - search: `this._a.search || ""`, - hash: `this._a.hash || ""`, - host: `this._a.host || ""`, - port: `this._a.port || ""` + hostname: `#{anchor}.hostname || ""`, + protocol: `#{anchor}.protocol || ""`, + origin: `#{anchor}.origin || ""`, + path: `#{anchor}.pathname || ""`, + search: `#{anchor}.search || ""`, + hash: `#{anchor}.hash || ""`, + host: `#{anchor}.host || ""`, + port: `#{anchor}.port || ""` }} })() ` diff --git a/core/source/Validation.mint b/core/source/Validation.mint index 0f64bf63d..828ba0568 100644 --- a/core/source/Validation.mint +++ b/core/source/Validation.mint @@ -7,8 +7,8 @@ return if the validation fails. The error is a `Tuple(String, String)` where the first parameter is the key of the field and the second is the error message. -The result of the validation is a `Maybe(error)`. If it's `Maybe::Nothing` then -there validation succeeded, otherwise it will be a `Maybe::Just(error)` meaning +The result of the validation is a `Maybe(error)`. If it's `Maybe.Nothing` then +there validation succeeded, otherwise it will be a `Maybe.Just(error)` meaning the validation failed. Here is an example of doing validation for a checkout form: @@ -77,7 +77,7 @@ module Validation { "", 5, {"zip", "Zip code does is not 5 characters!"}) == - Maybe::Just({"zip", "Zip code does is not 5 characters!"}) + Maybe.Just({"zip", "Zip code does is not 5 characters!"}) */ fun hasExactNumberOfCharacters ( value : String, @@ -99,7 +99,7 @@ module Validation { "", 5, {"zip", "Zip code does is not 5 characters or more!"}) == - Maybe::Just({"zip", "Zip code does is not 5 characters or more!"}) + Maybe.Just({"zip", "Zip code does is not 5 characters or more!"}) */ fun hasMinimumNumberOfCharacters ( value : String, @@ -118,7 +118,7 @@ module Validation { (contains only whitespace). Validation.isNotBlank("", {"name", "Name is empty!"}) == - Maybe::Just({"name", "Name is empty!"}) + Maybe.Just({"name", "Name is empty!"}) */ fun isNotBlank (value : String, error : Tuple(String, String)) : Maybe(Tuple(String, String)) { if String.isNotBlank(value) { @@ -132,7 +132,7 @@ module Validation { Returns the given error if the given string is not a number. Validation.isNumber("foo", {"multiplicand", "Multiplicand is not a number!"}) == - Maybe::Just({"multiplicand", "Multiplicand is not a number!"}) + Maybe.Just({"multiplicand", "Multiplicand is not a number!"}) */ fun isNumber (value : String, error : Tuple(String, String)) : Maybe(Tuple(String, String)) { case Number.fromString(value) { @@ -145,7 +145,7 @@ module Validation { Returns the given error if the given string does not consist of just digits. Validation.isDigits("1234x", {"zip", "Zip code is not just digits!"}) == - Maybe::Just({"zip", "Zip code is not just digits!"}) + Maybe.Just({"zip", "Zip code is not just digits!"}) */ fun isDigits (value : String, error : Tuple(String, String)) : Maybe(Tuple(String, String)) { if Regexp.match(DIGITS_REGEXP, value) { @@ -162,7 +162,7 @@ module Validation { "password", "confirmation", {"confirmation", "Confirmation is not the same!"}) == - Maybe::Just({"confirmation", "Confirmation is not the same!"}) + Maybe.Just({"confirmation", "Confirmation is not the same!"}) */ fun isSame (value : a, value2 : a, error : Tuple(String, String)) : Maybe(Tuple(String, String)) { if value == value2 { @@ -178,7 +178,7 @@ module Validation { Validation.isValidEmail( "test", {"email", "Email is not a valid email address!"}) == - Maybe::Just({"email", "Email is not a valid email address!"}) + Maybe.Just({"email", "Email is not a valid email address!"}) */ fun isValidEmail (value : String, error : Tuple(String, String)) : Maybe(Tuple(String, String)) { if Regexp.match(EMAIL_REGEXP, value) { @@ -209,7 +209,7 @@ module Validation { case item { Maybe.Just(error) => { - let #(key, message) = + let {key, message} = error let messages = diff --git a/core/source/Window.mint b/core/source/Window.mint index 5b2870e22..03938cd09 100644 --- a/core/source/Window.mint +++ b/core/source/Window.mint @@ -16,7 +16,7 @@ module Window { ` (() => { const listener = (event) => { - #{listener}(_normalizeEvent(event)) + #{listener}(#{%normalizeEvent%}(event)) } window.addEventListener(#{type}, listener, #{capture}); @@ -40,7 +40,6 @@ module Window { const query = window.matchMedia(#{query}); const listener = (event) => #{listener}(query.matches); query.addListener(listener) - #{listener}(query.matches) return () => query.removeListener(listener); })() ` @@ -78,9 +77,9 @@ module Window { let result = window.confirm(#{message}) if (result) { - resolve(#{Result::Ok(`result`)}) + resolve(#{Result.Ok(`result`)}) } else { - resolve(#{Result::Err("User cancelled!")}) + resolve(#{Result.Err("User cancelled!")}) } }) ` @@ -170,7 +169,7 @@ module Window { Window.jump("/new-url") */ fun jump (url : String) : Promise(Void) { - `_navigate( + `#{%navigate%}( #{url}, /* dispatch */ true, /* triggerJump */ true, @@ -194,7 +193,7 @@ module Window { Window.navigate("/new-url") */ fun navigate (url : String) : Promise(Void) { - `_navigate( + `#{%navigate%}( #{url}, /* dispatch */ true, /* triggerJump */ false, @@ -217,11 +216,11 @@ module Window { This function returns the entered text as a `Maybe(String)` and blocks execution until the popup is closed. If the user cancelled the popup it - returns `Maybe::Nothing`. + returns `Maybe.Nothing`. case (Window.prompt("How old are you?")) { - Maybe::Just(value) => Debug.log(value) - Maybe::Nothing => Debug.log("User cancelled") + Maybe.Just(value) => Debug.log(value) + Maybe.Nothing => Debug.log("User cancelled") } */ fun prompt (label : String, current : String = "") : Promise(Maybe(String)) { @@ -230,9 +229,9 @@ module Window { let result = window.prompt(#{label}, #{current}) if (result !== null) { - resolve(#{Maybe::Just(`result`)}) + resolve(#{Maybe.Just(`result`)}) } else { - resolve(#{Maybe::Nothing}) + resolve(#{Maybe.Nothing}) } }) ` @@ -329,7 +328,7 @@ module Window { Window.setUrl("/new-url") */ fun setUrl (url : String) : Promise(Void) { - `_navigate( + `#{%navigate%}( #{url}, /* dispatch */ false, /* triggerJump */ false, diff --git a/core/tests/.env b/core/tests/.env new file mode 100644 index 000000000..561cdd641 --- /dev/null +++ b/core/tests/.env @@ -0,0 +1 @@ +TEST=TEST diff --git a/core/tests/tests/Array.mint b/core/tests/tests/Array.mint index 3e817669f..dd7e1d101 100644 --- a/core/tests/tests/Array.mint +++ b/core/tests/tests/Array.mint @@ -91,13 +91,17 @@ suite "Array.deleteAt" { } suite "Array.dropEnd" { - test "drop n number of items from the end" { + test "drop number of items from the end" { Array.dropEnd([1, 2, 3, 4, 5, 6, 7, 8], 2) == [1, 2, 3, 4, 5, 6] } test "returns array if number of items is negative" { Array.dropEnd([1, 2, 3, 4], -2) == [1, 2, 3, 4] } + + test "removes all elements if the number is more than the length" { + Array.dropEnd([1, 2], 4) == [] + } } suite "Array.dropStart" { @@ -123,7 +127,7 @@ suite "Array.find" { suite "Array.findByAndMap" { test "finds the first item that matches the predicate and returns the second value of the tuple" { ([1, 2, 3, 4, 5, 6] - |> Array.findByAndMap((number : Number) { #(number == 3, "Three") }) + |> Array.findByAndMap((number : Number) { {number == 3, "Three"} }) |> Maybe.withDefault("")) == "Three" } } diff --git a/core/tests/tests/Connect.mint b/core/tests/tests/Connect.mint new file mode 100644 index 000000000..d95bd6415 --- /dev/null +++ b/core/tests/tests/Connect.mint @@ -0,0 +1,29 @@ +store Test.Store { + state test : String = "TEST" + state test2 : String = "TEST2" +} + +component Store.Test { + connect Test.Store exposing { test, test2 as x } + + fun render : Html { + <> + + test + + + + x + + + } +} + +suite "Store" { + test "connections" { + + |> Test.Html.start() + |> Test.Html.assertTextOf("span", "TEST") + |> Test.Html.assertTextOf("strong", "TEST2") + } +} diff --git a/core/tests/tests/Console.mint b/core/tests/tests/Console.mint index cfb4b9963..e3d5d7d1c 100644 --- a/core/tests/tests/Console.mint +++ b/core/tests/tests/Console.mint @@ -1,7 +1,7 @@ suite "Console.Counter" { test "it works once on 'Default' label using tuple" { // "Default" label - let #(a, b) = + let {a, b} = Console.count() // reset "Default" label @@ -29,7 +29,7 @@ suite "Console.Counter" { Console.count() } - let #(a, b) = + let {a, b} = Console.count() // reset "Default" label @@ -62,10 +62,10 @@ suite "Console.Counter" { Console.count("Test") } - let #(a, b) = + let {a, b} = Console.count() - let #(c, d) = + let {c, d} = Console.count("Test") // reset "Default" label diff --git a/core/tests/tests/Css.mint b/core/tests/tests/Css.mint new file mode 100644 index 000000000..4ad715385 --- /dev/null +++ b/core/tests/tests/Css.mint @@ -0,0 +1,24 @@ +component Test.CSS { + style root { + color: red; + + span { + color: blue; + } + } + + fun render : Html { + + + + } +} + +suite "CSS Definition" { + test "sets css values" { + + |> Test.Html.start() + |> Test.Html.assertCssOf("div", "color", "rgb(255, 0, 0)") + |> Test.Html.assertCssOf("span", "color", "rgb(0, 0, 255)") + } +} diff --git a/core/tests/tests/Decoding.mint b/core/tests/tests/Decoding.mint index bf9fd9437..c3fd257d8 100644 --- a/core/tests/tests/Decoding.mint +++ b/core/tests/tests/Decoding.mint @@ -1,7 +1,7 @@ suite "Decode" { test "it decodes tuples" { - case decode (encode #("A", 0, true)) as Tuple(String, Number, Bool) { - Result.Ok(decoded) => #("A", 0, true) == decoded + case decode (encode {"A", 0, true}) as Tuple(String, Number, Bool) { + Result.Ok(decoded) => {"A", 0, true} == decoded Result.Err => false } } diff --git a/core/tests/tests/Defer.mint b/core/tests/tests/Defer.mint new file mode 100644 index 000000000..f9be2be39 --- /dev/null +++ b/core/tests/tests/Defer.mint @@ -0,0 +1,10 @@ +suite "Defer" { + const DEFERRED = defer "Hello World!" + + test "it loads deferred content" { + let greeting = + await DEFERRED + + greeting == "Hello World!" + } +} diff --git a/core/tests/tests/Destructuring.mint b/core/tests/tests/Destructuring.mint new file mode 100644 index 000000000..8ef1a88c3 --- /dev/null +++ b/core/tests/tests/Destructuring.mint @@ -0,0 +1,22 @@ +suite "Array destructuring" { + test "spread" { + case ["a", "b"] { + [...b] => true + => false + } + } + + test "one item" { + case ["a"] { + [a] => true + => false + } + } + + test "empty" { + case [] { + [] => true + => false + } + } +} diff --git a/core/tests/tests/Directives.mint b/core/tests/tests/Directives.mint new file mode 100644 index 000000000..0a25d6bdb --- /dev/null +++ b/core/tests/tests/Directives.mint @@ -0,0 +1,57 @@ +suite "@inline" { + test "inlines the contents" { + @inline(../../../spec/fixtures/data.txt) == "Hello World!\n" + } +} + +suite "@asset" { + test "references the file" { + @asset(../../../spec/fixtures/data.txt) == "/__mint__/data_8ddd8be4b179a529afa5f2ffae4b9858.txt" + } +} + +suite "@svg" { + test "loads the file" { + @svg(../../../spec/fixtures/icon.svg) + |> Test.Html.start() + |> Test.Html.assertElementExists("svg") + } +} + +suite "@format" { + test "returns the formatter source" { + let {value, formatted} = + @format { + { + "Hello World!" + } + } + + value == "Hello World!" && + formatted == <<~MINT + { + "Hello World!" + } + MINT + } +} + +suite "@highlight" { + test "highlights the given code" { + @highlight { + "Hello World!" + }[1] + |> Test.Html.start() + |> Test.Html.assertElementExists("span.line") + |> Test.Html.assertElementExists("span.string") + } +} + +suite "@highlight-file" { + test "highlights the given file" { + @highlight-file(../../../spec/fixtures/Test.mint) + |> Test.Html.start() + |> Test.Html.assertElementExists("span.line") + |> Test.Html.assertElementExists("span.namespace") + } +} diff --git a/core/tests/tests/Dom.mint b/core/tests/tests/Dom.mint index d887166b9..61ccef163 100644 --- a/core/tests/tests/Dom.mint +++ b/core/tests/tests/Dom.mint @@ -147,3 +147,14 @@ suite "Dom.focusWhenVisible" { |> Test.Html.assertActiveElement("#input") } } + +suite "Dom.getChildren" { + test "it returns children" { + + |> Test.Html.start() + |> Test.Context.assert( + (element : Dom.Element) { + Array.size(Dom.getChildren(element)) == 3 + }) + } +} diff --git a/core/tests/tests/Encoding.mint b/core/tests/tests/Encoding.mint index 8ed5981e1..725e7f4ca 100644 --- a/core/tests/tests/Encoding.mint +++ b/core/tests/tests/Encoding.mint @@ -34,11 +34,11 @@ suite "Encode" { `typeof #{encode Time.now()} === "string"` } - test "it encodes Maybe::Just as its value" { - `#{encode Maybe::Just("Hello")} === "Hello"` + test "it encodes Maybe.Just as its value" { + `#{encode Maybe.Just("Hello")} === "Hello"` } - test "it encodes Maybe::Nothing as null" { + test "it encodes Maybe.Nothing as null" { `#{encode EncodeTest.nothing()} === null` } @@ -67,7 +67,7 @@ suite "Encode" { test "it encodes Tuple as array" { let encoded = - encode #("Hello", 0, true) + encode {"Hello", 0, true} `Array.isArray(#{encoded}) && #{encoded}[0] === "Hello"` && `Array.isArray(#{encoded}) && #{encoded}[1] === 0` && `Array.isArray(#{encoded}) && #{encoded}[2] === true` } diff --git a/core/tests/tests/Env.mint b/core/tests/tests/Env.mint new file mode 100644 index 000000000..4a197d01a --- /dev/null +++ b/core/tests/tests/Env.mint @@ -0,0 +1,5 @@ +suite "Env" { + test "loads from .env file" { + @TEST == "TEST" + } +} diff --git a/core/tests/tests/FieldAccess.mint b/core/tests/tests/FieldAccess.mint new file mode 100644 index 000000000..3c2d9fe58 --- /dev/null +++ b/core/tests/tests/FieldAccess.mint @@ -0,0 +1,14 @@ +suite "Field Access" { + test "it returns the value" { + let options = + { + caseInsensitive: true, + multiline: true, + sticky: false, + unicode: true, + global: true + } + + .sticky(Regexp.Options)(options) == false + } +} diff --git a/core/tests/tests/FileSize.mint b/core/tests/tests/FileSize.mint index b50faa593..fccef199b 100644 --- a/core/tests/tests/FileSize.mint +++ b/core/tests/tests/FileSize.mint @@ -7,6 +7,10 @@ suite "FileSize.format" { FileSize.format(1024) == "1 kB" } + test "for 1030 returns 1kB" { + FileSize.format(1030) == "1.01 kB" + } + test "for 1048576 returns 1MB" { FileSize.format(1048576) == "1 MB" } diff --git a/core/tests/tests/HereDocuments.mint b/core/tests/tests/HereDocuments.mint new file mode 100644 index 000000000..93eba5753 --- /dev/null +++ b/core/tests/tests/HereDocuments.mint @@ -0,0 +1,27 @@ +suite "Here Document" { + test "Preserved Whitespace" { + <<-TEST + Hello + TEST == " Hello" + } + + test "Removed Whitespace" { + <<~TEST + Hello + TEST == "Hello" + } + + test "Interpolation" { + <<~TEST + #{"Hello"} + TEST == "Hello" + } + + test "Markdown" { + <<#TEST + Hello + TEST + |> Test.Html.start() + |> Test.Html.assertTextOf("p", "Hello") + } +} diff --git a/core/tests/tests/Http.mint b/core/tests/tests/Http.mint index d46a6061a..514e83825 100644 --- a/core/tests/tests/Http.mint +++ b/core/tests/tests/Http.mint @@ -238,7 +238,7 @@ suite "Http.send" { Http.get("/blah") |> Http.send("A") - `#{Http.requests()}["A"] != undefined` + `#{Http.REQUESTS}["A"] != undefined` } } @@ -269,7 +269,7 @@ component Test.Http { |> wrap( ` (async (promise) => { - let _requests = #{Http.requests()} + let _requests = #{Http.REQUESTS} if (#{shouldError}) { _requests["test"].dispatchEvent(new CustomEvent("error")) @@ -323,15 +323,15 @@ component Test.Http { fun render : Html {
- <{ errorMessage }> + errorMessage - <{ body }> + body - <{ Number.toString(status) }> + Number.toString(status)
} diff --git a/core/tests/tests/Locale.mint b/core/tests/tests/Locale.mint new file mode 100644 index 000000000..81ec18807 --- /dev/null +++ b/core/tests/tests/Locale.mint @@ -0,0 +1,25 @@ +locale en { + key: "Hello World!" +} + +locale hu { + key: "Szia Világ!" +} + +component Test.Locale { + fun render : Html { +
+ :key +
+ } +} + +suite "Locale" { + test "Translates" { + + |> Test.Html.start() + |> Test.Html.assertTextOf("div", "Hello World!") + |> Test.Html.triggerClick("div") + |> Test.Html.assertTextOf("div", "Szia Világ!") + } +} diff --git a/core/tests/tests/Map.mint b/core/tests/tests/Map.mint index 45ff6db0d..94461dc12 100644 --- a/core/tests/tests/Map.mint +++ b/core/tests/tests/Map.mint @@ -1,3 +1,17 @@ +suite "Map literal" { + test "creates a map" { + Map.size( + { + "a" => "b", + "c" => "d" + }) == 2 + } + + test "accesses the map" { + { "a" => "b" }["a"] == Maybe.Just("b") + } +} + suite "Map with enums" { test "Map.set" { (Map.empty() @@ -248,7 +262,7 @@ suite "Map.entries" { (Map.empty() |> Map.set("a", 100) |> Map.set("b", 200) - |> Map.entries()) == [#("a", 100), #("b", 200)] + |> Map.entries()) == [{"a", 100}, {"b", 200}] } } @@ -256,6 +270,6 @@ suite "Map.fromArray" { test "convert an array of tuples into a map" { (Map.empty() |> Map.set("a", 1) - |> Map.set("b", 2)) == Map.fromArray([#("a", 1), #("b", 2)]) + |> Map.set("b", 2)) == Map.fromArray([{"a", 1}, {"b", 2}]) } } diff --git a/core/tests/tests/Math.mint b/core/tests/tests/Math.mint index 325bf9345..dcdc3cbce 100644 --- a/core/tests/tests/Math.mint +++ b/core/tests/tests/Math.mint @@ -101,49 +101,49 @@ suite "Math.random" { } } -suite "Math:E" { +suite "Math.E" { test "returns Math.E" { Math.E == `Math.E` } } -suite "Math:LN2" { +suite "Math.LN2" { test "returns Math.LN2" { Math.LN2 == `Math.LN2` } } -suite "Math:LN10" { +suite "Math.LN10" { test "returns Math.LN10" { Math.LN10 == `Math.LN10` } } -suite "Math:LOG2E" { +suite "Math.LOG2E" { test "returns Math.LOG2E" { Math.LOG2E == `Math.LOG2E` } } -suite "Math:LOG10E" { +suite "Math.LOG10E" { test "returns Math.LOG10E" { Math.LOG10E == `Math.LOG10E` } } -suite "Math:PI" { +suite "Math.PI" { test "returns Math.PI" { Math.PI == `Math.PI` } } -suite "Math:SQRT12" { +suite "Math.SQRT12" { test "returns Math.SQRT12" { Math.SQRT12 == `Math.SQRT1_2` } } -suite "Math:SQRT2" { +suite "Math.SQRT2" { test "returns Math.SQRT2" { Math.SQRT2 == `Math.SQRT2` } @@ -254,7 +254,7 @@ suite "Math.log" { suite "Math.log1p" { test "returns the natural log (base e) of x + 1, where x is the provided value" { - Math.log1p(Math.E) == `Math.log1p(#{Math:E})` + Math.log1p(Math.E) == `Math.log1p(#{Math.E})` } } diff --git a/core/tests/tests/Object/Decode.mint b/core/tests/tests/Object/Decode.mint index c82a3f3c6..2c19d5438 100644 --- a/core/tests/tests/Object/Decode.mint +++ b/core/tests/tests/Object/Decode.mint @@ -26,6 +26,11 @@ suite "Object.Decode.field" { } suite "Object.Decode.string" { + test "using decode keyword" { + decode (`""`) as String + |> Result.isOk() + } + test "it returns an error if it's not a string" { Object.Decode.string(`0`) |> Result.isError() @@ -38,6 +43,11 @@ suite "Object.Decode.string" { } suite "Object.Decode.time" { + test "using decode keyword" { + decode (`""`) as Time + |> Result.isError() + } + test "it returns an error if it's not a valid date" { Object.Decode.time(`"asd"`) |> Result.isError() @@ -50,6 +60,11 @@ suite "Object.Decode.time" { } suite "Object.Decode.number" { + test "using decode keyword" { + decode (`""`) as Number + |> Result.isError() + } + test "it returns an error if it's not a valid number" { Object.Decode.number(`"asd"`) |> Result.isError() @@ -62,6 +77,11 @@ suite "Object.Decode.number" { } suite "Object.Decode.boolean" { + test "using decode keyword" { + decode (`""`) as Bool + |> Result.isError() + } + test "it returns an error if it's not a valid boolean" { Object.Decode.boolean(`"asd"`) |> Result.isError() @@ -74,6 +94,11 @@ suite "Object.Decode.boolean" { } suite "Object.Decode.array" { + test "using decode keyword" { + decode (`""`) as Array(String) + |> Result.isError() + } + test "it returns an error if it's not a valid array" { Object.Decode.array(`"asd"`, Object.Decode.string) |> Result.isError() @@ -91,6 +116,11 @@ suite "Object.Decode.array" { } suite "Object.Decode.maybe" { + test "using decode keyword" { + decode (`""`) as Maybe(String) + |> Result.isOk() + } + test "it returns an error if it's not a valid string" { Object.Decode.maybe(`0`, Object.Decode.string) |> Result.isError() diff --git a/core/tests/tests/Object/Encode.mint b/core/tests/tests/Object/Encode.mint index 0b0b627c7..836c09c4b 100644 --- a/core/tests/tests/Object/Encode.mint +++ b/core/tests/tests/Object/Encode.mint @@ -1,22 +1,38 @@ suite "Object.Encode.string" { + test "using keyword" { + (encode "Test") == `"Test"` + } + test "encodes a string to object" { Object.Encode.string("Test") == `"Test"` } } suite "Object.Encode.boolean" { + test "using keyword" { + (encode true) == `true` + } + test "encodes a boolean to object" { Object.Encode.boolean(true) == `true` } } suite "Object.Encode.number" { - test "encodes a boolean to object" { + test "using keyword" { + (encode 10) == `10` + } + + test "encodes a number to object" { Object.Encode.number(10) == `10` } } suite "Object.Encode.time" { + test "using keyword" { + (encode Time.utcDate(2018, 1, 1)) == `"2018-01-01T00:00:00.000Z"` + } + test "encodes a date to object" { Object.Encode.time(Time.utcDate(2018, 1, 1)) == `"2018-01-01T00:00:00.000Z"` } @@ -44,6 +60,10 @@ suite "Object.Encode.object" { } suite "Object.Encode.array" { + test "using keyword" { + (encode [10]) == `[10]` + } + test "encodes an array of object into an object" { Object.Encode.array([`"a"`]) == `["a"]` } diff --git a/core/tests/tests/Promise.mint b/core/tests/tests/Promise.mint index 1905de1e9..2229f8b40 100644 --- a/core/tests/tests/Promise.mint +++ b/core/tests/tests/Promise.mint @@ -11,7 +11,7 @@ component Test.Promise { fun render : Html {
- <{ result }> + result @@ -24,7 +24,7 @@ component Test.Promise2 { state result : String = "" fun componentDidMount : Promise(Void) { - let #(resolve, promise) = + let {resolve, promise} = Promise.create() await next { resolve: resolve } @@ -38,7 +38,7 @@ component Test.Promise2 { fun render : Html {
- <{ result }> + result diff --git a/core/tests/tests/Provider/AnimationFrame.mint b/core/tests/tests/Provider/AnimationFrame.mint index e657cc915..281c7b436 100644 --- a/core/tests/tests/Provider/AnimationFrame.mint +++ b/core/tests/tests/Provider/AnimationFrame.mint @@ -14,7 +14,7 @@ component Test.Provider.AnimationFrame { fun render : Html {
- <{ Number.toString(frames) }> + Number.toString(frames)
} } @@ -23,8 +23,10 @@ suite "Provider.AnimationFrame.frames" { test "called on an animation frame" { |> Test.Html.start() - |> Test.Html.assertTextOf("div", "1") - |> Test.Html.assertTextOf("div", "2") - |> Test.Html.assertTextOf("div", "3") + |> Test.Context.timeout(10) + |> Test.Context.assert( + (element : Dom.Element) { + Dom.getTextContent(element) != "0" + }) } } diff --git a/core/tests/tests/Provider/Keyboard.mint b/core/tests/tests/Provider/Keyboard.mint index b128ac6fa..c2173bcec 100644 --- a/core/tests/tests/Provider/Keyboard.mint +++ b/core/tests/tests/Provider/Keyboard.mint @@ -10,11 +10,11 @@ component Test.Provider.Keyboard { fun render : Html {
- <{ Number.toString(downs) }> + Number.toString(downs) - <{ Number.toString(ups) }> + Number.toString(ups)
} diff --git a/core/tests/tests/Provider/Mouse.mint b/core/tests/tests/Provider/Mouse.mint index 9f7f32037..40a9b52d5 100644 --- a/core/tests/tests/Provider/Mouse.mint +++ b/core/tests/tests/Provider/Mouse.mint @@ -12,15 +12,15 @@ component Test.Provider.Mouse { fun render : Html {
- <{ Number.toString(clicks) }> + Number.toString(clicks) - <{ Number.toString(moves) }> + Number.toString(moves) - <{ Number.toString(ups) }> + Number.toString(ups)
} diff --git a/core/tests/tests/Provider/Scroll.mint b/core/tests/tests/Provider/Scroll.mint index 80f272cda..c993d2d5f 100644 --- a/core/tests/tests/Provider/Scroll.mint +++ b/core/tests/tests/Provider/Scroll.mint @@ -10,7 +10,7 @@ component Test.Provider.Scroll { fun render : Html { - <{ Number.toString(position) }> + Number.toString(position)
} } diff --git a/core/tests/tests/Provider/Tick.mint b/core/tests/tests/Provider/Tick.mint index c693fdae5..87aef6332 100644 --- a/core/tests/tests/Provider/Tick.mint +++ b/core/tests/tests/Provider/Tick.mint @@ -5,7 +5,7 @@ component Test.Provider.Tick { fun render : Html {
- <{ Number.toString(counter) }> + Number.toString(counter)
} } diff --git a/core/tests/tests/Time.mint b/core/tests/tests/Time.mint index a64bc20b0..5c41090b0 100644 --- a/core/tests/tests/Time.mint +++ b/core/tests/tests/Time.mint @@ -88,111 +88,111 @@ suite "Time.month" { suite "Time.calendarWeek" { const TEST_DATA = [ - #(#(1981, 1, 1), #(1981, 1, 4)), - #(#(1982, 1, 1), #(1981, 53, 5)), - #(#(1983, 1, 1), #(1982, 52, 6)), - #(#(1984, 1, 1), #(1983, 52, 7)), - #(#(1985, 1, 1), #(1985, 1, 2)), - #(#(1985, 4, 12), #(1985, 15, 5)), - #(#(1986, 1, 1), #(1986, 1, 3)), - #(#(1987, 1, 1), #(1987, 1, 4)), - #(#(1988, 1, 1), #(1987, 53, 5)), - #(#(1989, 1, 1), #(1988, 52, 7)), - #(#(1990, 1, 1), #(1990, 1, 1)), - #(#(1991, 1, 1), #(1991, 1, 2)), - #(#(1992, 1, 1), #(1992, 1, 3)), - #(#(1993, 1, 1), #(1992, 53, 5)), - #(#(1994, 1, 1), #(1993, 52, 6)), - #(#(1995, 1, 2), #(1995, 1, 1)), - #(#(1996, 1, 1), #(1996, 1, 1)), - #(#(1996, 1, 7), #(1996, 1, 7)), - #(#(1996, 1, 8), #(1996, 2, 1)), - #(#(1997, 1, 1), #(1997, 1, 3)), - #(#(1998, 1, 1), #(1998, 1, 4)), - #(#(1999, 1, 1), #(1998, 53, 5)), - #(#(2000, 1, 1), #(1999, 52, 6)), - #(#(2001, 1, 1), #(2001, 1, 1)), - #(#(2002, 1, 1), #(2002, 1, 2)), - #(#(2003, 1, 1), #(2003, 1, 3)), - #(#(2004, 1, 1), #(2004, 1, 4)), - #(#(2005, 1, 1), #(2004, 53, 6)), - #(#(2006, 1, 1), #(2005, 52, 7)), - #(#(2007, 1, 1), #(2007, 1, 1)), - #(#(2008, 1, 1), #(2008, 1, 2)), - #(#(2009, 1, 1), #(2009, 1, 4)), - #(#(2010, 1, 1), #(2009, 53, 5)), - #(#(2010, 1, 1), #(2009, 53, 5)), - #(#(2011, 1, 1), #(2010, 52, 6)), - #(#(2011, 1, 2), #(2010, 52, 7)), - #(#(2011, 1, 3), #(2011, 1, 1)), - #(#(2011, 1, 4), #(2011, 1, 2)), - #(#(2011, 1, 5), #(2011, 1, 3)), - #(#(2011, 1, 6), #(2011, 1, 4)), - #(#(2011, 1, 7), #(2011, 1, 5)), - #(#(2011, 1, 8), #(2011, 1, 6)), - #(#(2011, 1, 9), #(2011, 1, 7)), - #(#(2011, 1, 10), #(2011, 2, 1)), - #(#(2011, 1, 11), #(2011, 2, 2)), - #(#(2011, 6, 12), #(2011, 23, 7)), - #(#(2011, 6, 13), #(2011, 24, 1)), - #(#(2011, 12, 25), #(2011, 51, 7)), - #(#(2011, 12, 26), #(2011, 52, 1)), - #(#(2011, 12, 27), #(2011, 52, 2)), - #(#(2011, 12, 28), #(2011, 52, 3)), - #(#(2011, 12, 29), #(2011, 52, 4)), - #(#(2011, 12, 30), #(2011, 52, 5)), - #(#(2011, 12, 31), #(2011, 52, 6)), - #(#(1995, 1, 1), #(1994, 52, 7)), - #(#(2012, 1, 1), #(2011, 52, 7)), - #(#(2012, 1, 2), #(2012, 1, 1)), - #(#(2012, 1, 8), #(2012, 1, 7)), - #(#(2012, 1, 9), #(2012, 2, 1)), - #(#(2012, 12, 23), #(2012, 51, 7)), - #(#(2012, 12, 24), #(2012, 52, 1)), - #(#(2012, 12, 30), #(2012, 52, 7)), - #(#(2012, 12, 31), #(2013, 1, 1)), - #(#(2013, 1, 1), #(2013, 1, 2)), - #(#(2013, 1, 6), #(2013, 1, 7)), - #(#(2013, 1, 7), #(2013, 2, 1)), - #(#(2013, 12, 22), #(2013, 51, 7)), - #(#(2013, 12, 23), #(2013, 52, 1)), - #(#(2013, 12, 29), #(2013, 52, 7)), - #(#(2013, 12, 30), #(2014, 1, 1)), - #(#(2014, 1, 1), #(2014, 1, 3)), - #(#(2014, 1, 5), #(2014, 1, 7)), - #(#(2014, 1, 6), #(2014, 2, 1)), - #(#(2015, 1, 1), #(2015, 1, 4)), - #(#(2016, 1, 1), #(2015, 53, 5)), - #(#(2017, 1, 1), #(2016, 52, 7)), - #(#(2018, 1, 1), #(2018, 1, 1)), - #(#(2019, 1, 1), #(2019, 1, 2)), - #(#(2020, 1, 1), #(2020, 1, 3)), - #(#(2021, 1, 1), #(2020, 53, 5)), - #(#(2022, 1, 1), #(2021, 52, 6)), - #(#(2023, 1, 1), #(2022, 52, 7)), - #(#(2024, 1, 1), #(2024, 1, 1)), - #(#(2025, 1, 1), #(2025, 1, 3)), - #(#(2026, 1, 1), #(2026, 1, 4)), - #(#(2027, 1, 1), #(2026, 53, 5)), - #(#(2028, 1, 1), #(2027, 52, 6)), - #(#(2029, 1, 1), #(2029, 1, 1)), - #(#(2030, 1, 1), #(2030, 1, 2)), - #(#(2031, 1, 1), #(2031, 1, 3)), - #(#(2032, 1, 1), #(2032, 1, 4)), - #(#(2033, 1, 1), #(2032, 53, 6)), - #(#(2034, 1, 1), #(2033, 52, 7)), - #(#(2035, 1, 1), #(2035, 1, 1)), - #(#(2036, 1, 1), #(2036, 1, 2)), - #(#(2037, 1, 1), #(2037, 1, 4)), - #(#(2038, 1, 1), #(2037, 53, 5)), - #(#(2039, 1, 1), #(2038, 52, 6)), - #(#(2040, 1, 1), #(2039, 52, 7)) + {{1981, 1, 1}, {1981, 1, 4}}, + {{1982, 1, 1}, {1981, 53, 5}}, + {{1983, 1, 1}, {1982, 52, 6}}, + {{1984, 1, 1}, {1983, 52, 7}}, + {{1985, 1, 1}, {1985, 1, 2}}, + {{1985, 4, 12}, {1985, 15, 5}}, + {{1986, 1, 1}, {1986, 1, 3}}, + {{1987, 1, 1}, {1987, 1, 4}}, + {{1988, 1, 1}, {1987, 53, 5}}, + {{1989, 1, 1}, {1988, 52, 7}}, + {{1990, 1, 1}, {1990, 1, 1}}, + {{1991, 1, 1}, {1991, 1, 2}}, + {{1992, 1, 1}, {1992, 1, 3}}, + {{1993, 1, 1}, {1992, 53, 5}}, + {{1994, 1, 1}, {1993, 52, 6}}, + {{1995, 1, 2}, {1995, 1, 1}}, + {{1996, 1, 1}, {1996, 1, 1}}, + {{1996, 1, 7}, {1996, 1, 7}}, + {{1996, 1, 8}, {1996, 2, 1}}, + {{1997, 1, 1}, {1997, 1, 3}}, + {{1998, 1, 1}, {1998, 1, 4}}, + {{1999, 1, 1}, {1998, 53, 5}}, + {{2000, 1, 1}, {1999, 52, 6}}, + {{2001, 1, 1}, {2001, 1, 1}}, + {{2002, 1, 1}, {2002, 1, 2}}, + {{2003, 1, 1}, {2003, 1, 3}}, + {{2004, 1, 1}, {2004, 1, 4}}, + {{2005, 1, 1}, {2004, 53, 6}}, + {{2006, 1, 1}, {2005, 52, 7}}, + {{2007, 1, 1}, {2007, 1, 1}}, + {{2008, 1, 1}, {2008, 1, 2}}, + {{2009, 1, 1}, {2009, 1, 4}}, + {{2010, 1, 1}, {2009, 53, 5}}, + {{2010, 1, 1}, {2009, 53, 5}}, + {{2011, 1, 1}, {2010, 52, 6}}, + {{2011, 1, 2}, {2010, 52, 7}}, + {{2011, 1, 3}, {2011, 1, 1}}, + {{2011, 1, 4}, {2011, 1, 2}}, + {{2011, 1, 5}, {2011, 1, 3}}, + {{2011, 1, 6}, {2011, 1, 4}}, + {{2011, 1, 7}, {2011, 1, 5}}, + {{2011, 1, 8}, {2011, 1, 6}}, + {{2011, 1, 9}, {2011, 1, 7}}, + {{2011, 1, 10}, {2011, 2, 1}}, + {{2011, 1, 11}, {2011, 2, 2}}, + {{2011, 6, 12}, {2011, 23, 7}}, + {{2011, 6, 13}, {2011, 24, 1}}, + {{2011, 12, 25}, {2011, 51, 7}}, + {{2011, 12, 26}, {2011, 52, 1}}, + {{2011, 12, 27}, {2011, 52, 2}}, + {{2011, 12, 28}, {2011, 52, 3}}, + {{2011, 12, 29}, {2011, 52, 4}}, + {{2011, 12, 30}, {2011, 52, 5}}, + {{2011, 12, 31}, {2011, 52, 6}}, + {{1995, 1, 1}, {1994, 52, 7}}, + {{2012, 1, 1}, {2011, 52, 7}}, + {{2012, 1, 2}, {2012, 1, 1}}, + {{2012, 1, 8}, {2012, 1, 7}}, + {{2012, 1, 9}, {2012, 2, 1}}, + {{2012, 12, 23}, {2012, 51, 7}}, + {{2012, 12, 24}, {2012, 52, 1}}, + {{2012, 12, 30}, {2012, 52, 7}}, + {{2012, 12, 31}, {2013, 1, 1}}, + {{2013, 1, 1}, {2013, 1, 2}}, + {{2013, 1, 6}, {2013, 1, 7}}, + {{2013, 1, 7}, {2013, 2, 1}}, + {{2013, 12, 22}, {2013, 51, 7}}, + {{2013, 12, 23}, {2013, 52, 1}}, + {{2013, 12, 29}, {2013, 52, 7}}, + {{2013, 12, 30}, {2014, 1, 1}}, + {{2014, 1, 1}, {2014, 1, 3}}, + {{2014, 1, 5}, {2014, 1, 7}}, + {{2014, 1, 6}, {2014, 2, 1}}, + {{2015, 1, 1}, {2015, 1, 4}}, + {{2016, 1, 1}, {2015, 53, 5}}, + {{2017, 1, 1}, {2016, 52, 7}}, + {{2018, 1, 1}, {2018, 1, 1}}, + {{2019, 1, 1}, {2019, 1, 2}}, + {{2020, 1, 1}, {2020, 1, 3}}, + {{2021, 1, 1}, {2020, 53, 5}}, + {{2022, 1, 1}, {2021, 52, 6}}, + {{2023, 1, 1}, {2022, 52, 7}}, + {{2024, 1, 1}, {2024, 1, 1}}, + {{2025, 1, 1}, {2025, 1, 3}}, + {{2026, 1, 1}, {2026, 1, 4}}, + {{2027, 1, 1}, {2026, 53, 5}}, + {{2028, 1, 1}, {2027, 52, 6}}, + {{2029, 1, 1}, {2029, 1, 1}}, + {{2030, 1, 1}, {2030, 1, 2}}, + {{2031, 1, 1}, {2031, 1, 3}}, + {{2032, 1, 1}, {2032, 1, 4}}, + {{2033, 1, 1}, {2032, 53, 6}}, + {{2034, 1, 1}, {2033, 52, 7}}, + {{2035, 1, 1}, {2035, 1, 1}}, + {{2036, 1, 1}, {2036, 1, 2}}, + {{2037, 1, 1}, {2037, 1, 4}}, + {{2038, 1, 1}, {2037, 53, 5}}, + {{2039, 1, 1}, {2038, 52, 6}}, + {{2040, 1, 1}, {2039, 52, 7}} ] test "returns proper calendar week" { let expected = for item of TEST_DATA { - (#(item[1][0], item[1][1])) + ({item[1][0], item[1][1]}) } let actual = @@ -278,30 +278,30 @@ suite "Time.shift" { const TEST_DATA = [ - #(Time.Span.Milliseconds(0), Time.utc(2018, 4, 5, 14, 42, 54, 20)), - #(Time.Span.Milliseconds(2), Time.utc(2018, 4, 5, 14, 42, 54, 22)), - #(Time.Span.Milliseconds(-2), Time.utc(2018, 4, 5, 14, 42, 54, 18)), - #(Time.Span.Seconds(0), Time.utc(2018, 4, 5, 14, 42, 54, 20)), - #(Time.Span.Seconds(2), Time.utc(2018, 4, 5, 14, 42, 56, 20)), - #(Time.Span.Seconds(-2), Time.utc(2018, 4, 5, 14, 42, 52, 20)), - #(Time.Span.Minutes(0), Time.utc(2018, 4, 5, 14, 42, 54, 20)), - #(Time.Span.Minutes(2), Time.utc(2018, 4, 5, 14, 44, 54, 20)), - #(Time.Span.Minutes(-2), Time.utc(2018, 4, 5, 14, 40, 54, 20)), - #(Time.Span.Hours(0), Time.utc(2018, 4, 5, 14, 42, 54, 20)), - #(Time.Span.Hours(2), Time.utc(2018, 4, 5, 16, 42, 54, 20)), - #(Time.Span.Hours(-2), Time.utc(2018, 4, 5, 12, 42, 54, 20)), - #(Time.Span.Days(0), Time.utc(2018, 4, 5, 14, 42, 54, 20)), - #(Time.Span.Days(2), Time.utc(2018, 4, 7, 14, 42, 54, 20)), - #(Time.Span.Days(-2), Time.utc(2018, 4, 3, 14, 42, 54, 20)), - #(Time.Span.Weeks(0), Time.utc(2018, 4, 5, 14, 42, 54, 20)), - #(Time.Span.Weeks(2), Time.utc(2018, 4, 19, 14, 42, 54, 20)), - #(Time.Span.Weeks(-2), Time.utc(2018, 3, 22, 14, 42, 54, 20)), - #(Time.Span.Months(0), Time.utc(2018, 4, 5, 14, 42, 54, 20)), - #(Time.Span.Months(2), Time.utc(2018, 6, 5, 14, 42, 54, 20)), - #(Time.Span.Months(-2), Time.utc(2018, 2, 5, 14, 42, 54, 20)), - #(Time.Span.Years(0), Time.utc(2018, 4, 5, 14, 42, 54, 20)), - #(Time.Span.Years(2), Time.utc(2020, 4, 5, 14, 42, 54, 20)), - #(Time.Span.Years(-2), Time.utc(2016, 4, 5, 14, 42, 54, 20)) + {Time.Span.Milliseconds(0), Time.utc(2018, 4, 5, 14, 42, 54, 20)}, + {Time.Span.Milliseconds(2), Time.utc(2018, 4, 5, 14, 42, 54, 22)}, + {Time.Span.Milliseconds(-2), Time.utc(2018, 4, 5, 14, 42, 54, 18)}, + {Time.Span.Seconds(0), Time.utc(2018, 4, 5, 14, 42, 54, 20)}, + {Time.Span.Seconds(2), Time.utc(2018, 4, 5, 14, 42, 56, 20)}, + {Time.Span.Seconds(-2), Time.utc(2018, 4, 5, 14, 42, 52, 20)}, + {Time.Span.Minutes(0), Time.utc(2018, 4, 5, 14, 42, 54, 20)}, + {Time.Span.Minutes(2), Time.utc(2018, 4, 5, 14, 44, 54, 20)}, + {Time.Span.Minutes(-2), Time.utc(2018, 4, 5, 14, 40, 54, 20)}, + {Time.Span.Hours(0), Time.utc(2018, 4, 5, 14, 42, 54, 20)}, + {Time.Span.Hours(2), Time.utc(2018, 4, 5, 16, 42, 54, 20)}, + {Time.Span.Hours(-2), Time.utc(2018, 4, 5, 12, 42, 54, 20)}, + {Time.Span.Days(0), Time.utc(2018, 4, 5, 14, 42, 54, 20)}, + {Time.Span.Days(2), Time.utc(2018, 4, 7, 14, 42, 54, 20)}, + {Time.Span.Days(-2), Time.utc(2018, 4, 3, 14, 42, 54, 20)}, + {Time.Span.Weeks(0), Time.utc(2018, 4, 5, 14, 42, 54, 20)}, + {Time.Span.Weeks(2), Time.utc(2018, 4, 19, 14, 42, 54, 20)}, + {Time.Span.Weeks(-2), Time.utc(2018, 3, 22, 14, 42, 54, 20)}, + {Time.Span.Months(0), Time.utc(2018, 4, 5, 14, 42, 54, 20)}, + {Time.Span.Months(2), Time.utc(2018, 6, 5, 14, 42, 54, 20)}, + {Time.Span.Months(-2), Time.utc(2018, 2, 5, 14, 42, 54, 20)}, + {Time.Span.Years(0), Time.utc(2018, 4, 5, 14, 42, 54, 20)}, + {Time.Span.Years(2), Time.utc(2020, 4, 5, 14, 42, 54, 20)}, + {Time.Span.Years(-2), Time.utc(2016, 4, 5, 14, 42, 54, 20)} ] test "shifts the given time with the given span" { diff --git a/core/tests/tests/Time/Format.mint b/core/tests/tests/Time/Format.mint index c16dd5e53..3dd798a78 100644 --- a/core/tests/tests/Time/Format.mint +++ b/core/tests/tests/Time/Format.mint @@ -7,32 +7,32 @@ suite "Time.formatISO" { suite "Time.distanceOfTimeInWords" { const TEST_DATA = [ - #(Time.Span.Seconds(0), "right now"), - #(Time.Span.Seconds(-24), "just now"), - #(Time.Span.Seconds(-40), "40 seconds ago"), - #(Time.Span.Minutes(-1), "a minute ago"), - #(Time.Span.Minutes(-9), "9 minutes ago"), - #(Time.Span.Hours(-1), "an hour ago"), - #(Time.Span.Hours(-3), "3 hours ago"), - #(Time.Span.Days(-1), "yesterday"), - #(Time.Span.Days(-4), "4 days ago"), - #(Time.Span.Months(-1), "last month"), - #(Time.Span.Months(-5), "5 months ago"), - #(Time.Span.Years(-1), "last year"), - #(Time.Span.Years(-20), "20 years ago"), - #(Time.Span.Seconds(0), "right now"), - #(Time.Span.Seconds(24), "in a few seconds"), - #(Time.Span.Seconds(40), "in 40 seconds"), - #(Time.Span.Minutes(1), "in a minute"), - #(Time.Span.Minutes(9), "in 9 minutes"), - #(Time.Span.Hours(1), "in an hour"), - #(Time.Span.Hours(3), "in 3 hours"), - #(Time.Span.Days(1), "tomorrow"), - #(Time.Span.Days(4), "in 4 days"), - #(Time.Span.Months(1), "in a month"), - #(Time.Span.Months(5), "in 5 months"), - #(Time.Span.Years(1), "in a year"), - #(Time.Span.Years(20), "in 20 years") + {Time.Span.Seconds(0), "right now"}, + {Time.Span.Seconds(-24), "just now"}, + {Time.Span.Seconds(-40), "40 seconds ago"}, + {Time.Span.Minutes(-1), "a minute ago"}, + {Time.Span.Minutes(-9), "9 minutes ago"}, + {Time.Span.Hours(-1), "an hour ago"}, + {Time.Span.Hours(-3), "3 hours ago"}, + {Time.Span.Days(-1), "yesterday"}, + {Time.Span.Days(-4), "4 days ago"}, + {Time.Span.Months(-1), "last month"}, + {Time.Span.Months(-5), "5 months ago"}, + {Time.Span.Years(-1), "last year"}, + {Time.Span.Years(-20), "20 years ago"}, + {Time.Span.Seconds(0), "right now"}, + {Time.Span.Seconds(24), "in a few seconds"}, + {Time.Span.Seconds(40), "in 40 seconds"}, + {Time.Span.Minutes(1), "in a minute"}, + {Time.Span.Minutes(9), "in 9 minutes"}, + {Time.Span.Hours(1), "in an hour"}, + {Time.Span.Hours(3), "in 3 hours"}, + {Time.Span.Days(1), "tomorrow"}, + {Time.Span.Days(4), "in 4 days"}, + {Time.Span.Months(1), "in a month"}, + {Time.Span.Months(5), "in 5 months"}, + {Time.Span.Years(1), "in a year"}, + {Time.Span.Years(20), "in 20 years"} ] test "returns relative time in words" { @@ -58,27 +58,27 @@ suite "Time.distanceOfTimeInWords" { suite "Time.format" { const TEST_DATA = [ - #(Time.utcDate(1985, 4, 12), "%G-W%V-%u", "1985-W15-5"), - #(Time.utcDate(2005, 1, 1), "%G-W%V-%u", "2004-W53-6"), - #(Time.utcDate(2005, 1, 2), "%G-W%V-%u", "2004-W53-7"), - #(Time.utcDate(2005, 12, 31), "%G-W%V-%u", "2005-W52-6"), - #(Time.utcDate(2006, 1, 1), "%G-W%V-%u", "2005-W52-7"), - #(Time.utcDate(2006, 1, 2), "%G-W%V-%u", "2006-W01-1"), - #(Time.utcDate(2006, 12, 31), "%G-W%V-%u", "2006-W52-7"), - #(Time.utcDate(2007, 1, 1), "%G-W%V-%u", "2007-W01-1"), - #(Time.utcDate(2007, 12, 30), "%G-W%V-%u", "2007-W52-7"), - #(Time.utcDate(2007, 12, 31), "%G-W%V-%u", "2008-W01-1"), - #(Time.utcDate(2008, 1, 1), "%G-W%V-%u", "2008-W01-2"), - #(Time.utcDate(2008, 12, 28), "%G-W%V-%u", "2008-W52-7"), - #(Time.utcDate(2008, 12, 29), "%G-W%V-%u", "2009-W01-1"), - #(Time.utcDate(2008, 12, 30), "%G-W%V-%u", "2009-W01-2"), - #(Time.utcDate(2008, 12, 31), "%G-W%V-%u", "2009-W01-3"), - #(Time.utcDate(2009, 1, 1), "%G-W%V-%u", "2009-W01-4"), - #(Time.utcDate(2009, 12, 31), "%G-W%V-%u", "2009-W53-4"), - #(Time.utcDate(2010, 1, 1), "%G-W%V-%u", "2009-W53-5"), - #(Time.utcDate(2010, 1, 2), "%G-W%V-%u", "2009-W53-6"), - #(Time.utcDate(2010, 1, 3), "%G-W%V-%u", "2009-W53-7"), - #(Time.utcDate(1985, 4, 12), "%g-W%V-%u", "85-W15-5") + {Time.utcDate(1985, 4, 12), "%G-W%V-%u", "1985-W15-5"}, + {Time.utcDate(2005, 1, 1), "%G-W%V-%u", "2004-W53-6"}, + {Time.utcDate(2005, 1, 2), "%G-W%V-%u", "2004-W53-7"}, + {Time.utcDate(2005, 12, 31), "%G-W%V-%u", "2005-W52-6"}, + {Time.utcDate(2006, 1, 1), "%G-W%V-%u", "2005-W52-7"}, + {Time.utcDate(2006, 1, 2), "%G-W%V-%u", "2006-W01-1"}, + {Time.utcDate(2006, 12, 31), "%G-W%V-%u", "2006-W52-7"}, + {Time.utcDate(2007, 1, 1), "%G-W%V-%u", "2007-W01-1"}, + {Time.utcDate(2007, 12, 30), "%G-W%V-%u", "2007-W52-7"}, + {Time.utcDate(2007, 12, 31), "%G-W%V-%u", "2008-W01-1"}, + {Time.utcDate(2008, 1, 1), "%G-W%V-%u", "2008-W01-2"}, + {Time.utcDate(2008, 12, 28), "%G-W%V-%u", "2008-W52-7"}, + {Time.utcDate(2008, 12, 29), "%G-W%V-%u", "2009-W01-1"}, + {Time.utcDate(2008, 12, 30), "%G-W%V-%u", "2009-W01-2"}, + {Time.utcDate(2008, 12, 31), "%G-W%V-%u", "2009-W01-3"}, + {Time.utcDate(2009, 1, 1), "%G-W%V-%u", "2009-W01-4"}, + {Time.utcDate(2009, 12, 31), "%G-W%V-%u", "2009-W53-4"}, + {Time.utcDate(2010, 1, 1), "%G-W%V-%u", "2009-W53-5"}, + {Time.utcDate(2010, 1, 2), "%G-W%V-%u", "2009-W53-6"}, + {Time.utcDate(2010, 1, 3), "%G-W%V-%u", "2009-W53-7"}, + {Time.utcDate(1985, 4, 12), "%g-W%V-%u", "85-W15-5"} ] test "formats parts correctly" { diff --git a/core/tests/tests/Validation.mint b/core/tests/tests/Validation.mint index c9e55d210..eb062e3e6 100644 --- a/core/tests/tests/Validation.mint +++ b/core/tests/tests/Validation.mint @@ -1,82 +1,82 @@ suite "Validation.isNotBlank" { test "it returns nothing if the string is not blank" { - Validation.isNotBlank("a", #("key", "ERROR")) == Maybe.Nothing + Validation.isNotBlank("a", {"key", "ERROR"}) == Maybe.Nothing } test "it returns the error if the string is blank" { - Validation.isNotBlank("", #("key", "ERROR")) == Maybe.Just(#("key", "ERROR")) + Validation.isNotBlank("", {"key", "ERROR"}) == Maybe.Just({"key", "ERROR"}) } } suite "Validation.isNumber" { test "it returns nothing if the string can be converted to number" { - Validation.isNumber("0", #("key", "ERROR")) == Maybe.Nothing && - Validation.isNumber("0.1", #("key", "ERROR")) == Maybe.Nothing && - Validation.isNumber("0x10", #("key", "ERROR")) == Maybe.Nothing + Validation.isNumber("0", {"key", "ERROR"}) == Maybe.Nothing && + Validation.isNumber("0.1", {"key", "ERROR"}) == Maybe.Nothing && + Validation.isNumber("0x10", {"key", "ERROR"}) == Maybe.Nothing } test "it returns the error if the string cannot be converted to number" { - Validation.isNumber("", #("key", "ERROR")) == Maybe.Just(#("key", "ERROR")) + Validation.isNumber("", {"key", "ERROR"}) == Maybe.Just({"key", "ERROR"}) } test "it returns the error if the string contains letters at the end" { - Validation.isNumber("0a", #("key", "ERROR")) == Maybe.Just(#("key", "ERROR")) + Validation.isNumber("0a", {"key", "ERROR"}) == Maybe.Just({"key", "ERROR"}) } } suite "Validation.isDigits" { test "it returns nothing if the string consists of one or more digits" { - Validation.isDigits("123", #("key", "ERROR")) == Maybe.Nothing + Validation.isDigits("123", {"key", "ERROR"}) == Maybe.Nothing } test "it returns the error if the string is empty" { - Validation.isDigits("", #("key", "ERROR")) == Maybe.Just(#("key", "ERROR")) + Validation.isDigits("", {"key", "ERROR"}) == Maybe.Just({"key", "ERROR"}) } test "it returns the error if the string contains non-digits" { - Validation.isDigits("a", #("key", "ERROR")) == Maybe.Just(#("key", "ERROR")) && - Validation.isDigits(" 1 ", #("key", "ERROR")) == Maybe.Just(#("key", "ERROR")) && - Validation.isDigits("1.2", #("key", "ERROR")) == Maybe.Just(#("key", "ERROR")) + Validation.isDigits("a", {"key", "ERROR"}) == Maybe.Just({"key", "ERROR"}) && + Validation.isDigits(" 1 ", {"key", "ERROR"}) == Maybe.Just({"key", "ERROR"}) && + Validation.isDigits("1.2", {"key", "ERROR"}) == Maybe.Just({"key", "ERROR"}) } } suite "Validation.isSame" { test "it returns nothing if the two strings are the same" { - Validation.isSame("a", "a", #("key", "ERROR")) == Maybe.Nothing + Validation.isSame("a", "a", {"key", "ERROR"}) == Maybe.Nothing } test "it returns the error if the two strings are not the same" { - Validation.isSame("a", "b", #("key", "ERROR")) == Maybe.Just(#("key", "ERROR")) + Validation.isSame("a", "b", {"key", "ERROR"}) == Maybe.Just({"key", "ERROR"}) } } suite "Validation.hasExactNumberOfCharacters" { test "it returns nothing if the string have the exact number of characters" { - Validation.hasExactNumberOfCharacters("a", 1, #("key", "ERROR")) == Maybe.Nothing + Validation.hasExactNumberOfCharacters("a", 1, {"key", "ERROR"}) == Maybe.Nothing } test "it returns the error if the string does not have the exact number of characters" { - Validation.hasExactNumberOfCharacters("a", 2, #("key", "ERROR")) == Maybe.Just(#("key", "ERROR")) + Validation.hasExactNumberOfCharacters("a", 2, {"key", "ERROR"}) == Maybe.Just({"key", "ERROR"}) } } suite "Validation.hasMinimumNumberOfCharacters" { test "it returns nothing if the string has at last the given number of characters" { - Validation.hasMinimumNumberOfCharacters("a", 1, #("key", "ERROR")) == Maybe.Nothing + Validation.hasMinimumNumberOfCharacters("a", 1, {"key", "ERROR"}) == Maybe.Nothing } test "it returns the error if the string does not have at last the given number of characters" { - Validation.hasMinimumNumberOfCharacters("a", 2, #("key", "ERROR")) == Maybe.Just(#("key", "ERROR")) + Validation.hasMinimumNumberOfCharacters("a", 2, {"key", "ERROR"}) == Maybe.Just({"key", "ERROR"}) } } suite "Validation.isValidEmail" { test "it returns nothing if the string is a valid email" { - Validation.isValidEmail("test@test.com", #("key", "ERROR")) == Maybe.Nothing + Validation.isValidEmail("test@test.com", {"key", "ERROR"}) == Maybe.Nothing } test "it returns the error if the string does not have at last the given number of characters" { - Validation.isValidEmail("invalid", #("key", "ERROR")) == Maybe.Just(#("key", "ERROR")) + Validation.isValidEmail("invalid", {"key", "ERROR"}) == Maybe.Just({"key", "ERROR"}) } } @@ -84,8 +84,8 @@ suite "Validation.merge" { test "it merges the results of each validation" { Validation.merge( [ - Validation.isNotBlank("", #("firstName", "Please enter the first name.")), - Validation.isNotBlank("", #("message", "Please enter the message.")) + Validation.isNotBlank("", {"firstName", "Please enter the first name."}), + Validation.isNotBlank("", {"message", "Please enter the message."}) ]) == (Map.empty() |> Map.set("firstName", ["Please enter the first name."]) |> Map.set("message", ["Please enter the message."])) diff --git a/core/tests/tests/Window.mint b/core/tests/tests/Window.mint index 797536f66..010b05eb0 100644 --- a/core/tests/tests/Window.mint +++ b/core/tests/tests/Window.mint @@ -1,31 +1,55 @@ component ScrollTest { - use Provider.Scroll { scrolls: (event : Html.Event) : Promise(Void) { `this.forceUpdate()` } } + state scrollWidth = 0 + state scrollLeft = 0 + state scrollTop = 0 + + use Provider.Scroll { + scrolls: + (event : Html.Event) : Promise(Void) { + update() + } + } style base { height: 3000px; width: 3000px; } - fun componentDidMount : Void { - `this.forceUpdate()` + fun componentDidMount : Promise(Void) { + update() + } + + fun update { + next + { + scrollWidth: Window.scrollWidth(), + scrollLeft: Window.scrollLeft(), + scrollTop: Window.scrollTop() + } } fun render : Html { - <{ Number.toString(Window.scrollWidth()) }> + Number.toString(scrollWidth) + "|" + - <{ Number.toString(Window.scrollHeight()) }> + Number.toString(Window.scrollHeight()) + "|" + - <{ Number.toString(Window.scrollLeft()) }> + Number.toString(scrollLeft) + "|" + - <{ Number.toString(Window.scrollTop()) }> + Number.toString(scrollTop)
} @@ -33,12 +57,8 @@ component ScrollTest { suite "Window.navigate" { test "it navigates to the given url with push state" { - let url = - Window.url() - Window.navigate("/blah") - - Window.href() == "http://127.0.0.1:#{url.port}/blah" + String.endsWith(Window.href(), "/blah") } } @@ -57,13 +77,13 @@ suite "Window.setTitle" { suite "Window.url" { test "returns the current url" { - Window.url().hostname == "127.0.0.1" + Window.url().hostname == `window.location.hostname` } } suite "Window.href" { test "returns the current url as string" { - Window.href() == "http://127.0.0.1:#{Window.url().port}/" + Window.href() == `window.location.href` } } @@ -87,11 +107,6 @@ suite "Window.scrollWidth" { test "returns the scrollable width when overflown" { |> Test.Html.start() - |> Test.Context.then( - (subject : Dom.Element) : Promise(Dom.Element) { - await Timer.nextFrame() - subject - }) |> Test.Html.assertTextOf("scroll-width", "3008") } } diff --git a/documentation/Brand Book/logo-square.svg b/documentation/Brand Book/logo-square.svg new file mode 100644 index 000000000..c392ae425 --- /dev/null +++ b/documentation/Brand Book/logo-square.svg @@ -0,0 +1,80 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/documentation/Brand Book/logo-with-name-horizontal.svg b/documentation/Brand Book/logo-with-name-horizontal.svg new file mode 100644 index 000000000..b1025a6a0 --- /dev/null +++ b/documentation/Brand Book/logo-with-name-horizontal.svg @@ -0,0 +1,70 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/runtime/Makefile b/runtime/Makefile new file mode 100644 index 000000000..f85f6cbf7 --- /dev/null +++ b/runtime/Makefile @@ -0,0 +1,25 @@ +.PHONY: index +index: + yarn esbuild index.js \ + --outfile=../src/assets/runtime.js \ + --log-override:equals-nan=silent \ + --format=esm \ + --minify \ + --bundle + +.PHONY: index_testing +index_testing: + yarn esbuild index_testing.js \ + --outfile=../src/assets/runtime_test.js \ + --log-override:equals-nan=silent \ + --format=esm \ + --minify \ + --bundle + +.PHONY: format +format: + yarn prettier --write *.js **/*.js + +.PHONY: test +test: + yarn vitest --coverage diff --git a/runtime/index.js b/runtime/index.js new file mode 100644 index 000000000..fe5a3ef09 --- /dev/null +++ b/runtime/index.js @@ -0,0 +1,16 @@ +export { useComputed, computed, signal, effect, batch } from "@preact/signals"; +export { createElement, Fragment as fragment } from "preact"; +export { useEffect, useMemo, useRef } from "preact/hooks"; + +export * from "./src/pattern_matching"; +export * from "./src/normalize_event"; +export * from "./src/utilities"; +export * from "./src/translate"; +export * from "./src/equality"; +export * from "./src/provider"; +export * from "./src/decoders"; +export * from "./src/encoders"; +export * from "./src/program"; +export * from "./src/portals"; +export * from "./src/variant"; +export * from "./src/styles"; diff --git a/runtime/index_testing.js b/runtime/index_testing.js new file mode 100644 index 000000000..a0f50ab46 --- /dev/null +++ b/runtime/index_testing.js @@ -0,0 +1,3 @@ +export { render as testRender } from "preact"; +export * from "./src/testing"; +export * from "./index"; diff --git a/runtime/package.json b/runtime/package.json new file mode 100644 index 000000000..e85cd0685 --- /dev/null +++ b/runtime/package.json @@ -0,0 +1,19 @@ +{ + "private": true, + "dependencies": { + "route-parser": "mint-lang/mint-route-parser", + "@preact/signals": "^1.2.2", + "indent-string": "^5.0.0", + "fast-equals": "^5.0.1", + "uuid-random": "^1.3.2", + "preact": "^10.19.3" + }, + "devDependencies": { + "@testing-library/preact": "^3.2.3", + "@vitest/coverage-v8": "^1.2.1", + "esbuild": "^0.19.11", + "prettier": "^3.1.0", + "vitest": "^1.2.1", + "jsdom": "^23.2.0" + } +} diff --git a/runtime/src/decoders.js b/runtime/src/decoders.js new file mode 100644 index 000000000..20fc5a518 --- /dev/null +++ b/runtime/src/decoders.js @@ -0,0 +1,345 @@ +import indentString from "indent-string"; + +// Formats the given value as JSON with extra indentation. +const format = (value) => { + let string = JSON.stringify(value, "", 2); + + if (typeof string === "undefined") { + string = "undefined"; + } + + return indentString(string); +}; + +// A class to keep the errors when decoding. It keeps track of the path +// to the nested objects for reporting purpuses. +export class Error { + constructor(message, path = []) { + this.message = message; + this.object = null; + this.path = path; + } + + push(input) { + this.path.unshift(input); + } + + toString() { + const message = this.message.trim(); + + const path = this.path.reduce((memo, item) => { + if (memo.length) { + switch (item.type) { + case "FIELD": + return `${memo}.${item.value}`; + case "ARRAY": + return `${memo}[${item.value}]`; + } + } else { + switch (item.type) { + case "FIELD": + return item.value; + case "ARRAY": + return `[$(item.value)]`; + } + } + }, ""); + + if (path.length && this.object) { + return ( + message + + "\n\n" + + IN_OBJECT.trim() + .replace("{value}", format(this.object)) + .replace("{path}", path) + ); + } else { + return message; + } + } +} + +const IN_OBJECT = ` +The input is in this object: + +{value} + +at: {path} +`; + +const NOT_A_STRING = ` +I was trying to decode the value: + +{value} + +as a String, but could not. +`; + +const NOT_A_TIME = ` +I was trying to decode the value: + +{value} + +as a Time, but could not. +`; + +const NOT_A_NUMBER = ` +I was trying to decode the value: + +{value} + +as a Number, but could not. +`; + +const NOT_A_BOOLEAN = ` +I was trying to decode the value: + +{value} + +as a Bool, but could not. +`; + +const NOT_AN_OBJECT = ` +I was trying to decode the field "{field}" from the object: + +{value} + +but I could not because it's not an object. +`; + +const NOT_AN_ARRAY = ` +I was trying to decode the value: + +{value} + +as an Array, but could not. +`; + +const NOT_A_TUPLE = ` +I was trying to decode the value: + +{value} + +as an Tuple, but could not. +`; + +const TUPLE_ITEM_MISSING = ` +I was trying to decode one of the values of a tuple: + +{value} + +but could not. +`; + +const NOT_A_MAP = ` +I was trying to decode the value: + +{value} + +as a Map, but could not. +`; + +// Decodes `String` (by checking for the type equality). +export const decodeString = (ok, err) => (input) => { + if (typeof input != "string") { + return new err(new Error(NOT_A_STRING.replace("{value}", format(input)))); + } else { + return new ok(input); + } +}; + +// Decodes `Time` either a UNIX timestamp or any values that the +// environment can parse with the `Date` construtor. +export const decodeTime = (ok, err) => (input) => { + let parsed = NaN; + + if (typeof input === "number") { + parsed = new Date(input); + } else { + parsed = Date.parse(input); + } + + if (Number.isNaN(parsed)) { + return new err(new Error(NOT_A_TIME.replace("{value}", format(input)))); + } else { + return new ok(new Date(parsed)); + } +}; + +// Decodes `Number` using `parseFloat`. +export const decodeNumber = (ok, err) => (input) => { + let value = parseFloat(input); + + if (isNaN(value)) { + return new err(new Error(NOT_A_NUMBER.replace("{value}", format(input)))); + } else { + return new ok(value); + } +}; + +// Decodes `Bool` (by checking for type) +export const decodeBoolean = (ok, err) => (input) => { + if (typeof input != "boolean") { + return new err(new Error(NOT_A_BOOLEAN.replace("{value}", format(input)))); + } else { + return new ok(input); + } +}; + +// Decodes an object field using the decoder (only works on "object" types +// except arrays) +export const decodeField = (key, decoder, err) => (input) => { + if ( + typeof input !== "object" || + Array.isArray(input) || + input == undefined || + input == null + ) { + const message = NOT_AN_OBJECT.replace("{field}", key).replace( + "{value}", + format(input), + ); + + return new err(new Error(message)); + } else { + const decoded = decoder(input[key]); + + if (decoded instanceof err) { + decoded._0.push({ type: "FIELD", value: key }); + decoded._0.object = input; + } + + return decoded; + } +}; + +// Decodes `Array` with the decoder. +export const decodeArray = (decoder, ok, err) => (input) => { + if (!Array.isArray(input)) { + return new err(new Error(NOT_AN_ARRAY.replace("{value}", format(input)))); + } + + let results = []; + let index = 0; + + for (let item of input) { + let result = decoder(item); + + if (result instanceof err) { + result._0.push({ type: "ARRAY", value: index }); + result._0.object = input; + return result; + } else { + results.push(result._0); + } + + index++; + } + + return new ok(results); +}; + +// Decodes `Maybe`. `null` and `undefined` becomes `Nothing` otherwise +// the decoded value is returned as a `Just`. +export const decodeMaybe = (decoder, ok, err, just, nothing) => (input) => { + if (input === null || input === undefined) { + return new ok(new nothing()); + } else { + const result = decoder(input); + + if (result instanceof err) { + return result; + } else { + return new ok(new just(result._0)); + } + } +}; + +// Decodes `Tuple(...)` with the decoders. +export const decodeTuple = (decoders, ok, err) => (input) => { + if (!Array.isArray(input)) { + return new err(new Error(NOT_A_TUPLE.replace("{value}", format(input)))); + } + + let results = []; + let index = 0; + + for (let decoder of decoders) { + if (input[index] === undefined || input[index] === null) { + return new err( + new Error(TUPLE_ITEM_MISSING.replace("{value}", format(input[index]))), + ); + } else { + let result = decoder(input[index]); + + if (result instanceof err) { + result._0.push({ type: "ARRAY", value: index }); + result._0.object = input; + return result; + } else { + results.push(result._0); + } + } + + index++; + } + + return new ok(results); +}; + +// Decodes an object as a `Map(key, value)` (it only works on objects with +// string keys so normal objects). +export const decodeMap = (decoder, ok, err) => (input) => { + if ( + typeof input !== "object" || + Array.isArray(input) || + input == undefined || + input == null + ) { + const message = NOT_A_MAP.replace("{value}", format(input)); + + return new err(new Error(message)); + } else { + const map = []; + + for (let key in input) { + const result = decoder(input[key]); + + if (result instanceof err) { + return result; + } else { + map.push([key, result._0]); + } + } + + return new ok(map); + } +}; + +// Decodes a record, using the mappings. +export const decoder = (mappings, ok, err) => (input) => { + const object = {}; + + for (let key in mappings) { + let decoder = mappings[key]; + let target = key; + + if (Array.isArray(decoder)) { + decoder = mappings[key][0]; + target = mappings[key][1]; + } + + const result = decodeField(target, decoder, err)(input); + + if (result instanceof err) { + return result; + } + + object[key] = result._0; + } + + return new ok(object); +}; + +// Decodes an `object` by wrapping in an `Ok`. +export const decodeObject = (ok) => (value) => new ok(value); diff --git a/runtime/src/encoders.js b/runtime/src/encoders.js new file mode 100644 index 000000000..d97a1ac30 --- /dev/null +++ b/runtime/src/encoders.js @@ -0,0 +1,61 @@ +import { identity } from "./utilities"; + +// Encodes `Time` +export const encodeTime = (value) => value.toISOString(); + +// Encodes `Array(item)` +export const encodeArray = (encoder) => (value) => { + return value.map((item) => { + return encoder ? encoder(item) : item; + }); +}; + +// Encodes `Map(String, value)` as a JS object. `Map` internally is just +// an array of key, value pairs which is an array as well. +export const encodeMap = (encoder) => (value) => { + const result = {}; + + for (let item of value) { + result[item[0]] = encoder ? encoder(item[1]) : item[1]; + } + + return result; +}; + +// Encodes `Maybe`. `Nothing` becomes `null`, `Just` is unwrapped. +export const encodeMaybe = (encoder, just) => (value) => { + if (value instanceof just) { + return encoder(value._0); + } else { + return null; + } +}; + +// Encodes `Tuple(...)` +export const encodeTuple = (encoders) => (value) => { + return value.map((item, index) => { + const encoder = encoders[index]; + return encoder ? encoder(item) : item; + }); +}; + +// Encode a record with the encoders. An encoder can be a function or +// an array where the first item is the function the second is the key +// to use. +export const encoder = (encoders) => (value) => { + const result = {}; + + for (let key in encoders) { + let encoder = encoders[key]; + let field = key; + + if (Array.isArray(encoder)) { + encoder = encoders[key][0]; + field = encoders[key][1]; + } + + result[field] = (encoder || identity)(value[key]); + } + + return result; +}; diff --git a/runtime/src/equality.js b/runtime/src/equality.js new file mode 100644 index 000000000..189a67282 --- /dev/null +++ b/runtime/src/equality.js @@ -0,0 +1,176 @@ +// This file contains code to have value equality instead of reference equality. +// We use a `Symbol` to have a custom equality functions and then use these +// functions when comparing two values. +export const Equals = Symbol("Equals"); + +/* v8 ignore next 3 */ +if (typeof Node === "undefined") { + self.Node = class {} +} + +// We use regular functions instead of arrow functions because they have +// binding (this, arguments, etc...). +Boolean.prototype[Equals] = + Symbol.prototype[Equals] = + Number.prototype[Equals] = + String.prototype[Equals] = + function (other) { + return this.valueOf() === other; + }; + +Date.prototype[Equals] = function (other) { + return +this === +other; +}; + +Function.prototype[Equals] = Node.prototype[Equals] = function (other) { + return this === other; +}; + +// Search parameters need to be the same string to be equal. +URLSearchParams.prototype[Equals] = function (other) { + if (other === null || other === undefined) { + return false; + } + + return this.toString() === other.toString(); +}; + +// Sets need to have the same elements to be equal. +Set.prototype[Equals] = function (other) { + if (other === null || other === undefined) { + return false; + } + + return compare(Array.from(this).sort(), Array.from(other).sort()); +}; + +// Arrays need to have the same elements to be equal. +Array.prototype[Equals] = function (other) { + if (other === null || other === undefined) { + return false; + } + + if (this.length !== other.length) { + return false; + } + + if (this.length == 0) { + return true; + } + + for (let index in this) { + if (!compare(this[index], other[index])) { + return false; + } + } + + return true; +}; + +// Form data need to have the same elements to be equal. +FormData.prototype[Equals] = function (other) { + if (other === null || other === undefined) { + return false; + } + + const bKeys = Array.from(other.keys()).sort(); + const aKeys = Array.from(this.keys()).sort(); + + if (compare(aKeys, bKeys)) { + if (aKeys.length == 0) { + return true; + } + + for (let key of aKeys) { + const bValue = Array.from(other.getAll(key).sort()); + const aValue = Array.from(this.getAll(key).sort()); + + if (!compare(aValue, bValue)) { + return false; + } + } + + return true; + } else { + return false; + } +}; + +// Maps need to have the same keys and values to be equal. +Map.prototype[Equals] = function (other) { + if (other === null || other === undefined) { + return false; + } + + const aKeys = Array.from(this.keys()).sort(); + const bKeys = Array.from(other.keys()).sort(); + + if (compare(aKeys, bKeys)) { + if (aKeys.length == 0) { + return true; + } + + for (let key of aKeys) { + if (!compare(this.get(key), other.get(key))) { + return false; + } + } + + return true; + } else { + return false; + } +}; + +// If the object has a specific set of keys it's a Preact virtual DOM node. +const isVnode = (object) => + object !== undefined && + object !== null && + typeof object == "object" && + "constructor" in object && + "props" in object && + "type" in object && + "ref" in object && + "key" in object && + "__" in object + +// This is the custom comparison function. +export const compare = (a, b) => { + if ((a === undefined && b === undefined) || (a === null && b === null)) { + return true; + } else if (a != null && a != undefined && a[Equals]) { + return a[Equals](b); + } else if (b != null && b != undefined && b[Equals]) { + return b[Equals](a); + } else if (isVnode(a) || isVnode(b)) { + return a === b + } else { + return compareObjects(a, b); + } +}; + +// This is the custom comparison function for plain objects. +export const compareObjects = (a, b) => { + if (a instanceof Object && b instanceof Object) { + const aKeys = Object.keys(a); + const bKeys = Object.keys(b); + + if (aKeys.length !== bKeys.length) { + return false; + } + + const keys = new Set(aKeys.concat(bKeys)); + + for (let key of keys) { + if (!compare(a[key], b[key])) { + return false; + } + } + + return true; + } else { + // We fall back to strict equality if there is something we don't know + // how to compare. + return a === b; + } +}; diff --git a/runtime/src/normalize_event.js b/runtime/src/normalize_event.js new file mode 100644 index 000000000..3f37003c1 --- /dev/null +++ b/runtime/src/normalize_event.js @@ -0,0 +1,141 @@ +import { options } from "preact"; + +// Polyfill DataTransfer +if (!("DataTransfer" in window)) { + window.DataTransfer = class { + constructor() { + this.effectAllowed = "none"; + this.dropEffect = "none"; + this.files = []; + this.types = []; + this.cache = {}; + } + + getData(format) { + return this.cache[format] || ""; + } + + setData(format, data) { + this.cache[format] = data; + return null; + } + + clearData() { + this.cache = {}; + return null; + } + }; +} + +// Set the event option hook to normalize the event so we can use one type +// for events (`Html.Event``) instead of multiple event types like in +// JavaScript (`MouseEvent`, `KeyboardEvent`, etc...). Basically we make sure +// that there are values for all fields using a proxy (which makes it lazy). +export const normalizeEvent = (event) => { + return new Proxy(event, { + get: function (obj, prop) { + if (prop === "event") { + return event; + } else if (prop in obj) { + const value = obj[prop]; + + if (value instanceof Function) { + return () => obj[prop](); + } else { + return value; + } + } else { + switch (prop) { + // onCopy onCut onPaste + case "clipboardData": + return (obj.clipboardData = new DataTransfer()); + + // drag events + case "dataTransfer": + return (obj.dataTransfer = new DataTransfer()); + + // onCompositionEnd onCompositionStart onCompositionUpdate + case "data": + return ""; + + // onKeyDown onKeyPress onKeyUp + case "altKey": + return false; + case "charCode": + return -1; + case "ctrlKey": + return false; + case "key": + return ""; + case "keyCode": + return -1; + case "locale": + return ""; + case "location": + return -1; + case "metaKey": + return false; + case "repeat": + return false; + case "shiftKey": + return false; + case "which": + return -1; + + // onClick onContextMenu onDoubleClick onDrag onDragStart onDragEnd + // onDragEnter onDragExit onDragLeave onDragOver onDrop onMouseDown + // onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver + // onMouseUp + case "button": + return -1; + case "buttons": + return -1; + case "clientX": + return -1; + case "clientY": + return -1; + case "pageX": + return -1; + case "pageY": + return -1; + case "screenX": + return -1; + case "screenY": + return -1; + + // onScroll + case "detail": + return -1; + + // onWheel + case "deltaMode": + return -1; + case "deltaX": + return -1; + case "deltaY": + return -1; + case "deltaZ": + return -1; + + // onAnimationStart onAnimationEnd onAnimationIteration + case "animationName": + return ""; + case "pseudoElement": + return ""; + case "elapsedTime": + return -1; + + // onTransitionEnd + case "propertyName": + return ""; + + default: + return undefined; + } + } + }, + }); +}; + +// Set the event preact hook. +options.event = normalizeEvent; diff --git a/runtime/src/pattern_matching.js b/runtime/src/pattern_matching.js new file mode 100644 index 000000000..ab430faf7 --- /dev/null +++ b/runtime/src/pattern_matching.js @@ -0,0 +1,152 @@ +import { compare } from "./equality"; + +// This is a pattern for destructuring records. +class PatternRecord { + constructor(patterns) { + this.patterns = patterns; + } +} + +// This is a pattern for destructuring types. +class Pattern { + constructor(variant, pattern) { + this.pattern = pattern; + this.variant = variant; + } +} + +// Export functions for creating various patterns. +export const pattern = (variant, pattern) => new Pattern(variant, pattern); +export const patternRecord = (patterns) => new PatternRecord(patterns); + +// Symbols to use during pattern matching. +export const patternVariable = Symbol("Variable"); +export const patternSpread = Symbol("Spread"); + +// Destructures the value using the pattern and returns the matched values of +// the pattern as an array. If the value cannot be destructured it returns +// `false`. This is a recursive function. +export const destructure = (value, pattern, values = []) => { + // If the pattern is null it means that we skip this value. + if (pattern === null) { + // This branch matches a variable in the pattern + } else if (pattern === patternVariable) { + values.push(value); + // This branch covers tuples and arrays (they are the same) + } else if (Array.isArray(pattern)) { + const hasSpread = pattern.some((item) => item === patternSpread); + + // If we have spreads and the arrays length is bigger then the patterns + // length that means that there will be values in the spread. + if (hasSpread && value.length >= pattern.length - 1) { + let startIndex = 0; + let endValues = []; + let endIndex = 1; + + // This destructures the head patterns until a spread (if any). + while ( + pattern[startIndex] !== patternSpread && + startIndex < pattern.length + ) { + if (!destructure(value[startIndex], pattern[startIndex], values)) { + return false; + } + startIndex++; + } + + // This destructures the tail patterns backwards until a spread (if any). + while ( + pattern[pattern.length - endIndex] !== patternSpread && + endIndex < pattern.length + ) { + if ( + !destructure( + value[value.length - endIndex], + pattern[pattern.length - endIndex], + endValues, + ) + ) { + return false; + } + endIndex++; + } + + // Add in the spread + values.push(value.slice(startIndex, value.length - (endIndex - 1))); + + // Add in the end values + for (let item of endValues) { + values.push(item); + } + // This branch is for without spreads. We can only destructure patterns + // which have the same length. + } else { + if (pattern.length !== value.length) { + return false; + } else { + for (let index in pattern) { + if (!destructure(value[index], pattern[index], values)) { + return false; + } + } + } + } + // This branch covers type variants. + } else if (pattern instanceof Pattern) { + if (value instanceof pattern.variant) { + if (pattern.pattern instanceof PatternRecord) { + if (!destructure(value, pattern.pattern, values)) { + return false; + } + } else { + for (let index in pattern.pattern) { + if ( + !destructure(value[`_${index}`], pattern.pattern[index], values) + ) { + return false; + } + } + } + } else { + return false; + } + // This branch covers type variants as records. + } else if (pattern instanceof PatternRecord) { + for (let index in pattern.patterns) { + const item = pattern.patterns[index]; + + if (!destructure(value[item[0]], item[1], values)) { + return false; + } + } + // We compare anything else. + } else { + if (!compare(value, pattern)) { + return false; + } + } + + return values; +}; + +// Matches a value with different patterns and calls the function of the first +// matching pattern. +// +// match("Hello", [ +// ["World", () => "It's world"], +// [patternVariable, (value) => value] // This is matched +// ]) +// +export const match = (value, branches) => { + for (let branch of branches) { + if (branch[0] === null) { + return branch[1](); + } else { + const values = destructure(value, branch[0]); + + if (values) { + return branch[1].apply(null, values); + } + } + } +}; diff --git a/runtime/src/portals.js b/runtime/src/portals.js new file mode 100644 index 000000000..a828c428b --- /dev/null +++ b/runtime/src/portals.js @@ -0,0 +1,87 @@ +/* +================================================================================ + +DO NOT EDIT THIS FILE! IT IS COPIED FROM: + +https://github.com/preactjs/preact/blob/main/compat/src/portals.js +(commit e16b520eadac9f91a32c645a2447036b73ac98f4) + +THIS IS BECAUSE `preact/compat` IS NOT TREE SHAKEABLE AND THIS WAY THE BUNDLE +SIZE IS 5KB SMALLER. + +================================================================================ +*/ + +import { createElement, render } from "preact"; + +/** + * @param {import('../../src/index').RenderableProps<{ context: any }>} props + */ +function ContextProvider(props) { + this.getChildContext = () => props.context; + return props.children; +} + +/** + * Portal component + * @this {import('./internal').Component} + * @param {object | null | undefined} props + * + * TODO: use createRoot() instead of fake root + */ +function Portal(props) { + const _this = this; + let container = props._container; + + _this.componentWillUnmount = function () { + render(null, _this._temp); + _this._temp = null; + _this._container = null; + }; + + // When we change container we should clear our old container and + // indicate a new mount. + if (_this._container && _this._container !== container) { + _this.componentWillUnmount(); + } + + if (!_this._temp) { + _this._container = container; + + // Create a fake DOM parent node that manages a subset of `container`'s children: + _this._temp = { + nodeType: 1, + parentNode: container, + childNodes: [], + appendChild(child) { + this.childNodes.push(child); + _this._container.appendChild(child); + }, + insertBefore(child, before) { + this.childNodes.push(child); + _this._container.appendChild(child); + }, + removeChild(child) { + this.childNodes.splice(this.childNodes.indexOf(child) >>> 1, 1); + _this._container.removeChild(child); + }, + }; + } + + // Render our wrapping element into temp. + render( + createElement(ContextProvider, { context: _this.context }, props._vnode), + _this._temp, + ); +} + +/** + * Create a `Portal` to continue rendering the vnode tree at a different DOM node + * @param {import('./internal').VNode} vnode The vnode to render + * @param {import('./internal').PreactElement} container The DOM node to continue rendering in to. + */ +export function createPortal(vnode, container) { + const el = createElement(Portal, { _vnode: vnode, _container: container }); + el.containerInfo = container; + return el; +} diff --git a/runtime/src/program.js b/runtime/src/program.js new file mode 100644 index 000000000..5773b98c6 --- /dev/null +++ b/runtime/src/program.js @@ -0,0 +1,241 @@ +import { deepEqual } from "fast-equals"; +import RouteParser from "route-parser"; +import { h, render } from "preact"; + +// An internally used error when we can't decode route parameters. +class DecodingError extends Error {} + +// Comparison function for route variables later on. +const equals = (a, b) => { + if (a instanceof Object) { + return b instanceof Object && deepEqual(a, b); + } else { + return !(b instanceof Object) && a === b; + } +}; + +// `queueMicrotask` polyfill. +const queueTask = (callback) => { + if (typeof window.queueMicrotask !== "function") { + Promise.resolve() + .then(callback) + .catch((e) => + setTimeout(() => { + throw e; + }), + ); + } else { + window.queueMicrotask(callback); + } +}; + +// Returns the route information by parsing the route. +const getRouteInfo = (url, routes) => { + for (let route of routes) { + if (route.path === "*") { + return { route: route, vars: false, url: url }; + } else { + let vars = new RouteParser(route.path).match(url); + + if (vars) { + return { route: route, vars: vars, url: url }; + } + } + } + + return null; +}; + +class Program { + constructor(ok, routes) { + this.root = document.createElement("div"); + this.routeInfo = null; + this.routes = routes; + this.ok = ok; + + document.body.appendChild(this.root); + + window.addEventListener("popstate", this.handlePopState.bind(this)); + window.addEventListener("click", this.handleClick.bind(this), true); + } + + handleClick(event) { + // If someone prevented default we honor that. + if (event.defaultPrevented) { + return; + } + + // If the control is pressed it means that the user wants + // to open it a new tab so we honor that. + if (event.ctrlKey) { + return; + } + + for (let element of event.composedPath()) { + if (element.tagName === "A") { + // If the target is not empty then it's probably `_blank` or + // an other window or frame so we skip. + if (element.target.trim() !== "") { + return; + } + + // We only handle same origin URLs. + if (element.origin === window.location.origin) { + const fullPath = element.pathname + element.search + element.hash; + const routeInfo = getRouteInfo(fullPath, this.routes); + + // If we found a matchin route, we prevent default and navigate to + // that route. + if (routeInfo) { + event.preventDefault(); + + navigate( + fullPath, + /* dispatch */ true, + /* triggerJump */ true, + routeInfo, + ); + return; + } + } + } + } + } + + // Handles resolving the page position after a navigation event. + resolvePagePosition(triggerJump) { + // Queue a microTask, this will run after Preact does a render. + queueTask(() => { + // On the next frame, the DOM should be updated already. + requestAnimationFrame(() => { + const hash = window.location.hash; + + if (hash) { + let elem = null; + + try { + elem = + this.root.querySelector(hash) || // ID + this.root.querySelector(`a[name="${hash.slice(1)}"]`); // Anchor + } catch {} + + if (elem) { + if (triggerJump) { + elem.scrollIntoView(); + } + } else { + console.warn( + `MINT: ${hash} matches no element with an id and no link with a name`, + ); + } + } else if (triggerJump) { + window.scrollTo(0, 0); + } + }); + }); + } + + // Handles navigation events. + async handlePopState(event) { + const url = + window.location.pathname + window.location.search + window.location.hash; + + const routeInfo = event?.routeInfo || getRouteInfo(url, this.routes); + + if (routeInfo) { + if ( + this.routeInfo === null || + routeInfo.url !== this.routeInfo.url || + !equals(routeInfo.vars, this.routeInfo.vars) + ) { + const handler = this.runRouteHandler(routeInfo); + if (routeInfo.route.await) { await handler } + } + + this.resolvePagePosition(!!event?.triggerJump); + } + + this.routeInfo = routeInfo; + } + + // Helper function for above. + async runRouteHandler(routeInfo) { + const { route } = routeInfo; + + if (route.path === "*") { + return route.handler(); + } else { + const { vars } = routeInfo; + + try { + let args = route.mapping.map((name, index) => { + const value = vars[name]; + const result = route.decoders[index](value); + + if (result instanceof this.ok) { + return result._0; + } else { + throw new DecodingError(); + } + }); + + return route.handler.apply(null, args); + } catch (error) { + if (error.constructor !== DecodingError) { + throw error; + } + } + } + } + + // Renders the program and runs current route handlers. + render(main, globals) { + const components = []; + + for (let key in globals) { + components.push(h(globals[key], { key: key })); + } + + let mainNode; + if (typeof main !== "undefined") { + mainNode = h(main, { key: "MINT_MAIN" }) + } + + render([...components, mainNode], this.root); + this.handlePopState(); + } +} + +// Function to navigate to a different url. +export const navigate = ( + url, + dispatch = true, + triggerJump = true, + routeInfo = null, +) => { + let pathname = window.location.pathname; + let search = window.location.search; + let hash = window.location.hash; + + let fullPath = pathname + search + hash; + + if (fullPath !== url) { + if (dispatch) { + window.history.pushState({}, "", url); + } else { + window.history.replaceState({}, "", url); + } + } + + if (dispatch) { + let event = new PopStateEvent("popstate"); + event.triggerJump = triggerJump; + event.routeInfo = routeInfo; + dispatchEvent(event); + } +}; + +// Creates a program. +export const program = (main, globals, ok, routes = []) => { + new Program(ok, routes).render(main, globals); +}; diff --git a/runtime/src/provider.js b/runtime/src/provider.js new file mode 100644 index 000000000..b1218db4a --- /dev/null +++ b/runtime/src/provider.js @@ -0,0 +1,47 @@ +import { useEffect, useMemo } from "preact/hooks"; +import { untracked } from "@preact/signals"; +import { compare } from "./equality"; +import uuid from "uuid-random"; + +// This creates a function which is used for subscribing to a provider. We use +// `untracked` to not to subscribe to any outside signals. +export const createProvider = (subscriptions, update) => { + // This is the subscription function. + return (owner, object) => { + const unsubscribe = () => { + if (subscriptions.has(owner)) { + subscriptions.delete(owner); + untracked(update); + } + }; + + // This will only run when the component unmounts. + useEffect(() => { + return unsubscribe; + }, []); + + // This runs on every update so we don't return a cleanup function. + useEffect(() => { + const data = object(); + + // If the object is null that means we need to unsubscribe. + if (data === null) { + unsubscribe(); + } else { + const current = subscriptions.get(owner); + + if (!compare(current, data)) { + subscriptions.set(owner, data); + untracked(update); + } + } + }); + }; +}; + +// Returns the subscriptions as an array. +export const subscriptions = (items) => Array.from(items.values()); + +// Returns a unique ID for a component which doesn't change. +export const useId = () => useMemo(uuid, []); +export { uuid }; diff --git a/runtime/src/styles.js b/runtime/src/styles.js new file mode 100644 index 000000000..68a983896 --- /dev/null +++ b/runtime/src/styles.js @@ -0,0 +1,42 @@ +// Inserts styles into the document (used in tests). +export const insertStyles = (styles) => { + let style = document.createElement("style"); + document.head.appendChild(style); + style.innerHTML = styles; +}; + +// Parses style data for an HTML element which can come in multiple forms: +// +// style="color: red" - A CSS string (we need to parse this) +// style={Map.set(Map.empty(), "color", "red")} - A Mint `Map` +// style=[{"color", "red"}] - A Mint Array of tuples +// style={`{color: "red"}`} - A JavaScript object +export const style = (items) => { + const result = {}; + + const setKeyValue = (key, value) => { + result[key.toString().trim()] = value.toString().trim(); + }; + + for (let item of items) { + if (typeof item === "string") { + item.split(";").forEach((prop) => { + const [key, value] = prop.split(":"); + + if (key && value) { + setKeyValue(key, value); + } + }); + } else if (item instanceof Map || item instanceof Array) { + for (let [key, value] of item) { + setKeyValue(key, value); + } + } else { + for (let key in item) { + setKeyValue(key, item[key]); + } + } + } + + return result; +}; diff --git a/runtime/src/testing.js b/runtime/src/testing.js new file mode 100644 index 000000000..ba0aace64 --- /dev/null +++ b/runtime/src/testing.js @@ -0,0 +1,210 @@ +import { compare } from "./equality"; + +// This is a class for tests. It allows to have multiple steps which are +// evaluated asynchronously. +class TestContext { + constructor(subject, teardown) { + this.teardown = teardown; + this.subject = subject; + this.steps = []; + } + + async run() { + let result; + + try { + result = await new Promise(this.next.bind(this)); + } finally { + this.teardown && this.teardown(); + } + + return result; + } + + async next(resolve, reject) { + requestAnimationFrame(async () => { + let step = this.steps.shift(); + + if (step) { + try { + this.subject = await step(this.subject); + } catch (error) { + return reject(error); + } + } + + if (this.steps.length) { + this.next(resolve, reject); + } else { + resolve(this.subject); + } + }); + } + + step(proc) { + this.steps.push(proc); + return this; + } +} + +// This is the test runner which runs the tests and sends reports to +// the CLI using websockets. +class TestRunner { + constructor(suites, url, id) { + this.socket = new WebSocket(url); + this.suites = suites; + this.url = url; + this.id = id; + + // Catch debug messages. + window.DEBUG = { + log: (value) => { + let result = ""; + + if (value === undefined) { + result = "undefined"; + } else if (value === null) { + result = "null"; + } else { + result = value.toString(); + } + + this.log(result); + }, + }; + + let error = null; + + window.onerror = (message) => { + if (this.socket.readyState === 1) { + this.crash(message); + } else { + error = error || message; + } + }; + + this.socket.onopen = () => { + if (error != null) { + this.crash(error); + } + }; + + this.start(); + } + + start() { + if (this.socket.readyState === 1) { + this.run(); + } else { + this.socket.addEventListener("open", () => this.run()); + } + } + + run() { + return new Promise((resolve, reject) => { + this.next(resolve, reject); + }) + .catch((e) => this.log(e.reason)) + .finally(() => this.socket.send("DONE")); + } + + report(type, suite, name, message, location) { + if (message && message.toString) { + message = message.toString(); + } + + this.socket.send( + JSON.stringify({ + location: location, + result: message, + suite: suite, + id: this.id, + type: type, + name: name, + }), + ); + } + + reportTested(test, type, message) { + this.report(type, this.suite.name, test.name, message, test.location); + } + + crash(message) { + this.report("CRASHED", null, null, message); + } + + log(message) { + this.report("LOG", null, null, message); + } + + next(resolve, reject) { + requestAnimationFrame(async () => { + if (!this.suite || this.suite.tests.length === 0) { + this.suite = this.suites.shift(); + + if (this.suite) { + this.report("SUITE", this.suite.name); + } else { + return resolve(); + } + } + + const test = this.suite.tests.shift(); + + try { + const result = await test.proc.call(this.suite.context); + + // Set the URL to the root one. + if (window.location.pathname !== "/") { + window.history.replaceState({}, "", "/"); + } + + // Clear storages. + sessionStorage.clear(); + localStorage.clear(); + + // TODO: Reset Stores + + if (result instanceof TestContext) { + try { + await result.run(); + this.reportTested(test, "SUCCEEDED", result.subject); + } catch (error) { + this.reportTested(test, "FAILED", error); + } + } else { + if (result) { + this.reportTested(test, "SUCCEEDED"); + } else { + this.reportTested(test, "FAILED"); + } + } + } catch (error) { + // An error occurred while trying to run a test; this is different from the test itself failing. + this.reportTested(test, "ERRORED", error); + } + + this.next(resolve, reject); + }); + } +} + +// This function creates a test for an equality operation (either == or !=). +export const testOperation = (left, right, operator) => { + return new TestContext(left).step((subject) => { + let result = compare(subject, right); + + if (operator === "==") { + result = !result; + } + + if (result) { + throw `Assertion failed: ${right} ${operator} ${subject}`; + } + + return true; + }); +}; + +export const testContext = TestContext; +export const testRunner = TestRunner; diff --git a/runtime/src/translate.js b/runtime/src/translate.js new file mode 100644 index 000000000..1e2dca85a --- /dev/null +++ b/runtime/src/translate.js @@ -0,0 +1,11 @@ +import { signal } from "@preact/signals"; + +// We have global signals for translations. +export const translations = signal({}); +export const locale = signal({}); + +// Global functions to set the locale and translate a key +// with the current locale. +export const setLocale = (value) => (locale.value = value); +export const translate = (key) => + (translations.value[locale.value] || {})[key] || ""; diff --git a/runtime/src/utilities.js b/runtime/src/utilities.js new file mode 100644 index 000000000..996062e6c --- /dev/null +++ b/runtime/src/utilities.js @@ -0,0 +1,110 @@ +import { createRef as createRefOriginal, Component, createElement } from "preact"; +import { useEffect, useRef, useMemo } from "preact/hooks"; +import { signal } from "@preact/signals"; + +import { compare } from "./equality"; + +// This finds the first element matching the key in a map ([[key, value]]). +export const mapAccess = (map, key, just, nothing) => { + for (const item of map) { + if (compare(item[0], key)) { + return new just(item[1]) + } + } + + return new nothing(); +} + +// We need to have a different function for accessing array items because there +// is no concept of `null` in Mint so we return `Just(a)` or `Nothing`. +export const bracketAccess = (array, index, just, nothing) => { + if (array.length >= index + 1 && index >= 0) { + return new just(array[index]); + } else { + return new nothing(); + } +}; + +// This sets the references to an element or component. The current +// value is always a `Maybe` +export const setRef = (value, just) => (element) => { + if (value.current._0 !== element) { + value.current = new just(element); + } +}; + +// A version of `useSignal`` which subscribes to the signal by default (like a +// state) since we want to re-render every time the signal changes. +export const useSignal = (value) => { + const item = useMemo(() => signal(value), []); + item.value; + return item; +}; + +// A version of `createRef` with a default value. +export const createRef = (value) => { + const ref = createRefOriginal(); + ref.current = value; + return ref; +}; + +// A hook to replace the `componentDidUpdate` function. +export const useDidUpdate = (callback) => { + const hasMount = useRef(false); + + useEffect(() => { + if (hasMount.current) { + callback(); + } else { + hasMount.current = true; + } + }); +}; + +// Function for the `or` operator. +export const or = (nothing, err, item, value) => { + if (item instanceof nothing || item instanceof err) { + return value; + } else { + return item._0; + } +}; + +// Converts the arguments into an array. +export const toArray = (...args) => { + let items = Array.from(args); + + if (Array.isArray(items[0]) && items.length === 1) { + return items[0]; + } else { + return items; + } +}; + +// Function for member access. +export const access = (field) => (value) => value[field]; + +// Identity function, used in encoders. +export const identity = (a) => a; + +export class lazyComponent extends Component { + async componentDidMount() { + let x = await this.props.x(); + this.setState({ x: x }) + } + + render() { + if (this.state.x) { + return createElement(this.state.x, this.props.p, this.props.c) + } else { + return null + } + } +} + +export const lazy = (path) => async () => load(path) + +export const load = async (path) => { + const x = await import(path) + return x.default +} diff --git a/runtime/src/variant.js b/runtime/src/variant.js new file mode 100644 index 000000000..b90f9282c --- /dev/null +++ b/runtime/src/variant.js @@ -0,0 +1,56 @@ +import { Equals, compareObjects, compare } from "./equality"; + +// The base class for variants. +class Variant { + [Equals](other) { + if (!(other instanceof this.constructor)) { + return false; + } + + if (other.length !== this.length) { + return false; + } + + if (this.record) { + return compareObjects(this, other); + } + + for (let index = 0; index < this.length; index++) { + if (!compare(this["_" + index], other["_" + index])) { + return false; + } + } + + return true; + } +} + +// Creates an type variant class, this is needed so we can do proper +// comparisons and pattern matching / destructuring. +export const variant = (input) => { + return class extends Variant { + constructor(...args) { + super(); + if (Array.isArray(input)) { + this.length = input.length; + this.record = true; + + for (let index = 0; index < input.length; index++) { + this[input[index]] = args[index]; + } + } else { + this.length = input; + + for (let index = 0; index < input; index++) { + this[`_${index}`] = args[index]; + } + } + } + }; +}; + +// Creates a new variant from variable arguments. +export const newVariant = + (item) => + (...args) => + new item(...args); diff --git a/runtime/tests/equality.test.js b/runtime/tests/equality.test.js new file mode 100644 index 000000000..91de76a21 --- /dev/null +++ b/runtime/tests/equality.test.js @@ -0,0 +1,285 @@ +import { expect, test, describe } from "vitest"; +import { compare } from "../index_testing"; + +test("comparing nulls", () => { + expect(compare(null, null)).toBe(true); + expect(compare(null, undefined)).toBe(false); + expect(compare(undefined, "")).toBe(false); +}); + +test("comparing nodes", () => { + expect(compare(document.body, document.body)).toBe(true); + expect(compare(document.body, document.head)).toBe(false); +}); + +test("comparing same symbols", () => { + expect(compare(Symbol("A"), Symbol("A"))).toBe(false); +}); + +test("comparing vnodes", () => { + expect(compare( + {props: {}, type: {}, ref: {}, key: {},"__": {}}, + {props: {}, type: {}, ref: {}, key: {},"__": {}} + )).toBe(false); +}) + +test("comparing same arrays", () => { + expect(["A"] == ["A"]).toBe(false); + expect(compare(["A"], ["A"])).toBe(true); +}); + +test("comparing functions", () => { + expect( + compare( + () => {}, + () => {}, + ), + ).toBe(false); +}); + +test("comparing empty arrays", () => { + expect([] == []).toBe(false); + expect(compare([], [])).toBe(true); +}); + +test("comparing arrays with null", () => { + expect(compare([], null)).toBe(false); +}); + +test("comparing arrays with undefined", () => { + expect(compare([], undefined)).toBe(false); +}); + +test("comparing different length arrays", () => { + expect(["A"] == ["A"]).toBe(false); + expect(compare(["A", "B"], ["A"])).toBe(false); +}); + +test("comparing different arrays", () => { + expect(compare(["A"], ["B"])).toBe(false); +}); + +test("comparing same dates", () => { + expect(new Date() == new Date()).toBe(false); + expect(compare(new Date(), new Date())).toBe(true); +}); + +test("comparing different dates", () => { + expect(compare(new Date(2018, 1, 1), new Date(2018, 1, 2))).toBe(false); +}); + +test("comparing same strings", () => { + expect(compare("A", "A")).toBe(true); +}); + +test("comparing same numbers", () => { + expect(compare(0, 0.0)).toBe(true); +}); + +test("comparing booleans", () => { + expect(compare(true, true)).toBe(true); +}); + +test("comparing objects", () => { + expect(compare({ a: "a" }, { a: "a" })).toBe(true); + expect(compare({ a: "a" }, { a: "b" })).toBe(false); + expect(compare({ a: "a" }, { a: "a", b: "c" })).toBe(false); +}); + +describe("URLSearchParams", () => { + test("false for null", () => { + const a = new URLSearchParams("a=b&c=d"); + + expect(compare(a, null)).toBe(false); + }); + + test("false for undefined", () => { + const a = new URLSearchParams("a=b&c=d"); + + expect(compare(a, undefined)).toBe(false); + }); + + test("same data are equal", () => { + const a = new URLSearchParams("a=b&c=d"); + const b = new URLSearchParams("a=b&c=d"); + + expect(compare(a, b)).toBe(true); + }); +}); + +describe("Map", () => { + test("false for undefined", () => { + const a = new Map(); + + expect(compare(a, undefined)).toBe(false); + }); + + test("false for null", () => { + const a = new Map(); + + expect(compare(a, null)).toBe(false); + }); + + test("same data are equal", () => { + const a = new Map([ + ["A", "B"], + ["X", "Y"], + ]); + const b = new Map([ + ["A", "B"], + ["X", "Y"], + ]); + + expect(compare(a, b)).toBe(true); + }); + + test("same data with different order are equal", () => { + const a = new Map([ + ["X", "Y"], + ["A", "B"], + ]); + const b = new Map([ + ["A", "B"], + ["X", "Y"], + ]); + + expect(compare(a, b)).toBe(true); + }); + + test("empty maps are equal", () => { + const a = new Map(); + const b = new Map(); + + expect(compare(a, b)).toBe(true); + }); + + test("different data are not equal", () => { + const a = new Map([ + ["A", "B"], + ["X", "Z"], + ]); + const b = new Map([ + ["A", "B"], + ["X", "Y"], + ]); + + expect(compare(a, b)).toBe(false); + }); + + test("data with different number of keys are not equal", () => { + const a = new Map([["A", "B"]]); + const b = new Map([ + ["A", "B"], + ["X", "Y"], + ]); + + expect(compare(a, b)).toBe(false); + }); +}); + +describe("Set", () => { + test("false for undefined", () => { + const a = new Set([]); + + expect(compare(a, undefined)).toBe(false); + }); + + test("false for null", () => { + const a = new Set([]); + + expect(compare(a, null)).toBe(false); + }); + + test("same data are equal", () => { + const a = new Set(["A", "B", "B"]); + const b = new Set(["A", "B", "B"]); + + expect(compare(a, b)).toBe(true); + }); + + test("same data not in order are equal", () => { + const a = new Set(["B", "A", "A"]); + const b = new Set(["A", "B", "B"]); + + expect(compare(a, b)).toBe(true); + }); + + test("different data does not equal", () => { + const a = new Set(["B", "C", "A"]); + const b = new Set(["A", "B", "B"]); + + expect(compare(a, b)).toBe(false); + }); +}); + +describe("FormData", () => { + test("false for undefined", () => { + const a = new FormData(); + + expect(compare(a, undefined)).toBe(false); + }); + + test("false for null", () => { + const a = new FormData(); + + expect(compare(a, null)).toBe(false); + }); + + test("empty form datas are equal", () => { + expect(compare(new FormData(), new FormData())).toBe(true); + }); + + test("same data form datas are equal", () => { + const a = new FormData(); + a.append("a", "a"); + + const b = new FormData(); + b.append("a", "a"); + + expect(compare(a, b)).toBe(true); + }); + + test("different datas are not equal", () => { + const a = new FormData(); + a.append("a", "a"); + + const b = new FormData(); + b.append("b", "a"); + + expect(compare(a, b)).toBe(false); + }); + + test("different datas are not equal", () => { + const a = new FormData(); + a.append("a", "b"); + + const b = new FormData(); + b.append("a", "a"); + + expect(compare(a, b)).toBe(false); + }); + + test("same multiple data form datas are equal", () => { + const a = new FormData(); + a.append("a", "a"); + a.append("a", "b"); + + const b = new FormData(); + b.append("a", "b"); + b.append("a", "a"); + + expect(compare(a, b)).toBe(true); + }); + + test("same multiple data form datas with different order are equal", () => { + const a = new FormData(); + a.append("a", "b"); + a.append("x", "y"); + + const b = new FormData(); + b.append("x", "y"); + b.append("a", "b"); + + expect(compare(a, b)).toBe(true); + }); +}); diff --git a/runtime/tests/normalize_event.test.js b/runtime/tests/normalize_event.test.js new file mode 100644 index 000000000..06f659283 --- /dev/null +++ b/runtime/tests/normalize_event.test.js @@ -0,0 +1,50 @@ +import { expect, test, describe } from "vitest"; +import { normalizeEvent } from "../index"; + +describe("normalizeEvent", () => { + test("returns default values if they are not defined", () => { + const original = { test: "X", preventDefault: () => "P" }; + const event = normalizeEvent(original); + + expect(event.dataTransfer).not.toBe(undefined); + expect(event.dataTransfer.setData("test", "test")).toBe(null); + expect(event.dataTransfer.getData("not present")).toBe(""); + expect(event.dataTransfer.getData("test")).toBe("test"); + expect(event.dataTransfer.clearData()).toBe(null); + + expect(event.clipboardData).not.toBe(undefined); + expect(event.preventDefault()).toBe("P"); + expect(event.animationName).toBe(""); + expect(event.pseudoElement).toBe(""); + expect(event.propertyName).toBe(""); + expect(event.elapsedTime).toBe(-1); + expect(event.shiftKey).toBe(false); + expect(event.blah).toBe(undefined); + expect(event.event).toBe(original); + expect(event.metaKey).toBe(false); + expect(event.ctrlKey).toBe(false); + expect(event.repeat).toBe(false); + expect(event.altKey).toBe(false); + expect(event.deltaMode).toBe(-1); + expect(event.charCode).toBe(-1); + expect(event.location).toBe(-1); + expect(event.keyCode).toBe(-1); + expect(event.buttons).toBe(-1); + expect(event.clientX).toBe(-1); + expect(event.clientY).toBe(-1); + expect(event.screenY).toBe(-1); + expect(event.screenX).toBe(-1); + expect(event.button).toBe(-1); + expect(event.detail).toBe(-1); + expect(event.which).toBe(-1); + expect(event.pageX).toBe(-1); + expect(event.pageY).toBe(-1); + expect(event.deltaX).toBe(-1); + expect(event.deltaY).toBe(-1); + expect(event.deltaZ).toBe(-1); + expect(event.locale).toBe(""); + expect(event.test).toBe("X"); + expect(event.data).toBe(""); + expect(event.key).toBe(""); + }); +}); diff --git a/runtime/tests/provider.test.js b/runtime/tests/provider.test.js new file mode 100644 index 000000000..fd34acebd --- /dev/null +++ b/runtime/tests/provider.test.js @@ -0,0 +1,29 @@ +import { render, fireEvent } from "@testing-library/preact"; +import { expect, test, describe } from "vitest"; +import { useState } from "preact/hooks"; +import { h } from "preact"; + +import { createProvider, useProviders, useId, subscriptions } from "../index"; + +const map = new Map(); +const provider = createProvider(map, () => {}); + +describe("providers", () => { + test("works correctly", () => { + /* + const item = h(() => { + const [count, setCount] = useState(0); + const id = useId(); + + useProviders([() => provider(id, count == 1 ? {} : null)]); + + return h("div", { onClick: () => setCount(1) }, "TEST"); + }); + + const items = subscriptions(map); + const container = render(item); + + fireEvent.click(container.getByText("TEST")); + */ + }); +}); diff --git a/runtime/tests/styles.test.js b/runtime/tests/styles.test.js new file mode 100644 index 000000000..d92dd27e0 --- /dev/null +++ b/runtime/tests/styles.test.js @@ -0,0 +1,32 @@ +import { expect, test, describe } from "vitest"; +import { insertStyles, style } from "../index"; + +describe("insertStyles", () => { + test("adds styles to the document", () => { + insertStyles("test"); + expect(document.head.querySelector("style").textContent).toBe("test"); + }); +}); + +describe("style", () => { + test("it creates an object from objects and maps", () => { + expect( + style([ + "opacity:0; z-index: 100 ; ", + new Map([["a", "b"]]), + new Map([[101, "d"]]), + [["x", "y"]], + { c: "d" }, + { z: 123 }, + ]), + ).toEqual({ + "z-index": "100", + opacity: "0", + a: "b", + 101: "d", + x: "y", + c: "d", + z: "123", + }); + }); +}); diff --git a/runtime/tests/translate.test.js b/runtime/tests/translate.test.js new file mode 100644 index 000000000..9dd24f128 --- /dev/null +++ b/runtime/tests/translate.test.js @@ -0,0 +1,15 @@ +import { expect, test, describe } from "vitest"; +import { setLocale, translate, locale } from "../index"; + +describe("setLocale", () => { + test("setting locale", () => { + setLocale("en"); + expect(locale.value).toEqual("en"); + }); +}); + +describe("translate", () => { + test("translates a key", () => { + expect(translate("test")).toEqual(""); + }); +}); diff --git a/runtime/tests/utilities.test.js b/runtime/tests/utilities.test.js new file mode 100644 index 000000000..bb3652c43 --- /dev/null +++ b/runtime/tests/utilities.test.js @@ -0,0 +1,85 @@ +import { render, fireEvent } from "@testing-library/preact"; +import { expect, test, describe } from "vitest"; +import { useState } from "preact/hooks"; +import { h } from "preact"; + +import { + useDidUpdate, + bracketAccess, + useFunction, + identity, + variant, + toArray, + access, + or, +} from "../index"; + +const Nothing = variant(); +const Just = variant(1); +const Err = variant(1); + +describe("bracketAccess", () => { + test("it returns a just for an element", () => { + let result = bracketAccess([0], 0, Just, Nothing); + + expect(result).toBeInstanceOf(Just); + expect(result._0).toBe(0); + }); + + test("it returns nothing for an element", () => { + let result = bracketAccess([0], 1, Just, Nothing); + + expect(result).toBeInstanceOf(Nothing); + }); + + test("it returns nothing if index is negative", () => { + let result = bracketAccess([0], -1, Just, Nothing); + + expect(result).toBeInstanceOf(Nothing); + }); +}); + +describe("or", () => { + test("it returns the given item", () => { + expect(or(Nothing, Err, new Just("a"), "b")).toEqual("a"); + }); + + test("it returns the given item", () => { + expect(or(Nothing, Err, new Nothing, "b")).toEqual("b"); + }); +}); + +describe("access", () => { + test("it returns the field", () => { + expect(access("a")({ a: "b" })).toEqual("b"); + }); +}); + +describe("identity", () => { + test("it returns the value", () => { + expect(identity("a")).toEqual("a"); + }); +}); + +describe("toArray", () => { + test("it returns an array for not arrays", () => { + expect(toArray(0)).toEqual([0]); + }); + + test("returns the input array for an arrays", () => { + expect(toArray([0])).toEqual([0]); + }); +}); + +describe("useDidUpdate", () => { + test("calls on changes", () => { + const item = h(() => { + useDidUpdate(() => {}); + const [count, setCount] = useState(0); + return h("div", { onClick: () => setCount(1) }, "TEST"); + }); + + const container = render(item); + fireEvent.click(container.getByText("TEST")); + }); +}); diff --git a/runtime/tests/variant.test.js b/runtime/tests/variant.test.js new file mode 100644 index 000000000..b85f5c23d --- /dev/null +++ b/runtime/tests/variant.test.js @@ -0,0 +1,54 @@ +import { variant, compare, newVariant } from "../index"; +import { expect, test, describe } from "vitest"; + +const RecordEnum = variant(["a", "b"]); +const TestEnum2 = variant(2); +const TestEnum = variant(0); + +describe("equality", () => { + test("same intance equals true", () => { + expect(compare(new TestEnum(), new TestEnum())).toEqual(true); + }); + + test("same parameters equals true", () => { + expect(compare(new TestEnum2("0", "1"), new TestEnum2("0", "1"))).toEqual( + true, + ); + }); + + test("different instances equals false", () => { + expect(compare(new TestEnum2("0", "2"), new TestEnum())).toEqual(false); + }); + + test("different lengths equals false", () => { + const a = new TestEnum2("0", "2"); + const b = new TestEnum2("0", "2"); + b.length = 10; + + expect(compare(a, b)).toEqual(false); + }); + + test("different parameters equals false", () => { + expect(compare(new TestEnum2("0", "2"), new TestEnum2("0", "1"))).toEqual( + false, + ); + }); + + test("same enum equals true", () => { + expect( + compare( + newVariant(RecordEnum)("a", "b"), + newVariant(RecordEnum)("a", "b"), + ), + ).toEqual(true); + }); + + test("different enum equals false", () => { + expect( + compare( + newVariant(RecordEnum)("a", "b"), + newVariant(RecordEnum)("a", "c"), + ), + ).toEqual(false); + }); +}); diff --git a/runtime/vite.config.js b/runtime/vite.config.js new file mode 100644 index 000000000..bfd0ef485 --- /dev/null +++ b/runtime/vite.config.js @@ -0,0 +1,10 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + environment: "jsdom", + coverage: { + provider: "v8", + }, + }, +}); diff --git a/runtime/yarn-error.log b/runtime/yarn-error.log new file mode 100644 index 000000000..19ec79c1b --- /dev/null +++ b/runtime/yarn-error.log @@ -0,0 +1,2009 @@ +Arguments: + /home/gus/.asdf/installs/nodejs/20.10.0/bin/node /home/gus/.asdf/installs/yarn/1.22.19/bin/yarn.js + +PATH: + /home/gus/.asdf/plugins/nodejs/shims:/home/gus/.asdf/installs/nodejs/20.10.0/.npm/bin:/home/gus/.asdf/installs/nodejs/20.10.0/bin:/home/gus/.asdf/installs/yarn/1.22.19/bin:/home/gus/.fly/bin:/home/gus/.asdf/shims:/home/gus/.asdf/bin:/home/gus/.cache/rebar3/bin:/home/gus/.bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/lib/jvm/java-17-oracle/bin:/usr/lib/jvm/java-17-oracle/db/bin + +Yarn version: + 1.22.19 + +Node version: + 20.10.0 + +Platform: + linux x64 + +Trace: + SyntaxError: /home/gus/Projects/mint-lang/mint/runtime/package.json: Expected double-quoted property name in JSON at position 242 + at JSON.parse () + at /home/gus/.asdf/installs/yarn/1.22.19/lib/cli.js:1629:59 + at Generator.next () + at step (/home/gus/.asdf/installs/yarn/1.22.19/lib/cli.js:310:30) + at /home/gus/.asdf/installs/yarn/1.22.19/lib/cli.js:321:13 + +npm manifest: + { + "private": true, + "dependencies": { + "@preact/signals": "^1.2.2", + "fast-equals": "^5.0.1", + "indent-string": "^5.0.0", + "preact": "^10.19.3", + "route-parser": "mint-lang/mint-route-parser", + "uuid-random": "^1.3.2", + }, + "devDependencies": { + "@testing-library/preact": "^3.2.3", + "@vitest/coverage-v8": "^1.2.1", + "esbuild": "^0.19.11", + "prettier": "^3.1.0", + "vitest": "^1.2.1", + "jsdom": "^23.2.0", + } + } + +yarn manifest: + No manifest + +Lockfile: + # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. + # yarn lockfile v1 + + + "@ampproject/remapping@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + + "@babel/code-frame@^7.10.4": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" + integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== + dependencies: + "@babel/highlight" "^7.23.4" + chalk "^2.4.2" + + "@babel/helper-string-parser@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" + integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== + + "@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + + "@babel/highlight@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" + integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + + "@babel/parser@^7.23.3": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b" + integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ== + + "@babel/runtime@^7.12.5": + version "7.23.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.7.tgz#dd7c88deeb218a0f8bd34d5db1aa242e0f203193" + integrity sha512-w06OXVOFso7LcbzMiDGt+3X7Rh7Ho8MmgPoWU3rarH+8upf+wSU/grlGbWzQyr3DkdN6ZeuMFjpdwW0Q+HxobA== + dependencies: + regenerator-runtime "^0.14.0" + + "@babel/types@^7.23.3": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.6.tgz#be33fdb151e1f5a56877d704492c240fc71c7ccd" + integrity sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg== + dependencies: + "@babel/helper-string-parser" "^7.23.4" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + + "@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + + "@esbuild/aix-ppc64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.11.tgz#2acd20be6d4f0458bc8c784103495ff24f13b1d3" + integrity sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g== + + "@esbuild/android-arm64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.11.tgz#b45d000017385c9051a4f03e17078abb935be220" + integrity sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q== + + "@esbuild/android-arm64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.8.tgz#fb7130103835b6d43ea499c3f30cfb2b2ed58456" + integrity sha512-B8JbS61bEunhfx8kasogFENgQfr/dIp+ggYXwTqdbMAgGDhRa3AaPpQMuQU0rNxDLECj6FhDzk1cF9WHMVwrtA== + + "@esbuild/android-arm@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.11.tgz#f46f55414e1c3614ac682b29977792131238164c" + integrity sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw== + + "@esbuild/android-arm@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.8.tgz#b46e4d9e984e6d6db6c4224d72c86b7757e35bcb" + integrity sha512-31E2lxlGM1KEfivQl8Yf5aYU/mflz9g06H6S15ITUFQueMFtFjESRMoDSkvMo8thYvLBax+VKTPlpnx+sPicOA== + + "@esbuild/android-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.11.tgz#bfc01e91740b82011ef503c48f548950824922b2" + integrity sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg== + + "@esbuild/android-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.8.tgz#a13db9441b5a4f4e4fec4a6f8ffacfea07888db7" + integrity sha512-rdqqYfRIn4jWOp+lzQttYMa2Xar3OK9Yt2fhOhzFXqg0rVWEfSclJvZq5fZslnz6ypHvVf3CT7qyf0A5pM682A== + + "@esbuild/darwin-arm64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.11.tgz#533fb7f5a08c37121d82c66198263dcc1bed29bf" + integrity sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ== + + "@esbuild/darwin-arm64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.8.tgz#49f5718d36541f40dd62bfdf84da9c65168a0fc2" + integrity sha512-RQw9DemMbIq35Bprbboyf8SmOr4UXsRVxJ97LgB55VKKeJOOdvsIPy0nFyF2l8U+h4PtBx/1kRf0BelOYCiQcw== + + "@esbuild/darwin-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.11.tgz#62f3819eff7e4ddc656b7c6815a31cf9a1e7d98e" + integrity sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g== + + "@esbuild/darwin-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.8.tgz#75c5c88371eea4bfc1f9ecfd0e75104c74a481ac" + integrity sha512-3sur80OT9YdeZwIVgERAysAbwncom7b4bCI2XKLjMfPymTud7e/oY4y+ci1XVp5TfQp/bppn7xLw1n/oSQY3/Q== + + "@esbuild/freebsd-arm64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.11.tgz#d478b4195aa3ca44160272dab85ef8baf4175b4a" + integrity sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA== + + "@esbuild/freebsd-arm64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.8.tgz#9d7259fea4fd2b5f7437b52b542816e89d7c8575" + integrity sha512-WAnPJSDattvS/XtPCTj1tPoTxERjcTpH6HsMr6ujTT+X6rylVe8ggxk8pVxzf5U1wh5sPODpawNicF5ta/9Tmw== + + "@esbuild/freebsd-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.11.tgz#7bdcc1917409178257ca6a1a27fe06e797ec18a2" + integrity sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw== + + "@esbuild/freebsd-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.8.tgz#abac03e1c4c7c75ee8add6d76ec592f46dbb39e3" + integrity sha512-ICvZyOplIjmmhjd6mxi+zxSdpPTKFfyPPQMQTK/w+8eNK6WV01AjIztJALDtwNNfFhfZLux0tZLC+U9nSyA5Zg== + + "@esbuild/linux-arm64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.11.tgz#58ad4ff11685fcc735d7ff4ca759ab18fcfe4545" + integrity sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg== + + "@esbuild/linux-arm64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.8.tgz#c577932cf4feeaa43cb9cec27b89cbe0df7d9098" + integrity sha512-z1zMZivxDLHWnyGOctT9JP70h0beY54xDDDJt4VpTX+iwA77IFsE1vCXWmprajJGa+ZYSqkSbRQ4eyLCpCmiCQ== + + "@esbuild/linux-arm@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.11.tgz#ce82246d873b5534d34de1e5c1b33026f35e60e3" + integrity sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q== + + "@esbuild/linux-arm@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.8.tgz#d6014d8b98b5cbc96b95dad3d14d75bb364fdc0f" + integrity sha512-H4vmI5PYqSvosPaTJuEppU9oz1dq2A7Mr2vyg5TF9Ga+3+MGgBdGzcyBP7qK9MrwFQZlvNyJrvz6GuCaj3OukQ== + + "@esbuild/linux-ia32@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.11.tgz#cbae1f313209affc74b80f4390c4c35c6ab83fa4" + integrity sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA== + + "@esbuild/linux-ia32@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.8.tgz#2379a0554307d19ac4a6cdc15b08f0ea28e7a40d" + integrity sha512-1a8suQiFJmZz1khm/rDglOc8lavtzEMRo0v6WhPgxkrjcU0LkHj+TwBrALwoz/OtMExvsqbbMI0ChyelKabSvQ== + + "@esbuild/linux-loong64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.11.tgz#5f32aead1c3ec8f4cccdb7ed08b166224d4e9121" + integrity sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg== + + "@esbuild/linux-loong64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.8.tgz#e2a5bbffe15748b49356a6cd7b2d5bf60c5a7123" + integrity sha512-fHZWS2JJxnXt1uYJsDv9+b60WCc2RlvVAy1F76qOLtXRO+H4mjt3Tr6MJ5l7Q78X8KgCFudnTuiQRBhULUyBKQ== + + "@esbuild/linux-mips64el@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.11.tgz#38eecf1cbb8c36a616261de858b3c10d03419af9" + integrity sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg== + + "@esbuild/linux-mips64el@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.8.tgz#1359331e6f6214f26f4b08db9b9df661c57cfa24" + integrity sha512-Wy/z0EL5qZYLX66dVnEg9riiwls5IYnziwuju2oUiuxVc+/edvqXa04qNtbrs0Ukatg5HEzqT94Zs7J207dN5Q== + + "@esbuild/linux-ppc64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.11.tgz#9c5725a94e6ec15b93195e5a6afb821628afd912" + integrity sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA== + + "@esbuild/linux-ppc64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.8.tgz#9ba436addc1646dc89dae48c62d3e951ffe70951" + integrity sha512-ETaW6245wK23YIEufhMQ3HSeHO7NgsLx8gygBVldRHKhOlD1oNeNy/P67mIh1zPn2Hr2HLieQrt6tWrVwuqrxg== + + "@esbuild/linux-riscv64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.11.tgz#2dc4486d474a2a62bbe5870522a9a600e2acb916" + integrity sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ== + + "@esbuild/linux-riscv64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.8.tgz#fbcf0c3a0b20f40b5fc31c3b7695f0769f9de66b" + integrity sha512-T2DRQk55SgoleTP+DtPlMrxi/5r9AeFgkhkZ/B0ap99zmxtxdOixOMI570VjdRCs9pE4Wdkz7JYrsPvsl7eESg== + + "@esbuild/linux-s390x@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.11.tgz#4ad8567df48f7dd4c71ec5b1753b6f37561a65a8" + integrity sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q== + + "@esbuild/linux-s390x@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.8.tgz#989e8a05f7792d139d5564ffa7ff898ac6f20a4a" + integrity sha512-NPxbdmmo3Bk7mbNeHmcCd7R7fptJaczPYBaELk6NcXxy7HLNyWwCyDJ/Xx+/YcNH7Im5dHdx9gZ5xIwyliQCbg== + + "@esbuild/linux-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.11.tgz#b7390c4d5184f203ebe7ddaedf073df82a658766" + integrity sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA== + + "@esbuild/linux-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.8.tgz#b187295393a59323397fe5ff51e769ec4e72212b" + integrity sha512-lytMAVOM3b1gPypL2TRmZ5rnXl7+6IIk8uB3eLsV1JwcizuolblXRrc5ShPrO9ls/b+RTp+E6gbsuLWHWi2zGg== + + "@esbuild/netbsd-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.11.tgz#d633c09492a1721377f3bccedb2d821b911e813d" + integrity sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ== + + "@esbuild/netbsd-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.8.tgz#c1ec0e24ea82313cb1c7bae176bd5acd5bde7137" + integrity sha512-hvWVo2VsXz/8NVt1UhLzxwAfo5sioj92uo0bCfLibB0xlOmimU/DeAEsQILlBQvkhrGjamP0/el5HU76HAitGw== + + "@esbuild/openbsd-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.11.tgz#17388c76e2f01125bf831a68c03a7ffccb65d1a2" + integrity sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw== + + "@esbuild/openbsd-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.8.tgz#0c5b696ac66c6d70cf9ee17073a581a28af9e18d" + integrity sha512-/7Y7u77rdvmGTxR83PgaSvSBJCC2L3Kb1M/+dmSIvRvQPXXCuC97QAwMugBNG0yGcbEGfFBH7ojPzAOxfGNkwQ== + + "@esbuild/sunos-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.11.tgz#e320636f00bb9f4fdf3a80e548cb743370d41767" + integrity sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ== + + "@esbuild/sunos-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.8.tgz#2a697e1f77926ff09fcc457d8f29916d6cd48fb1" + integrity sha512-9Lc4s7Oi98GqFA4HzA/W2JHIYfnXbUYgekUP/Sm4BG9sfLjyv6GKKHKKVs83SMicBF2JwAX6A1PuOLMqpD001w== + + "@esbuild/win32-arm64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.11.tgz#c778b45a496e90b6fc373e2a2bb072f1441fe0ee" + integrity sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ== + + "@esbuild/win32-arm64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.8.tgz#ec029e62a2fca8c071842ecb1bc5c2dd20b066f1" + integrity sha512-rq6WzBGjSzihI9deW3fC2Gqiak68+b7qo5/3kmB6Gvbh/NYPA0sJhrnp7wgV4bNwjqM+R2AApXGxMO7ZoGhIJg== + + "@esbuild/win32-ia32@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.11.tgz#481a65fee2e5cce74ec44823e6b09ecedcc5194c" + integrity sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg== + + "@esbuild/win32-ia32@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.8.tgz#cbb9a3146bde64dc15543e48afe418c7a3214851" + integrity sha512-AIAbverbg5jMvJznYiGhrd3sumfwWs8572mIJL5NQjJa06P8KfCPWZQ0NwZbPQnbQi9OWSZhFVSUWjjIrn4hSw== + + "@esbuild/win32-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.11.tgz#a5d300008960bb39677c46bf16f53ec70d8dee04" + integrity sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw== + + "@esbuild/win32-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.8.tgz#c8285183dbdb17008578dbacb6e22748709b4822" + integrity sha512-bfZ0cQ1uZs2PqpulNL5j/3w+GDhP36k1K5c38QdQg+Swy51jFZWWeIkteNsufkQxp986wnqRRsb/bHbY1WQ7TA== + + "@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + + "@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + + "@jridgewell/gen-mapping@^0.3.0": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + + "@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + + "@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + + "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + + "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.20" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f" + integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + + "@preact/signals-core@^1.4.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@preact/signals-core/-/signals-core-1.5.0.tgz#5d34db4d3c242c93e1cefb7ce8b2d10ecbdbfa79" + integrity sha512-U2diO1Z4i1n2IoFgMYmRdHWGObNrcuTRxyNEn7deSq2cru0vj0583HYQZHsAqcs7FE+hQyX3mjIV7LAfHCvy8w== + + "@preact/signals@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@preact/signals/-/signals-1.2.2.tgz#78df53b2d7e6cdda0bb32843f12eb0418a0d82b0" + integrity sha512-ColCqdo4cRP18bAuIR4Oik5rDpiyFtPIJIygaYPMEAwTnl4buWkBOflGBSzhYyPyJfKpkwlekrvK+1pzQ2ldWw== + dependencies: + "@preact/signals-core" "^1.4.0" + + "@rollup/rollup-android-arm-eabi@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.2.tgz#ccb02257556bacbc1e756ab9b0b973cea2c7a664" + integrity sha512-RKzxFxBHq9ysZ83fn8Iduv3A283K7zPPYuhL/z9CQuyFrjwpErJx0h4aeb/bnJ+q29GRLgJpY66ceQ/Wcsn3wA== + + "@rollup/rollup-android-arm64@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.2.tgz#21bd0fbafdf442c6a17645b840f6a94556b0e9bb" + integrity sha512-yZ+MUbnwf3SHNWQKJyWh88ii2HbuHCFQnAYTeeO1Nb8SyEiWASEi5dQUygt3ClHWtA9My9RQAYkjvrsZ0WK8Xg== + + "@rollup/rollup-darwin-arm64@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.2.tgz#9f2e5d5637677f9839dbe1622130d0592179136a" + integrity sha512-vqJ/pAUh95FLc/G/3+xPqlSBgilPnauVf2EXOQCZzhZJCXDXt/5A8mH/OzU6iWhb3CNk5hPJrh8pqJUPldN5zw== + + "@rollup/rollup-darwin-x64@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.2.tgz#1b06291ff1c41af94d2786cd167188c5bf7caec9" + integrity sha512-otPHsN5LlvedOprd3SdfrRNhOahhVBwJpepVKUN58L0RnC29vOAej1vMEaVU6DadnpjivVsNTM5eNt0CcwTahw== + + "@rollup/rollup-linux-arm-gnueabihf@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.2.tgz#147069948bba00f435122f411210624e72638ebf" + integrity sha512-ewG5yJSp+zYKBYQLbd1CUA7b1lSfIdo9zJShNTyc2ZP1rcPrqyZcNlsHgs7v1zhgfdS+kW0p5frc0aVqhZCiYQ== + + "@rollup/rollup-linux-arm64-gnu@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.2.tgz#3a50f0e7ae6e444d11c61fce12783196454a4efb" + integrity sha512-pL6QtV26W52aCWTG1IuFV3FMPL1m4wbsRG+qijIvgFO/VBsiXJjDPE/uiMdHBAO6YcpV4KvpKtd0v3WFbaxBtg== + + "@rollup/rollup-linux-arm64-musl@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.2.tgz#82b5e75484d91c25d4e649d018d9523e72d6dac2" + integrity sha512-On+cc5EpOaTwPSNetHXBuqylDW+765G/oqB9xGmWU3npEhCh8xu0xqHGUA+4xwZLqBbIZNcBlKSIYfkBm6ko7g== + + "@rollup/rollup-linux-riscv64-gnu@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.2.tgz#ca96f2d43a553d73aec736e991c07010561bc7a9" + integrity sha512-Wnx/IVMSZ31D/cO9HSsU46FjrPWHqtdF8+0eyZ1zIB5a6hXaZXghUKpRrC4D5DcRTZOjml2oBhXoqfGYyXKipw== + + "@rollup/rollup-linux-x64-gnu@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.2.tgz#db1cece244ea46706c0e1a522ec19ca0173abc55" + integrity sha512-ym5x1cj4mUAMBummxxRkI4pG5Vht1QMsJexwGP8547TZ0sox9fCLDHw9KCH9c1FO5d9GopvkaJsBIOkTKxksdw== + + "@rollup/rollup-linux-x64-musl@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.2.tgz#c15b26b86827f75977bf59ebd41ce5d788713936" + integrity sha512-m0hYELHGXdYx64D6IDDg/1vOJEaiV8f1G/iO+tejvRCJNSwK4jJ15e38JQy5Q6dGkn1M/9KcyEOwqmlZ2kqaZg== + + "@rollup/rollup-win32-arm64-msvc@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.2.tgz#60152948f9fb08e8c50c1555e334ca9f9f1f53aa" + integrity sha512-x1CWburlbN5JjG+juenuNa4KdedBdXLjZMp56nHFSHTOsb/MI2DYiGzLtRGHNMyydPGffGId+VgjOMrcltOksA== + + "@rollup/rollup-win32-ia32-msvc@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.2.tgz#657288cff10311f997d8dbd648590441760ae6d9" + integrity sha512-VVzCB5yXR1QlfsH1Xw1zdzQ4Pxuzv+CPr5qpElpKhVxlxD3CRdfubAG9mJROl6/dmj5gVYDDWk8sC+j9BI9/kQ== + + "@rollup/rollup-win32-x64-msvc@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.2.tgz#830f3a3fba67f6216a5884368431918029045afe" + integrity sha512-SYRedJi+mweatroB+6TTnJYLts0L0bosg531xnQWtklOI6dezEagx4Q0qDyvRdK+qgdA3YZpjjGuPFtxBmddBA== + + "@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + + "@testing-library/dom@^8.11.1": + version "8.20.1" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.20.1.tgz#2e52a32e46fc88369eef7eef634ac2a192decd9f" + integrity sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/runtime" "^7.12.5" + "@types/aria-query" "^5.0.1" + aria-query "5.1.3" + chalk "^4.1.0" + dom-accessibility-api "^0.5.9" + lz-string "^1.5.0" + pretty-format "^27.0.2" + + "@testing-library/preact@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@testing-library/preact/-/preact-3.2.3.tgz#0d331b7a7f934a4b0fc6c95ff3a9e1d6fa93094e" + integrity sha512-y6Kklp1XK3f1X2fWCbujmJyzkf+1BgLYXNgAx21j9+D4CoqMTz5qC4SQufb1L6q/jxLGACzrQ90ewVOTBvHOfg== + dependencies: + "@testing-library/dom" "^8.11.1" + + "@types/aria-query@^5.0.1": + version "5.0.4" + resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.4.tgz#1a31c3d378850d2778dabb6374d036dcba4ba708" + integrity sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw== + + "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + + "@vitest/coverage-v8@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-1.1.1.tgz#8cf41ef4c4e8bf979937452f5ab446e29e61aba1" + integrity sha512-TCXSh6sA92t7D5p7HJ64sPCi+szP8E3NiKTsR3YR8vVEVZB9yclQu2btktCthxahKBl7PwheP5OuejYg13xccg== + dependencies: + "@ampproject/remapping" "^2.2.1" + "@bcoe/v8-coverage" "^0.2.3" + debug "^4.3.4" + istanbul-lib-coverage "^3.2.2" + istanbul-lib-report "^3.0.1" + istanbul-lib-source-maps "^4.0.1" + istanbul-reports "^3.1.6" + magic-string "^0.30.5" + magicast "^0.3.2" + picocolors "^1.0.0" + std-env "^3.5.0" + test-exclude "^6.0.0" + v8-to-istanbul "^9.2.0" + + "@vitest/expect@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.1.1.tgz#6b00a5e9ecccdc9da112e89214693a857564e39c" + integrity sha512-Qpw01C2Hyb3085jBkOJLQ7HRX0Ncnh2qV4p+xWmmhcIUlMykUF69zsnZ1vPmAjZpomw9+5tWEGOQ0GTfR8U+kA== + dependencies: + "@vitest/spy" "1.1.1" + "@vitest/utils" "1.1.1" + chai "^4.3.10" + + "@vitest/runner@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.1.1.tgz#c2c2a6baa25f3964c3434e94628b324bc0f19587" + integrity sha512-8HokyJo1SnSi3uPFKfWm/Oq1qDwLC4QDcVsqpXIXwsRPAg3gIDh8EbZ1ri8cmQkBxdOu62aOF9B4xcqJhvt4xQ== + dependencies: + "@vitest/utils" "1.1.1" + p-limit "^5.0.0" + pathe "^1.1.1" + + "@vitest/snapshot@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.1.1.tgz#40261901102e131cb09f23034884ad2c1c5af317" + integrity sha512-WnMHjv4VdHLbFGgCdVVvyRkRPnOKN75JJg+LLTdr6ah7YnL75W+7CTIMdzPEPzaDxA8r5yvSVlc1d8lH3yE28w== + dependencies: + magic-string "^0.30.5" + pathe "^1.1.1" + pretty-format "^29.7.0" + + "@vitest/spy@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.1.1.tgz#49a9c3f9b86f07b86333fc14d1667691b9a77a5c" + integrity sha512-hDU2KkOTfFp4WFFPWwHFauddwcKuGQ7gF6Un/ZZkCogoAiTMN7/7YKvUDbywPZZ754iCQGjdUmXN3t4k0jm1IQ== + dependencies: + tinyspy "^2.2.0" + + "@vitest/utils@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.1.1.tgz#493d1963d917a3ac29fbd4c36c1c31cfd17a7b41" + integrity sha512-E9LedH093vST/JuBSyHLFMpxJKW3dLhe/flUSPFedoyj4wKiFX7Jm8gYLtOIiin59dgrssfmFv0BJ1u8P/LC/A== + dependencies: + diff-sequences "^29.6.3" + loupe "^2.3.7" + pretty-format "^29.7.0" + + acorn-walk@^8.3.0: + version "8.3.1" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.1.tgz#2f10f5b69329d90ae18c58bf1fa8fccd8b959a43" + integrity sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw== + + acorn@^8.10.0: + version "8.11.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== + + agent-base@^7.0.2, agent-base@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.0.tgz#536802b76bc0b34aa50195eb2442276d613e3434" + integrity sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg== + dependencies: + debug "^4.3.4" + + ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + + ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + + ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + + ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + + aria-query@5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e" + integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ== + dependencies: + deep-equal "^2.0.5" + + array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" + + assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + + asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + + available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + + balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + + brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + + cac@^6.7.14: + version "6.7.14" + resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== + + call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" + integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== + dependencies: + function-bind "^1.1.2" + get-intrinsic "^1.2.1" + set-function-length "^1.1.1" + + chai@^4.3.10: + version "4.3.10" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.10.tgz#d784cec635e3b7e2ffb66446a63b4e33bd390384" + integrity sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" + pathval "^1.1.1" + type-detect "^4.0.8" + + chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + + chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + + check-error@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== + dependencies: + get-func-name "^2.0.2" + + color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + + color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + + color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + + color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + + combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + + concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + + convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + + cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + + cssstyle@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-3.0.0.tgz#17ca9c87d26eac764bb8cfd00583cff21ce0277a" + integrity sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg== + dependencies: + rrweb-cssom "^0.6.0" + + data-urls@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-5.0.0.tgz#2f76906bce1824429ffecb6920f45a0b30f00dde" + integrity sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg== + dependencies: + whatwg-mimetype "^4.0.0" + whatwg-url "^14.0.0" + + debug@4, debug@^4.1.1, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + + decimal.js@^10.4.3: + version "10.4.3" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" + integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== + + deep-eql@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" + integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== + dependencies: + type-detect "^4.0.0" + + deep-equal@^2.0.5: + version "2.2.3" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.3.tgz#af89dafb23a396c7da3e862abc0be27cf51d56e1" + integrity sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.5" + es-get-iterator "^1.1.3" + get-intrinsic "^1.2.2" + is-arguments "^1.1.1" + is-array-buffer "^3.0.2" + is-date-object "^1.0.5" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + isarray "^2.0.5" + object-is "^1.1.5" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.1" + side-channel "^1.0.4" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.13" + + define-data-property@^1.0.1, define-data-property@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" + integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== + dependencies: + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + + define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + + delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + + diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + + dom-accessibility-api@^0.5.9: + version "0.5.16" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz#5a7429e6066eb3664d911e33fb0e45de8eb08453" + integrity sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg== + + entities@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + + es-get-iterator@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" + integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + is-arguments "^1.1.1" + is-map "^2.0.2" + is-set "^2.0.2" + is-string "^1.0.7" + isarray "^2.0.5" + stop-iteration-iterator "^1.0.0" + + esbuild@^0.19.3: + version "0.19.11" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.11.tgz#4a02dca031e768b5556606e1b468fe72e3325d96" + integrity sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA== + optionalDependencies: + "@esbuild/aix-ppc64" "0.19.11" + "@esbuild/android-arm" "0.19.11" + "@esbuild/android-arm64" "0.19.11" + "@esbuild/android-x64" "0.19.11" + "@esbuild/darwin-arm64" "0.19.11" + "@esbuild/darwin-x64" "0.19.11" + "@esbuild/freebsd-arm64" "0.19.11" + "@esbuild/freebsd-x64" "0.19.11" + "@esbuild/linux-arm" "0.19.11" + "@esbuild/linux-arm64" "0.19.11" + "@esbuild/linux-ia32" "0.19.11" + "@esbuild/linux-loong64" "0.19.11" + "@esbuild/linux-mips64el" "0.19.11" + "@esbuild/linux-ppc64" "0.19.11" + "@esbuild/linux-riscv64" "0.19.11" + "@esbuild/linux-s390x" "0.19.11" + "@esbuild/linux-x64" "0.19.11" + "@esbuild/netbsd-x64" "0.19.11" + "@esbuild/openbsd-x64" "0.19.11" + "@esbuild/sunos-x64" "0.19.11" + "@esbuild/win32-arm64" "0.19.11" + "@esbuild/win32-ia32" "0.19.11" + "@esbuild/win32-x64" "0.19.11" + + esbuild@^0.19.8: + version "0.19.8" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.8.tgz#ad05b72281d84483fa6b5345bd246c27a207b8f1" + integrity sha512-l7iffQpT2OrZfH2rXIp7/FkmaeZM0vxbxN9KfiCwGYuZqzMg/JdvX26R31Zxn/Pxvsrg3Y9N6XTcnknqDyyv4w== + optionalDependencies: + "@esbuild/android-arm" "0.19.8" + "@esbuild/android-arm64" "0.19.8" + "@esbuild/android-x64" "0.19.8" + "@esbuild/darwin-arm64" "0.19.8" + "@esbuild/darwin-x64" "0.19.8" + "@esbuild/freebsd-arm64" "0.19.8" + "@esbuild/freebsd-x64" "0.19.8" + "@esbuild/linux-arm" "0.19.8" + "@esbuild/linux-arm64" "0.19.8" + "@esbuild/linux-ia32" "0.19.8" + "@esbuild/linux-loong64" "0.19.8" + "@esbuild/linux-mips64el" "0.19.8" + "@esbuild/linux-ppc64" "0.19.8" + "@esbuild/linux-riscv64" "0.19.8" + "@esbuild/linux-s390x" "0.19.8" + "@esbuild/linux-x64" "0.19.8" + "@esbuild/netbsd-x64" "0.19.8" + "@esbuild/openbsd-x64" "0.19.8" + "@esbuild/sunos-x64" "0.19.8" + "@esbuild/win32-arm64" "0.19.8" + "@esbuild/win32-ia32" "0.19.8" + "@esbuild/win32-x64" "0.19.8" + + escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + + event-propagation-path@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/event-propagation-path/-/event-propagation-path-1.0.5.tgz#1eeffa9878c9043e314849cbfa275c7e6e8f15fc" + integrity sha512-1/UU/xRPq3h/7UrWejsYj3ZzJtEA3FdUxKZtWjQ26KLy6yDXxtD+z1wP5mdE+BrlZAIHk7W7cGyG1uaV/Cpstg== + + execa@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" + integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^8.0.1" + human-signals "^5.0.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^4.1.0" + strip-final-newline "^3.0.0" + + fast-equals@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-5.0.1.tgz#a4eefe3c5d1c0d021aeed0bc10ba5e0c12ee405d" + integrity sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ== + + for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + + form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + + fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + + fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + + function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + + functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + + get-func-name@^2.0.1, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== + + get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" + integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== + dependencies: + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + + get-stream@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" + integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== + + glob@^7.1.4: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + + gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + + has-bigints@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + + has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + + has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + + has-property-descriptors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" + integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== + dependencies: + get-intrinsic "^1.2.2" + + has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + + has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + + has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + + hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + + html-encoding-sniffer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz#696df529a7cfd82446369dc5193e590a3735b448" + integrity sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ== + dependencies: + whatwg-encoding "^3.1.1" + + html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + + http-proxy-agent@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz#e9096c5afd071a3fce56e6252bb321583c124673" + integrity sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + + https-proxy-agent@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b" + integrity sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA== + dependencies: + agent-base "^7.0.2" + debug "4" + + human-signals@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" + integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== + + iconv-lite@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + + indent-string@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-5.0.0.tgz#4fd2980fccaf8622d14c64d694f4cf33c81951a5" + integrity sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg== + + inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + + inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + + internal-slot@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.6.tgz#37e756098c4911c5e912b8edbf71ed3aa116f930" + integrity sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg== + dependencies: + get-intrinsic "^1.2.2" + hasown "^2.0.0" + side-channel "^1.0.4" + + is-arguments@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + + is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" + + is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + + is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + + is-callable@^1.1.3: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + + is-date-object@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + + is-map@^2.0.1, is-map@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" + integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== + + is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + + is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + + is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + + is-set@^2.0.1, is-set@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" + integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== + + is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + + is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + + is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + + is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + + is-typed-array@^1.1.10: + version "1.1.12" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" + integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== + dependencies: + which-typed-array "^1.1.11" + + is-weakmap@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" + integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== + + is-weakset@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" + integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + + isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + + isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + + istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + + istanbul-lib-report@^3.0.0, istanbul-lib-report@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + + istanbul-lib-source-maps@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + + istanbul-reports@^3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a" + integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + + js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + + jsdom@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-23.0.1.tgz#ede7ff76e89ca035b11178d200710d8982ebfee0" + integrity sha512-2i27vgvlUsGEBO9+/kJQRbtqtm+191b5zAZrU/UezVmnC2dlDAFLgDYJvAEi94T4kjsRKkezEtLQTgsNEsW2lQ== + dependencies: + cssstyle "^3.0.0" + data-urls "^5.0.0" + decimal.js "^10.4.3" + form-data "^4.0.0" + html-encoding-sniffer "^4.0.0" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.2" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.7" + parse5 "^7.1.2" + rrweb-cssom "^0.6.0" + saxes "^6.0.0" + symbol-tree "^3.2.4" + tough-cookie "^4.1.3" + w3c-xmlserializer "^5.0.0" + webidl-conversions "^7.0.0" + whatwg-encoding "^3.1.1" + whatwg-mimetype "^4.0.0" + whatwg-url "^14.0.0" + ws "^8.14.2" + xml-name-validator "^5.0.0" + + jsonc-parser@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" + integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== + + local-pkg@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.5.0.tgz#093d25a346bae59a99f80e75f6e9d36d7e8c925c" + integrity sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg== + dependencies: + mlly "^1.4.2" + pkg-types "^1.0.3" + + loupe@^2.3.6, loupe@^2.3.7: + version "2.3.7" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== + dependencies: + get-func-name "^2.0.1" + + lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + + lz-string@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" + integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ== + + magic-string@^0.30.5: + version "0.30.5" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.5.tgz#1994d980bd1c8835dc6e78db7cbd4ae4f24746f9" + integrity sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.15" + + magicast@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.3.2.tgz#42dcade5573ed8f10f5540f9d04964e21dba9130" + integrity sha512-Fjwkl6a0syt9TFN0JSYpOybxiMCkYNEeOTnOTNRbjphirLakznZXAqrXgj/7GG3D1dvETONNwrBfinvAbpunDg== + dependencies: + "@babel/parser" "^7.23.3" + "@babel/types" "^7.23.3" + source-map-js "^1.0.2" + + make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + + merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + + mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + + mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + + mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + + minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + + mlly@^1.2.0, mlly@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.4.2.tgz#7cf406aa319ff6563d25da6b36610a93f2a8007e" + integrity sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg== + dependencies: + acorn "^8.10.0" + pathe "^1.1.1" + pkg-types "^1.0.3" + ufo "^1.3.0" + + ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + + nanoid@^3.3.7: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + + npm-run-path@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.2.0.tgz#224cdd22c755560253dd71b83a1ef2f758b2e955" + integrity sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg== + dependencies: + path-key "^4.0.0" + + nwsapi@^2.2.7: + version "2.2.7" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" + integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ== + + object-inspect@^1.9.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + + object-is@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + + object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + + object.assign@^4.1.4: + version "4.1.5" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" + integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== + dependencies: + call-bind "^1.0.5" + define-properties "^1.2.1" + has-symbols "^1.0.3" + object-keys "^1.1.1" + + once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + + onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + + p-limit@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-5.0.0.tgz#6946d5b7140b649b7a33a027d89b4c625b3a5985" + integrity sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ== + dependencies: + yocto-queue "^1.0.0" + + parse5@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" + integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== + dependencies: + entities "^4.4.0" + + path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + + path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + + path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + + pathe@^1.1.0, pathe@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.1.tgz#1dd31d382b974ba69809adc9a7a347e65d84829a" + integrity sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q== + + pathval@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== + + picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + + pkg-types@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.0.3.tgz#988b42ab19254c01614d13f4f65a2cfc7880f868" + integrity sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A== + dependencies: + jsonc-parser "^3.2.0" + mlly "^1.2.0" + pathe "^1.1.0" + + postcss@^8.4.32: + version "8.4.32" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.32.tgz#1dac6ac51ab19adb21b8b34fd2d93a86440ef6c9" + integrity sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw== + dependencies: + nanoid "^3.3.7" + picocolors "^1.0.0" + source-map-js "^1.0.2" + + preact@^10.19.2: + version "10.19.2" + resolved "https://registry.yarnpkg.com/preact/-/preact-10.19.2.tgz#841797620dba649aaac1f8be42d37c3202dcea8b" + integrity sha512-UA9DX/OJwv6YwP9Vn7Ti/vF80XL+YA5H2l7BpCtUr3ya8LWHFzpiO5R+N7dN16ujpIxhekRFuOOF82bXX7K/lg== + + prettier@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.0.tgz#c6d16474a5f764ea1a4a373c593b779697744d5e" + integrity sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw== + + pretty-format@^27.0.2: + version "27.5.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" + integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== + dependencies: + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + + pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + + psl@^1.1.33: + version "1.9.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== + + punycode@^2.1.1, punycode@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + + querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + + react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + + react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + + regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + + regexp.prototype.flags@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" + integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + set-function-name "^2.0.0" + + requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + + rollup@^4.2.0: + version "4.9.2" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.9.2.tgz#19d730219b7ec5f51372c6cf15cfb841990489fe" + integrity sha512-66RB8OtFKUTozmVEh3qyNfH+b+z2RXBVloqO2KCC/pjFaGaHtxP9fVfOQKPSGXg2mElmjmxjW/fZ7iKrEpMH5Q== + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.9.2" + "@rollup/rollup-android-arm64" "4.9.2" + "@rollup/rollup-darwin-arm64" "4.9.2" + "@rollup/rollup-darwin-x64" "4.9.2" + "@rollup/rollup-linux-arm-gnueabihf" "4.9.2" + "@rollup/rollup-linux-arm64-gnu" "4.9.2" + "@rollup/rollup-linux-arm64-musl" "4.9.2" + "@rollup/rollup-linux-riscv64-gnu" "4.9.2" + "@rollup/rollup-linux-x64-gnu" "4.9.2" + "@rollup/rollup-linux-x64-musl" "4.9.2" + "@rollup/rollup-win32-arm64-msvc" "4.9.2" + "@rollup/rollup-win32-ia32-msvc" "4.9.2" + "@rollup/rollup-win32-x64-msvc" "4.9.2" + fsevents "~2.3.2" + + route-parser@mint-lang/mint-route-parser: + version "0.0.5" + resolved "https://codeload.github.com/mint-lang/mint-route-parser/tar.gz/903d07a62fe7649fccb6be6694445ee4217c933e" + + rrweb-cssom@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1" + integrity sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw== + + "safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + + saxes@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-6.0.0.tgz#fe5b4a4768df4f14a201b1ba6a65c1f3d9988cc5" + integrity sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA== + dependencies: + xmlchars "^2.2.0" + + semver@^7.5.3: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + + set-function-length@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" + integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ== + dependencies: + define-data-property "^1.1.1" + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + + set-function-name@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" + integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== + dependencies: + define-data-property "^1.0.1" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.0" + + shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + + shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + + side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + + siginfo@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" + integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== + + signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + + source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + + source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + + stackback@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b" + integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw== + + std-env@^3.5.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.7.0.tgz#c9f7386ced6ecf13360b6c6c55b8aaa4ef7481d2" + integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg== + + stop-iteration-iterator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" + integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== + dependencies: + internal-slot "^1.0.4" + + strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + + strip-literal@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-1.3.0.tgz#db3942c2ec1699e6836ad230090b84bb458e3a07" + integrity sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg== + dependencies: + acorn "^8.10.0" + + supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + + supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + + symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + + test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + + tinybench@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.5.1.tgz#3408f6552125e53a5a48adee31261686fd71587e" + integrity sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg== + + tinypool@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.8.1.tgz#b6c4e4972ede3e3e5cda74a3da1679303d386b03" + integrity sha512-zBTCK0cCgRROxvs9c0CGK838sPkeokNGdQVUUwHAbynHFlmyJYj825f/oRs528HaIJ97lo0pLIlDUzwN+IorWg== + + tinyspy@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-2.2.0.tgz#9dc04b072746520b432f77ea2c2d17933de5d6ce" + integrity sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg== + + to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + + tough-cookie@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" + integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" + + tr46@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-5.0.0.tgz#3b46d583613ec7283020d79019f1335723801cec" + integrity sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g== + dependencies: + punycode "^2.3.1" + + type-detect@^4.0.0, type-detect@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + + ufo@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.3.2.tgz#c7d719d0628a1c80c006d2240e0d169f6e3c0496" + integrity sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA== + + universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + + url-parse@^1.5.3: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + + uuid-random@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/uuid-random/-/uuid-random-1.3.2.tgz#96715edbaef4e84b1dcf5024b00d16f30220e2d0" + integrity sha512-UOzej0Le/UgkbWEO8flm+0y+G+ljUon1QWTEZOq1rnMAsxo2+SckbiZdKzAHHlVh6gJqI1TjC/xwgR50MuCrBQ== + + v8-to-istanbul@^9.2.0: + version "9.2.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz#2ed7644a245cddd83d4e087b9b33b3e62dfd10ad" + integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + + vite-node@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.1.1.tgz#8cf16d5f841898de919653462c56dc99bb7d2b94" + integrity sha512-2bGE5w4jvym5v8llF6Gu1oBrmImoNSs4WmRVcavnG2me6+8UQntTqLiAMFyiAobp+ZXhj5ZFhI7SmLiFr/jrow== + dependencies: + cac "^6.7.14" + debug "^4.3.4" + pathe "^1.1.1" + picocolors "^1.0.0" + vite "^5.0.0" + + vite@^5.0.0: + version "5.0.10" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.10.tgz#1e13ef5c3cf5aa4eed81f5df6d107b3c3f1f6356" + integrity sha512-2P8J7WWgmc355HUMlFrwofacvr98DAjoE52BfdbwQtyLH06XKwaL/FMnmKM2crF0iX4MpmMKoDlNCB1ok7zHCw== + dependencies: + esbuild "^0.19.3" + postcss "^8.4.32" + rollup "^4.2.0" + optionalDependencies: + fsevents "~2.3.3" + + vitest@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.1.1.tgz#8ebd1a3cdca05da6e589b7d1f504ae952fecbeef" + integrity sha512-Ry2qs4UOu/KjpXVfOCfQkTnwSXYGrqTbBZxw6reIYEFjSy1QUARRg5pxiI5BEXy+kBVntxUYNMlq4Co+2vD3fQ== + dependencies: + "@vitest/expect" "1.1.1" + "@vitest/runner" "1.1.1" + "@vitest/snapshot" "1.1.1" + "@vitest/spy" "1.1.1" + "@vitest/utils" "1.1.1" + acorn-walk "^8.3.0" + cac "^6.7.14" + chai "^4.3.10" + debug "^4.3.4" + execa "^8.0.1" + local-pkg "^0.5.0" + magic-string "^0.30.5" + pathe "^1.1.1" + picocolors "^1.0.0" + std-env "^3.5.0" + strip-literal "^1.3.0" + tinybench "^2.5.1" + tinypool "^0.8.1" + vite "^5.0.0" + vite-node "1.1.1" + why-is-node-running "^2.2.2" + + w3c-xmlserializer@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz#f925ba26855158594d907313cedd1476c5967f6c" + integrity sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA== + dependencies: + xml-name-validator "^5.0.0" + + webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + + whatwg-encoding@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz#d0f4ef769905d426e1688f3e34381a99b60b76e5" + integrity sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ== + dependencies: + iconv-lite "0.6.3" + + whatwg-mimetype@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz#bc1bf94a985dc50388d54a9258ac405c3ca2fc0a" + integrity sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg== + + whatwg-url@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-14.0.0.tgz#00baaa7fd198744910c4b1ef68378f2200e4ceb6" + integrity sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw== + dependencies: + tr46 "^5.0.0" + webidl-conversions "^7.0.0" + + which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + + which-collection@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" + integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== + dependencies: + is-map "^2.0.1" + is-set "^2.0.1" + is-weakmap "^2.0.1" + is-weakset "^2.0.1" + + which-typed-array@^1.1.11, which-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" + integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.4" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + + which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + + why-is-node-running@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/why-is-node-running/-/why-is-node-running-2.2.2.tgz#4185b2b4699117819e7154594271e7e344c9973e" + integrity sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA== + dependencies: + siginfo "^2.0.0" + stackback "0.0.2" + + wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + + ws@^8.14.2: + version "8.16.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" + integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== + + xml-name-validator@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-5.0.0.tgz#82be9b957f7afdacf961e5980f1bf227c0bf7673" + integrity sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg== + + xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + + yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + + yocto-queue@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251" + integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g== diff --git a/runtime/yarn.lock b/runtime/yarn.lock new file mode 100644 index 000000000..170c2b76b --- /dev/null +++ b/runtime/yarn.lock @@ -0,0 +1,1860 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@asamuzakjp/dom-selector@^2.0.1": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@asamuzakjp/dom-selector/-/dom-selector-2.0.2.tgz#160f601d9a465bbdf641410afdc527f37325506e" + integrity sha512-x1KXOatwofR6ZAYzXRBL5wrdV0vwNxlTCK9NCuLqAzQYARqGcvFwiJA6A1ERuh+dgeA4Dxm3JBYictIes+SqUQ== + dependencies: + bidi-js "^1.0.3" + css-tree "^2.3.1" + is-potential-custom-element-name "^1.0.1" + +"@babel/code-frame@^7.10.4": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" + integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== + dependencies: + "@babel/highlight" "^7.23.4" + chalk "^2.4.2" + +"@babel/helper-string-parser@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" + integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== + +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + +"@babel/highlight@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" + integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b" + integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ== + +"@babel/runtime@^7.12.5": + version "7.23.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.7.tgz#dd7c88deeb218a0f8bd34d5db1aa242e0f203193" + integrity sha512-w06OXVOFso7LcbzMiDGt+3X7Rh7Ho8MmgPoWU3rarH+8upf+wSU/grlGbWzQyr3DkdN6ZeuMFjpdwW0Q+HxobA== + dependencies: + regenerator-runtime "^0.14.0" + +"@babel/types@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.6.tgz#be33fdb151e1f5a56877d704492c240fc71c7ccd" + integrity sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg== + dependencies: + "@babel/helper-string-parser" "^7.23.4" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@esbuild/aix-ppc64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.11.tgz#2acd20be6d4f0458bc8c784103495ff24f13b1d3" + integrity sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g== + +"@esbuild/android-arm64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.11.tgz#b45d000017385c9051a4f03e17078abb935be220" + integrity sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q== + +"@esbuild/android-arm@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.11.tgz#f46f55414e1c3614ac682b29977792131238164c" + integrity sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw== + +"@esbuild/android-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.11.tgz#bfc01e91740b82011ef503c48f548950824922b2" + integrity sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg== + +"@esbuild/darwin-arm64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.11.tgz#533fb7f5a08c37121d82c66198263dcc1bed29bf" + integrity sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ== + +"@esbuild/darwin-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.11.tgz#62f3819eff7e4ddc656b7c6815a31cf9a1e7d98e" + integrity sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g== + +"@esbuild/freebsd-arm64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.11.tgz#d478b4195aa3ca44160272dab85ef8baf4175b4a" + integrity sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA== + +"@esbuild/freebsd-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.11.tgz#7bdcc1917409178257ca6a1a27fe06e797ec18a2" + integrity sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw== + +"@esbuild/linux-arm64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.11.tgz#58ad4ff11685fcc735d7ff4ca759ab18fcfe4545" + integrity sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg== + +"@esbuild/linux-arm@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.11.tgz#ce82246d873b5534d34de1e5c1b33026f35e60e3" + integrity sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q== + +"@esbuild/linux-ia32@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.11.tgz#cbae1f313209affc74b80f4390c4c35c6ab83fa4" + integrity sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA== + +"@esbuild/linux-loong64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.11.tgz#5f32aead1c3ec8f4cccdb7ed08b166224d4e9121" + integrity sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg== + +"@esbuild/linux-mips64el@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.11.tgz#38eecf1cbb8c36a616261de858b3c10d03419af9" + integrity sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg== + +"@esbuild/linux-ppc64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.11.tgz#9c5725a94e6ec15b93195e5a6afb821628afd912" + integrity sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA== + +"@esbuild/linux-riscv64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.11.tgz#2dc4486d474a2a62bbe5870522a9a600e2acb916" + integrity sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ== + +"@esbuild/linux-s390x@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.11.tgz#4ad8567df48f7dd4c71ec5b1753b6f37561a65a8" + integrity sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q== + +"@esbuild/linux-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.11.tgz#b7390c4d5184f203ebe7ddaedf073df82a658766" + integrity sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA== + +"@esbuild/netbsd-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.11.tgz#d633c09492a1721377f3bccedb2d821b911e813d" + integrity sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ== + +"@esbuild/openbsd-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.11.tgz#17388c76e2f01125bf831a68c03a7ffccb65d1a2" + integrity sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw== + +"@esbuild/sunos-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.11.tgz#e320636f00bb9f4fdf3a80e548cb743370d41767" + integrity sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ== + +"@esbuild/win32-arm64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.11.tgz#c778b45a496e90b6fc373e2a2bb072f1441fe0ee" + integrity sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ== + +"@esbuild/win32-ia32@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.11.tgz#481a65fee2e5cce74ec44823e6b09ecedcc5194c" + integrity sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg== + +"@esbuild/win32-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.11.tgz#a5d300008960bb39677c46bf16f53ec70d8dee04" + integrity sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw== + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jridgewell/gen-mapping@^0.3.0": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.20" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f" + integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@preact/signals-core@^1.4.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@preact/signals-core/-/signals-core-1.5.0.tgz#5d34db4d3c242c93e1cefb7ce8b2d10ecbdbfa79" + integrity sha512-U2diO1Z4i1n2IoFgMYmRdHWGObNrcuTRxyNEn7deSq2cru0vj0583HYQZHsAqcs7FE+hQyX3mjIV7LAfHCvy8w== + +"@preact/signals@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@preact/signals/-/signals-1.2.2.tgz#78df53b2d7e6cdda0bb32843f12eb0418a0d82b0" + integrity sha512-ColCqdo4cRP18bAuIR4Oik5rDpiyFtPIJIygaYPMEAwTnl4buWkBOflGBSzhYyPyJfKpkwlekrvK+1pzQ2ldWw== + dependencies: + "@preact/signals-core" "^1.4.0" + +"@rollup/rollup-android-arm-eabi@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.2.tgz#ccb02257556bacbc1e756ab9b0b973cea2c7a664" + integrity sha512-RKzxFxBHq9ysZ83fn8Iduv3A283K7zPPYuhL/z9CQuyFrjwpErJx0h4aeb/bnJ+q29GRLgJpY66ceQ/Wcsn3wA== + +"@rollup/rollup-android-arm64@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.2.tgz#21bd0fbafdf442c6a17645b840f6a94556b0e9bb" + integrity sha512-yZ+MUbnwf3SHNWQKJyWh88ii2HbuHCFQnAYTeeO1Nb8SyEiWASEi5dQUygt3ClHWtA9My9RQAYkjvrsZ0WK8Xg== + +"@rollup/rollup-darwin-arm64@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.2.tgz#9f2e5d5637677f9839dbe1622130d0592179136a" + integrity sha512-vqJ/pAUh95FLc/G/3+xPqlSBgilPnauVf2EXOQCZzhZJCXDXt/5A8mH/OzU6iWhb3CNk5hPJrh8pqJUPldN5zw== + +"@rollup/rollup-darwin-x64@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.2.tgz#1b06291ff1c41af94d2786cd167188c5bf7caec9" + integrity sha512-otPHsN5LlvedOprd3SdfrRNhOahhVBwJpepVKUN58L0RnC29vOAej1vMEaVU6DadnpjivVsNTM5eNt0CcwTahw== + +"@rollup/rollup-linux-arm-gnueabihf@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.2.tgz#147069948bba00f435122f411210624e72638ebf" + integrity sha512-ewG5yJSp+zYKBYQLbd1CUA7b1lSfIdo9zJShNTyc2ZP1rcPrqyZcNlsHgs7v1zhgfdS+kW0p5frc0aVqhZCiYQ== + +"@rollup/rollup-linux-arm64-gnu@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.2.tgz#3a50f0e7ae6e444d11c61fce12783196454a4efb" + integrity sha512-pL6QtV26W52aCWTG1IuFV3FMPL1m4wbsRG+qijIvgFO/VBsiXJjDPE/uiMdHBAO6YcpV4KvpKtd0v3WFbaxBtg== + +"@rollup/rollup-linux-arm64-musl@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.2.tgz#82b5e75484d91c25d4e649d018d9523e72d6dac2" + integrity sha512-On+cc5EpOaTwPSNetHXBuqylDW+765G/oqB9xGmWU3npEhCh8xu0xqHGUA+4xwZLqBbIZNcBlKSIYfkBm6ko7g== + +"@rollup/rollup-linux-riscv64-gnu@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.2.tgz#ca96f2d43a553d73aec736e991c07010561bc7a9" + integrity sha512-Wnx/IVMSZ31D/cO9HSsU46FjrPWHqtdF8+0eyZ1zIB5a6hXaZXghUKpRrC4D5DcRTZOjml2oBhXoqfGYyXKipw== + +"@rollup/rollup-linux-x64-gnu@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.2.tgz#db1cece244ea46706c0e1a522ec19ca0173abc55" + integrity sha512-ym5x1cj4mUAMBummxxRkI4pG5Vht1QMsJexwGP8547TZ0sox9fCLDHw9KCH9c1FO5d9GopvkaJsBIOkTKxksdw== + +"@rollup/rollup-linux-x64-musl@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.2.tgz#c15b26b86827f75977bf59ebd41ce5d788713936" + integrity sha512-m0hYELHGXdYx64D6IDDg/1vOJEaiV8f1G/iO+tejvRCJNSwK4jJ15e38JQy5Q6dGkn1M/9KcyEOwqmlZ2kqaZg== + +"@rollup/rollup-win32-arm64-msvc@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.2.tgz#60152948f9fb08e8c50c1555e334ca9f9f1f53aa" + integrity sha512-x1CWburlbN5JjG+juenuNa4KdedBdXLjZMp56nHFSHTOsb/MI2DYiGzLtRGHNMyydPGffGId+VgjOMrcltOksA== + +"@rollup/rollup-win32-ia32-msvc@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.2.tgz#657288cff10311f997d8dbd648590441760ae6d9" + integrity sha512-VVzCB5yXR1QlfsH1Xw1zdzQ4Pxuzv+CPr5qpElpKhVxlxD3CRdfubAG9mJROl6/dmj5gVYDDWk8sC+j9BI9/kQ== + +"@rollup/rollup-win32-x64-msvc@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.2.tgz#830f3a3fba67f6216a5884368431918029045afe" + integrity sha512-SYRedJi+mweatroB+6TTnJYLts0L0bosg531xnQWtklOI6dezEagx4Q0qDyvRdK+qgdA3YZpjjGuPFtxBmddBA== + +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + +"@testing-library/dom@^8.11.1": + version "8.20.1" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.20.1.tgz#2e52a32e46fc88369eef7eef634ac2a192decd9f" + integrity sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/runtime" "^7.12.5" + "@types/aria-query" "^5.0.1" + aria-query "5.1.3" + chalk "^4.1.0" + dom-accessibility-api "^0.5.9" + lz-string "^1.5.0" + pretty-format "^27.0.2" + +"@testing-library/preact@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@testing-library/preact/-/preact-3.2.3.tgz#0d331b7a7f934a4b0fc6c95ff3a9e1d6fa93094e" + integrity sha512-y6Kklp1XK3f1X2fWCbujmJyzkf+1BgLYXNgAx21j9+D4CoqMTz5qC4SQufb1L6q/jxLGACzrQ90ewVOTBvHOfg== + dependencies: + "@testing-library/dom" "^8.11.1" + +"@types/aria-query@^5.0.1": + version "5.0.4" + resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.4.tgz#1a31c3d378850d2778dabb6374d036dcba4ba708" + integrity sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw== + +"@types/estree@^1.0.0": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + +"@types/istanbul-lib-coverage@^2.0.1": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@vitest/coverage-v8@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-1.2.1.tgz#e76d64c8f0a8cb882543f12f7a2bc7615b84cbee" + integrity sha512-fJEhKaDwGMZtJUX7BRcGxooGwg1Hl0qt53mVup/ZJeznhvL5EodteVnb/mcByhEcvVWbK83ZF31c7nPEDi4LOQ== + dependencies: + "@ampproject/remapping" "^2.2.1" + "@bcoe/v8-coverage" "^0.2.3" + debug "^4.3.4" + istanbul-lib-coverage "^3.2.2" + istanbul-lib-report "^3.0.1" + istanbul-lib-source-maps "^4.0.1" + istanbul-reports "^3.1.6" + magic-string "^0.30.5" + magicast "^0.3.3" + picocolors "^1.0.0" + std-env "^3.5.0" + test-exclude "^6.0.0" + v8-to-istanbul "^9.2.0" + +"@vitest/expect@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.2.1.tgz#574c0ac138a9e34522da202ea4c48a3adfe7240e" + integrity sha512-/bqGXcHfyKgFWYwIgFr1QYDaR9e64pRKxgBNWNXPefPFRhgm+K3+a/dS0cUGEreWngets3dlr8w8SBRw2fCfFQ== + dependencies: + "@vitest/spy" "1.2.1" + "@vitest/utils" "1.2.1" + chai "^4.3.10" + +"@vitest/runner@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.2.1.tgz#13e65b47eb04e572b99757e55f063f8f025822b2" + integrity sha512-zc2dP5LQpzNzbpaBt7OeYAvmIsRS1KpZQw4G3WM/yqSV1cQKNKwLGmnm79GyZZjMhQGlRcSFMImLjZaUQvNVZQ== + dependencies: + "@vitest/utils" "1.2.1" + p-limit "^5.0.0" + pathe "^1.1.1" + +"@vitest/snapshot@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.2.1.tgz#bd2dcae2322b90bab1660421ff9dae73fc84ecc0" + integrity sha512-Tmp/IcYEemKaqAYCS08sh0vORLJkMr0NRV76Gl8sHGxXT5151cITJCET20063wk0Yr/1koQ6dnmP6eEqezmd/Q== + dependencies: + magic-string "^0.30.5" + pathe "^1.1.1" + pretty-format "^29.7.0" + +"@vitest/spy@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.2.1.tgz#2777444890de9d32e55e600e34a13b2074cabc18" + integrity sha512-vG3a/b7INKH7L49Lbp0IWrG6sw9j4waWAucwnksPB1r1FTJgV7nkBByd9ufzu6VWya/QTvQW4V9FShZbZIB2UQ== + dependencies: + tinyspy "^2.2.0" + +"@vitest/utils@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.2.1.tgz#ad798cb13ec9e9e97b13be65d135e9e8e3c586aa" + integrity sha512-bsH6WVZYe/J2v3+81M5LDU8kW76xWObKIURpPrOXm2pjBniBu2MERI/XP60GpS4PHU3jyK50LUutOwrx4CyHUg== + dependencies: + diff-sequences "^29.6.3" + estree-walker "^3.0.3" + loupe "^2.3.7" + pretty-format "^29.7.0" + +acorn-walk@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.2.tgz#7703af9415f1b6db9315d6895503862e231d34aa" + integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== + +acorn@^8.10.0: + version "8.11.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== + +agent-base@^7.0.2, agent-base@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.0.tgz#536802b76bc0b34aa50195eb2442276d613e3434" + integrity sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg== + dependencies: + debug "^4.3.4" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +aria-query@5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e" + integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ== + dependencies: + deep-equal "^2.0.5" + +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" + +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +bidi-js@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/bidi-js/-/bidi-js-1.0.3.tgz#6f8bcf3c877c4d9220ddf49b9bb6930c88f877d2" + integrity sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw== + dependencies: + require-from-string "^2.0.2" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +cac@^6.7.14: + version "6.7.14" + resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== + +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" + integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== + dependencies: + function-bind "^1.1.2" + get-intrinsic "^1.2.1" + set-function-length "^1.1.1" + +chai@^4.3.10: + version "4.3.10" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.10.tgz#d784cec635e3b7e2ffb66446a63b4e33bd390384" + integrity sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" + pathval "^1.1.1" + type-detect "^4.0.8" + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +check-error@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== + dependencies: + get-func-name "^2.0.2" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +css-tree@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.3.1.tgz#10264ce1e5442e8572fc82fbe490644ff54b5c20" + integrity sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw== + dependencies: + mdn-data "2.0.30" + source-map-js "^1.0.1" + +cssstyle@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-4.0.1.tgz#ef29c598a1e90125c870525490ea4f354db0660a" + integrity sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ== + dependencies: + rrweb-cssom "^0.6.0" + +data-urls@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-5.0.0.tgz#2f76906bce1824429ffecb6920f45a0b30f00dde" + integrity sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg== + dependencies: + whatwg-mimetype "^4.0.0" + whatwg-url "^14.0.0" + +debug@4, debug@^4.1.1, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +decimal.js@^10.4.3: + version "10.4.3" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" + integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== + +deep-eql@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" + integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== + dependencies: + type-detect "^4.0.0" + +deep-equal@^2.0.5: + version "2.2.3" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.3.tgz#af89dafb23a396c7da3e862abc0be27cf51d56e1" + integrity sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.5" + es-get-iterator "^1.1.3" + get-intrinsic "^1.2.2" + is-arguments "^1.1.1" + is-array-buffer "^3.0.2" + is-date-object "^1.0.5" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + isarray "^2.0.5" + object-is "^1.1.5" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.1" + side-channel "^1.0.4" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.13" + +define-data-property@^1.0.1, define-data-property@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" + integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== + dependencies: + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + +dom-accessibility-api@^0.5.9: + version "0.5.16" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz#5a7429e6066eb3664d911e33fb0e45de8eb08453" + integrity sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg== + +entities@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + +es-get-iterator@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" + integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + is-arguments "^1.1.1" + is-map "^2.0.2" + is-set "^2.0.2" + is-string "^1.0.7" + isarray "^2.0.5" + stop-iteration-iterator "^1.0.0" + +esbuild@^0.19.11, esbuild@^0.19.3: + version "0.19.11" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.11.tgz#4a02dca031e768b5556606e1b468fe72e3325d96" + integrity sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA== + optionalDependencies: + "@esbuild/aix-ppc64" "0.19.11" + "@esbuild/android-arm" "0.19.11" + "@esbuild/android-arm64" "0.19.11" + "@esbuild/android-x64" "0.19.11" + "@esbuild/darwin-arm64" "0.19.11" + "@esbuild/darwin-x64" "0.19.11" + "@esbuild/freebsd-arm64" "0.19.11" + "@esbuild/freebsd-x64" "0.19.11" + "@esbuild/linux-arm" "0.19.11" + "@esbuild/linux-arm64" "0.19.11" + "@esbuild/linux-ia32" "0.19.11" + "@esbuild/linux-loong64" "0.19.11" + "@esbuild/linux-mips64el" "0.19.11" + "@esbuild/linux-ppc64" "0.19.11" + "@esbuild/linux-riscv64" "0.19.11" + "@esbuild/linux-s390x" "0.19.11" + "@esbuild/linux-x64" "0.19.11" + "@esbuild/netbsd-x64" "0.19.11" + "@esbuild/openbsd-x64" "0.19.11" + "@esbuild/sunos-x64" "0.19.11" + "@esbuild/win32-arm64" "0.19.11" + "@esbuild/win32-ia32" "0.19.11" + "@esbuild/win32-x64" "0.19.11" + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +estree-walker@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" + integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== + dependencies: + "@types/estree" "^1.0.0" + +execa@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" + integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^8.0.1" + human-signals "^5.0.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^4.1.0" + strip-final-newline "^3.0.0" + +fast-equals@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-5.0.1.tgz#a4eefe3c5d1c0d021aeed0bc10ba5e0c12ee405d" + integrity sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ== + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +get-func-name@^2.0.1, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" + integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== + dependencies: + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +get-stream@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" + integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== + +glob@^7.1.4: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +has-bigints@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" + integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== + dependencies: + get-intrinsic "^1.2.2" + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + +html-encoding-sniffer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz#696df529a7cfd82446369dc5193e590a3735b448" + integrity sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ== + dependencies: + whatwg-encoding "^3.1.1" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +http-proxy-agent@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz#e9096c5afd071a3fce56e6252bb321583c124673" + integrity sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + +https-proxy-agent@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b" + integrity sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA== + dependencies: + agent-base "^7.0.2" + debug "4" + +human-signals@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" + integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== + +iconv-lite@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +indent-string@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-5.0.0.tgz#4fd2980fccaf8622d14c64d694f4cf33c81951a5" + integrity sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +internal-slot@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.6.tgz#37e756098c4911c5e912b8edbf71ed3aa116f930" + integrity sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg== + dependencies: + get-intrinsic "^1.2.2" + hasown "^2.0.0" + side-channel "^1.0.4" + +is-arguments@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-callable@^1.1.3: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-date-object@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-map@^2.0.1, is-map@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" + integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-set@^2.0.1, is-set@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" + integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== + +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.10: + version "1.1.12" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" + integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== + dependencies: + which-typed-array "^1.1.11" + +is-weakmap@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" + integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== + +is-weakset@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" + integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-report@^3.0.0, istanbul-lib-report@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a" + integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +jsdom@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-23.2.0.tgz#08083220146d41c467efa1c6969f02b525ba6c1d" + integrity sha512-L88oL7D/8ufIES+Zjz7v0aes+oBMh2Xnh3ygWvL0OaICOomKEPKuPnIfBJekiXr+BHbbMjrWn/xqrDQuxFTeyA== + dependencies: + "@asamuzakjp/dom-selector" "^2.0.1" + cssstyle "^4.0.1" + data-urls "^5.0.0" + decimal.js "^10.4.3" + form-data "^4.0.0" + html-encoding-sniffer "^4.0.0" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.2" + is-potential-custom-element-name "^1.0.1" + parse5 "^7.1.2" + rrweb-cssom "^0.6.0" + saxes "^6.0.0" + symbol-tree "^3.2.4" + tough-cookie "^4.1.3" + w3c-xmlserializer "^5.0.0" + webidl-conversions "^7.0.0" + whatwg-encoding "^3.1.1" + whatwg-mimetype "^4.0.0" + whatwg-url "^14.0.0" + ws "^8.16.0" + xml-name-validator "^5.0.0" + +jsonc-parser@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" + integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== + +local-pkg@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.5.0.tgz#093d25a346bae59a99f80e75f6e9d36d7e8c925c" + integrity sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg== + dependencies: + mlly "^1.4.2" + pkg-types "^1.0.3" + +loupe@^2.3.6, loupe@^2.3.7: + version "2.3.7" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== + dependencies: + get-func-name "^2.0.1" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +lz-string@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" + integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ== + +magic-string@^0.30.5: + version "0.30.5" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.5.tgz#1994d980bd1c8835dc6e78db7cbd4ae4f24746f9" + integrity sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.15" + +magicast@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.3.3.tgz#a15760f982deec9dabc5f314e318d7c6bddcb27b" + integrity sha512-ZbrP1Qxnpoes8sz47AM0z08U+jW6TyRgZzcWy3Ma3vDhJttwMwAFDMMQFobwdBxByBD46JYmxRzeF7w2+wJEuw== + dependencies: + "@babel/parser" "^7.23.6" + "@babel/types" "^7.23.6" + source-map-js "^1.0.2" + +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +mdn-data@2.0.30: + version "2.0.30" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc" + integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +mlly@^1.2.0, mlly@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.4.2.tgz#7cf406aa319ff6563d25da6b36610a93f2a8007e" + integrity sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg== + dependencies: + acorn "^8.10.0" + pathe "^1.1.1" + pkg-types "^1.0.3" + ufo "^1.3.0" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nanoid@^3.3.7: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + +npm-run-path@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.2.0.tgz#224cdd22c755560253dd71b83a1ef2f758b2e955" + integrity sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg== + dependencies: + path-key "^4.0.0" + +object-inspect@^1.9.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + +object-is@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.4: + version "4.1.5" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" + integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== + dependencies: + call-bind "^1.0.5" + define-properties "^1.2.1" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + +p-limit@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-5.0.0.tgz#6946d5b7140b649b7a33a027d89b4c625b3a5985" + integrity sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ== + dependencies: + yocto-queue "^1.0.0" + +parse5@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" + integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== + dependencies: + entities "^4.4.0" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + +pathe@^1.1.0, pathe@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.1.tgz#1dd31d382b974ba69809adc9a7a347e65d84829a" + integrity sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q== + +pathval@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +pkg-types@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.0.3.tgz#988b42ab19254c01614d13f4f65a2cfc7880f868" + integrity sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A== + dependencies: + jsonc-parser "^3.2.0" + mlly "^1.2.0" + pathe "^1.1.0" + +postcss@^8.4.32: + version "8.4.32" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.32.tgz#1dac6ac51ab19adb21b8b34fd2d93a86440ef6c9" + integrity sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw== + dependencies: + nanoid "^3.3.7" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +preact@^10.19.3: + version "10.19.3" + resolved "https://registry.yarnpkg.com/preact/-/preact-10.19.3.tgz#7a7107ed2598a60676c943709ea3efb8aaafa899" + integrity sha512-nHHTeFVBTHRGxJXKkKu5hT8C/YWBkPso4/Gad6xuj5dbptt9iF9NZr9pHbPhBrnT2klheu7mHTxTZ/LjwJiEiQ== + +prettier@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.0.tgz#c6d16474a5f764ea1a4a373c593b779697744d5e" + integrity sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw== + +pretty-format@^27.0.2: + version "27.5.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" + integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== + dependencies: + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + +pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +psl@^1.1.33: + version "1.9.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== + +punycode@^2.1.1, punycode@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + +regexp.prototype.flags@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" + integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + set-function-name "^2.0.0" + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +rollup@^4.2.0: + version "4.9.2" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.9.2.tgz#19d730219b7ec5f51372c6cf15cfb841990489fe" + integrity sha512-66RB8OtFKUTozmVEh3qyNfH+b+z2RXBVloqO2KCC/pjFaGaHtxP9fVfOQKPSGXg2mElmjmxjW/fZ7iKrEpMH5Q== + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.9.2" + "@rollup/rollup-android-arm64" "4.9.2" + "@rollup/rollup-darwin-arm64" "4.9.2" + "@rollup/rollup-darwin-x64" "4.9.2" + "@rollup/rollup-linux-arm-gnueabihf" "4.9.2" + "@rollup/rollup-linux-arm64-gnu" "4.9.2" + "@rollup/rollup-linux-arm64-musl" "4.9.2" + "@rollup/rollup-linux-riscv64-gnu" "4.9.2" + "@rollup/rollup-linux-x64-gnu" "4.9.2" + "@rollup/rollup-linux-x64-musl" "4.9.2" + "@rollup/rollup-win32-arm64-msvc" "4.9.2" + "@rollup/rollup-win32-ia32-msvc" "4.9.2" + "@rollup/rollup-win32-x64-msvc" "4.9.2" + fsevents "~2.3.2" + +route-parser@mint-lang/mint-route-parser: + version "0.0.5" + resolved "https://codeload.github.com/mint-lang/mint-route-parser/tar.gz/903d07a62fe7649fccb6be6694445ee4217c933e" + +rrweb-cssom@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1" + integrity sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw== + +"safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +saxes@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-6.0.0.tgz#fe5b4a4768df4f14a201b1ba6a65c1f3d9988cc5" + integrity sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA== + dependencies: + xmlchars "^2.2.0" + +semver@^7.5.3: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + +set-function-length@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" + integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ== + dependencies: + define-data-property "^1.1.1" + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +set-function-name@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" + integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== + dependencies: + define-data-property "^1.0.1" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +siginfo@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" + integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== + +signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +source-map-js@^1.0.1, source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +stackback@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b" + integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw== + +std-env@^3.5.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.7.0.tgz#c9f7386ced6ecf13360b6c6c55b8aaa4ef7481d2" + integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg== + +stop-iteration-iterator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" + integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== + dependencies: + internal-slot "^1.0.4" + +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + +strip-literal@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-1.3.0.tgz#db3942c2ec1699e6836ad230090b84bb458e3a07" + integrity sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg== + dependencies: + acorn "^8.10.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +tinybench@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.5.1.tgz#3408f6552125e53a5a48adee31261686fd71587e" + integrity sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg== + +tinypool@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.8.1.tgz#b6c4e4972ede3e3e5cda74a3da1679303d386b03" + integrity sha512-zBTCK0cCgRROxvs9c0CGK838sPkeokNGdQVUUwHAbynHFlmyJYj825f/oRs528HaIJ97lo0pLIlDUzwN+IorWg== + +tinyspy@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-2.2.0.tgz#9dc04b072746520b432f77ea2c2d17933de5d6ce" + integrity sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +tough-cookie@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" + integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" + +tr46@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-5.0.0.tgz#3b46d583613ec7283020d79019f1335723801cec" + integrity sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g== + dependencies: + punycode "^2.3.1" + +type-detect@^4.0.0, type-detect@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +ufo@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.3.2.tgz#c7d719d0628a1c80c006d2240e0d169f6e3c0496" + integrity sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA== + +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + +url-parse@^1.5.3: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +uuid-random@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/uuid-random/-/uuid-random-1.3.2.tgz#96715edbaef4e84b1dcf5024b00d16f30220e2d0" + integrity sha512-UOzej0Le/UgkbWEO8flm+0y+G+ljUon1QWTEZOq1rnMAsxo2+SckbiZdKzAHHlVh6gJqI1TjC/xwgR50MuCrBQ== + +v8-to-istanbul@^9.2.0: + version "9.2.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz#2ed7644a245cddd83d4e087b9b33b3e62dfd10ad" + integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + +vite-node@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.2.1.tgz#bca96ae91b2b1ee9a7aa73685908362d70ce26a8" + integrity sha512-fNzHmQUSOY+y30naohBvSW7pPn/xn3Ib/uqm+5wAJQJiqQsU0NBR78XdRJb04l4bOFKjpTWld0XAfkKlrDbySg== + dependencies: + cac "^6.7.14" + debug "^4.3.4" + pathe "^1.1.1" + picocolors "^1.0.0" + vite "^5.0.0" + +vite@^5.0.0: + version "5.0.10" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.10.tgz#1e13ef5c3cf5aa4eed81f5df6d107b3c3f1f6356" + integrity sha512-2P8J7WWgmc355HUMlFrwofacvr98DAjoE52BfdbwQtyLH06XKwaL/FMnmKM2crF0iX4MpmMKoDlNCB1ok7zHCw== + dependencies: + esbuild "^0.19.3" + postcss "^8.4.32" + rollup "^4.2.0" + optionalDependencies: + fsevents "~2.3.3" + +vitest@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.2.1.tgz#9afb705826a2c6260a71b625d28b49117833dce6" + integrity sha512-TRph8N8rnSDa5M2wKWJCMnztCZS9cDcgVTQ6tsTFTG/odHJ4l5yNVqvbeDJYJRZ6is3uxaEpFs8LL6QM+YFSdA== + dependencies: + "@vitest/expect" "1.2.1" + "@vitest/runner" "1.2.1" + "@vitest/snapshot" "1.2.1" + "@vitest/spy" "1.2.1" + "@vitest/utils" "1.2.1" + acorn-walk "^8.3.2" + cac "^6.7.14" + chai "^4.3.10" + debug "^4.3.4" + execa "^8.0.1" + local-pkg "^0.5.0" + magic-string "^0.30.5" + pathe "^1.1.1" + picocolors "^1.0.0" + std-env "^3.5.0" + strip-literal "^1.3.0" + tinybench "^2.5.1" + tinypool "^0.8.1" + vite "^5.0.0" + vite-node "1.2.1" + why-is-node-running "^2.2.2" + +w3c-xmlserializer@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz#f925ba26855158594d907313cedd1476c5967f6c" + integrity sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA== + dependencies: + xml-name-validator "^5.0.0" + +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + +whatwg-encoding@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz#d0f4ef769905d426e1688f3e34381a99b60b76e5" + integrity sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ== + dependencies: + iconv-lite "0.6.3" + +whatwg-mimetype@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz#bc1bf94a985dc50388d54a9258ac405c3ca2fc0a" + integrity sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg== + +whatwg-url@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-14.0.0.tgz#00baaa7fd198744910c4b1ef68378f2200e4ceb6" + integrity sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw== + dependencies: + tr46 "^5.0.0" + webidl-conversions "^7.0.0" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-collection@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" + integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== + dependencies: + is-map "^2.0.1" + is-set "^2.0.1" + is-weakmap "^2.0.1" + is-weakset "^2.0.1" + +which-typed-array@^1.1.11, which-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" + integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.4" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +why-is-node-running@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/why-is-node-running/-/why-is-node-running-2.2.2.tgz#4185b2b4699117819e7154594271e7e344c9973e" + integrity sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA== + dependencies: + siginfo "^2.0.0" + stackback "0.0.2" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@^8.16.0: + version "8.16.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" + integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== + +xml-name-validator@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-5.0.0.tgz#82be9b957f7afdacf961e5980f1bf227c0bf7673" + integrity sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg== + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yocto-queue@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251" + integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g== diff --git a/shard.lock b/shard.lock index 89edb8809..0848ca486 100644 --- a/shard.lock +++ b/shard.lock @@ -6,7 +6,7 @@ shards: ameba: git: https://github.com/crystal-ameba/ameba.git - version: 1.5.0 + version: 1.6.1 ansi-escapes: git: https://github.com/gtramontina/ansi-escapes.cr.git diff --git a/shard.yml b/shard.yml index 7c9d56b3f..08460c779 100644 --- a/shard.yml +++ b/shard.yml @@ -27,7 +27,7 @@ dependencies: development_dependencies: ameba: github: crystal-ameba/ameba - version: ~> 1.5.0 + version: ~> 1.6.1 targets: mint: diff --git a/spec/compilers/access b/spec/compilers/access index 83d31eb97..8337f9b0a 100644 --- a/spec/compilers/access +++ b/spec/compilers/access @@ -1,4 +1,4 @@ -record X { +type X { name : String } diff --git a/spec/compilers/block_with_early_return b/spec/compilers/block_with_early_return index b334f6be1..e08ced87d 100644 --- a/spec/compilers/block_with_early_return +++ b/spec/compilers/block_with_early_return @@ -1,12 +1,12 @@ -enum Test { +type Test { A(String) B(String) } component Main { fun render : String { - let Test::A(a) = - Test::A("Some string...") or return "RETURN" + let Test.A(a) = + Test.A("Some string...") or return "RETURN" a } diff --git a/spec/compilers/block_with_early_return_await b/spec/compilers/block_with_early_return_await index 086018cf1..8b6a924c3 100644 --- a/spec/compilers/block_with_early_return_await +++ b/spec/compilers/block_with_early_return_await @@ -1,4 +1,4 @@ -enum Test { +type Test { A(String) B(String) } @@ -6,8 +6,8 @@ enum Test { component Main { fun render : String { { - let Test::A(a) = - await Test::A("Some string...") or return "RETURN" + let Test.A(a) = + await Test.A("Some string...") or return "RETURN" a } diff --git a/spec/compilers/array_access b/spec/compilers/bracket_access similarity index 100% rename from spec/compilers/array_access rename to spec/compilers/bracket_access diff --git a/spec/compilers/case_with_nested_tuple_destructuring b/spec/compilers/case_with_nested_tuple_destructuring index 556ea4b71..436d7f072 100644 --- a/spec/compilers/case_with_nested_tuple_destructuring +++ b/spec/compilers/case_with_nested_tuple_destructuring @@ -1,10 +1,10 @@ component Main { fun render : String { - case ({"A", {"B"}}) { - {"A", {"C"}} => + case ({"A", {"B", ""}}) { + {"A", {"C", ""}} => "B" - {"A", {"B"}} => + {"A", {"B", ""}} => "A" {a, b} => @@ -18,12 +18,13 @@ component Main { -------------------------------------------------------------------------------- class A extends _C { render() { - return _match([`A`, [`B`]],[ + return _match([`A`, [`B`, ``]],[ [ [ `A`, [ - `C` + `C`, + `` ] ], () => { @@ -34,7 +35,8 @@ class A extends _C { [ `A`, [ - `B` + `B`, + `` ] ], () => { diff --git a/spec/compilers/case_with_type_destructuring b/spec/compilers/case_with_type_destructuring index 38b0343d1..44c41e680 100644 --- a/spec/compilers/case_with_type_destructuring +++ b/spec/compilers/case_with_type_destructuring @@ -1,8 +1,8 @@ -enum A(a) { +type A(a) { B(a) } -enum C(a) { +type C(a) { D(A(a)) X } @@ -10,17 +10,17 @@ enum C(a) { component Main { fun test (b : C(a)) : a { case (b) { - C::X => "" - C::D(a) => + C.X => "" + C.D(a) => case (a) { - A::B(c) => + A.B(c) => c } } } fun render : String { - test(C::D(A::B(""))) + test(C.D(A.B(""))) "" } diff --git a/spec/compilers/component_global b/spec/compilers/component_global index 8bf24d861..5d36ae5f4 100644 --- a/spec/compilers/component_global +++ b/spec/compilers/component_global @@ -13,7 +13,7 @@ global component Notifications { component Main { fun render : Html {
- <{ Notifications.notify("Hello") }> + Notifications.notify("Hello")
} } diff --git a/spec/compilers/component_instance_access b/spec/compilers/component_instance_access index b40f516e3..9182fffe7 100644 --- a/spec/compilers/component_instance_access +++ b/spec/compilers/component_instance_access @@ -1,4 +1,4 @@ -enum Maybe(value) { +type Maybe(value) { Just(value) Nothing } @@ -16,8 +16,8 @@ component Instance { component Main { fun handleClick : String { case (instance) { - Maybe::Just(component) => component.name - Maybe::Nothing => "" + Just(component) => component.name + Nothing => "" } } diff --git a/spec/compilers/component_with_provider b/spec/compilers/component_with_provider index a67ec779b..a92200cff 100644 --- a/spec/compilers/component_with_provider +++ b/spec/compilers/component_with_provider @@ -1,4 +1,4 @@ -record MouseProvider.Data { +type MouseProvider.Data { moves : Function(Position, Void), ups : Function(Position, Void) } diff --git a/spec/compilers/component_with_provider_and_lifecycle_functions b/spec/compilers/component_with_provider_and_lifecycle_functions index da8fcd832..9883e4b81 100644 --- a/spec/compilers/component_with_provider_and_lifecycle_functions +++ b/spec/compilers/component_with_provider_and_lifecycle_functions @@ -1,4 +1,4 @@ -record MouseProvider.Data { +type MouseProvider.Data { moves : Function(Position, Void), ups : Function(Position, Void) } diff --git a/spec/compilers/component_with_provider_and_store b/spec/compilers/component_with_provider_and_store index b891b213b..37d45c867 100644 --- a/spec/compilers/component_with_provider_and_store +++ b/spec/compilers/component_with_provider_and_store @@ -1,4 +1,4 @@ -record MouseProvider.Data { +type MouseProvider.Data { moves : Function(Position, Void), ups : Function(Position, Void) } diff --git a/spec/compilers/constant_global_component b/spec/compilers/constant_global_component index 7047e82d5..0d7f7a9cd 100644 --- a/spec/compilers/constant_global_component +++ b/spec/compilers/constant_global_component @@ -9,7 +9,7 @@ global component Test { component Main { fun render : Html {
- <{ Test:NAME }> + Test.NAME
} } diff --git a/spec/compilers/constant_module b/spec/compilers/constant_module index 0857c6718..4b162515d 100644 --- a/spec/compilers/constant_module +++ b/spec/compilers/constant_module @@ -5,7 +5,7 @@ module Test { component Main { fun render : Html {
- <{ Test:NAME }> + Test.NAME
} } diff --git a/spec/compilers/constant_store b/spec/compilers/constant_store index 5603a0f5b..562b0c94f 100644 --- a/spec/compilers/constant_store +++ b/spec/compilers/constant_store @@ -5,7 +5,7 @@ store Test { component Main { fun render : Html {
- <{ Test:NAME }> + Test.NAME
} } diff --git a/spec/compilers/constant_store_exposed b/spec/compilers/constant_store_exposed index 386310f21..4840abb12 100644 --- a/spec/compilers/constant_store_exposed +++ b/spec/compilers/constant_store_exposed @@ -7,14 +7,14 @@ component Main { fun render : Html {
- <{ NAME }> + NAME
} } -------------------------------------------------------------------------------- class A extends _C { - get a() { - return B.b; + get b() { + return B.a; } componentWillUnmount() { @@ -40,7 +40,7 @@ const B = new(class extends _S { this.state = {}; this._d({ - b: () => { + a: () => { return `ASD` } }); diff --git a/spec/compilers/dce_remove_enum b/spec/compilers/dce_remove_enum index 7b9580bc0..422202fea 100644 --- a/spec/compilers/dce_remove_enum +++ b/spec/compilers/dce_remove_enum @@ -1,4 +1,4 @@ -enum Test { +type Test { X Y Z diff --git a/spec/compilers/dce_remove_provider b/spec/compilers/dce_remove_provider index c190c9187..e1b107f6b 100644 --- a/spec/compilers/dce_remove_provider +++ b/spec/compilers/dce_remove_provider @@ -1,6 +1,16 @@ -provider MouseProvider : Unit { +type Subscription { + name : String +} + +provider MouseProvider : Subscription { fun attach : Void { void } } -------------------------------------------------------------------------------- +const A = _R({ + name: [ + "name", + Decoder.string + ] +}); diff --git a/spec/compilers/decode b/spec/compilers/decode index b1ec8e605..1e76ab71a 100644 --- a/spec/compilers/decode +++ b/spec/compilers/decode @@ -1,8 +1,8 @@ -record X.Y { +type X.Y { blah : String } -record X { +type X { name : String, y: X.Y } diff --git a/spec/compilers/decode_function b/spec/compilers/decode_function index 65ffd9c2d..4c7d96ff1 100644 --- a/spec/compilers/decode_function +++ b/spec/compilers/decode_function @@ -1,8 +1,8 @@ -record X.Y { +type X.Y { blah : String } -record X { +type X { name : String, y: X.Y } diff --git a/spec/compilers/decoder b/spec/compilers/decoder index f1f8d1be8..5f10b3227 100644 --- a/spec/compilers/decoder +++ b/spec/compilers/decoder @@ -1,8 +1,8 @@ -record Y { +type Y { size : Number using "SIIIZEEE" } -record X { +type X { string : String, number : Number, bool : Bool, diff --git a/spec/compilers/destructuring b/spec/compilers/destructuring index 1cbcbcde2..be48dfb6a 100644 --- a/spec/compilers/destructuring +++ b/spec/compilers/destructuring @@ -1,4 +1,4 @@ -enum Test { +type Test { Item( matchString : String, content : String, @@ -9,14 +9,14 @@ enum Test { component Main { fun content (item : Test) : String { case item { - Test::Item(content) => content - Test::None => "" + Test.Item(content) => content + Test.None => "" } } fun render : String { content( - Test::Item( + Test.Item( matchString: "MATCHSTRING", content: "CONTENT", key: "KEY")) diff --git a/spec/compilers/directives/asset b/spec/compilers/directives/asset index 2aa9f0e3d..367c2e0f9 100644 --- a/spec/compilers/directives/asset +++ b/spec/compilers/directives/asset @@ -6,7 +6,7 @@ component Main { -------------------------------------------------------------------------------- class A extends _C { render() { - return `/assets/icon_c97b81630bc53286dadc8996727d348e.svg`; + return `/__mint__/icon_c97b81630bc53286dadc8996727d348e.svg`; } }; diff --git a/spec/compilers/encode b/spec/compilers/encode index 999142955..70152e283 100644 --- a/spec/compilers/encode +++ b/spec/compilers/encode @@ -1,4 +1,4 @@ -record Test { +type Test { name : String, age : Number } diff --git a/spec/compilers/field b/spec/compilers/field index 407513b38..83200c435 100644 --- a/spec/compilers/field +++ b/spec/compilers/field @@ -1,4 +1,4 @@ -record Test { +type Test { a : String, b : Number } diff --git a/spec/compilers/member_access b/spec/compilers/field_access similarity index 94% rename from spec/compilers/member_access rename to spec/compilers/field_access index a48353184..fbaa79a7d 100644 --- a/spec/compilers/member_access +++ b/spec/compilers/field_access @@ -1,4 +1,4 @@ -record X { +type X { name : String } @@ -18,7 +18,7 @@ component Main { name: "Doe" } ] - |> Array.map(.name) + |> Array.map(.name(X)) "asd" } diff --git a/spec/compilers/for b/spec/compilers/for index 654197c2d..2dcd7d551 100644 --- a/spec/compilers/for +++ b/spec/compilers/for @@ -2,7 +2,7 @@ component Main { fun render : Array(Html) { for (item of ["A", "B"]) {
- <{ item }> + item
} } diff --git a/spec/compilers/for_with_index b/spec/compilers/for_with_index index c2484ee15..6ca9221a4 100644 --- a/spec/compilers/for_with_index +++ b/spec/compilers/for_with_index @@ -2,7 +2,7 @@ component Main { fun render : Array(Html) { for (item, index of ["A", "B"]) {
- <{ item }> + item
} when { index == 10 diff --git a/spec/compilers/for_with_index_2 b/spec/compilers/for_with_index_2 index a06357edb..7557e890f 100644 --- a/spec/compilers/for_with_index_2 +++ b/spec/compilers/for_with_index_2 @@ -2,7 +2,7 @@ component Main { fun render : Array(Html) { for (item, index of ["A", "B"]) {
- <{ item }> + item
} } diff --git a/spec/compilers/html_attribute_html_expression b/spec/compilers/html_attribute_html_fragment similarity index 81% rename from spec/compilers/html_attribute_html_expression rename to spec/compilers/html_attribute_html_fragment index 8deaa4d08..39cefe537 100644 --- a/spec/compilers/html_attribute_html_expression +++ b/spec/compilers/html_attribute_html_fragment @@ -8,7 +8,7 @@ component Thing { component Main { fun render { - /> + "x"/> } } -------------------------------------------------------------------------------- @@ -33,12 +33,12 @@ A.displayName = "Thing"; class B extends _C { render() { - return $a(); + return _h(A, { + a: _h(React.Fragment, {}, [ + `x` + ]) + }); } }; B.displayName = "Main"; - -const $a = _m(() => _h(A, { - a: `x` -})); diff --git a/spec/compilers/html_attribute_ref b/spec/compilers/html_attribute_ref index 7d8b5daf5..afd5c48a4 100644 --- a/spec/compilers/html_attribute_ref +++ b/spec/compilers/html_attribute_ref @@ -1,4 +1,4 @@ -enum Maybe(value) { +type Maybe(value) { Just(value) Nothing } diff --git a/spec/compilers/html_expression b/spec/compilers/html_expression deleted file mode 100644 index 659fd2859..000000000 --- a/spec/compilers/html_expression +++ /dev/null @@ -1,15 +0,0 @@ -component Main { - fun render : Html { -
<{ "Hello" }>
- } -} --------------------------------------------------------------------------------- -class A extends _C { - render() { - return _h("div", {}, [ - `Hello` - ]); - } -}; - -A.displayName = "Main"; diff --git a/spec/compilers/html_fragment b/spec/compilers/html_fragment index 45724458d..a12c92a70 100644 --- a/spec/compilers/html_fragment +++ b/spec/compilers/html_fragment @@ -2,7 +2,7 @@ component Main { fun render : Html {
<> - <{ "A" }> + "A"
} diff --git a/spec/compilers/if_let b/spec/compilers/if_let index ffb6c5639..ca0780f2c 100644 --- a/spec/compilers/if_let +++ b/spec/compilers/if_let @@ -1,11 +1,11 @@ -enum T { +type T { A(String) B } component Main { fun render : String { - if (let T::A(a) = T::A("")) { + if (let T.A(a) = T.A("")) { a } else { "b" diff --git a/spec/compilers/if_let_await b/spec/compilers/if_let_await index f04a7da60..c56e5b73c 100644 --- a/spec/compilers/if_let_await +++ b/spec/compilers/if_let_await @@ -1,15 +1,19 @@ -enum T { +type T { A(String) B } component Main { fun render : String { - if (let T::A(a) = await T::A("")) { - a - } else { - "b" + { + if (let T.A(a) = await T.A("")) { + a + } else { + "b" + } } + + "" } } -------------------------------------------------------------------------------- @@ -30,7 +34,7 @@ class B extends _E { class C extends _C { render() { - return (async () => { + (async () => { let b = await _n(A)(``); return _match(b,[ @@ -50,6 +54,8 @@ class C extends _C { ] ]); })(); + + return ``; } }; diff --git a/spec/compilers/module b/spec/compilers/module index 1012b60c2..2ed07c7e9 100644 --- a/spec/compilers/module +++ b/spec/compilers/module @@ -1,7 +1,7 @@ module Html.Testing { fun renderAll : Html {

- <{ "It should work" }> + "It should work"

} } diff --git a/spec/compilers/module_access_subscriptions b/spec/compilers/module_access_subscriptions index bb89442eb..58ec66eaa 100644 --- a/spec/compilers/module_access_subscriptions +++ b/spec/compilers/module_access_subscriptions @@ -1,4 +1,4 @@ -record Test { +type Test { test : String } diff --git a/spec/compilers/operation_or b/spec/compilers/operation_or index 0deb365aa..105357e47 100644 --- a/spec/compilers/operation_or +++ b/spec/compilers/operation_or @@ -1,11 +1,11 @@ -enum Maybe(a) { +type Maybe(a) { Nothing Just(a) } component Main { fun test : String { - Maybe::Nothing or "Hello" + Maybe.Nothing or "Hello" } fun render : String { diff --git a/spec/compilers/pipe b/spec/compilers/pipe index 986c157a9..080c08a50 100644 --- a/spec/compilers/pipe +++ b/spec/compilers/pipe @@ -1,8 +1,8 @@ component Main { fun render : Html {
- <{ (n : String) : String { n }("3") }> - <{ "3" |> (n : String) : String { n } }> + (n : String) : String { n }("3") + "3" |> (n : String) : String { n }
} } diff --git a/spec/compilers/provider_with_items b/spec/compilers/provider_with_items index e1cfe9c0e..e53cae737 100644 --- a/spec/compilers/provider_with_items +++ b/spec/compilers/provider_with_items @@ -1,4 +1,4 @@ -record Subscription { +type Subscription { a : Bool, b : Bool } diff --git a/spec/compilers/record b/spec/compilers/record index 407513b38..83200c435 100644 --- a/spec/compilers/record +++ b/spec/compilers/record @@ -1,4 +1,4 @@ -record Test { +type Test { a : String, b : Number } diff --git a/spec/compilers/record_update b/spec/compilers/record_update index 8b1dc6a8c..29a60759c 100644 --- a/spec/compilers/record_update +++ b/spec/compilers/record_update @@ -1,4 +1,4 @@ -record Record { +type Record { name: String } diff --git a/spec/compilers/static_component b/spec/compilers/static_component index e96ea5203..f6f98ba62 100644 --- a/spec/compilers/static_component +++ b/spec/compilers/static_component @@ -2,7 +2,7 @@ component Test { property text : String = "" fun render : Html { -
<{ text }>
+
text
} } @@ -10,7 +10,7 @@ component Test2 { property text : String = "" fun render : Html { -
<{ text }>
+
text
} } @@ -19,7 +19,7 @@ component TestWithChildren { property text : String = "" fun render : Html { -
<{ text }>
+
text
} } diff --git a/spec/compilers/store b/spec/compilers/store index f24b8a744..a19d8a621 100644 --- a/spec/compilers/store +++ b/spec/compilers/store @@ -15,8 +15,8 @@ component Main { } -------------------------------------------------------------------------------- class A extends _C { - get a() { - return B.b; + get b() { + return B.a; } componentWillUnmount() { @@ -39,12 +39,12 @@ const B = new(class extends _S { super(); this.state = { - b: `` + a: `` }; } - get b() { - return this.state.b; + get a() { + return this.state.a; } c() { diff --git a/spec/compilers/store_with_get b/spec/compilers/store_with_get index d09d51cd7..f875102f5 100644 --- a/spec/compilers/store_with_get +++ b/spec/compilers/store_with_get @@ -15,8 +15,8 @@ component Main { } -------------------------------------------------------------------------------- class A extends _C { - get a() { - return B.b; + get b() { + return B.a; } componentWillUnmount() { @@ -39,12 +39,12 @@ const B = new(class extends _S { super(); this.state = { - b: `` + a: `` }; } - get b() { - return this.state.b; + get a() { + return this.state.a; } get c() { diff --git a/spec/compilers/type b/spec/compilers/type index f9fc00de1..343ae2f20 100644 --- a/spec/compilers/type +++ b/spec/compilers/type @@ -1,10 +1,10 @@ -enum Test(a) { +type Test(a) { X Y Z(Res(a, Number)) } -enum Res(error, value) { +type Res(error, value) { Error(error) Ok(value) Other(error, value) @@ -12,15 +12,15 @@ enum Res(error, value) { component Main { fun a : Test(a) { - Test::X + Test.X } fun b : Res(String, String) { - Res::Other("", "") + Res.Other("", "") } fun c : Test(String) { - Test::Z(Res::Error("")) + Test.Z(Res.Error("")) } fun render : String { diff --git a/spec/compilers/type_with_variants b/spec/compilers/type_with_variants index 58d9ee4cb..6e7c3b7be 100644 --- a/spec/compilers/type_with_variants +++ b/spec/compilers/type_with_variants @@ -1,13 +1,13 @@ -enum A { +type A { B(name : String, color : String) C } component Main { fun render : String { - case (A::B(name: "Joe", color: "Blue")) { - A::B(color, name) => color - A::C => "" + case (A.B(name: "Joe", color: "Blue")) { + A.B(color, name) => color + A.C => "" } } } diff --git a/spec/compilers2/access b/spec/compilers2/access new file mode 100644 index 000000000..52c19f469 --- /dev/null +++ b/spec/compilers2/access @@ -0,0 +1,15 @@ +type X { + name : String +} + +component Main { + fun render : String { + { name: "test" }.name + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return { + name: `test` + }.name +}; diff --git a/spec/compilers2/access_deep b/spec/compilers2/access_deep new file mode 100644 index 000000000..46545f681 --- /dev/null +++ b/spec/compilers2/access_deep @@ -0,0 +1,35 @@ +type Locale { + level1: Level1 +} + +type Level1 { + level2: Level2 +} + +type Level2 { + name : String +} + +store Settings { + state locale : Locale = { level1: { level2: { name: "Test" }} } +} + +component Main { + fun render : String { + Settings.locale.level1.level2.name + } +} +-------------------------------------------------------------------------------- +import { signal as A } from "./runtime.js"; + +export const + a = A({ + level1: { + level2: { + name: `Test` + } + } + }), + B = () => { + return a.value.level1.level2.name + }; diff --git a/spec/compilers2/argument b/spec/compilers2/argument new file mode 100644 index 000000000..e38d7c8a5 --- /dev/null +++ b/spec/compilers2/argument @@ -0,0 +1,19 @@ +component Main { + fun test (a : String, b : Number) : Number { + b + } + + fun render : String { + test("", 0) + + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + const a = (b, c) => { + return c + }; + a(``, 0); + return `` +}; diff --git a/spec/compilers2/argument_with_default b/spec/compilers2/argument_with_default new file mode 100644 index 000000000..a8433d8b6 --- /dev/null +++ b/spec/compilers2/argument_with_default @@ -0,0 +1,19 @@ +component Main { + fun test (a : String, b : Number = 0) : Number { + b + } + + fun render : String { + test("") + + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + const a = (b, c = 0) => { + return c + }; + a(``); + return `` +}; diff --git a/spec/compilers2/argument_with_default_inline_function b/spec/compilers2/argument_with_default_inline_function new file mode 100644 index 000000000..ef98ddc90 --- /dev/null +++ b/spec/compilers2/argument_with_default_inline_function @@ -0,0 +1,20 @@ +component Main { + fun render : String { + let test = + (a : String, b : Number = 0) : Number { + b + } + + test("") + + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + const a = (b, c = 0) => { + return c + }; + a(``); + return `` +}; diff --git a/spec/compilers2/array_literal b/spec/compilers2/array_literal new file mode 100644 index 000000000..c2e86a127 --- /dev/null +++ b/spec/compilers2/array_literal @@ -0,0 +1,20 @@ +component Main { + fun render : String { + [ + "Hello", + "Blah", + "Joe" + ] + + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + [ + `Hello`, + `Blah`, + `Joe` + ]; + return `` +}; diff --git a/spec/compilers2/block b/spec/compilers2/block new file mode 100644 index 000000000..07661b944 --- /dev/null +++ b/spec/compilers2/block @@ -0,0 +1,12 @@ +component Main { + fun render : String { + let a = "Some string..." + + a + ", other string..." + } +} +-------------------------------------------------------------------------------- +export const A = () => { + const a = `Some string...`; + return a + `, other string...` +}; diff --git a/spec/compilers2/block_with_await b/spec/compilers2/block_with_await new file mode 100644 index 000000000..97dfafca4 --- /dev/null +++ b/spec/compilers2/block_with_await @@ -0,0 +1,27 @@ +component Main { + fun promise : Promise(String) { + `` as Promise(String) + } + + fun promiseTest : Promise(String) { + await promise() + } + + fun render : String { + promiseTest() + + "Hello" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + const + a = () => { + return undefined + }, + b = async () => { + return await a() + }; + b(); + return `Hello` +}; diff --git a/spec/compilers2/block_with_early_return b/spec/compilers2/block_with_early_return new file mode 100644 index 000000000..3cb3a2504 --- /dev/null +++ b/spec/compilers2/block_with_early_return @@ -0,0 +1,33 @@ +type Test { + A(String) + B(String) +} + +component Main { + fun render : String { + let Test.A(a) = + Test.A("Some string...") or return "RETURN" + + a + } +} +-------------------------------------------------------------------------------- +import { + patternVariable as H, + destructure as E, + newVariant as F, + pattern as G, + variant as B +} from "./runtime.js"; + +export const + A = B(1), + C = B(1), + D = () => { + const a = E(F(A)(`Some string...`), G(A, [H])); + if (a === false) { + return `RETURN` + }; + const [b] = a; + return b + }; diff --git a/spec/compilers2/block_with_early_return_2 b/spec/compilers2/block_with_early_return_2 new file mode 100644 index 000000000..022607659 --- /dev/null +++ b/spec/compilers2/block_with_early_return_2 @@ -0,0 +1,11 @@ +component Main { + fun render : String { + return "YES" + "NO" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return `YES`; + return `NO` +}; diff --git a/spec/compilers2/block_with_early_return_await b/spec/compilers2/block_with_early_return_await new file mode 100644 index 000000000..ab2071bf4 --- /dev/null +++ b/spec/compilers2/block_with_early_return_await @@ -0,0 +1,40 @@ +type Test { + A(String) + B(String) +} + +component Main { + fun render : String { + { + let Test.A(a) = + await Test.A("Some string...") or return "RETURN" + + a + } + + "" + } +} +-------------------------------------------------------------------------------- +import { + patternVariable as H, + destructure as E, + newVariant as F, + pattern as G, + variant as B +} from "./runtime.js"; + +export const + A = B(1), + C = B(1), + D = () => { + (async () => { + const a = E(await F(A)(`Some string...`), G(A, [H])); + if (a === false) { + return `RETURN` + }; + const [b] = a; + return b + })(); + return `` + }; diff --git a/spec/compilers2/block_with_tuple_destructuring b/spec/compilers2/block_with_tuple_destructuring new file mode 100644 index 000000000..c625e9694 --- /dev/null +++ b/spec/compilers2/block_with_tuple_destructuring @@ -0,0 +1,18 @@ +component Main { + fun render : String { + let {a, b} = {"Some string...", "B"} + + a + ", other string..." + } +} +-------------------------------------------------------------------------------- +export const A = () => { + const [ + a, + b + ] = [ + `Some string...`, + `B` + ]; + return a + `, other string...` +}; diff --git a/spec/compilers2/bool_literal_false b/spec/compilers2/bool_literal_false new file mode 100644 index 000000000..f602b7803 --- /dev/null +++ b/spec/compilers2/bool_literal_false @@ -0,0 +1,12 @@ +component Main { + fun render : String { + false + + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + false; + return `` +}; diff --git a/spec/compilers2/bool_literal_true b/spec/compilers2/bool_literal_true new file mode 100644 index 000000000..67d0b3639 --- /dev/null +++ b/spec/compilers2/bool_literal_true @@ -0,0 +1,12 @@ +component Main { + fun render : String { + true + + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + true; + return `` +}; diff --git a/spec/compilers2/bracket_access b/spec/compilers2/bracket_access new file mode 100644 index 000000000..d128c83af --- /dev/null +++ b/spec/compilers2/bracket_access @@ -0,0 +1,43 @@ +type Maybe(a) { + Nothing + Just(a) +} + +component Main { + fun render : String { + [ + "Hello", + "Blah", + "Joe" + ][1] + + [][1] + + { "key" => "value" }["key"] + + "" + } +} +-------------------------------------------------------------------------------- +import { + bracketAccess as E, + mapAccess as F, + variant as B +} from "./runtime.js"; + +export const + A = B(0), + C = B(1), + D = () => { + E([ + `Hello`, + `Blah`, + `Joe` + ], 1, C, A); + E([], 1, C, A); + F([[ + `key`, + `value` + ]], `key`, C, A); + return `` + }; diff --git a/spec/compilers2/builtin b/spec/compilers2/builtin new file mode 100644 index 000000000..4fd5d370b --- /dev/null +++ b/spec/compilers2/builtin @@ -0,0 +1,17 @@ +component Main { + fun render : Html { + `#{%decodeBoolean%}` + +
+ } +} +-------------------------------------------------------------------------------- +import { + createElement as C, + decodeBoolean as B +} from "./runtime.js"; + +export const A = () => { + (B); + return C(`div`, {}) +}; diff --git a/spec/compilers2/call_labelled b/spec/compilers2/call_labelled new file mode 100644 index 000000000..d3a9a60aa --- /dev/null +++ b/spec/compilers2/call_labelled @@ -0,0 +1,16 @@ +component Main { + fun test (argument1 : String, argument2: Number) : String { + "" + } + + fun render : String { + test(argument2: 0, argument1: "") + } +} +-------------------------------------------------------------------------------- +export const A = () => { + const a = (b, c) => { + return `` + }; + return a(``, 0) +}; diff --git a/spec/compilers2/case b/spec/compilers2/case new file mode 100644 index 000000000..1b4049e7c --- /dev/null +++ b/spec/compilers2/case @@ -0,0 +1,37 @@ +component Main { + fun render : String { + case ("Hello") { + "test" => true + "Hello" => false + => false + } + + "" + } +} +-------------------------------------------------------------------------------- +import { match as B } from "./runtime.js"; + +export const A = () => { + B(`Hello`, [ + [ + `test`, + () => { + return true + } + ], + [ + `Hello`, + () => { + return false + } + ], + [ + null, + () => { + return false + } + ] + ]); + return `` +}; diff --git a/spec/compilers2/case_await b/spec/compilers2/case_await new file mode 100644 index 000000000..de930af3a --- /dev/null +++ b/spec/compilers2/case_await @@ -0,0 +1,40 @@ +component Main { + fun render : String { + case await "Hello" { + "test" => true + "Hello" => false + => false + } + + "" + } +} +-------------------------------------------------------------------------------- +import { match as B } from "./runtime.js"; + +export const A = () => { + (async () => { + let a = await `Hello`; + return B(a, [ + [ + `test`, + () => { + return true + } + ], + [ + `Hello`, + () => { + return false + } + ], + [ + null, + () => { + return false + } + ] + ]) + })(); + return `` +}; diff --git a/spec/compilers2/case_empty b/spec/compilers2/case_empty new file mode 100644 index 000000000..c1812f1d6 --- /dev/null +++ b/spec/compilers2/case_empty @@ -0,0 +1,18 @@ +component Main { + fun render : String { + case ("Hello") { + => "false" + } + } +} +-------------------------------------------------------------------------------- +import { match as B } from "./runtime.js"; + +export const A = () => { + return B(`Hello`, [[ + null, + () => { + return `false` + } + ]]) +}; diff --git a/spec/compilers2/case_with_array_destructuring b/spec/compilers2/case_with_array_destructuring new file mode 100644 index 000000000..17ec9463c --- /dev/null +++ b/spec/compilers2/case_with_array_destructuring @@ -0,0 +1,62 @@ +component Main { + fun render : Array(String) { + case ([]) { + [] => [""] + ["a"] => ["a"] + [a] => [a] + [a, b] => [a, b] + [a, ...middle, b] => middle + } + } +} +-------------------------------------------------------------------------------- +import { + patternVariable as C, + patternSpread as D, + match as B +} from "./runtime.js"; + +export const A = () => { + return B([], [ + [ + [], + () => { + return [``] + } + ], + [ + [`a`], + () => { + return [`a`] + } + ], + [ + [C], + (a) => { + return [a] + } + ], + [ + [ + C, + C + ], + (b, c) => { + return [ + b, + c + ] + } + ], + [ + [ + C, + D, + C + ], + (d, e, f) => { + return e + } + ] + ]) +}; diff --git a/spec/compilers2/case_with_nested_tuple_destructuring b/spec/compilers2/case_with_nested_tuple_destructuring new file mode 100644 index 000000000..69e9a95b1 --- /dev/null +++ b/spec/compilers2/case_with_nested_tuple_destructuring @@ -0,0 +1,78 @@ +component Main { + fun render : String { + case ({"A", {"B", "C"}}) { + {"A", {"C", "D"}} => + "B" + + {"A", {"B", "C"}} => + "A" + + {a, b} => + a + + {a, {b, c}} => + b + } + } +} +-------------------------------------------------------------------------------- +import { + patternVariable as C, + match as B +} from "./runtime.js"; + +export const A = () => { + return B([ + `A`, + [ + `B`, + `C` + ] + ], [ + [ + [ + `A`, + [ + `C`, + `D` + ] + ], + () => { + return `B` + } + ], + [ + [ + `A`, + [ + `B`, + `C` + ] + ], + () => { + return `A` + } + ], + [ + [ + C, + C + ], + (a, b) => { + return a + } + ], + [ + [ + C, + [ + C, + C + ] + ], + (c, d, e) => { + return d + } + ] + ]) +}; diff --git a/spec/compilers2/case_with_tuple_destructuring b/spec/compilers2/case_with_tuple_destructuring new file mode 100644 index 000000000..273dd6555 --- /dev/null +++ b/spec/compilers2/case_with_tuple_destructuring @@ -0,0 +1,58 @@ +component Main { + fun render : String { + case ({"A", 0, true}) { + {"A", 0, false} => + "B" + + {"A", 0, true} => + "A" + + {a, b, c} => + a + } + } +} +-------------------------------------------------------------------------------- +import { + patternVariable as C, + match as B +} from "./runtime.js"; + +export const A = () => { + return B([ + `A`, + 0, + true + ], [ + [ + [ + `A`, + 0, + false + ], + () => { + return `B` + } + ], + [ + [ + `A`, + 0, + true + ], + () => { + return `A` + } + ], + [ + [ + C, + C, + C + ], + (a, b, c) => { + return a + } + ] + ]) +}; diff --git a/spec/compilers2/case_with_tuple_destructuring_bool b/spec/compilers2/case_with_tuple_destructuring_bool new file mode 100644 index 000000000..d466229b7 --- /dev/null +++ b/spec/compilers2/case_with_tuple_destructuring_bool @@ -0,0 +1,47 @@ +component Main { + fun render : String { + case ({false, true}) { + {true, false} => + "B" + + {false, true} => + "A" + + => "C" + } + } +} +-------------------------------------------------------------------------------- +import { match as B } from "./runtime.js"; + +export const A = () => { + return B([ + false, + true + ], [ + [ + [ + true, + false + ], + () => { + return `B` + } + ], + [ + [ + false, + true + ], + () => { + return `A` + } + ], + [ + null, + () => { + return `C` + } + ] + ]) +}; diff --git a/spec/compilers2/case_with_type_destructuring b/spec/compilers2/case_with_type_destructuring new file mode 100644 index 000000000..892c40be6 --- /dev/null +++ b/spec/compilers2/case_with_type_destructuring @@ -0,0 +1,58 @@ +type A(a) { + B(a) +} + +type C(a) { + D(A(a)) + X +} + +component Main { + fun render : String { + case (C.D(A.B(""))) { + C.X => "" + C.D(a) => + case (a) { + A.B(c) => + c + } + } + + "" + } +} +-------------------------------------------------------------------------------- +import { + patternVariable as I, + newVariant as G, + pattern as H, + variant as B, + match as F +} from "./runtime.js"; + +export const + A = B(1), + C = B(0), + D = B(1), + E = () => { + F(G(A)(G(D)(``)), [ + [ + H(C, []), + () => { + return `` + } + ], + [ + H(A, [I]), + (a) => { + return F(a, [[ + H(D, [I]), + (b) => { + return b + } + ]]) + } + ] + ]); + return `` + }; diff --git a/spec/compilers2/component b/spec/compilers2/component new file mode 100644 index 000000000..49d297c64 --- /dev/null +++ b/spec/compilers2/component @@ -0,0 +1,9 @@ +component Main { + fun render : String { + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return `` +}; diff --git a/spec/compilers2/component_async b/spec/compilers2/component_async new file mode 100644 index 000000000..db6c9ee8a --- /dev/null +++ b/spec/compilers2/component_async @@ -0,0 +1,81 @@ +async component Test { + fun render : Html { +
+ Greeter.greet("async") + Greeter.both() +
+ } +} + +module Greeter { + // Only used in Test so it should be compiled with it. + fun greet (name : String) { + "I'm #{name}!" + } + + // Only used in Main so it should be compiled with it. + fun main { + "I'm in Main!" + } + + // Only used in both so it should be compiled with Main. + fun both { + "I'm in both!" + } +} + +component Main { + fun render : Html { +
+ Greeter.main() + Greeter.both() + +
+ } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.js ===--- +import { + lazyComponent as E, + createElement as D, + lazy as B +} from "./runtime.js"; + +export const + a = () => { + return `I'm in Main!` + }, + b = () => { + return `I'm in both!` + }, + A = B(`./1.js`), + C = () => { + return D(`div`, {}, [ + a(), + b(), + D(E, { + c: [], + key: `Test`, + p: {}, + x: A + }) + ]) + }; + +---=== /__mint__/1.js ===--- +import { createElement as B } from "./runtime.js"; + +import { b as c } from "./index.js"; + +export const + a = (b) => { + return `I'm ${b}!` + }, + A = () => { + return B(`div`, {}, [ + a(`async`), + c() + ]) + }; + +export default A; diff --git a/spec/compilers2/component_async_2 b/spec/compilers2/component_async_2 new file mode 100644 index 000000000..036beee5a --- /dev/null +++ b/spec/compilers2/component_async_2 @@ -0,0 +1,84 @@ +async component First { + fun render : Html { +
+ "First" +
+ } +} + +async component Second { + fun render : Html { +
+ + "Second" +
+ } +} + +component Main { + fun render : Html { +
+ + +
+ } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.js ===--- +import { + lazyComponent as F, + createElement as E, + lazy as B +} from "./runtime.js"; + +export const + A = B(`./1.js`), + C = B(`./2.js`), + D = () => { + return E(`div`, {}, [ + E(F, { + c: [], + key: `First`, + p: {}, + x: A + }), + E(F, { + c: [], + key: `Second`, + p: {}, + x: C + }) + ]) + }; + +---=== /__mint__/1.js ===--- +import { createElement as B } from "./runtime.js"; + +export const A = () => { + return B(`div`, {}, [`First`]) +}; + +export default A; + +---=== /__mint__/2.js ===--- +import { + lazyComponent as E, + createElement as D, + lazy as B +} from "./runtime.js"; + +export const + A = B(`./1.js`), + C = () => { + return D(`div`, {}, [ + D(E, { + c: [], + key: `First`, + p: {}, + x: A + }), + `Second` + ]) + }; + +export default C; diff --git a/spec/compilers2/component_async_3 b/spec/compilers2/component_async_3 new file mode 100644 index 000000000..05442c94a --- /dev/null +++ b/spec/compilers2/component_async_3 @@ -0,0 +1,99 @@ +module Test { + fun blah { + halb() + } + + fun halb() { + "" + } +} + +async component First { + fun render : Html { +
+ "First" + Test.blah() +
+ } +} + +async component Second { + fun render : Html { +
+ "Second" + Test.blah() +
+ } +} + +component Main { + fun render : Html { +
+ + + Test.blah() +
+ } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.js ===--- +import { + lazyComponent as F, + createElement as E, + lazy as B +} from "./runtime.js"; + +export const + a = () => { + return `` + }, + b = () => { + return a() + }, + A = B(`./1.js`), + C = B(`./2.js`), + D = () => { + return E(`div`, {}, [ + E(F, { + c: [], + key: `First`, + p: {}, + x: A + }), + E(F, { + c: [], + key: `Second`, + p: {}, + x: C + }), + b() + ]) + }; + +---=== /__mint__/1.js ===--- +import { createElement as B } from "./runtime.js"; + +import { b as a } from "./index.js"; + +export const A = () => { + return B(`div`, {}, [ + `First`, + a() + ]) +}; + +export default A; + +---=== /__mint__/2.js ===--- +import { createElement as B } from "./runtime.js"; + +import { b as a } from "./index.js"; + +export const A = () => { + return B(`div`, {}, [ + `Second`, + a() + ]) +}; + +export default A; diff --git a/spec/compilers2/component_async_4 b/spec/compilers2/component_async_4 new file mode 100644 index 000000000..dd1e1213d --- /dev/null +++ b/spec/compilers2/component_async_4 @@ -0,0 +1,90 @@ +component First { + property prop : String = "" + + fun render : Html { +
+ prop +
+ } +} + +component Content { + property fontSize : Number = 18 + + fun render : Html { +
+ "#{fontSize}px" +
+ } +} + +async component Test { + property test : String = "" + property test2 : String = "" + property test3 : String = "" + + fun render : Html { + + } +} + +component Main { + fun render : Html { +
+ + + +
+ } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.js ===--- +import { + lazyComponent as G, + createElement as B, + lazy as E +} from "./runtime.js"; + +export const + A = ({ + a = `` + }) => { + return B(`div`, {}, [a]) + }, + C = ({ + b = 18 + }) => { + return B(`div`, {}, [`${b}px`]) + }, + D = E(`./1.js`), + F = () => { + return B(`div`, {}, [ + B(A, { + a: `blah` + }), + B(C, {}), + B(G, { + c: [], + key: `Test`, + p: {}, + x: D + }) + ]) + }; + +---=== /__mint__/1.js ===--- +import { createElement as B } from "./runtime.js"; + +import { C } from "./index.js"; + +export const A = ({ + a = ``, + b = ``, + c = `` +}) => { + return B(C, { + b: 16 + }) +}; + +export default A; diff --git a/spec/compilers2/component_async_5 b/spec/compilers2/component_async_5 new file mode 100644 index 000000000..82c4d1ea9 --- /dev/null +++ b/spec/compilers2/component_async_5 @@ -0,0 +1,63 @@ +component First { + property test : String = "" + + fun render : String { + test + } +} + +async component Lesson { + property test : String = "" + + fun render : String { + test + } +} + +component Main { + fun render : Html { +
+ + +
+ } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.js ===--- +import { + lazyComponent as F, + createElement as E, + lazy as C +} from "./runtime.js"; + +export const + A = ({ + a = `` + }) => { + return a + }, + B = C(`./1.js`), + D = () => { + return E(`div`, {}, [ + E(A, { + a: `Blah` + }), + E(F, { + c: [], + key: `Lesson`, + p: { + a: `Hello` + }, + x: B + }) + ]) + }; + +---=== /__mint__/1.js ===--- +export const A = ({ + a = `` +}) => { + return a +}; + +export default A; diff --git a/spec/compilers2/component_children b/spec/compilers2/component_children new file mode 100644 index 000000000..16460f257 --- /dev/null +++ b/spec/compilers2/component_children @@ -0,0 +1,28 @@ +component Test { + property children : Array(Html) = [] + + fun render : Array(Html) { + children + } +} + +component Main { + fun render : Html { + "" + } +} +-------------------------------------------------------------------------------- +import { + createElement as C, + toArray as D +} from "./runtime.js"; + +export const + A = ({ + children: a = [] + }) => { + return a + }, + B = () => { + return C(A, {}, D(``)) + }; diff --git a/spec/compilers2/component_global b/spec/compilers2/component_global new file mode 100644 index 000000000..e78a0b59d --- /dev/null +++ b/spec/compilers2/component_global @@ -0,0 +1,45 @@ +global component Notifications { + state test : String = "" + + get value : String { + test + } + + fun notify (value : String) : String { + value + } + + fun render : Html { +
+ value +
+ } +} + +component Main { + fun render : Html { +
+ Notifications.notify("Hello") +
+ } +} +-------------------------------------------------------------------------------- +import { + createElement as B, + signal as D +} from "./runtime.js"; + +export const + A = () => { + return B(`div`, {}, [a()]) + }, + b = (c) => { + return c + }, + C = () => { + return B(`div`, {}, [b(`Hello`)]) + }, + d = D(``), + a = () => { + return d.value + }; diff --git a/spec/compilers2/component_instance_access b/spec/compilers2/component_instance_access new file mode 100644 index 000000000..71bc658c1 --- /dev/null +++ b/spec/compilers2/component_instance_access @@ -0,0 +1,83 @@ +type Maybe(value) { + Just(value) + Nothing +} + +component Instance { + get name : String { + "Instance" + } + + fun render : Html { +
+ } +} + +component Main { + fun handleClick : String { + case (instance) { + Just(component) => component.name + Nothing => "" + } + } + + fun render : Html { +
+ +
+ } +} +-------------------------------------------------------------------------------- +import { + patternVariable as K, + createElement as F, + pattern as J, + useMemo as E, + variant as B, + setRef as L, + useRef as H, + match as I +} from "./runtime.js"; + +export const + A = B(1), + C = B(0), + D = ({ + _ + }) => { + const a = () => { + return `Instance` + }; + const b = E(() => { + return { + a + } + }, []); + (_ ? _(b) : null); + return F(`div`, {}) + }, + G = () => { + const + c = H(new C()), + d = () => { + return I(c.current, [ + [ + J(A, [K]), + (e) => { + return e.a() + } + ], + [ + J(C, []), + () => { + return `` + } + ] + ]) + }; + return F(`div`, { + "onClick": d + }, [F(D, { + _: L(c, A) + })]) + }; diff --git a/spec/compilers2/component_instance_access_ref b/spec/compilers2/component_instance_access_ref new file mode 100644 index 000000000..187c08086 --- /dev/null +++ b/spec/compilers2/component_instance_access_ref @@ -0,0 +1,79 @@ +type Maybe(value) { + Just(value) + Nothing +} + +component Instance { + fun render : Html { +
+ } +} + +component Main { + fun handleClick { + case (instance) { + Maybe.Just(component) => component.base + Maybe.Nothing => Maybe.Nothing + } + } + + fun render : Html { +
+ +
+ } +} +-------------------------------------------------------------------------------- +import { + patternVariable as L, + createElement as G, + pattern as K, + useMemo as F, + variant as B, + setRef as H, + useRef as E, + match as J +} from "./runtime.js"; + +export const + A = B(1), + C = B(0), + D = ({ + _ + }) => { + const a = E(new C()); + const b = F(() => { + return { + a + } + }, []); + (_ ? _(b) : null); + return G(`div`, { + ref: H(a, A) + }) + }, + I = () => { + const + c = E(new C()), + d = () => { + return J(c.current, [ + [ + K(A, [L]), + (e) => { + return e.a.current + } + ], + [ + K(C, []), + () => { + return new C() + } + ] + ]) + }; + return G(`div`, { + "onClick": d + }, [G(D, { + _: H(c, A) + })]) + }; diff --git a/spec/compilers2/component_namespaced b/spec/compilers2/component_namespaced new file mode 100644 index 000000000..450ad76d7 --- /dev/null +++ b/spec/compilers2/component_namespaced @@ -0,0 +1,21 @@ +component Ui.Dropdown { + fun render : String { + "test" + } +} + +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +import { createElement as C } from "./runtime.js"; + +export const + A = () => { + return `test` + }, + B = () => { + return C(A, {}) + }; diff --git a/spec/compilers2/component_namespaced_with_style b/spec/compilers2/component_namespaced_with_style new file mode 100644 index 000000000..7c36f4e5e --- /dev/null +++ b/spec/compilers2/component_namespaced_with_style @@ -0,0 +1,35 @@ +component Ui.Dropdown { + style base { + background: red; + } + + fun render : Html { + + "test" + + } +} + +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Ui·Dropdown_base { + background: red; +} + +---=== /__mint__/index.js ===--- +import { createElement as B } from "./runtime.js"; + +export const + A = () => { + return B(`div`, { + className: `Ui·Dropdown_base` + }, [`test`]) + }, + C = () => { + return B(A, {}) + }; diff --git a/spec/compilers2/component_readonly b/spec/compilers2/component_readonly new file mode 100644 index 000000000..536a5716d --- /dev/null +++ b/spec/compilers2/component_readonly @@ -0,0 +1,27 @@ +component Test { + property readonly : Bool = false + + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const + A = ({ + a = false + }) => { + return B(`div`, {}) + }, + C = () => { + return B(A, { + a: true + }) + }; diff --git a/spec/compilers2/component_with_provider b/spec/compilers2/component_with_provider new file mode 100644 index 000000000..d3c75e115 --- /dev/null +++ b/spec/compilers2/component_with_provider @@ -0,0 +1,50 @@ +type MouseProvider.Data { + moves : Function(Position, Void), + ups : Function(Position, Void) +} + +provider MouseProvider : MouseProvider.Data { + fun update : Void { + void + } +} + +component Main { + use MouseProvider { + moves: (data : Position) : Void { void }, + ups: (data : Position) : Void { void } + } when { + false + } + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +import { + createProvider as B, + createElement as E, + useId as D +} from "./runtime.js"; + +export const + a = new Map(), + A = B(a, () => { + return null + }), + C = () => { + const b = D(); + A(b, () => { + return (false ? { + moves: (c) => { + return null + }, + ups: (d) => { + return null + } + } : null) + }); + return E(`div`, {}) + }; + diff --git a/spec/compilers2/component_with_provider_and_lifecycle_functions b/spec/compilers2/component_with_provider_and_lifecycle_functions new file mode 100644 index 000000000..78184033a --- /dev/null +++ b/spec/compilers2/component_with_provider_and_lifecycle_functions @@ -0,0 +1,74 @@ +type MouseProvider.Data { + moves : Function(Position, Void), + ups : Function(Position, Void) +} + +provider MouseProvider : MouseProvider.Data { + fun update : Void { + void + } +} + +component Main { + use MouseProvider { + moves: (data : Position) : Void { void }, + ups: (data : Position) : Void { void } + } when { + false + } + + fun componentWillUnmount : Void { + void + } + + fun componentDidUpdate : Void { + void + } + + fun componentDidMount : Void { + void + } + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +import { + createProvider as B, + createElement as G, + useDidUpdate as F, + useEffect as E, + useId as D +} from "./runtime.js"; + +export const + a = new Map(), + A = B(a, () => { + return null + }), + C = () => { + const b = D(); + E(() => { + (() => { + return null + })(); + return () => { + return null + } + }, []); + F(() => { + return null + }); + A(b, () => { + return (false ? { + moves: (c) => { + return null + }, + ups: (d) => { + return null + } + } : null) + }); + return G(`div`, {}) + }; diff --git a/spec/compilers2/component_with_provider_and_store b/spec/compilers2/component_with_provider_and_store new file mode 100644 index 000000000..75cfa0f77 --- /dev/null +++ b/spec/compilers2/component_with_provider_and_store @@ -0,0 +1,64 @@ +type MouseProvider.Data { + moves : Function(Position, Void), + ups : Function(Position, Void) +} + +provider MouseProvider : MouseProvider.Data { + fun update : Void { + void + } +} + +store Blah { + state test : String = "" + + fun x : String { + "hello" + } +} + +component Main { + use MouseProvider { + moves: (data : Position) : Void { void }, + ups: (data : Position) : Void { void } + } when { + false + } + + connect Blah exposing { test, x } + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +import { + createProvider as C, + createElement as F, + signal as A, + useId as E +} from "./runtime.js"; + +export const + a = new Map(), + b = () => { + return `hello` + }, + c = A(``), + B = C(a, () => { + return null + }), + D = () => { + const d = E(); + B(d, () => { + return (false ? { + moves: (e) => { + return null + }, + ups: (f) => { + return null + } + } : null) + }); + return F(`div`, {}) + }; diff --git a/spec/compilers2/constant_component b/spec/compilers2/constant_component new file mode 100644 index 000000000..22be68c2f --- /dev/null +++ b/spec/compilers2/constant_component @@ -0,0 +1,12 @@ +component Main { + const NAME = "ASD" + + fun render : String { + NAME + } +} +-------------------------------------------------------------------------------- +export const A = () => { + const a = `ASD`; + return a +}; diff --git a/spec/compilers2/constant_global_component b/spec/compilers2/constant_global_component new file mode 100644 index 000000000..2f286b541 --- /dev/null +++ b/spec/compilers2/constant_global_component @@ -0,0 +1,26 @@ +global component Test { + const NAME = "ASD" + + fun render : String { + NAME + } +} + +component Main { + fun render : Html { +
+ Test.NAME +
+ } +} +-------------------------------------------------------------------------------- +import { createElement as C } from "./runtime.js"; + +export const + A = () => { + return a + }, + a = `ASD`, + B = () => { + return C(`div`, {}, [a]) + }; diff --git a/spec/compilers2/constant_module b/spec/compilers2/constant_module new file mode 100644 index 000000000..2957d19db --- /dev/null +++ b/spec/compilers2/constant_module @@ -0,0 +1,20 @@ +module Test { + const NAME = "ASD" +} + +component Main { + fun render : Html { +
+ Test.NAME +
+ } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const + a = `ASD`, + A = () => { + return B(`div`, {}, [a]) + }; + diff --git a/spec/compilers2/constant_store b/spec/compilers2/constant_store new file mode 100644 index 000000000..c0dcfedc5 --- /dev/null +++ b/spec/compilers2/constant_store @@ -0,0 +1,20 @@ +store Test { + const NAME = "ASD" +} + +component Main { + fun render : Html { +
+ Test.NAME +
+ } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const + a = `ASD`, + A = () => { + return B(`div`, {}, [a]) + }; + diff --git a/spec/compilers2/constant_store_exposed b/spec/compilers2/constant_store_exposed new file mode 100644 index 000000000..983dbddec --- /dev/null +++ b/spec/compilers2/constant_store_exposed @@ -0,0 +1,21 @@ +store Test { + const NAME = "ASD" +} + +component Main { + connect Test exposing { NAME } + + fun render : Html { +
+ NAME +
+ } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const + a = `ASD`, + A = () => { + return B(`div`, {}, [a]) + }; diff --git a/spec/compilers2/css_definition b/spec/compilers2/css_definition new file mode 100644 index 000000000..bd72fb6bf --- /dev/null +++ b/spec/compilers2/css_definition @@ -0,0 +1,41 @@ +component Main { + style test { + margin: #{margin}px 0px; + } + + get margin : Number { + 10 + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_test { + margin: var(--a-a); +} + +---=== /__mint__/index.js ===--- +import { + createElement as B, + style as C +} from "./runtime.js"; + +export const A = () => { + const + a = () => { + return 10 + }, + b = () => { + const _ = { + [`--a-a`]: a() + `px 0px` + }; + return _ + }; + return B(`div`, { + className: `Main_test`, + style: C([b()]) + }) +}; diff --git a/spec/compilers2/css_font_face b/spec/compilers2/css_font_face new file mode 100644 index 000000000..0d40aa332 --- /dev/null +++ b/spec/compilers2/css_font_face @@ -0,0 +1,39 @@ +component Main { + style test { + @font-face { + src: url(sansation_light.woff); + font-family: myFirstFont; + } + + @font-face { + src: url(sansation_light2.woff); + font-family: myFirstFont; + font-weight: bold; + } + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +@font-face { + src: url(sansation_light.woff); + font-family: myFirstFont; +} + +@font-face { + src: url(sansation_light2.woff); + font-family: myFirstFont; + font-weight: bold; +} + +---=== /__mint__/index.js ===--- +import { createElement as B } from "./runtime.js"; + +export const A = () => { + return B(`div`, { + className: `Main_test` + }) +}; diff --git a/spec/compilers2/css_font_face_with_quotes b/spec/compilers2/css_font_face_with_quotes new file mode 100644 index 000000000..379a60465 --- /dev/null +++ b/spec/compilers2/css_font_face_with_quotes @@ -0,0 +1,33 @@ +component Main { + style test { + @font-face { + src: url(sansation_light.woff); + font-family: myFirstFont; + } + + font-family: "myFirstFont"; + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_test { + font-family: "myFirstFont"; +} + +@font-face { + src: url(sansation_light.woff); + font-family: myFirstFont; +} + +---=== /__mint__/index.js ===--- +import { createElement as B } from "./runtime.js"; + +export const A = () => { + return B(`div`, { + className: `Main_test` + }) +}; diff --git a/spec/compilers2/css_keyframes b/spec/compilers2/css_keyframes new file mode 100644 index 000000000..eb807256d --- /dev/null +++ b/spec/compilers2/css_keyframes @@ -0,0 +1,72 @@ +component Main { + state opacity : Number = 1 + + style test { + @keyframes animation { + from { + opacity: 0; + } + + to { + opacity: #{opacity}; + } + } + + @keyframes animation { + from { + opacity: 0; + } + + to { + opacity: 1; + } + } + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +@keyframes animation { + from { + opacity: 0; + } + + to { + opacity: var(--a-a); + } +} + +@keyframes animation { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +---=== /__mint__/index.js ===--- +import { + createElement as C, + useSignal as B, + style as D +} from "./runtime.js"; + +export const A = () => { + const + a = B(1), + b = () => { + const _ = { + [`--a-a`]: a.value + }; + return _ + }; + return C(`div`, { + className: `Main_test`, + style: D([b()]) + }) +}; diff --git a/spec/compilers2/css_media b/spec/compilers2/css_media new file mode 100644 index 000000000..105687c2e --- /dev/null +++ b/spec/compilers2/css_media @@ -0,0 +1,54 @@ +component Main { + style test { + div { + color: #{color}; + } + + @media (screen) { + color: #{color}; + } + } + + get color : String { + "blue" + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_test div { + color: var(--a-a); +} + +@media (screen) { + .Main_test { + color: var(--b-a); + } +} + +---=== /__mint__/index.js ===--- +import { + createElement as B, + style as C +} from "./runtime.js"; + +export const A = () => { + const + a = () => { + return `blue` + }, + b = () => { + const _ = { + [`--a-a`]: a(), + [`--b-a`]: a() + }; + return _ + }; + return B(`div`, { + className: `Main_test`, + style: C([b()]) + }) +}; diff --git a/spec/compilers2/css_media_with_if b/spec/compilers2/css_media_with_if new file mode 100644 index 000000000..a309f821a --- /dev/null +++ b/spec/compilers2/css_media_with_if @@ -0,0 +1,46 @@ +component Main { + style test { + color: yellow; + + @media (max-width: 300px) { + if (true) { + color: red; + } + } + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_test { + color: yellow; +} + +@media (max-width: 300px) { + .Main_test { + color: var(--a-a); + } +} + +---=== /__mint__/index.js ===--- +import { + createElement as B, + style as C +} from "./runtime.js"; + +export const A = () => { + const a = () => { + const _ = {}; + (true ? Object.assign(_, { + [`--a-a`]: `red` + }) : null); + return _ + }; + return B(`div`, { + className: `Main_test`, + style: C([a()]) + }) +}; diff --git a/spec/compilers2/css_selector b/spec/compilers2/css_selector new file mode 100644 index 000000000..cb4e1cd3e --- /dev/null +++ b/spec/compilers2/css_selector @@ -0,0 +1,51 @@ +component Main { + style test { + div { + color: #{color}; + } + + &:focus { + color: red; + } + } + + get color : String { + "blue" + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_test div { + color: var(--a-a); +} + +.Main_test:focus { + color: red; +} + +---=== /__mint__/index.js ===--- +import { + createElement as B, + style as C +} from "./runtime.js"; + +export const A = () => { + const + a = () => { + return `blue` + }, + b = () => { + const _ = { + [`--a-a`]: a() + }; + return _ + }; + return B(`div`, { + className: `Main_test`, + style: C([b()]) + }) +}; diff --git a/spec/compilers2/css_selector_multiple b/spec/compilers2/css_selector_multiple new file mode 100644 index 000000000..c56eeb3e6 --- /dev/null +++ b/spec/compilers2/css_selector_multiple @@ -0,0 +1,56 @@ +component Main { + style test { + div { + color: #{color}; + } + + &:focus, + &:hover { + color: red; + } + } + + get color : String { + "blue" + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_test div { + color: var(--a-a); +} + +.Main_test:focus { + color: red; +} + +.Main_test:hover { + color: red; +} + +---=== /__mint__/index.js ===--- +import { + createElement as B, + style as C +} from "./runtime.js"; + +export const A = () => { + const + a = () => { + return `blue` + }, + b = () => { + const _ = { + [`--a-a`]: a() + }; + return _ + }; + return B(`div`, { + className: `Main_test`, + style: C([b()]) + }) +}; diff --git a/spec/compilers2/css_string b/spec/compilers2/css_string new file mode 100644 index 000000000..18848fa9c --- /dev/null +++ b/spec/compilers2/css_string @@ -0,0 +1,42 @@ +component Main { + state name : String = "Joe" + + style unicode { + span::after { + content: "Hi" blah #{name} "Here is some content; Thanks #{name}"; + } + } + + fun render { + + +
+ } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_unicode span::after { + content: var(--a-a); +} + +---=== /__mint__/index.js ===--- +import { + createElement as C, + useSignal as B, + style as D +} from "./runtime.js"; + +export const A = () => { + const + a = B(`Joe`), + b = () => { + const _ = { + [`--a-a`]: `"Hi"` + ` blah ` + a.value + ` ` + `"Here is some content; Thanks ${a.value}"` + }; + return _ + }; + return C(`div`, { + className: `Main_unicode`, + style: D([b()]) + }, [C(`span`, {})]) +}; diff --git a/spec/compilers2/css_supports b/spec/compilers2/css_supports new file mode 100644 index 000000000..18c78c620 --- /dev/null +++ b/spec/compilers2/css_supports @@ -0,0 +1,42 @@ +component Main { + state color : String = "blue" + + style test { + @supports (screen) { + color: #{color}; + } + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +@supports (screen) { + .Main_test { + color: var(--a-a); + } +} + +---=== /__mint__/index.js ===--- +import { + createElement as C, + useSignal as B, + style as D +} from "./runtime.js"; + +export const A = () => { + const + a = B(`blue`), + b = () => { + const _ = { + [`--a-a`]: a.value + }; + return _ + }; + return C(`div`, { + className: `Main_test`, + style: D([b()]) + }) +}; diff --git a/spec/compilers2/css_with_ands b/spec/compilers2/css_with_ands new file mode 100644 index 000000000..c7ed74e87 --- /dev/null +++ b/spec/compilers2/css_with_ands @@ -0,0 +1,41 @@ +component Main { + style test { + &:focus { + color: red; + } + + &[someattribute] { + color: red; + } + + &.someclass { + color: red; + } + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_test:focus { + color: red; +} + +.Main_test[someattribute] { + color: red; +} + +.Main_test.someclass { + color: red; +} + +---=== /__mint__/index.js ===--- +import { createElement as B } from "./runtime.js"; + +export const A = () => { + return B(`div`, { + className: `Main_test` + }) +}; diff --git a/spec/compilers2/css_with_arguments b/spec/compilers2/css_with_arguments new file mode 100644 index 000000000..da0f4deec --- /dev/null +++ b/spec/compilers2/css_with_arguments @@ -0,0 +1,33 @@ +component Main { + style test(color : String) { + color: #{color}; + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_test { + color: var(--a-a); +} + +---=== /__mint__/index.js ===--- +import { + createElement as B, + style as C +} from "./runtime.js"; + +export const A = () => { + const a = (b) => { + const _ = { + [`--a-a`]: b + }; + return _ + }; + return B(`div`, { + className: `Main_test`, + style: C([a(`red`)]) + }) +}; diff --git a/spec/compilers2/css_with_case b/spec/compilers2/css_with_case new file mode 100644 index 000000000..b3154b5dd --- /dev/null +++ b/spec/compilers2/css_with_case @@ -0,0 +1,58 @@ +component Main { + style test { + color: yellow; + + case ("a") { + "a" => + color: red; + + => + color: blue; + } + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_test { + color: var(--a-a, yellow); +} + +---=== /__mint__/index.js ===--- +import { + createElement as C, + style as D, + match as B +} from "./runtime.js"; + +export const A = () => { + const a = () => { + const _ = {}; + B(`a`, [ + [ + `a`, + () => { + return Object.assign(_, { + [`--a-a`]: `red` + }) + } + ], + [ + null, + () => { + return Object.assign(_, { + [`--a-a`]: `blue` + }) + } + ] + ]); + return _ + }; + return C(`div`, { + className: `Main_test`, + style: D([a()]) + }) +}; diff --git a/spec/compilers2/css_with_else_if b/spec/compilers2/css_with_else_if new file mode 100644 index 000000000..2579ad24d --- /dev/null +++ b/spec/compilers2/css_with_else_if @@ -0,0 +1,47 @@ +component Main { + style base(color : String) { + height: 20px; + + if (color == "red") { + background: red; + } else if (color == "blue") { + background: blue; + } + } + + + fun render : Html { +
+ +
+ } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_base { + height: 20px; + background: var(--a-a); +} + +---=== /__mint__/index.js ===--- +import { + createElement as C, + compare as B, + style as D +} from "./runtime.js"; + +export const A = () => { + const a = (b) => { + const _ = {}; + (B(b, `red`) ? Object.assign(_, { + [`--a-a`]: `red` + }) : (B(b, `blue`) ? Object.assign(_, { + [`--a-a`]: `blue` + }) : null)); + return _ + }; + return C(`div`, {}, [C(`div`, { + className: `Main_base`, + style: D([a(`blue`)]) + })]) +}; diff --git a/spec/compilers2/css_with_if b/spec/compilers2/css_with_if new file mode 100644 index 000000000..4ef9ba40c --- /dev/null +++ b/spec/compilers2/css_with_if @@ -0,0 +1,42 @@ +component Main { + style test { + color: yellow; + + if (true) { + color: red; + } else { + color: blue; + } + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_test { + color: var(--a-a, yellow); +} + +---=== /__mint__/index.js ===--- +import { + createElement as B, + style as C +} from "./runtime.js"; + +export const A = () => { + const a = () => { + const _ = {}; + (true ? Object.assign(_, { + [`--a-a`]: `red` + }) : Object.assign(_, { + [`--a-a`]: `blue` + })); + return _ + }; + return B(`div`, { + className: `Main_test`, + style: C([a()]) + }) +}; diff --git a/spec/compilers2/css_with_if_and_case b/spec/compilers2/css_with_if_and_case new file mode 100644 index 000000000..912338228 --- /dev/null +++ b/spec/compilers2/css_with_if_and_case @@ -0,0 +1,66 @@ +component Main { + style test { + color: yellow; + + case (true) { + true => color: yellow; + => color: cyan; + } + + if (true) { + color: red; + } else { + color: blue; + } + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_test { + color: var(--a-a, yellow); +} + +---=== /__mint__/index.js ===--- +import { + createElement as C, + style as D, + match as B +} from "./runtime.js"; + +export const A = () => { + const a = () => { + const _ = {}; + B(true, [ + [ + true, + () => { + return Object.assign(_, { + [`--a-a`]: `yellow` + }) + } + ], + [ + null, + () => { + return Object.assign(_, { + [`--a-a`]: `cyan` + }) + } + ] + ]); + (true ? Object.assign(_, { + [`--a-a`]: `red` + }) : Object.assign(_, { + [`--a-a`]: `blue` + })); + return _ + }; + return C(`div`, { + className: `Main_test`, + style: D([a()]) + }) +}; diff --git a/spec/compilers2/css_with_if_same_condition b/spec/compilers2/css_with_if_same_condition new file mode 100644 index 000000000..b470533b5 --- /dev/null +++ b/spec/compilers2/css_with_if_same_condition @@ -0,0 +1,59 @@ +component Main { + style test { + .tag { + if (true) { + color: red; + } else { + color: blue; + } + } + + .string { + if (true) { + color: yellow; + } else { + color: cyan; + } + } + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_test .tag { + color: var(--a-a); +} + +.Main_test .string { + color: var(--b-a); +} + +---=== /__mint__/index.js ===--- +import { + createElement as B, + style as C +} from "./runtime.js"; + +export const A = () => { + const a = () => { + const _ = {}; + (true ? Object.assign(_, { + [`--a-a`]: `red` + }) : Object.assign(_, { + [`--a-a`]: `blue` + })); + (true ? Object.assign(_, { + [`--b-a`]: `yellow` + }) : Object.assign(_, { + [`--b-a`]: `cyan` + })); + return _ + }; + return B(`div`, { + className: `Main_test`, + style: C([a()]) + }) +}; diff --git a/spec/compilers2/css_with_if_variables b/spec/compilers2/css_with_if_variables new file mode 100644 index 000000000..9420809b4 --- /dev/null +++ b/spec/compilers2/css_with_if_variables @@ -0,0 +1,52 @@ +store Application { + state isDarkMode : Bool = false +} + +component Main { + connect Application exposing { isDarkMode } + + style test { + if isDarkMode { + --color: red; + } else { + --color: blue; + } + + font-size: 18px; + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_test { + font-size: 18px; + --color: var(--a-a); +} + +---=== /__mint__/index.js ===--- +import { + createElement as C, + signal as A, + style as D +} from "./runtime.js"; + +export const + a = A(false), + B = () => { + const b = () => { + const _ = {}; + (a.value ? Object.assign(_, { + [`--a-a`]: `red` + }) : Object.assign(_, { + [`--a-a`]: `blue` + })); + return _ + }; + return C(`div`, { + className: `Main_test`, + style: D([b()]) + }) + }; diff --git a/spec/compilers2/css_with_if_with_interpolation b/spec/compilers2/css_with_if_with_interpolation new file mode 100644 index 000000000..54a2e3500 --- /dev/null +++ b/spec/compilers2/css_with_if_with_interpolation @@ -0,0 +1,42 @@ +component Main { + style test { + color: yellow; + + if (true) { + color: #{"red"}; + } else { + color: blue; + } + } + + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_test { + color: var(--a-a, yellow); +} + +---=== /__mint__/index.js ===--- +import { + createElement as B, + style as C +} from "./runtime.js"; + +export const A = () => { + const a = () => { + const _ = {}; + (true ? Object.assign(_, { + [`--a-a`]: `red` + }) : Object.assign(_, { + [`--a-a`]: `blue` + })); + return _ + }; + return B(`div`, { + className: `Main_test`, + style: C([a()]) + }) +}; diff --git a/spec/compilers2/dce_remove_component b/spec/compilers2/dce_remove_component new file mode 100644 index 000000000..bf8074864 --- /dev/null +++ b/spec/compilers2/dce_remove_component @@ -0,0 +1,6 @@ +component Test { + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- diff --git a/spec/compilers2/dce_remove_component_computed_property b/spec/compilers2/dce_remove_component_computed_property new file mode 100644 index 000000000..4313d58e8 --- /dev/null +++ b/spec/compilers2/dce_remove_component_computed_property @@ -0,0 +1,15 @@ +component Main { + get test : String { + "" + } + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const A = () => { + return B(`div`, {}) +}; diff --git a/spec/compilers2/dce_remove_component_function b/spec/compilers2/dce_remove_component_function new file mode 100644 index 000000000..b7e25d8a6 --- /dev/null +++ b/spec/compilers2/dce_remove_component_function @@ -0,0 +1,15 @@ +component Main { + fun test : String { + "" + } + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const A = () => { + return B(`div`, {}) +}; diff --git a/spec/compilers2/dce_remove_enum b/spec/compilers2/dce_remove_enum new file mode 100644 index 000000000..422202fea --- /dev/null +++ b/spec/compilers2/dce_remove_enum @@ -0,0 +1,6 @@ +type Test { + X + Y + Z +} +-------------------------------------------------------------------------------- diff --git a/spec/compilers2/dce_remove_module b/spec/compilers2/dce_remove_module new file mode 100644 index 000000000..ffd83a5f9 --- /dev/null +++ b/spec/compilers2/dce_remove_module @@ -0,0 +1,6 @@ +module Test { + fun test : String { + "" + } +} +-------------------------------------------------------------------------------- diff --git a/spec/compilers2/dce_remove_module_function b/spec/compilers2/dce_remove_module_function new file mode 100644 index 000000000..1660281fc --- /dev/null +++ b/spec/compilers2/dce_remove_module_function @@ -0,0 +1,23 @@ +module Test { + fun test : String { + "" + } + + fun x : String { + "" + } +} + +component Main { + fun render : String { + Test.test() + } +} +-------------------------------------------------------------------------------- +export const + a = () => { + return `` + }, + A = () => { + return a() + }; diff --git a/spec/compilers2/dce_remove_provider b/spec/compilers2/dce_remove_provider new file mode 100644 index 000000000..b4a62740e --- /dev/null +++ b/spec/compilers2/dce_remove_provider @@ -0,0 +1,10 @@ +type Subscription { + name : String +} + +provider MouseProvider : Subscription { + fun attach : Void { + void + } +} +-------------------------------------------------------------------------------- diff --git a/spec/compilers2/dce_remove_store b/spec/compilers2/dce_remove_store new file mode 100644 index 000000000..da746ab3e --- /dev/null +++ b/spec/compilers2/dce_remove_store @@ -0,0 +1,6 @@ +store Test { + fun test : String { + "" + } +} +-------------------------------------------------------------------------------- diff --git a/spec/compilers2/dce_style b/spec/compilers2/dce_style new file mode 100644 index 000000000..278f4f988 --- /dev/null +++ b/spec/compilers2/dce_style @@ -0,0 +1,15 @@ +component Main { + style test { + color: red; + } + + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const A = () => { + return B(`div`, {}) +}; diff --git a/spec/compilers2/decode b/spec/compilers2/decode new file mode 100644 index 000000000..027759c6f --- /dev/null +++ b/spec/compilers2/decode @@ -0,0 +1,42 @@ +type Result(error, value) { + Err(error) + Ok(value) +} + +type X.Y { + blah : String +} + +type X { + name : String, + y: X.Y +} + +component Main { + fun render : String { + decode `null` as Object as X + + "" + } +} +-------------------------------------------------------------------------------- +import { + decodeString as E, + decoder as D, + variant as B +} from "./runtime.js"; + +export const + A = B(1), + C = B(1), + a = D({ + blah: E(C, A) + }, C, A), + b = D({ + name: E(C, A), + y: a + }, C, A), + F = () => { + b((null)); + return `` + }; diff --git a/spec/compilers2/decode_function b/spec/compilers2/decode_function new file mode 100644 index 000000000..824734bac --- /dev/null +++ b/spec/compilers2/decode_function @@ -0,0 +1,42 @@ +type Result(error, value) { + Err(error) + Ok(value) +} + +type X.Y { + blah : String +} + +type X { + name : String, + y: X.Y +} + +component Main { + fun render : String { + (decode as X)(`null`) + + "" + } +} +-------------------------------------------------------------------------------- +import { + decodeString as E, + decoder as D, + variant as B +} from "./runtime.js"; + +export const + A = B(1), + C = B(1), + a = D({ + blah: E(C, A) + }, C, A), + b = D({ + name: E(C, A), + y: a + }, C, A), + F = () => { + (b)((null)); + return `` + }; diff --git a/spec/compilers2/decode_map b/spec/compilers2/decode_map new file mode 100644 index 000000000..5b42bd6e9 --- /dev/null +++ b/spec/compilers2/decode_map @@ -0,0 +1,26 @@ +type Result(error, value) { + Err(error) + Ok(value) +} + +component Main { + fun render : String { + decode (`[]`) as Map(String, Number) + + "" + } +} +-------------------------------------------------------------------------------- +import { + decodeNumber as F, + decodeMap as E, + variant as B +} from "./runtime.js"; + +export const + A = B(1), + C = B(1), + D = () => { + E(F(C, A), C, A)((([]))); + return `` + }; diff --git a/spec/compilers2/decode_tuple b/spec/compilers2/decode_tuple new file mode 100644 index 000000000..ec12d75e8 --- /dev/null +++ b/spec/compilers2/decode_tuple @@ -0,0 +1,31 @@ +type Result(error, value) { + Err(error) + Ok(value) +} + +component Main { + fun render : String { + decode (`[]`) as Tuple(String, Number, String) + + "" + } +} +-------------------------------------------------------------------------------- +import { + decodeNumber as G, + decodeString as F, + decodeTuple as E, + variant as B +} from "./runtime.js"; + +export const + A = B(1), + C = B(1), + D = () => { + E([ + F(C, A), + G(C, A), + F(C, A) + ], C, A)((([]))); + return `` + }; diff --git a/spec/compilers2/decoder b/spec/compilers2/decoder new file mode 100644 index 000000000..b92ae10e7 --- /dev/null +++ b/spec/compilers2/decoder @@ -0,0 +1,66 @@ +type Result(error, value) { + Err(error) + Ok(value) +} + +type Maybe(a) { + Just(a) + Nothing +} + +type Y { + size : Number using "SIIIZEEE" +} + +type X { + maybe : Maybe(String), + array : Array(String), + string : String, + number : Number, + bool : Bool, + time : Time, + y : Y +} + +component Main { + fun render : String { + decode `` as Object as X + "" + } +} +-------------------------------------------------------------------------------- +import { + decodeBoolean as K, + decodeString as I, + decodeNumber as G, + decodeArray as J, + decodeMaybe as H, + decodeTime as L, + decoder as F, + variant as B +} from "./runtime.js"; + +export const + A = B(1), + C = B(0), + D = B(1), + E = B(1), + a = F({ + size: [ + G(E, D), + "SIIIZEEE" + ] + }, E, D), + b = F({ + maybe: H(I(E, D), E, D, A, C), + array: J(I(E, D), E, D), + string: I(E, D), + number: G(E, D), + bool: K(E, D), + time: L(E, D), + y: a + }, E, D), + M = () => { + b(undefined); + return `` + }; diff --git a/spec/compilers2/defer b/spec/compilers2/defer new file mode 100644 index 000000000..a82b625c9 --- /dev/null +++ b/spec/compilers2/defer @@ -0,0 +1,60 @@ +module Test { + const TEST = defer { test() + B.c() } + + fun test { + "Hello!" + } +} + +module B { + fun c { + "Blah" + } +} + +component Main { + fun componentDidMount : Promise(String) { + let a = await Test.TEST + + a + } + + fun render : Html { +
+ B.c() +
+ } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.js ===--- +import { + createElement as D, + useEffect as B, + load as C +} from "./runtime.js"; + +export const + a = () => { + return `Blah` + }, + b = `./1.js`, + A = () => { + B(() => { + (async () => { + const c = await C(b); + return c + })() + }, []); + return D(`div`, {}, [a()]) + }; + +---=== /__mint__/1.js ===--- +import { a as c } from "./index.js"; + +export const + a = () => { + return `Hello!` + }, + b = a() + c(); + +export default b; diff --git a/spec/compilers2/defer_2 b/spec/compilers2/defer_2 new file mode 100644 index 000000000..c9acd434e --- /dev/null +++ b/spec/compilers2/defer_2 @@ -0,0 +1,52 @@ +module Data { + const ITEMS = defer [ defer ITEM_1 ] + const ITEM_1 = "Hello" +} + +component Main { + fun componentDidMount : Promise(String) { + let [item] = await Data.ITEMS or return "" + await item + } + + fun render : Html { +
""
+ } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.js ===--- +import { + patternVariable as E, + createElement as F, + destructure as C, + useEffect as B, + load as D +} from "./runtime.js"; + +export const + a = `./1.js`, + A = () => { + B(() => { + (async () => { + const b = C(await D(a), [E]); + if (b === false) { + return `` + }; + const [c] = b; + return await D(c) + })() + }, []); + return F(`div`, {}, [``]) + }; + +---=== /__mint__/1.js ===--- +export const a = [`./2.js`]; + +export default a; + +---=== /__mint__/2.js ===--- +export const + a = `Hello`, + b = a; + +export default b; diff --git a/spec/compilers2/destructuring b/spec/compilers2/destructuring new file mode 100644 index 000000000..1d1d178f4 --- /dev/null +++ b/spec/compilers2/destructuring @@ -0,0 +1,59 @@ +type Test { + Item( + matchString : String, + content : String, + key : String) + None +} + +component Main { + fun render : String { + let item = + Test.Item( + matchString: "MATCHSTRING", + content: "CONTENT", + key: "KEY") + + case item { + Test.Item(content) => content + Test.None => "" + } + } +} +-------------------------------------------------------------------------------- +import { + patternVariable as I, + patternRecord as H, + newVariant as E, + pattern as G, + variant as B, + match as F +} from "./runtime.js"; + +export const + A = B([ + "matchString", + "content", + "key" + ]), + C = B(0), + D = () => { + const a = E(A)(`MATCHSTRING`, `CONTENT`, `KEY`); + return F(a, [ + [ + G(A, H([[ + `content`, + I + ]])), + (b) => { + return b + } + ], + [ + G(C, []), + () => { + return `` + } + ] + ]) + }; diff --git a/spec/compilers2/destructuring_constant b/spec/compilers2/destructuring_constant new file mode 100644 index 000000000..c9b0e2a38 --- /dev/null +++ b/spec/compilers2/destructuring_constant @@ -0,0 +1,33 @@ +module Html.Event { + const DOWN_ARROW = "Hello" +} + +component Main { + fun render : String { + case "" { + Html.Event.DOWN_ARROW => "a" + => "b" + } + } +} +-------------------------------------------------------------------------------- +import { match as B } from "./runtime.js"; + +export const + a = `Hello`, + A = () => { + return B(``, [ + [ + a, + () => { + return `a` + } + ], + [ + null, + () => { + return `b` + } + ] + ]) + }; diff --git a/spec/compilers2/destructuring_state b/spec/compilers2/destructuring_state new file mode 100644 index 000000000..be6d9ab08 --- /dev/null +++ b/spec/compilers2/destructuring_state @@ -0,0 +1,36 @@ +store Html.Event { + state downArrow = "Hello" +} + +component Main { + fun render : String { + case "" { + Html.Event.downArrow => "a" + => "b" + } + } +} +-------------------------------------------------------------------------------- +import { + signal as A, + match as C +} from "./runtime.js"; + +export const + a = A(`Hello`), + B = () => { + return C(``, [ + [ + a.value, + () => { + return `a` + } + ], + [ + null, + () => { + return `b` + } + ] + ]) + }; diff --git a/spec/compilers2/directives/asset b/spec/compilers2/directives/asset new file mode 100644 index 000000000..af918d403 --- /dev/null +++ b/spec/compilers2/directives/asset @@ -0,0 +1,15 @@ +component Main { + fun render : String { + @asset(../../fixtures/icon.svg) + } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.js ===--- +export const A = () => { + return `/__mint__/icon_c97b81630bc53286dadc8996727d348e.svg` +}; + +---=== /__mint__/icon_c97b81630bc53286dadc8996727d348e.svg ===--- + + + diff --git a/spec/compilers2/directives/documentation b/spec/compilers2/directives/documentation new file mode 100644 index 000000000..e0f781118 --- /dev/null +++ b/spec/compilers2/directives/documentation @@ -0,0 +1,12 @@ +component Main { + fun render : String { + @documentation(Main) + + "Hello There" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + {"description":null,"name":"Main","connects":[],"computed-properties":[],"properties":[],"functions":[{"type":"String","description":null,"name":"render","source":"fun render : String {\n @documentation(Main)\n\n \"Hello There\"\n}","arguments":[]}],"providers":[],"states":[]}; + return `Hello There` +}; diff --git a/spec/compilers2/directives/format b/spec/compilers2/directives/format new file mode 100644 index 000000000..9d06e114b --- /dev/null +++ b/spec/compilers2/directives/format @@ -0,0 +1,23 @@ +component Main { + fun render : String { + let {result, formatted} = + @format { + "HelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloH" \ + "Bello" + } + + result + formatted + } +} +-------------------------------------------------------------------------------- +export const A = () => { + const [ + a, + b + ] = [ + `HelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHBello`, + `"HelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloH" \\ +"Bello"` + ]; + return a + b +}; diff --git a/spec/compilers2/directives/highlight b/spec/compilers2/directives/highlight new file mode 100644 index 000000000..d84cc1219 --- /dev/null +++ b/spec/compilers2/directives/highlight @@ -0,0 +1,23 @@ +component Main { + fun render : Html { + @highlight { + "Test" + }[1] + } +} +-------------------------------------------------------------------------------- +import { + createElement as B, + fragment as C +} from "./runtime.js"; + +export const A = () => { + return [ + `Test`, + B(C, {}, [B("span", { + className: "line" + }, [B("span", { + className: "string" + }, [`"Test"`])])]) + ][1] +}; diff --git a/spec/compilers2/directives/highlight-file b/spec/compilers2/directives/highlight-file new file mode 100644 index 000000000..2d16a9615 --- /dev/null +++ b/spec/compilers2/directives/highlight-file @@ -0,0 +1,63 @@ +component Main { + fun render : Html { + @highlight-file(../../fixtures/Test.mint) + } +} +-------------------------------------------------------------------------------- +import { + createElement as B, + fragment as C +} from "./runtime.js"; + +export const A = () => { + return B(C, {}, [ + B("span", { + className: "line" + }, [ + B("span", { + className: "keyword" + }, [`component`]), + ` `, + B("span", { + className: "type" + }, [`Main`]), + ` { +` + ]), + B("span", { + className: "line" + }, [ + ` `, + B("span", { + className: "keyword" + }, [`fun`]), + ` render : `, + B("span", { + className: "type" + }, [`Html`]), + ` { +` + ]), + B("span", { + className: "line" + }, [ + ` <`, + B("span", { + className: "namespace" + }, [`div`]), + `> +` + ]), + B("span", { + className: "line" + }, [` } +`]), + B("span", { + className: "line" + }, [`}`]) + ]) +}; diff --git a/spec/compilers2/directives/inline b/spec/compilers2/directives/inline new file mode 100644 index 000000000..3cd4f244a --- /dev/null +++ b/spec/compilers2/directives/inline @@ -0,0 +1,10 @@ +component Main { + fun render : String { + @inline(../../fixtures/data.txt) + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return `Hello World! +` +}; diff --git a/spec/compilers2/directives/svg b/spec/compilers2/directives/svg new file mode 100644 index 000000000..b29598232 --- /dev/null +++ b/spec/compilers2/directives/svg @@ -0,0 +1,20 @@ +component Main { + fun render : Html { + @svg(../../fixtures/icon.svg) + } +} +-------------------------------------------------------------------------------- +import { createElement as A } from "./runtime.js"; + +export const + a = A(`svg`, { + dangerouslySetInnerHTML: { + __html: `` + }, + viewBox: `0 0 24 24`, + height: `24`, + width: `24` + }), + B = () => { + return a + }; diff --git a/spec/compilers2/encode b/spec/compilers2/encode new file mode 100644 index 000000000..8998765c2 --- /dev/null +++ b/spec/compilers2/encode @@ -0,0 +1,30 @@ +type Test { + name : String, + age : Number +} + +component Main { + fun render : String { + encode { name: "Hello", age: 20 } + + "" + } +} +-------------------------------------------------------------------------------- +import { + identity as B, + encoder as A +} from "./runtime.js"; + +export const + a = A({ + name: B, + age: B + }), + C = () => { + a({ + name: `Hello`, + age: 20 + }); + return `` + }; diff --git a/spec/compilers2/encode_nested b/spec/compilers2/encode_nested new file mode 100644 index 000000000..8ea677a55 --- /dev/null +++ b/spec/compilers2/encode_nested @@ -0,0 +1,39 @@ +type Test { + nested : Nested, + name : String +} + +type Nested { + name : String +} + +component Main { + fun render : String { + encode { name: "Hello", nested: { name: "Test" } } + + "" + } +} +-------------------------------------------------------------------------------- +import { + identity as B, + encoder as A +} from "./runtime.js"; + +export const + a = A({ + name: B + }), + b = A({ + nested: a, + name: B + }), + C = () => { + b({ + name: `Hello`, + nested: { + name: `Test` + } + }); + return `` + }; diff --git a/spec/compilers2/encode_no_record b/spec/compilers2/encode_no_record new file mode 100644 index 000000000..7433fbdbe --- /dev/null +++ b/spec/compilers2/encode_no_record @@ -0,0 +1,25 @@ +component Main { + fun render : String { + encode { name: "Hello", age: 20 } + + "" + } +} +-------------------------------------------------------------------------------- +import { + identity as B, + encoder as A +} from "./runtime.js"; + +export const + a = A({ + name: B, + age: B + }), + C = () => { + a({ + name: `Hello`, + age: 20 + }); + return `` + }; diff --git a/spec/compilers2/encode_with_mapping b/spec/compilers2/encode_with_mapping new file mode 100644 index 000000000..d864b193c --- /dev/null +++ b/spec/compilers2/encode_with_mapping @@ -0,0 +1,33 @@ +type Test { + name : String using "test_name", + age : Number +} + +component Main { + fun render : String { + encode { name: "Hello", age: 20 } + + "" + } +} +-------------------------------------------------------------------------------- +import { + identity as B, + encoder as A +} from "./runtime.js"; + +export const + a = A({ + name: [ + B, + "test_name" + ], + age: B + }), + C = () => { + a({ + name: `Hello`, + age: 20 + }); + return `` + }; diff --git a/spec/compilers2/encoder_and_decoder b/spec/compilers2/encoder_and_decoder new file mode 100644 index 000000000..0c9358616 --- /dev/null +++ b/spec/compilers2/encoder_and_decoder @@ -0,0 +1,47 @@ +type Result(error, value) { + Err(error) + Ok(value) +} + +type Test { + string : String, + number : Number, +} + +component Main { + fun render : String { + decode `` as Object as Test + encode { string: "String", number: 10 } + + "" + } +} +-------------------------------------------------------------------------------- +import { + decodeNumber as F, + decodeString as E, + identity as H, + encoder as G, + decoder as D, + variant as B +} from "./runtime.js"; + +export const + A = B(1), + C = B(1), + a = D({ + string: E(C, A), + number: F(C, A) + }, C, A), + b = G({ + string: H, + number: H + }), + I = () => { + a(undefined); + b({ + string: `String`, + number: 10 + }); + return `` + }; diff --git a/spec/compilers2/env b/spec/compilers2/env new file mode 100644 index 000000000..ed8ec9192 --- /dev/null +++ b/spec/compilers2/env @@ -0,0 +1,9 @@ +component Main { + fun render : String { + @TEST + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return `TRUE` +}; diff --git a/spec/compilers2/field b/spec/compilers2/field new file mode 100644 index 000000000..fa3afe1d4 --- /dev/null +++ b/spec/compilers2/field @@ -0,0 +1,25 @@ +type Test { + a : String, + b : Number +} + +component Main { + fun render : Html { + { + a: "Hello", + b: 0 + } + +
+ } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const A = () => { + { + a: `Hello`, + b: 0 + }; + return B(`div`, {}) +}; diff --git a/spec/compilers2/field_access b/spec/compilers2/field_access new file mode 100644 index 000000000..d71b54574 --- /dev/null +++ b/spec/compilers2/field_access @@ -0,0 +1,43 @@ +type X { + name : String +} + +module Array { + fun map (array : Array(a), method : Function(a, b)) : Array(b) { + `` + } +} + +component Main { + fun render : String { + [ + { + name: "Joe" + }, + { + name: "Doe" + } + ] + |> Array.map(.name(X)) + + "asd" + } +} +-------------------------------------------------------------------------------- +import { access as B } from "./runtime.js"; + +export const + a = (b, c) => { + return undefined + }, + A = () => { + a([ + { + name: `Joe` + }, + { + name: `Doe` + } + ], B(`name`)); + return `asd` + }; diff --git a/spec/compilers2/for b/spec/compilers2/for new file mode 100644 index 000000000..22d344709 --- /dev/null +++ b/spec/compilers2/for @@ -0,0 +1,27 @@ +component Main { + fun render : Array(Html) { + for (item of ["A", "B"]) { +
+ item +
+ } + } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const A = () => { + return (() => { + const _0 = []; + const _1 = [ + `A`, + `B` + ]; + let _i = -1; + for (let a of _1) { + _i++; + _0.push(B(`div`, {}, [a])) + }; + return _0 + })() +}; diff --git a/spec/compilers2/for_with_index b/spec/compilers2/for_with_index new file mode 100644 index 000000000..1b1e470ec --- /dev/null +++ b/spec/compilers2/for_with_index @@ -0,0 +1,37 @@ +component Main { + fun render : Array(Html) { + for (item, index of ["A", "B"]) { +
+ item +
+ } when { + index == 10 + } + } +} +-------------------------------------------------------------------------------- +import { + createElement as C, + compare as B +} from "./runtime.js"; + +export const A = () => { + return (() => { + const _0 = []; + const _1 = [ + `A`, + `B` + ]; + let _i = -1; + for (let a of _1) { + _i++; + const b = _i; + const _2 = B(b, 10); + if (!_2) { + continue + }; + _0.push(C(`div`, {}, [a])) + }; + return _0 + })() +}; diff --git a/spec/compilers2/for_with_index_2 b/spec/compilers2/for_with_index_2 new file mode 100644 index 000000000..3cb443082 --- /dev/null +++ b/spec/compilers2/for_with_index_2 @@ -0,0 +1,28 @@ +component Main { + fun render : Array(Html) { + for (item, index of ["A", "B"]) { +
+ item +
+ } + } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const A = () => { + return (() => { + const _0 = []; + const _1 = [ + `A`, + `B` + ]; + let _i = -1; + for (let a of _1) { + _i++; + const b = _i; + _0.push(B(`div`, {}, [a])) + }; + return _0 + })() +}; diff --git a/spec/compilers2/function b/spec/compilers2/function new file mode 100644 index 000000000..818cf7f9b --- /dev/null +++ b/spec/compilers2/function @@ -0,0 +1,19 @@ +component Main { + fun test : Bool { + true + } + + fun render : String { + test() + + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + const a = () => { + return true + }; + a(); + return `` +}; diff --git a/spec/compilers2/function_call_simple b/spec/compilers2/function_call_simple new file mode 100644 index 000000000..bd1275c9c --- /dev/null +++ b/spec/compilers2/function_call_simple @@ -0,0 +1,27 @@ +component Main { + fun a : String { + "test" + } + + fun test : String { + a() + } + + fun render : String { + test() + + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + const + a = () => { + return `test` + }, + b = () => { + return a() + }; + b(); + return `` +}; diff --git a/spec/compilers2/function_call_with_arguments b/spec/compilers2/function_call_with_arguments new file mode 100644 index 000000000..9188dc239 --- /dev/null +++ b/spec/compilers2/function_call_with_arguments @@ -0,0 +1,28 @@ +component Main { + fun call (a : String, b : Bool) : Bool { + b + } + + fun test : Bool { + call("Hello", true) + } + + fun render : String { + test() + + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + const + a = (b, c) => { + return c + }, + d = () => { + return a(`Hello`, true) + }; + d(); + return `` +}; + diff --git a/spec/compilers2/get b/spec/compilers2/get new file mode 100644 index 000000000..54aa99bc6 --- /dev/null +++ b/spec/compilers2/get @@ -0,0 +1,16 @@ +component Main { + get test : String { + "" + } + + fun render : String { + test + } +} +-------------------------------------------------------------------------------- +export const A = () => { + const a = () => { + return `` + }; + return a() +}; diff --git a/spec/compilers2/here_doc_markdown b/spec/compilers2/here_doc_markdown new file mode 100644 index 000000000..05f5b8b24 --- /dev/null +++ b/spec/compilers2/here_doc_markdown @@ -0,0 +1,21 @@ +component Main { + fun render : Html { + <<#MARKDOWN + ## Hello There + + WTF + MARKDOWN + } +} +-------------------------------------------------------------------------------- +import { + createElement as B, + fragment as C +} from "./runtime.js"; + +export const A = () => { + return B(C, {}, [ + B('h2', {}, [`Hello There`]), + B('p', {}, [`WTF`]) + ]) +}; diff --git a/spec/compilers2/here_doc_markdown_escape b/spec/compilers2/here_doc_markdown_escape new file mode 100644 index 000000000..630f7980c --- /dev/null +++ b/spec/compilers2/here_doc_markdown_escape @@ -0,0 +1,77 @@ +component Main { + fun render : Html { + <<#MARKDOWN(highlight) + \#{name} + ```mint + `Something` + "\#{name}" + "First line" \ + "Second line" \ + "Third line" + ``` + MARKDOWN + } +} +-------------------------------------------------------------------------------- +import { + createElement as B, + fragment as C +} from "./runtime.js"; + +export const A = () => { + return B(C, {}, [ + B('p', {}, [`#{name}`]), + B('pre', {}, [B('code', { + class: "language-mint" + }, [ + B('span', { + className: "line" + }, [`\`Something\` +`]), + B('span', { + className: "line" + }, [ + ``, + B('span', { + className: "string" + }, [`"#{`]), + B('span', { + className: "variable" + }, [`name`]), + B('span', { + className: "string" + }, [`}"`]), + ` +` + ]), + B('span', { + className: "line" + }, [ + ``, + B('span', { + className: "string" + }, [`"First line" \\`]), + ` +` + ]), + B('span', { + className: "line" + }, [ + ``, + B('span', { + className: "string" + }, [`"Second line" \\`]), + ` +` + ]), + B('span', { + className: "line" + }, [ + ``, + B('span', { + className: "string" + }, [`"Third line"`]) + ]) + ])]) + ]) +}; diff --git a/spec/compilers2/here_doc_markdown_in_markdown b/spec/compilers2/here_doc_markdown_in_markdown new file mode 100644 index 000000000..997d23f44 --- /dev/null +++ b/spec/compilers2/here_doc_markdown_in_markdown @@ -0,0 +1,84 @@ +component Main { + fun render : Html { + <<#MARKDOWN(highlight) + ~~~mint + <<#MD(highlight) + This is a paragraph. + + ```mint + module Mint { + // This will be syntax highlighted + } + ``` + MD + ~~~ + MARKDOWN + } +} +-------------------------------------------------------------------------------- +import { + createElement as B, + fragment as C +} from "./runtime.js"; + +export const A = () => { + return B(C, {}, [B('pre', {}, [B('code', { + class: "language-mint" + }, [ + B('span', { + className: "line" + }, [ + `<<#MD(`, + B('span', { + className: "keyword" + }, [`highlight`]), + `)`, + B('span', { + className: "string" + }, [``]) + ]), + B('span', { + className: "line" + }, [B('span', { + className: "string" + }, [`This is a paragraph.`])]), + B('span', { + className: "line" + }, [B('span', { + className: "string" + }, [``])]), + B('span', { + className: "line" + }, [B('span', { + className: "string" + }, [`\`\`\`mint`])]), + B('span', { + className: "line" + }, [B('span', { + className: "string" + }, [`module Mint {`])]), + B('span', { + className: "line" + }, [B('span', { + className: "string" + }, [` // This will be syntax highlighted`])]), + B('span', { + className: "line" + }, [B('span', { + className: "string" + }, [`}`])]), + B('span', { + className: "line" + }, [B('span', { + className: "string" + }, [`\`\`\``])]), + B('span', { + className: "line" + }, [ + B('span', { + className: "string" + }, [``]), + `MD` + ]) + ])])]) +}; diff --git a/spec/compilers2/here_doc_markdown_with_code_block b/spec/compilers2/here_doc_markdown_with_code_block new file mode 100644 index 000000000..def765347 --- /dev/null +++ b/spec/compilers2/here_doc_markdown_with_code_block @@ -0,0 +1,39 @@ +component Main { + fun render : Html { + <<#MARKDOWN(highlight) + Text + + ```mint + module Time {} + ``` + + Text + MARKDOWN + } +} +-------------------------------------------------------------------------------- +import { + createElement as B, + fragment as C +} from "./runtime.js"; + +export const A = () => { + return B(C, {}, [ + B('p', {}, [`Text`]), + B('pre', {}, [B('code', { + class: "language-mint" + }, [B('span', { + className: "line" + }, [ + B('span', { + className: "keyword" + }, [`module`]), + ` `, + B('span', { + className: "type" + }, [`Time`]), + ` {}` + ])])]), + B('p', {}, [`Text`]) + ]) +}; diff --git a/spec/compilers2/here_doc_markdown_with_code_block_multiline b/spec/compilers2/here_doc_markdown_with_code_block_multiline new file mode 100644 index 000000000..ae0a672b4 --- /dev/null +++ b/spec/compilers2/here_doc_markdown_with_code_block_multiline @@ -0,0 +1,65 @@ +component Main { + fun render : Html { + <<#MARKDOWN(highlight) + Text + + ```mint + module Time { + const NOW = "" + } + ``` + + Text + MARKDOWN + } +} +-------------------------------------------------------------------------------- +import { + createElement as B, + fragment as C +} from "./runtime.js"; + +export const A = () => { + return B(C, {}, [ + B('p', {}, [`Text`]), + B('pre', {}, [B('code', { + class: "language-mint" + }, [ + B('span', { + className: "line" + }, [ + B('span', { + className: "keyword" + }, [`module`]), + ` `, + B('span', { + className: "type" + }, [`Time`]), + ` { +` + ]), + B('span', { + className: "line" + }, [ + ` `, + B('span', { + className: "keyword" + }, [`const`]), + ` `, + B('span', { + className: "type" + }, [`NOW`]), + ` = `, + B('span', { + className: "string" + }, [`""`]), + ` +` + ]), + B('span', { + className: "line" + }, [`}`]) + ])]), + B('p', {}, [`Text`]) + ]) +}; diff --git a/spec/compilers2/here_doc_markdown_with_html_interpolation b/spec/compilers2/here_doc_markdown_with_html_interpolation new file mode 100644 index 000000000..3cac2344a --- /dev/null +++ b/spec/compilers2/here_doc_markdown_with_html_interpolation @@ -0,0 +1,23 @@ +component Main { + const HTML =
+ + fun render : Html { + <<#MARKDOWN + #{HTML} Some text... + MARKDOWN + } +} +-------------------------------------------------------------------------------- +import { + createElement as B, + fragment as C +} from "./runtime.js"; + +export const A = () => { + const a = B(`div`, {}); + return B(C, {}, [B('p', {}, [ + ``, + a, + ` Some text...` + ])]) +}; diff --git a/spec/compilers2/here_doc_markdown_with_inline_code b/spec/compilers2/here_doc_markdown_with_inline_code new file mode 100644 index 000000000..5d2835a49 --- /dev/null +++ b/spec/compilers2/here_doc_markdown_with_inline_code @@ -0,0 +1,20 @@ +component Main { + fun render : Html { + <<#MARKDOWN + * When open pressing `Esc` closes it. + MARKDOWN + } +} +-------------------------------------------------------------------------------- +import { + createElement as B, + fragment as C +} from "./runtime.js"; + +export const A = () => { + return B(C, {}, [B('ul', {}, [B('li', {}, [ + `When open pressing `, + B('code', {}, [`Esc`]), + ` closes it.` + ])])]) +}; diff --git a/spec/compilers2/here_doc_markdown_with_interpolation b/spec/compilers2/here_doc_markdown_with_interpolation new file mode 100644 index 000000000..25a697a3b --- /dev/null +++ b/spec/compilers2/here_doc_markdown_with_interpolation @@ -0,0 +1,29 @@ +component Main { + fun render : Html { + <<#MARKDOWN + ## Hello There + #{
"Hello"
} + World! + MARKDOWN + } +} +-------------------------------------------------------------------------------- +import { + createElement as B, + fragment as C +} from "./runtime.js"; + +export const A = () => { + return B(C, {}, [ + B('h2', {}, [`Hello There`]), + B('p', {}, [ + ``, + B(`div`, {}, [`Hello`]), + ``, + ` +`, + `World`, + `!` + ]) + ]) +}; diff --git a/spec/compilers2/here_doc_new_line_char b/spec/compilers2/here_doc_new_line_char new file mode 100644 index 000000000..b56de4e4e --- /dev/null +++ b/spec/compilers2/here_doc_new_line_char @@ -0,0 +1,11 @@ +component Main { + fun render : String { + <<~MINT + \n + MINT + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return `\\n` +}; diff --git a/spec/compilers2/here_doc_with_interpolation b/spec/compilers2/here_doc_with_interpolation new file mode 100644 index 000000000..96d8db68c --- /dev/null +++ b/spec/compilers2/here_doc_with_interpolation @@ -0,0 +1,17 @@ +component Main { + fun render : String { + <<-TEXT + Hello There! + #{"interpolation"} + This line should be indented by 2 spaces. + This line should be indented by 4 spaces. + TEXT + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return ` Hello There! + ${`interpolation`} + This line should be indented by 2 spaces. + This line should be indented by 4 spaces.` +}; diff --git a/spec/compilers2/here_doc_without_indentation b/spec/compilers2/here_doc_without_indentation new file mode 100644 index 000000000..52cc1dde9 --- /dev/null +++ b/spec/compilers2/here_doc_without_indentation @@ -0,0 +1,15 @@ +component Main { + fun render : String { + <<~TEXT + Hello There! + This line should be indented by 2 spaces. + This line should be indented by 4 spaces. + TEXT + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return `Hello There! + This line should be indented by 2 spaces. + This line should be indented by 4 spaces.` +}; diff --git a/spec/compilers2/html_attribute_class b/spec/compilers2/html_attribute_class new file mode 100644 index 000000000..7a7780962 --- /dev/null +++ b/spec/compilers2/html_attribute_class @@ -0,0 +1,14 @@ +component Main { + fun render : Html { +
+
+ } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const A = () => { + return B(`div`, { + className: `something` + }) +}; diff --git a/spec/compilers2/html_attribute_class_with_style b/spec/compilers2/html_attribute_class_with_style new file mode 100644 index 000000000..b0ffe2c6c --- /dev/null +++ b/spec/compilers2/html_attribute_class_with_style @@ -0,0 +1,24 @@ +component Main { + style base { + width: 100%; + } + + fun render : Html { + +
+ } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_base { + width: 100%; +} + +---=== /__mint__/index.js ===--- +import { createElement as B } from "./runtime.js"; + +export const A = () => { + return B(`div`, { + className: `something` + ` Main_base` + }) +}; diff --git a/spec/compilers2/html_attribute_html_fragment b/spec/compilers2/html_attribute_html_fragment new file mode 100644 index 000000000..cbc9584a8 --- /dev/null +++ b/spec/compilers2/html_attribute_html_fragment @@ -0,0 +1,27 @@ +component Thing { + property things : Html = <> + + fun render : Html { +
+ } +} + +component Main { + fun render { + "x"/> + } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const + A = ({ + a = null + }) => { + return B(`div`, {}) + }, + C = () => { + return B(A, { + a: `x` + }) + }; diff --git a/spec/compilers2/html_attribute_readonly b/spec/compilers2/html_attribute_readonly new file mode 100644 index 000000000..e2ec4c2ef --- /dev/null +++ b/spec/compilers2/html_attribute_readonly @@ -0,0 +1,13 @@ +component Main { + fun render : Html { +
+
+ } +} +--------------------------------------------------------------------------------import { createElement as B } from "./runtime.js"; + +export const A = () => { + return B(`div`, { + readOnly: true + }) +}; diff --git a/spec/compilers2/html_attribute_ref b/spec/compilers2/html_attribute_ref new file mode 100644 index 000000000..4569c3e4e --- /dev/null +++ b/spec/compilers2/html_attribute_ref @@ -0,0 +1,29 @@ +type Maybe(value) { + Just(value) + Nothing +} + +component Main { + fun render : Html { +
+
+ } +} +-------------------------------------------------------------------------------- +import { + createElement as F, + variant as B, + setRef as G, + useRef as E +} from "./runtime.js"; + +export const + A = B(1), + C = B(0), + D = () => { + const a = E(new C()); + return F(`div`, { + ref: G(a, A) + }) + }; + diff --git a/spec/compilers2/html_attribute_simple b/spec/compilers2/html_attribute_simple new file mode 100644 index 000000000..0f80d1280 --- /dev/null +++ b/spec/compilers2/html_attribute_simple @@ -0,0 +1,14 @@ +component Main { + fun render : Html { +
+
+ } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const A = () => { + return B(`div`, { + "title": `Hello` + }) +}; diff --git a/spec/compilers2/html_attribute_with_expression b/spec/compilers2/html_attribute_with_expression new file mode 100644 index 000000000..5bad2b743 --- /dev/null +++ b/spec/compilers2/html_attribute_with_expression @@ -0,0 +1,14 @@ +component Main { + fun render : Html { +
+
+ } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const A = () => { + return B(`div`, { + "title": `Hello ` + `there!` + }) +}; diff --git a/spec/compilers2/html_component b/spec/compilers2/html_component new file mode 100644 index 000000000..eebf41252 --- /dev/null +++ b/spec/compilers2/html_component @@ -0,0 +1,21 @@ +component Test { + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const + A = () => { + return B(`div`, {}) + }, + C = () => { + return B(A, {}) + }; diff --git a/spec/compilers2/html_fragment b/spec/compilers2/html_fragment new file mode 100644 index 000000000..ccf06589f --- /dev/null +++ b/spec/compilers2/html_fragment @@ -0,0 +1,22 @@ +component Main { + fun render : Html { +
+ <> + "A" + "B" + +
+ } +} +-------------------------------------------------------------------------------- +import { + createElement as B, + fragment as C +} from "./runtime.js"; + +export const A = () => { + return B(`div`, {}, [B(C, {}, [ + `A`, + `B` + ])]) +}; diff --git a/spec/compilers2/html_fragment_empty b/spec/compilers2/html_fragment_empty new file mode 100644 index 000000000..51f5a8206 --- /dev/null +++ b/spec/compilers2/html_fragment_empty @@ -0,0 +1,14 @@ +component Main { + fun render : Html { +
+ <> + +
+ } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const A = () => { + return B(`div`, {}, [null]) +}; diff --git a/spec/compilers2/html_with_custom_style b/spec/compilers2/html_with_custom_style new file mode 100644 index 000000000..07e5a8140 --- /dev/null +++ b/spec/compilers2/html_with_custom_style @@ -0,0 +1,24 @@ +component Main { + get styles : Map(String, String) { + `` + } + + fun render : Html { +
+
+ } +} +-------------------------------------------------------------------------------- +import { + createElement as B, + style as C +} from "./runtime.js"; + +export const A = () => { + const a = () => { + return undefined + }; + return B(`div`, { + style: C([a()]) + }) +}; diff --git a/spec/compilers2/html_with_multiple_styles b/spec/compilers2/html_with_multiple_styles new file mode 100644 index 000000000..ecca4946b --- /dev/null +++ b/spec/compilers2/html_with_multiple_styles @@ -0,0 +1,32 @@ +component Main { + style one { + color: red; + } + + style two { + color: blue; + } + + fun render : Html { + +
+ } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_one { + color: red; +} + +.Main_two { + color: blue; +} + +---=== /__mint__/index.js ===--- +import { createElement as B } from "./runtime.js"; + +export const A = () => { + return B(`div`, { + className: `Main_one Main_two` + }) +}; diff --git a/spec/compilers2/html_with_multiple_styles_and_parameters b/spec/compilers2/html_with_multiple_styles_and_parameters new file mode 100644 index 000000000..6f308f986 --- /dev/null +++ b/spec/compilers2/html_with_multiple_styles_and_parameters @@ -0,0 +1,42 @@ +component Main { + style one { + color: red; + } + + style two(color : String) { + color: #{color}; + } + + fun render : Html { + +
+ } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_one { + color: red; +} + +.Main_two { + color: var(--a-a); +} + +---=== /__mint__/index.js ===--- +import { + createElement as B, + style as C +} from "./runtime.js"; + +export const A = () => { + const a = (b) => { + const _ = { + [`--a-a`]: b + }; + return _ + }; + return B(`div`, { + className: `Main_one Main_two`, + style: C([a(`blue`)]) + }) +}; diff --git a/spec/compilers2/html_with_multiple_styles_and_parameters_2 b/spec/compilers2/html_with_multiple_styles_and_parameters_2 new file mode 100644 index 000000000..b8b87a846 --- /dev/null +++ b/spec/compilers2/html_with_multiple_styles_and_parameters_2 @@ -0,0 +1,52 @@ +component Main { + style one(color: String) { + color: #{color}; + } + + style two(color : String) { + color: #{color}; + } + + fun render : Html { + +
+ } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_one { + color: var(--a-a); +} + +.Main_two { + color: var(--b-a); +} + +---=== /__mint__/index.js ===--- +import { + createElement as B, + style as C +} from "./runtime.js"; + +export const A = () => { + const + a = (b) => { + const _ = { + [`--a-a`]: b + }; + return _ + }, + c = (d) => { + const _ = { + [`--b-a`]: d + }; + return _ + }; + return B(`div`, { + className: `Main_one Main_two`, + style: C([ + a(`red`), + c(`blue`) + ]) + }) +}; diff --git a/spec/compilers2/html_with_pseudos b/spec/compilers2/html_with_pseudos new file mode 100644 index 000000000..787fb1c5a --- /dev/null +++ b/spec/compilers2/html_with_pseudos @@ -0,0 +1,73 @@ +component Main { + state hoverBackground : String = "yellow" + state background : String = "blue" + + style test { + background: #{background}; + color: red; + + &:hover { + background: #{hoverBackground}; + color: cyan; + } + + &::first-line { + text-transform: uppercase; + } + + div { + font-family: #{"Hello"}; + color: blue; + } + } + + fun render : Html { + +
+ } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_test { + background: var(--a-a); + color: red; +} + +.Main_test:hover { + background: var(--b-a); + color: cyan; +} + +.Main_test::first-line { + text-transform: uppercase; +} + +.Main_test div { + font-family: var(--c-a); + color: blue; +} + +---=== /__mint__/index.js ===--- +import { + createElement as C, + useSignal as B, + style as D +} from "./runtime.js"; + +export const A = () => { + const + a = B(`yellow`), + b = B(`blue`), + c = () => { + const _ = { + [`--a-a`]: b.value, + [`--b-a`]: a.value, + [`--c-a`]: `Hello` + }; + return _ + }; + return C(`div`, { + className: `Main_test`, + style: D([c()]) + }) +}; diff --git a/spec/compilers2/html_with_string_style b/spec/compilers2/html_with_string_style new file mode 100644 index 000000000..726ef0718 --- /dev/null +++ b/spec/compilers2/html_with_string_style @@ -0,0 +1,16 @@ +component Main { + fun render : Html { +
+ } +} +-------------------------------------------------------------------------------- +import { + createElement as B, + style as C +} from "./runtime.js"; + +export const A = () => { + return B(`div`, { + style: C([`opacity:0;`]) + }) +}; diff --git a/spec/compilers2/html_with_style b/spec/compilers2/html_with_style new file mode 100644 index 000000000..bf103d91b --- /dev/null +++ b/spec/compilers2/html_with_style @@ -0,0 +1,87 @@ +component Main { + state background : String = "blue" + state color : String = "yellow" + + style test { + -webkit-tap-highlight-color: rgba(0,0,0,0); + -webkit-touch-callout: none; + + border-color: #{background}; + background: #{background}; + border: #{background}; + color: #{color}; + + & { + font-size: 1em; + } + + &.big { + font-size: 1.5em; + } + + &[data-foo="bar"] { + font-size: 3em; + } + + > span { + font-size: .8em; + } + } + + fun render : Html { + +
+ } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_test { + -webkit-tap-highlight-color: rgba(0,0,0,0); + -webkit-touch-callout: none; + border-color: var(--a-a); + background: var(--a-b); + border: var(--a-c); + color: var(--a-d); +} + +.Main_test { + font-size: 1em; +} + +.Main_test.big { + font-size: 1.5em; +} + +.Main_test[data-foo="bar"] { + font-size: 3em; +} + +.Main_test > span { + font-size: .8em; +} + +---=== /__mint__/index.js ===--- +import { + createElement as C, + useSignal as B, + style as D +} from "./runtime.js"; + +export const A = () => { + const + a = B(`blue`), + b = B(`yellow`), + c = () => { + const _ = { + [`--a-a`]: a.value, + [`--a-b`]: a.value, + [`--a-c`]: a.value, + [`--a-d`]: b.value + }; + return _ + }; + return C(`div`, { + className: `Main_test`, + style: D([c()]) + }) +}; diff --git a/spec/compilers2/html_with_style_and_custom_style b/spec/compilers2/html_with_style_and_custom_style new file mode 100644 index 000000000..f2e22d49a --- /dev/null +++ b/spec/compilers2/html_with_style_and_custom_style @@ -0,0 +1,51 @@ +component Main { + state background : String = "blue" + + get styles : Map(String, String) { + `` + } + + style test { + background: #{background}; + color: red; + } + + fun render : Html { + +
+ } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_test { + background: var(--a-a); + color: red; +} + +---=== /__mint__/index.js ===--- +import { + createElement as C, + useSignal as B, + style as D +} from "./runtime.js"; + +export const A = () => { + const + a = B(`blue`), + b = () => { + return undefined + }, + c = () => { + const _ = { + [`--a-a`]: a.value + }; + return _ + }; + return C(`div`, { + className: `Main_test`, + style: D([ + c(), + b() + ]) + }) +}; diff --git a/spec/compilers2/if b/spec/compilers2/if new file mode 100644 index 000000000..335d1847d --- /dev/null +++ b/spec/compilers2/if @@ -0,0 +1,18 @@ +component Main { + fun render : String { + if ("asd" == "asd2") { + true + } else { + false + } + + "" + } +} +-------------------------------------------------------------------------------- +import { compare as B } from "./runtime.js"; + +export const A = () => { + (B(`asd`, `asd2`) ? true : false); + return `` +}; diff --git a/spec/compilers2/if_let b/spec/compilers2/if_let new file mode 100644 index 000000000..05a13b8e5 --- /dev/null +++ b/spec/compilers2/if_let @@ -0,0 +1,42 @@ +type T { + A(String) + B +} + +component Main { + fun render : String { + if (let T.A(a) = T.A("")) { + a + } else { + "b" + } + } +} +-------------------------------------------------------------------------------- +import { + patternVariable as H, + newVariant as F, + pattern as G, + variant as B, + match as E +} from "./runtime.js"; + +export const + A = B(1), + C = B(0), + D = () => { + return E(F(A)(``), [ + [ + G(A, [H]), + (a) => { + return a + } + ], + [ + null, + () => { + return `b` + } + ] + ]) + }; diff --git a/spec/compilers2/if_let_await b/spec/compilers2/if_let_await new file mode 100644 index 000000000..95e6bf2a1 --- /dev/null +++ b/spec/compilers2/if_let_await @@ -0,0 +1,50 @@ +type T { + A(String) + B +} + +component Main { + fun render : String { + { + if (let T.A(a) = await T.A("")) { + a + } else { + "b" + } + } + + "" + } +} +-------------------------------------------------------------------------------- +import { + patternVariable as H, + newVariant as E, + pattern as G, + variant as B, + match as F +} from "./runtime.js"; + +export const + A = B(1), + C = B(0), + D = () => { + (async () => { + let a = await E(A)(``); + return F(a, [ + [ + G(A, [H]), + (b) => { + return b + } + ], + [ + null, + () => { + return `b` + } + ] + ]) + })(); + return `` + }; diff --git a/spec/compilers2/if_without_else_array b/spec/compilers2/if_without_else_array new file mode 100644 index 000000000..41e93e5b4 --- /dev/null +++ b/spec/compilers2/if_without_else_array @@ -0,0 +1,13 @@ +component Main { + fun render : Array(String) { + if ("asd" == "asd2") { + ["ARRAY"] + } + } +} +-------------------------------------------------------------------------------- +import { compare as B } from "./runtime.js"; + +export const A = () => { + return (B(`asd`, `asd2`) ? [`ARRAY`] : []) +}; diff --git a/spec/compilers2/if_without_else_promise b/spec/compilers2/if_without_else_promise new file mode 100644 index 000000000..b36a60690 --- /dev/null +++ b/spec/compilers2/if_without_else_promise @@ -0,0 +1,16 @@ +component Main { + fun render : String { + if ("asd" == "asd2") { + next {} + } + + "" + } +} +-------------------------------------------------------------------------------- +import { compare as B } from "./runtime.js"; + +export const A = () => { + (B(`asd`, `asd2`) ? null : null); + return `` +}; diff --git a/spec/compilers2/if_without_else_string b/spec/compilers2/if_without_else_string new file mode 100644 index 000000000..75726e3f1 --- /dev/null +++ b/spec/compilers2/if_without_else_string @@ -0,0 +1,13 @@ +component Main { + fun render : String { + if ("asd" == "asd2") { + "TRUE" + } + } +} +-------------------------------------------------------------------------------- +import { compare as B } from "./runtime.js"; + +export const A = () => { + return (B(`asd`, `asd2`) ? `TRUE` : "") +}; diff --git a/spec/compilers2/indirect_connect b/spec/compilers2/indirect_connect new file mode 100644 index 000000000..d93738c1c --- /dev/null +++ b/spec/compilers2/indirect_connect @@ -0,0 +1,32 @@ +store Test { + state a : String = "" + + fun b : String { + "hello" + } +} + +store A { + state test : Array(String) = [""] + state other : String = "" +} + +component Main { + connect Test exposing { a } + + fun render : String { + A.other + } +} +-------------------------------------------------------------------------------- +import { signal as A } from "./runtime.js"; + +export const + a = () => { + return `hello` + }, + b = A(``), + c = A(``), + B = () => { + return c.value + }; diff --git a/spec/compilers2/inline_function b/spec/compilers2/inline_function new file mode 100644 index 000000000..0f55720b5 --- /dev/null +++ b/spec/compilers2/inline_function @@ -0,0 +1,15 @@ +component Main { + fun render : String { + let a = + () : String { "Hello" } + + a() + } +} +-------------------------------------------------------------------------------- +export const A = () => { + const a = () => { + return `Hello` + }; + return a() +}; diff --git a/spec/compilers2/inline_function_recursive b/spec/compilers2/inline_function_recursive new file mode 100644 index 000000000..13c292257 --- /dev/null +++ b/spec/compilers2/inline_function_recursive @@ -0,0 +1,35 @@ +module Test { + fun factorial(n : Number) : Number { + let helper = (n : Number, acc : Number) : Number { + if (n == 0) { + acc + } else { + helper(n - 1, acc * n) + } + } + + helper(n, 1) + } +} + +component Main { + fun render : String { + Test.factorial(3) + + "" + } +} +-------------------------------------------------------------------------------- +import { compare as A } from "./runtime.js"; + +export const + a = (b) => { + const c = (d, e) => { + return (A(d, 0) ? e : c(d - 1, e * d)) + }; + return c(b, 1) + }, + B = () => { + a(3); + return `` + }; diff --git a/spec/compilers2/inline_function_with_arguments b/spec/compilers2/inline_function_with_arguments new file mode 100644 index 000000000..2038ed326 --- /dev/null +++ b/spec/compilers2/inline_function_with_arguments @@ -0,0 +1,25 @@ +component Main { + fun test : String { + let getName = + (name : String) : String { name } + + getName("Joe") + } + + fun render : String { + test() + + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + const a = () => { + const b = (c) => { + return c + }; + return b(`Joe`) + }; + a(); + return `` +}; diff --git a/spec/compilers2/js b/spec/compilers2/js new file mode 100644 index 000000000..7639d253d --- /dev/null +++ b/spec/compilers2/js @@ -0,0 +1,9 @@ +component Main { + fun render : String { + ` "Hello" ` + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return ("Hello") +}; diff --git a/spec/compilers2/js_with_double_interpolation b/spec/compilers2/js_with_double_interpolation new file mode 100644 index 000000000..aa012544b --- /dev/null +++ b/spec/compilers2/js_with_double_interpolation @@ -0,0 +1,9 @@ +component Main { + fun render : String { + ` "Hello" + #{`"World!"`} ` + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return ("Hello" + ("World!")) +}; diff --git a/spec/compilers2/js_with_interpolation b/spec/compilers2/js_with_interpolation new file mode 100644 index 000000000..169797cdd --- /dev/null +++ b/spec/compilers2/js_with_interpolation @@ -0,0 +1,9 @@ +component Main { + fun render : String { + ` "Hello" + #{"World!"} ` + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return ("Hello" + `World!`) +}; diff --git a/spec/compilers2/locale_key b/spec/compilers2/locale_key new file mode 100644 index 000000000..91330bfe1 --- /dev/null +++ b/spec/compilers2/locale_key @@ -0,0 +1,27 @@ +locale en { + test: "Hello" +} + +component Main { + fun render : String { + :test + } +} +-------------------------------------------------------------------------------- +import { + translations as C, + translate as B, + locale as D +} from "./runtime.js"; + +export const A = () => { + return B(`test`) +}; + +C.value = { + en: { + 'test': `Hello` + } +}; + +D.value = `en`; diff --git a/spec/compilers2/map b/spec/compilers2/map new file mode 100644 index 000000000..2a9901e99 --- /dev/null +++ b/spec/compilers2/map @@ -0,0 +1,26 @@ +component Main { + fun render : Html { + { + "a" => "Hello", + "b" => "World" + } + +
+ } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const A = () => { + [ + [ + `a`, + `Hello` + ], + [ + `b`, + `World` + ] + ]; + return B(`div`, {}) +}; diff --git a/spec/compilers2/module b/spec/compilers2/module new file mode 100644 index 000000000..fea9e8f97 --- /dev/null +++ b/spec/compilers2/module @@ -0,0 +1,23 @@ +module Html.Testing { + fun renderAll : Html { +

+ "It should work" +

+ } +} + +component Main { + fun render : Html { + Html.Testing.renderAll() + } +} +-------------------------------------------------------------------------------- +import { createElement as A } from "./runtime.js"; + +export const + a = () => { + return A(`p`, {}, [`It should work`]) + }, + B = () => { + return a() + }; diff --git a/spec/compilers2/module_access b/spec/compilers2/module_access new file mode 100644 index 000000000..25926594f --- /dev/null +++ b/spec/compilers2/module_access @@ -0,0 +1,30 @@ +module Test { + fun a : String { + "Hello" + } + + fun b : Function(String) { + Test.a + } +} + +component Main { + fun render : String { + let x = + Test.b() + + x() + } +} +-------------------------------------------------------------------------------- +export const + a = () => { + return `Hello` + }, + b = () => { + return a + }, + A = () => { + const c = b(); + return c() + }; diff --git a/spec/compilers2/module_access_get b/spec/compilers2/module_access_get new file mode 100644 index 000000000..43bb133ee --- /dev/null +++ b/spec/compilers2/module_access_get @@ -0,0 +1,26 @@ +store Test { + get a : String { + "Hello" + } + + fun b : String { + a + } +} + +component Main { + fun render : String { + Test.b() + } +} +-------------------------------------------------------------------------------- +export const + a = () => { + return `Hello` + }, + b = () => { + return a() + }, + A = () => { + return b() + }; diff --git a/spec/compilers2/module_access_subscriptions b/spec/compilers2/module_access_subscriptions new file mode 100644 index 000000000..fe14e8097 --- /dev/null +++ b/spec/compilers2/module_access_subscriptions @@ -0,0 +1,51 @@ +type Test { + test : String +} + +provider Test : Test { + fun update : Promise(Void) { + subscriptions + await void + } + + fun print (a : String) : String { + a + } +} + +component Main { + use Test { + test: "" + } + + fun render : String { + Test.subscriptions + Test.print("a") + } +} +-------------------------------------------------------------------------------- +import { + createProvider as B, + subscriptions as C, + useId as E +} from "./runtime.js"; + +export const + a = new Map(), + b = (c) => { + return c + }, + A = B(a, async () => { + C(a); + return await null + }), + D = () => { + const d = E(); + A(d, () => { + return { + test: `` + } + }); + C(a); + return b(`a`) + }; diff --git a/spec/compilers2/module_call b/spec/compilers2/module_call new file mode 100644 index 000000000..e8690f524 --- /dev/null +++ b/spec/compilers2/module_call @@ -0,0 +1,26 @@ +module Test { + fun a (value : String) : String { + value + } + + fun b : String { + Test.a("Lorem ipsum dolor sit amet") + } +} + +component Main { + fun render : String { + Test.b() + } +} +-------------------------------------------------------------------------------- +export const + a = (b) => { + return b + }, + c = () => { + return a(`Lorem ipsum dolor sit amet`) + }, + A = () => { + return c() + }; diff --git a/spec/compilers2/module_call_piped b/spec/compilers2/module_call_piped new file mode 100644 index 000000000..21ba67372 --- /dev/null +++ b/spec/compilers2/module_call_piped @@ -0,0 +1,27 @@ +module Test { + fun a (x : Bool, value : String) : String { + value + } + + fun b : String { + true + |> Test.a("Lorem ipsum dolor sit amet") + } +} + +component Main { + fun render : String { + Test.b() + } +} +-------------------------------------------------------------------------------- +export const + a = (b, c) => { + return c + }, + d = () => { + return a(true, `Lorem ipsum dolor sit amet`) + }, + A = () => { + return d() + }; diff --git a/spec/compilers2/next_call b/spec/compilers2/next_call new file mode 100644 index 000000000..3e8b9774b --- /dev/null +++ b/spec/compilers2/next_call @@ -0,0 +1,37 @@ +component Main { + state name : String = "Joe" + state age : Number = 24 + + fun test : Promise(Void) { + next + { + name: "Hello", + age: 30 + } + } + + fun render : String { + test() + + "" + } +} +-------------------------------------------------------------------------------- +import { + useSignal as B, + batch as C +} from "./runtime.js"; + +export const A = () => { + const + a = B(`Joe`), + b = B(24), + c = () => { + return C(() => { + a.value = `Hello`; + b.value = 30 + }) + }; + c(); + return `` +}; diff --git a/spec/compilers2/next_call_empty b/spec/compilers2/next_call_empty new file mode 100644 index 000000000..dc991181f --- /dev/null +++ b/spec/compilers2/next_call_empty @@ -0,0 +1,11 @@ +component Main { + fun render : String { + next {} + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + null; + return `` +}; diff --git a/spec/compilers2/number_literal_negative b/spec/compilers2/number_literal_negative new file mode 100644 index 000000000..a348075c2 --- /dev/null +++ b/spec/compilers2/number_literal_negative @@ -0,0 +1,11 @@ +component Main { + fun render : String { + -42 + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + -42; + return `` +}; diff --git a/spec/compilers2/number_literal_simple b/spec/compilers2/number_literal_simple new file mode 100644 index 000000000..efcc15473 --- /dev/null +++ b/spec/compilers2/number_literal_simple @@ -0,0 +1,11 @@ +component Main { + fun render : String { + 10 + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + 10; + return `` +}; diff --git a/spec/compilers2/number_literal_with_decimal b/spec/compilers2/number_literal_with_decimal new file mode 100644 index 000000000..70c37398a --- /dev/null +++ b/spec/compilers2/number_literal_with_decimal @@ -0,0 +1,11 @@ +component Main { + fun render : String { + 10.120 + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + 10.120; + return `` +}; diff --git a/spec/compilers2/operation_chained b/spec/compilers2/operation_chained new file mode 100644 index 000000000..636b05463 --- /dev/null +++ b/spec/compilers2/operation_chained @@ -0,0 +1,13 @@ +component Main { + fun render : String { + "a" == "b" && true != false + "" + } +} +-------------------------------------------------------------------------------- +import { compare as B } from "./runtime.js"; + +export const A = () => { + B(`a`, `b`) && !B(true, false); + return `` +}; diff --git a/spec/compilers2/operation_or b/spec/compilers2/operation_or new file mode 100644 index 000000000..8bc4b5158 --- /dev/null +++ b/spec/compilers2/operation_or @@ -0,0 +1,29 @@ +type Result(error, value) { + Err(error) + Ok(value) +} + +type Maybe(value) { + Nothing + Just(value) +} + +component Main { + fun render : String { + Maybe.Nothing or "Hello" + } +} +-------------------------------------------------------------------------------- +import { + variant as B, + or as G +} from "./runtime.js"; + +export const + A = B(0), + C = B(1), + D = B(1), + E = B(1), + F = () => { + return G(A, D, new A(), `Hello`) + }; diff --git a/spec/compilers2/operation_simple b/spec/compilers2/operation_simple new file mode 100644 index 000000000..c779827db --- /dev/null +++ b/spec/compilers2/operation_simple @@ -0,0 +1,13 @@ +component Main { + fun render : String { + "a" == "b" + "" + } +} +-------------------------------------------------------------------------------- +import { compare as B } from "./runtime.js"; + +export const A = () => { + B(`a`, `b`); + return `` +}; diff --git a/spec/compilers2/parenthesized_expression b/spec/compilers2/parenthesized_expression new file mode 100644 index 000000000..b9352f3c8 --- /dev/null +++ b/spec/compilers2/parenthesized_expression @@ -0,0 +1,11 @@ +component Main { + fun render : String { + (true) + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + (true); + return `` +}; diff --git a/spec/compilers2/pipe b/spec/compilers2/pipe new file mode 100644 index 000000000..f5887061f --- /dev/null +++ b/spec/compilers2/pipe @@ -0,0 +1,21 @@ +component Main { + fun render : Html { +
+ (n : String) : String { n }("3") + "3" |> (n : String) : String { n } +
+ } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const A = () => { + return B(`div`, {}, [ + ((a) => { + return a + })(`3`), + ((b) => { + return b + })(`3`) + ]) +}; diff --git a/spec/compilers2/property b/spec/compilers2/property new file mode 100644 index 000000000..89df7270a --- /dev/null +++ b/spec/compilers2/property @@ -0,0 +1,25 @@ +component Test { + property name : String = "Joe" + + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const + A = ({ + a = `Joe` + }) => { + return B(`div`, {}) + }, + C = () => { + return B(A, {}) + }; diff --git a/spec/compilers2/property_without_default b/spec/compilers2/property_without_default new file mode 100644 index 000000000..11a665665 --- /dev/null +++ b/spec/compilers2/property_without_default @@ -0,0 +1,28 @@ +component Test { + property name : String + + fun render : Html { +
+ } +} + +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const + A = ({ + a + }) => { + return B(`div`, {}) + }, + C = () => { + return B(A, { + a: `HELLO` + }) + }; + diff --git a/spec/compilers2/provider_with_items b/spec/compilers2/provider_with_items new file mode 100644 index 000000000..cdbac6618 --- /dev/null +++ b/spec/compilers2/provider_with_items @@ -0,0 +1,64 @@ +type Subscription { + a : Bool, + b : Bool +} + +provider Provider : Subscription { + const NAME = "hello" + + state a : String = "" + + get b : String { + a + } + + fun update : Promise(Void) { + await void + } + + fun name : String { + NAME + } +} + +component Main { + use Provider { + a: true, + b: false + } + + fun render { +
+ } +} +-------------------------------------------------------------------------------- +import { + createProvider as C, + createElement as F, + signal as A, + useId as E +} from "./runtime.js"; + +export const + a = new Map(), + b = `hello`, + c = () => { + return b + }, + d = A(``), + e = () => { + return d.value + }, + B = C(a, async () => { + return await null + }), + D = () => { + const f = E(); + B(f, () => { + return { + a: true, + b: false + } + }); + return F(`div`, {}) + }; diff --git a/spec/compilers2/record b/spec/compilers2/record new file mode 100644 index 000000000..fa3afe1d4 --- /dev/null +++ b/spec/compilers2/record @@ -0,0 +1,25 @@ +type Test { + a : String, + b : Number +} + +component Main { + fun render : Html { + { + a: "Hello", + b: 0 + } + +
+ } +} +-------------------------------------------------------------------------------- +import { createElement as B } from "./runtime.js"; + +export const A = () => { + { + a: `Hello`, + b: 0 + }; + return B(`div`, {}) +}; diff --git a/spec/compilers2/record_update b/spec/compilers2/record_update new file mode 100644 index 000000000..69d73368d --- /dev/null +++ b/spec/compilers2/record_update @@ -0,0 +1,28 @@ +type Record { + name: String +} + +component Main { + state record : Record = { name: "Doe" } + + fun render : Html { + { record | name: "John" } +
+ } +} +-------------------------------------------------------------------------------- +import { + createElement as C, + useSignal as B +} from "./runtime.js"; + +export const A = () => { + const a = B({ + name: `Doe` + }); + { + ...a.value, + name: `John` + }; + return C(`div`, {}) +}; diff --git a/spec/compilers2/regexp_literal b/spec/compilers2/regexp_literal new file mode 100644 index 000000000..e9d582296 --- /dev/null +++ b/spec/compilers2/regexp_literal @@ -0,0 +1,11 @@ +component Main { + fun render : String { + /.*/gm + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + /.*/gm; + return `` +}; diff --git a/spec/compilers2/state b/spec/compilers2/state new file mode 100644 index 000000000..d2d317b47 --- /dev/null +++ b/spec/compilers2/state @@ -0,0 +1,25 @@ +component Main { + state test : String = "Hello" + state blah : String = "0" + + fun asd : String { + test + blah + } + + fun render : String { + asd() + } +} +-------------------------------------------------------------------------------- +import { useSignal as B } from "./runtime.js"; + +export const A = () => { + const + a = B(`Hello`), + b = B(`0`), + c = () => { + return a.value + b.value + }; + return c() +}; + diff --git a/spec/compilers2/state_setter b/spec/compilers2/state_setter new file mode 100644 index 000000000..97dc94939 --- /dev/null +++ b/spec/compilers2/state_setter @@ -0,0 +1,18 @@ +component Main { + state value : String = "" + + fun render : String { + ->value("Hello") + value + } +} +-------------------------------------------------------------------------------- +import { useSignal as B } from "./runtime.js"; + +export const A = () => { + const a = B(``); + (b) => { + a.value = b + }(`Hello`); + return a.value +}; diff --git a/spec/compilers2/statement b/spec/compilers2/statement new file mode 100644 index 000000000..d473aff79 --- /dev/null +++ b/spec/compilers2/statement @@ -0,0 +1,13 @@ +component Main { + fun render : String { + let x = + "hello" + + x + } +} +-------------------------------------------------------------------------------- +export const A = () => { + const a = `hello`; + return a +}; diff --git a/spec/compilers2/store b/spec/compilers2/store new file mode 100644 index 000000000..5d4031673 --- /dev/null +++ b/spec/compilers2/store @@ -0,0 +1,26 @@ +store Test { + state test : String = "" + + fun hello : String { + "hello" + } +} + +component Main { + connect Test exposing { test } + + fun render : String { + test + } +} +-------------------------------------------------------------------------------- +import { signal as A } from "./runtime.js"; + +export const + a = () => { + return `hello` + }, + b = A(``), + B = () => { + return b.value + }; diff --git a/spec/compilers2/store_with_get b/spec/compilers2/store_with_get new file mode 100644 index 000000000..0e707cd3d --- /dev/null +++ b/spec/compilers2/store_with_get @@ -0,0 +1,29 @@ +store Test { + state test : String = "" + + get hello : String { + "hello" + } +} + +component Main { + connect Test exposing { test as xxx } + + fun render : String { + xxx + Test.hello + } +} +-------------------------------------------------------------------------------- +import { signal as A } from "./runtime.js"; + +export const + a = A(``), + b = () => { + return `hello` + }, + B = () => { + a.value; + return b() + }; + diff --git a/spec/compilers2/string_literal_broken b/spec/compilers2/string_literal_broken new file mode 100644 index 000000000..fdcdcd7c2 --- /dev/null +++ b/spec/compilers2/string_literal_broken @@ -0,0 +1,11 @@ +component Main { + fun render : String { + "First line" \ + "Second line" \ + "Third line" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return `First lineSecond lineThird line` +}; diff --git a/spec/compilers2/string_literal_escaped b/spec/compilers2/string_literal_escaped new file mode 100644 index 000000000..5df330860 --- /dev/null +++ b/spec/compilers2/string_literal_escaped @@ -0,0 +1,9 @@ +component Main { + fun render : String { + "Hello There \"Joe\"" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return `Hello There "Joe"` +}; diff --git a/spec/compilers2/string_literal_simple b/spec/compilers2/string_literal_simple new file mode 100644 index 000000000..50db540f9 --- /dev/null +++ b/spec/compilers2/string_literal_simple @@ -0,0 +1,9 @@ +component Main { + fun render : String { + "Hello There" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return `Hello There` +}; diff --git a/spec/compilers2/string_literal_with_backtick b/spec/compilers2/string_literal_with_backtick new file mode 100644 index 000000000..936a625db --- /dev/null +++ b/spec/compilers2/string_literal_with_backtick @@ -0,0 +1,9 @@ +component Main { + fun render : String { + "Hello There `Joe`" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return `Hello There \`Joe\`` +}; diff --git a/spec/compilers2/string_literal_with_escaped_interpolation b/spec/compilers2/string_literal_with_escaped_interpolation new file mode 100644 index 000000000..f05bee66c --- /dev/null +++ b/spec/compilers2/string_literal_with_escaped_interpolation @@ -0,0 +1,9 @@ +component Main { + fun render : String { + "Hello There \#{name}" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return `Hello There #{name}` +}; diff --git a/spec/compilers2/string_literal_with_interpolation b/spec/compilers2/string_literal_with_interpolation new file mode 100644 index 000000000..7ebcebb6f --- /dev/null +++ b/spec/compilers2/string_literal_with_interpolation @@ -0,0 +1,9 @@ +component Main { + fun render : String { + "Hello There #{"Hello"}" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return `Hello There ${`Hello`}` +}; diff --git a/spec/compilers2/string_literal_with_interpolation_and_js_iterpolation b/spec/compilers2/string_literal_with_interpolation_and_js_iterpolation new file mode 100644 index 000000000..7ebcebb6f --- /dev/null +++ b/spec/compilers2/string_literal_with_interpolation_and_js_iterpolation @@ -0,0 +1,9 @@ +component Main { + fun render : String { + "Hello There #{"Hello"}" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return `Hello There ${`Hello`}` +}; diff --git a/spec/compilers2/string_literal_with_interpolation_of_number b/spec/compilers2/string_literal_with_interpolation_of_number new file mode 100644 index 000000000..797598e2c --- /dev/null +++ b/spec/compilers2/string_literal_with_interpolation_of_number @@ -0,0 +1,9 @@ +component Main { + fun render : String { + "Hello There #{0}" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return `Hello There ${0}` +}; diff --git a/spec/compilers2/string_literal_with_js_iterpolation b/spec/compilers2/string_literal_with_js_iterpolation new file mode 100644 index 000000000..f6baea1bd --- /dev/null +++ b/spec/compilers2/string_literal_with_js_iterpolation @@ -0,0 +1,9 @@ +component Main { + fun render : String { + "Hello There ${a}" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + return `Hello There \${a}` +}; diff --git a/spec/compilers2/style_with_argument b/spec/compilers2/style_with_argument new file mode 100644 index 000000000..1ebb28757 --- /dev/null +++ b/spec/compilers2/style_with_argument @@ -0,0 +1,34 @@ +component Main { + style test (color : String) { + color: #{color}; + } + + fun render : Html { + +
+ } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_test { + color: var(--a-a); +} + +---=== /__mint__/index.js ===--- +import { + createElement as B, + style as C +} from "./runtime.js"; + +export const A = () => { + const a = (b) => { + const _ = { + [`--a-a`]: b + }; + return _ + }; + return B(`div`, { + className: `Main_test`, + style: C([a(`red`)]) + }) +}; diff --git a/spec/compilers2/style_with_default_argument b/spec/compilers2/style_with_default_argument new file mode 100644 index 000000000..333ba2ce6 --- /dev/null +++ b/spec/compilers2/style_with_default_argument @@ -0,0 +1,34 @@ +component Main { + style test (color : String = "red") { + color: #{color}; + } + + fun render : Html { + +
+ } +} +-------------------------------------------------------------------------------- +---=== /__mint__/index.css ===--- +.Main_test { + color: var(--a-a); +} + +---=== /__mint__/index.js ===--- +import { + createElement as B, + style as C +} from "./runtime.js"; + +export const A = () => { + const a = (b = `red`) => { + const _ = { + [`--a-a`]: b + }; + return _ + }; + return B(`div`, { + className: `Main_test`, + style: C([a()]) + }) +}; diff --git a/spec/compilers2/tuple_literal b/spec/compilers2/tuple_literal new file mode 100644 index 000000000..3ba53ea10 --- /dev/null +++ b/spec/compilers2/tuple_literal @@ -0,0 +1,19 @@ +component Main { + fun render : String { + { + "Hello", + "Blah", + "Joe" + } + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + [ + `Hello`, + `Blah`, + `Joe` + ]; + return `` +}; diff --git a/spec/compilers2/type b/spec/compilers2/type new file mode 100644 index 000000000..884bdaef7 --- /dev/null +++ b/spec/compilers2/type @@ -0,0 +1,39 @@ +type Test(a) { + X + Y + Z(Res(a, Number)) +} + +type Res(error, value) { + Error(error) + Ok(value) + Other(error, value) +} + +component Main { + fun render : String { + Test.X + Res.Other("", "") + Test.Z(Res.Error("")) + "" + } +} +-------------------------------------------------------------------------------- +import { + newVariant as I, + variant as B +} from "./runtime.js"; + +export const + A = B(1), + C = B(0), + D = B(0), + E = B(1), + F = B(1), + G = B(2), + H = () => { + new C(); + I(G)(``, ``); + I(E)(I(F)(``)); + return `` + }; diff --git a/spec/compilers2/type_with_variants b/spec/compilers2/type_with_variants new file mode 100644 index 000000000..fb961ca1b --- /dev/null +++ b/spec/compilers2/type_with_variants @@ -0,0 +1,54 @@ +type A { + B(name : String, color : String) + C +} + +component Main { + fun render : String { + case (A.B(name: "Joe", color: "Blue")) { + A.B(color, name) => color + A.C => "" + } + } +} +-------------------------------------------------------------------------------- +import { + patternVariable as I, + patternRecord as H, + newVariant as F, + pattern as G, + variant as B, + match as E +} from "./runtime.js"; + +export const + A = B([ + "name", + "color" + ]), + C = B(0), + D = () => { + return E(F(A)(`Joe`, `Blue`), [ + [ + G(A, H([ + [ + `color`, + I + ], + [ + `name`, + I + ] + ])), + (a, b) => { + return a + } + ], + [ + G(C, []), + () => { + return `` + } + ] + ]) + }; diff --git a/spec/compilers2/unary_minus b/spec/compilers2/unary_minus new file mode 100644 index 000000000..b99bff095 --- /dev/null +++ b/spec/compilers2/unary_minus @@ -0,0 +1,12 @@ +component Main { + fun render : String { + -(42) + + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + -((42)); + return `` +}; diff --git a/spec/compilers2/variable_argument b/spec/compilers2/variable_argument new file mode 100644 index 000000000..149c82824 --- /dev/null +++ b/spec/compilers2/variable_argument @@ -0,0 +1,16 @@ +component Main { + fun test (a : String) : String { + a + } + + fun render : String { + test("X") + } +} +-------------------------------------------------------------------------------- +export const A = () => { + const a = (b) => { + return b + }; + return a(`X`) +}; diff --git a/spec/compilers2/variable_component_function b/spec/compilers2/variable_component_function new file mode 100644 index 000000000..bdc82ee57 --- /dev/null +++ b/spec/compilers2/variable_component_function @@ -0,0 +1,16 @@ +component Main { + fun test : String { + "Hello" + } + + fun render : String { + test() + } +} +-------------------------------------------------------------------------------- +export const A = () => { + const a = () => { + return `Hello` + }; + return a() +}; diff --git a/spec/compilers2/variable_component_get b/spec/compilers2/variable_component_get new file mode 100644 index 000000000..c1c323fcf --- /dev/null +++ b/spec/compilers2/variable_component_get @@ -0,0 +1,16 @@ +component Main { + get test : String { + "Hello" + } + + fun render : String { + test + } +} +-------------------------------------------------------------------------------- +export const A = () => { + const a = () => { + return `Hello` + }; + return a() +}; diff --git a/spec/compilers2/variable_component_property b/spec/compilers2/variable_component_property new file mode 100644 index 000000000..7ac6fcc32 --- /dev/null +++ b/spec/compilers2/variable_component_property @@ -0,0 +1,25 @@ +component Test { + property test : String = "Hello" + + fun render : String { + test + } +} + +component Main { + fun render : Html { + + } +} +-------------------------------------------------------------------------------- +import { createElement as C } from "./runtime.js"; + +export const + A = ({ + a = `Hello` + }) => { + return a + }, + B = () => { + return C(A, {}) + }; diff --git a/spec/compilers2/variable_module_function b/spec/compilers2/variable_module_function new file mode 100644 index 000000000..a4ef29b14 --- /dev/null +++ b/spec/compilers2/variable_module_function @@ -0,0 +1,30 @@ +module A { + fun a : String { + "Hello" + } + + fun b : Function(String) { + a + } +} + +component Main { + fun render : String { + let a = + A.b() + + a() + } +} +-------------------------------------------------------------------------------- +export const + a = () => { + return `Hello` + }, + b = () => { + return a + }, + A = () => { + const c = b(); + return c() + }; diff --git a/spec/compilers2/void b/spec/compilers2/void new file mode 100644 index 000000000..6365978da --- /dev/null +++ b/spec/compilers2/void @@ -0,0 +1,11 @@ +component Main { + fun render : String { + void + "" + } +} +-------------------------------------------------------------------------------- +export const A = () => { + null; + return `` +}; diff --git a/spec/compilers2_spec.cr b/spec/compilers2_spec.cr new file mode 100644 index 000000000..b0f05dace --- /dev/null +++ b/spec/compilers2_spec.cr @@ -0,0 +1,70 @@ +require "./spec_helper" + +Dir + .glob("./spec/compilers2/**/*") + .select! { |file| File.file?(file) } + .sort! + .each do |file| + it file do + begin + # Read and separate sample from expected + sample, expected = File.read(file).split("-" * 80) + + # Parse the sample + ast = Mint::Parser.parse(sample, file) + ast.class.should eq(Mint::Ast) + + artifacts = + Mint::TypeChecker.check(ast) + + config = + Mint::Bundler::Config.new( + generate_manifest: false, + include_program: false, + live_reload: false, + runtime_path: nil, + skip_icons: false, + hash_assets: true, + relative: false, + optimize: false, + test: nil) + + json = + Mint::MintJson.new + + files = + Mint::Bundler.new( + artifacts: artifacts, + config: config, + json: json + ).bundle.map do |path, contents| + {path, case contents + in Proc(String) + contents.call + in String + contents + end} + end.to_h + .reject { |_, contents| contents.blank? } + .reject { |key, _| key.in?("/__mint__/runtime.js", "index.html") } + + result = + case files.size + when 1 + files.first[1] + else + files + .map { |path, contents| "---=== #{path} ===---\n#{contents}" } + .join("\n\n").strip + end + + begin + result.should eq(expected.strip) + rescue error + fail diff(expected, result) + end + rescue error : Mint::Error + fail error.to_terminal.to_s + end + end + end diff --git a/spec/errors/access_field_not_found b/spec/errors/access_field_not_found index 7153471a5..1acb35f27 100644 --- a/spec/errors/access_field_not_found +++ b/spec/errors/access_field_not_found @@ -1,4 +1,4 @@ -record Blah { +type Blah { blah : String } diff --git a/spec/errors/array_access_expected_closing_bracket b/spec/errors/bracket_access_expected_closing_bracket similarity index 52% rename from spec/errors/array_access_expected_closing_bracket rename to spec/errors/bracket_access_expected_closing_bracket index 1e230f46b..67b2cd508 100644 --- a/spec/errors/array_access_expected_closing_bracket +++ b/spec/errors/bracket_access_expected_closing_bracket @@ -2,13 +2,13 @@ component Main { fun render : String { array[0 -------------------------------------------------------------------------------- -░ ERROR (ARRAY_ACCESS_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ +░ ERROR (BRACKET_ACCESS_EXPECTED_CLOSING_BRACKET) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ -I was expecting the closing bracket of an array access but I found "a space" +I was expecting the closing bracket of a bracket access but I found "a space" instead: - ┌ ./spec/errors/array_access_expected_closing_bracket:3:11 - ├───────────────────────────────────────────────────────── + ┌ ./spec/errors/bracket_access_expected_closing_bracket:3:11 + ├─────────────────────────────────────────────────────────── 1│ component Main { 2│ fun render : String { 3│ array[0 diff --git a/spec/errors/array_access_expected_index b/spec/errors/bracket_access_expected_index similarity index 53% rename from spec/errors/array_access_expected_index rename to spec/errors/bracket_access_expected_index index d015ccb70..832c17bc2 100644 --- a/spec/errors/array_access_expected_index +++ b/spec/errors/bracket_access_expected_index @@ -2,12 +2,12 @@ component Main { fun render : String { array[ -------------------------------------------------------------------------------- -░ ERROR (ARRAY_ACCESS_EXPECTED_INDEX) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ +░ ERROR (BRACKET_ACCESS_EXPECTED_INDEX) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ -I was expecting the index of an array access but I found "a space" instead: +I was expecting the index of a bracket access but I found "a space" instead: - ┌ ./spec/errors/array_access_expected_index:3:10 - ├─────────────────────────────────────────────── + ┌ ./spec/errors/bracket_access_expected_index:3:10 + ├───────────────────────────────────────────────── 1│ component Main { 2│ fun render : String { 3│ array[ diff --git a/spec/errors/array_access_index_not_number b/spec/errors/bracket_access_index_not_number similarity index 68% rename from spec/errors/array_access_index_not_number rename to spec/errors/bracket_access_index_not_number index 51b0e6625..d4205dd16 100644 --- a/spec/errors/array_access_index_not_number +++ b/spec/errors/bracket_access_index_not_number @@ -14,9 +14,9 @@ component Main { } } -------------------------------------------------------------------------------- -░ ERROR (ARRAY_ACCESS_INDEX_NOT_NUMBER) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ +░ ERROR (BRACKET_ACCESS_INDEX_NOT_NUMBER) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ -The type of the index of an array access is not a number. +The type of the index of a bracket access is not a number. I was expecting: @@ -28,8 +28,8 @@ Instead it is: The index in question is here: - ┌ ./spec/errors/array_access_index_not_number:7:7 - ├──────────────────────────────────────────────── + ┌ ./spec/errors/bracket_access_index_not_number:7:7 + ├────────────────────────────────────────────────── 3│ [ 4│ "Hello", 5│ "Blah", diff --git a/spec/errors/array_access_invalid_tuple b/spec/errors/bracket_access_invalid_tuple similarity index 51% rename from spec/errors/array_access_invalid_tuple rename to spec/errors/bracket_access_invalid_tuple index 1ad006344..fbc838b85 100644 --- a/spec/errors/array_access_invalid_tuple +++ b/spec/errors/bracket_access_invalid_tuple @@ -1,6 +1,6 @@ component Main { fun test : Maybe(String) { - {"Hello"}[1] + {"Hello", ""}[2] } fun render : Html { @@ -10,21 +10,23 @@ component Main { } } -------------------------------------------------------------------------------- -░ ERROR (ARRAY_ACCESS_INVALID_TUPLE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ +░ ERROR (BRACKET_ACCESS_INVALID_TUPLE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ -The tuple have only 1 members, but you wanted to access the 2nd. The exact type +The tuple has only 2 members, but you wanted to access the 3rd. The exact type of the tuple is: - Tuple(String) + Tuple( + String, + String) The tuple in question is here: - ┌ ./spec/errors/array_access_invalid_tuple:3:5 - ├───────────────────────────────────────────── + ┌ ./spec/errors/bracket_access_invalid_tuple:3:5 + ├─────────────────────────────────────────────── 1│ component Main { 2│ fun test : Maybe(String) { - 3│ {"Hello"}[1] - │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ {"Hello", ""}[2] + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ 4│ } 5│ 6│ fun render : Html { diff --git a/spec/errors/array_access_not_an_array b/spec/errors/bracket_access_not_accessible similarity index 62% rename from spec/errors/array_access_not_an_array rename to spec/errors/bracket_access_not_accessible index 54bf00b9b..7dda63d3b 100644 --- a/spec/errors/array_access_not_an_array +++ b/spec/errors/bracket_access_not_accessible @@ -1,6 +1,6 @@ component Main { fun test : Maybe(String) { - {}[0] + 0[0] } fun render : Html { @@ -10,26 +10,27 @@ component Main { } } -------------------------------------------------------------------------------- -░ ERROR (ARRAY_ACCESS_NOT_AN_ARRAY) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ +░ ERROR (BRACKET_ACCESS_NOT_ACCESSIBLE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ -The entity you are trying to access an item from is not an array or a tuple. +The entity you are trying to access an item from is not an array, map or a +tuple. I was expecting: - Array(a), Tuple(...) + Array(a), Map(a, b) or Tuple(...) Instead it is: - Unit + Number The array in question is here: - ┌ ./spec/errors/array_access_not_an_array:3:5 - ├──────────────────────────────────────────── + ┌ ./spec/errors/bracket_access_not_accessible:3:5 + ├──────────────────────────────────────────────── 1│ component Main { 2│ fun test : Maybe(String) { - 3│ {}[0] - │ ⌃⌃ + 3│ 0[0] + │ ⌃ 4│ } 5│ 6│ fun render : Html { diff --git a/spec/errors/case_type_not_covered b/spec/errors/case_type_not_covered index 71cb92627..371b9b4cd 100644 --- a/spec/errors/case_type_not_covered +++ b/spec/errors/case_type_not_covered @@ -1,4 +1,4 @@ -enum A { +type A { B C D @@ -6,9 +6,9 @@ enum A { component Main { fun render : String { - case (A::B) { - A::B => "a" - A::C => "c" + case (A.B) { + A.B => "a" + A.C => "c" } } } @@ -18,7 +18,7 @@ component Main { Not all possibilities of a case expression are covered. To cover all remaining possibilities create branches for the following cases: - A::D + A.D The case in question is here: @@ -28,11 +28,11 @@ The case in question is here: 6│ 7│ component Main { 8│ fun render : String { - │ ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄ - 9│ case (A::B) { - 10│ A::B => "a" - 11│ A::C => "c" + │ ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄ + 9│ case (A.B) { + 10│ A.B => "a" + 11│ A.C => "c" 12│ } - │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ 13│ } 14│ } diff --git a/spec/errors/case_unnecessary_all b/spec/errors/case_unnecessary_all index 173d53028..231db06bf 100644 --- a/spec/errors/case_unnecessary_all +++ b/spec/errors/case_unnecessary_all @@ -1,13 +1,13 @@ -enum A { +type A { B C } component Main { fun render : String { - case (A::B) { - A::B => "a" - A::C => "c" + case (A.B) { + A.B => "a" + A.C => "c" => "x" } } @@ -21,9 +21,9 @@ needed and can be safely removed. ┌ ./spec/errors/case_unnecessary_all:11:7 ├──────────────────────────────────────── 7│ fun render : String { - 8│ case (A::B) { - 9│ A::B => "a" - 10│ A::C => "c" + 8│ case (A.B) { + 9│ A.B => "a" + 10│ A.C => "c" 11│ => "x" │ ⌃⌃⌃⌃⌃⌃ 12│ } diff --git a/spec/errors/decode_complex_type b/spec/errors/decode_complex_type index 08e8d9e87..dc69cc902 100644 --- a/spec/errors/decode_complex_type +++ b/spec/errors/decode_complex_type @@ -1,4 +1,4 @@ -record X { +type X { name : Blah } diff --git a/spec/errors/decode_expected_object b/spec/errors/decode_expected_object index 2002e53e9..fa240ef5d 100644 --- a/spec/errors/decode_expected_object +++ b/spec/errors/decode_expected_object @@ -1,4 +1,4 @@ -record X { +type X { name : String } diff --git a/spec/errors/destructuring_type_field_missing b/spec/errors/destructuring_type_field_missing index c9ed79487..67dfdabf8 100644 --- a/spec/errors/destructuring_type_field_missing +++ b/spec/errors/destructuring_type_field_missing @@ -1,10 +1,10 @@ -enum Maybe { +type Maybe { Just(item : String) } component Main { fun render : String { - let Maybe::Just(key) = Maybe::Just(item: "") or return "" + let Maybe.Just(key) = Maybe.Just(item: "") or return "" "" } } @@ -17,14 +17,14 @@ I could not find a field for a destructuring: The destructuring in question is here: - ┌ ./spec/errors/destructuring_type_field_missing:7:21 - ├────────────────────────────────────────────────────────────── + ┌ ./spec/errors/destructuring_type_field_missing:7:20 + ├──────────────────────────────────────────────────────────── 3│ } 4│ 5│ component Main { 6│ fun render : String { - 7│ let Maybe::Just(key) = Maybe::Just(item: "") or return "" - │ ⌃⌃⌃ + 7│ let Maybe.Just(key) = Maybe.Just(item: "") or return "" + │ ⌃⌃⌃ 8│ "" 9│ } 10│ } diff --git a/spec/errors/destructuring_type_missing b/spec/errors/destructuring_type_missing index e9c004e0e..6089185bd 100644 --- a/spec/errors/destructuring_type_missing +++ b/spec/errors/destructuring_type_missing @@ -1,6 +1,6 @@ component Main { fun render : String { - let Maybe::Just(a) = "" or return "" + let Maybe.Just(a) = "" or return "" "" } } @@ -17,8 +17,8 @@ The destructuring in question is here: ├───────────────────────────────────────────── 1│ component Main { 2│ fun render : String { - 3│ let Maybe::Just(a) = "" or return "" - │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 3│ let Maybe.Just(a) = "" or return "" + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ 4│ "" 5│ } 6│ } diff --git a/spec/errors/destructuring_type_variant_missing b/spec/errors/destructuring_type_variant_missing index b2deed6e5..eb53da87b 100644 --- a/spec/errors/destructuring_type_variant_missing +++ b/spec/errors/destructuring_type_variant_missing @@ -1,10 +1,10 @@ -enum Maybe { +type Maybe { Nothing } component Main { fun render : String { - let Maybe::Just(a) = "" or return "" + let Maybe.Just(a) = "" or return "" "" } } @@ -19,8 +19,8 @@ I could not find the variant "Just" of type "Maybe" for a destructuring: 4│ 5│ component Main { 6│ fun render : String { - 7│ let Maybe::Just(a) = "" or return "" - │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 7│ let Maybe.Just(a) = "" or return "" + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ 8│ "" 9│ } 10│ } @@ -30,11 +30,11 @@ The type is defined here: ┌ ./spec/errors/destructuring_type_variant_missing:1:1 ├───────────────────────────────────────────────────── │ ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄ - 1│ enum Maybe { + 1│ type Maybe { 2│ Nothing 3│ } │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ 4│ 5│ component Main { 6│ fun render : String { - 7│ let Maybe::Just(a) = "" or return "" + 7│ let Maybe.Just(a) = "" or return "" diff --git a/spec/errors/encode_complex_type b/spec/errors/encode_complex_type index ae9aeadf9..aef6c2c0e 100644 --- a/spec/errors/encode_complex_type +++ b/spec/errors/encode_complex_type @@ -1,10 +1,10 @@ -enum Maybe { +type Maybe { Just(String) } component Main { fun render : Html { - encode Maybe::Just("") + encode Maybe.Just("") } } -------------------------------------------------------------------------------- @@ -33,7 +33,7 @@ The encode in question is here: 4│ 5│ component Main { 6│ fun render : Html { - 7│ encode Maybe::Just("") - │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 7│ encode Maybe.Just("") + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ 8│ } 9│ } diff --git a/spec/errors/field_access_expected_closing_parenthesis b/spec/errors/field_access_expected_closing_parenthesis new file mode 100644 index 000000000..0e5f29935 --- /dev/null +++ b/spec/errors/field_access_expected_closing_parenthesis @@ -0,0 +1,15 @@ +component Main { + fun render : Html { + .a(A +-------------------------------------------------------------------------------- +░ ERROR (FIELD_ACCESS_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the closing parentheses of a field access but I found "a space" +instead: + + ┌ ./spec/errors/field_access_expected_closing_parenthesis:3:8 + ├──────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ .a(A + │ ⌃⌃⌃⌃ diff --git a/spec/errors/field_access_expected_opening_parenthesis b/spec/errors/field_access_expected_opening_parenthesis new file mode 100644 index 000000000..5f69d4c73 --- /dev/null +++ b/spec/errors/field_access_expected_opening_parenthesis @@ -0,0 +1,15 @@ +component Main { + fun render : Html { + .a +-------------------------------------------------------------------------------- +░ ERROR (FIELD_ACCESS_EXPECTED_OPENING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the opening parenthesis of a field access but I found "a space" +instead: + + ┌ ./spec/errors/field_access_expected_opening_parenthesis:3:6 + ├──────────────────────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ .a + │ ⌃⌃⌃⌃ diff --git a/spec/errors/field_access_expected_type b/spec/errors/field_access_expected_type new file mode 100644 index 000000000..dbb7cd73c --- /dev/null +++ b/spec/errors/field_access_expected_type @@ -0,0 +1,14 @@ +component Main { + fun render : Html { + .a( +-------------------------------------------------------------------------------- +░ ERROR (FIELD_ACCESS_EXPECTED_TYPE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +I was expecting the type of a field access but I found "a space" instead: + + ┌ ./spec/errors/field_access_expected_type:3:7 + ├───────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ .a( + │ ⌃⌃⌃⌃ diff --git a/spec/errors/html_expression_expected_closing_tag b/spec/errors/field_access_expected_variable similarity index 53% rename from spec/errors/html_expression_expected_closing_tag rename to spec/errors/field_access_expected_variable index 2ef487e1c..b748546d4 100644 --- a/spec/errors/html_expression_expected_closing_tag +++ b/spec/errors/field_access_expected_variable @@ -1,15 +1,15 @@ component Main { fun render : Html { - <{ + . -------------------------------------------------------------------------------- -░ ERROR (HTML_EXPRESSION_EXPECTED_CLOSING_TAG) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ +░ ERROR (FIELD_ACCESS_EXPECTED_VARIABLE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ -I was expecting the closing tag of an HTML expression but I found "a space" -instead: +I was expecting the field of the accessed entity of a field access but I found +"a space" instead: - ┌ ./spec/errors/html_expression_expected_closing_tag:3:6 - ├─────────────────────────────────────────────────────── + ┌ ./spec/errors/field_access_expected_variable:3:5 + ├───────────────────────────────────────────────── 1│ component Main { 2│ fun render : Html { - 3│ <{ - │ ⌃⌃⌃⌃ + 3│ . + │ ⌃⌃⌃⌃ diff --git a/spec/errors/field_access_field_not_found b/spec/errors/field_access_field_not_found new file mode 100644 index 000000000..6978682d9 --- /dev/null +++ b/spec/errors/field_access_field_not_found @@ -0,0 +1,28 @@ +type A { + b: String +} + +component Main { + fun render : Html { + .a(A) + } +} +-------------------------------------------------------------------------------- +░ ERROR (FIELD_ACCESS_FIELD_NOT_FOUND) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The field a does not exists on the type: + + A(b: String) + +The field access in question is here: + + ┌ ./spec/errors/field_access_field_not_found:7:5 + ├─────────────────────────────────────────────── + 3│ } + 4│ + 5│ component Main { + 6│ fun render : Html { + 7│ .a(A) + │ ⌃⌃⌃⌃⌃ + 8│ } + 9│ } diff --git a/spec/errors/field_access_not_record b/spec/errors/field_access_not_record new file mode 100644 index 000000000..72bd3026f --- /dev/null +++ b/spec/errors/field_access_not_record @@ -0,0 +1,22 @@ +component Main { + fun render : Html { + .a(String) + } +} +-------------------------------------------------------------------------------- +░ ERROR (FIELD_ACCESS_NOT_RECORD) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +The type of the accessed entity is not a record: + + String + +The field access in question is here: + + ┌ ./spec/errors/field_access_not_record:3:5 + ├────────────────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ .a(String) + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 4│ } + 5│ } diff --git a/spec/errors/for_array_or_set_arguments_mismatch b/spec/errors/for_array_or_set_arguments_mismatch index 73bc663e1..585667cc2 100644 --- a/spec/errors/for_array_or_set_arguments_mismatch +++ b/spec/errors/for_array_or_set_arguments_mismatch @@ -2,7 +2,7 @@ component Main { fun render : Array(Html) { for (item, item2, item3 of ["A", "B"]) {
- <{ item }> + item
} } @@ -20,6 +20,6 @@ to the have only 1 argument: 3│ for (item, item2, item3 of ["A", "B"]) { │ ⌃⌃⌃⌃ 4│
- 5│ <{ item }> + 5│ item 6│
7│ } diff --git a/spec/errors/for_condition_type_mismatch b/spec/errors/for_condition_type_mismatch index 737053451..c4c59575e 100644 --- a/spec/errors/for_condition_type_mismatch +++ b/spec/errors/for_condition_type_mismatch @@ -2,7 +2,7 @@ component Main { fun render : Array(Html) { for (item of ["A", "B"]) {
- <{ item }> + item
} when { item @@ -25,7 +25,7 @@ The value in question is here: ┌ ./spec/errors/for_condition_type_mismatch:8:7 ├────────────────────────────────────────────── 4│
- 5│ <{ item }> + 5│ item 6│
7│ } when { 8│ item diff --git a/spec/errors/for_map_arguments_mismatch b/spec/errors/for_map_arguments_mismatch index fc5136b5d..9e333549e 100644 --- a/spec/errors/for_map_arguments_mismatch +++ b/spec/errors/for_map_arguments_mismatch @@ -6,7 +6,7 @@ component Main { fun render : Array(Html) { for (item of map) {
- <{ item }> + item
} } @@ -26,6 +26,6 @@ arguments: 7│ for (item of map) { │ ⌃⌃⌃⌃ 8│
- 9│ <{ item }> + 9│ item 10│
11│ } diff --git a/spec/errors/for_type_mismatch b/spec/errors/for_type_mismatch index f3e18b487..34a57267d 100644 --- a/spec/errors/for_type_mismatch +++ b/spec/errors/for_type_mismatch @@ -2,7 +2,7 @@ component Main { fun render : Array(Html) { for (item of "A") {
- <{ item }> + item
} } @@ -29,6 +29,6 @@ The iterable object in question is here: 3│ for (item of "A") { │ ⌃⌃⌃ 4│
- 5│ <{ item }> + 5│ item 6│
7│ } diff --git a/spec/errors/here_doc_interpolation_type_mismatch b/spec/errors/here_doc_interpolation_type_mismatch index 2538fadbd..58b2f0d5e 100644 --- a/spec/errors/here_doc_interpolation_type_mismatch +++ b/spec/errors/here_doc_interpolation_type_mismatch @@ -8,7 +8,7 @@ component Main { -------------------------------------------------------------------------------- ░ ERROR (HERE_DOC_INTERPOLATION_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ -An interpolation in here document is causing a mismatch. +An interpolation in a here document is causing a mismatch. I was expecting: diff --git a/spec/errors/html_content_type_mismatch b/spec/errors/html_content_type_mismatch index 7567dfd75..276e174f8 100644 --- a/spec/errors/html_content_type_mismatch +++ b/spec/errors/html_content_type_mismatch @@ -1,6 +1,6 @@ component Main { fun render : Html { -
<{ 0 }>
+
0
} } -------------------------------------------------------------------------------- @@ -19,11 +19,11 @@ Instead it is: Number - ┌ ./spec/errors/html_content_type_mismatch:3:13 + ┌ ./spec/errors/html_content_type_mismatch:3:10 ├────────────────────────────────────────────── 1│ component Main { 2│ fun render : Html { - 3│
<{ 0 }>
- │ ⌃ + 3│
0
+ │ ⌃ 4│ } 5│ } diff --git a/spec/errors/html_element_ref_forbidden b/spec/errors/html_element_ref_forbidden index 82d6218e0..41ac998f5 100644 --- a/spec/errors/html_element_ref_forbidden +++ b/spec/errors/html_element_ref_forbidden @@ -17,6 +17,6 @@ The use of "ref" attribute is forbidden: 4│ } 5│ } -If you want to assign a variable to an element, use the as keyword: +Please use the "as" keyword instead:
diff --git a/spec/errors/html_style_argument_size_mismatch b/spec/errors/html_style_argument_size_mismatch index 4db2dfb6a..5ddd2e362 100644 --- a/spec/errors/html_style_argument_size_mismatch +++ b/spec/errors/html_style_argument_size_mismatch @@ -8,9 +8,18 @@ component Main { } } -------------------------------------------------------------------------------- -░ ERROR (HTML_STYLE_ARGUMENT_SIZE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ +░ ERROR (CALL_ARGUMENT_SIZE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ -The style call takes 2 arguments, while you tried to call it with 1: +The function you called takes 2 arguments, while you tried to call it with 1. + +The type of the function is: + + Function( + name: String, + active: Bool, + Void) + +The call in question is here: ┌ ./spec/errors/html_style_argument_size_mismatch:7:9 ├──────────────────────────────────────────────────── diff --git a/spec/errors/html_style_argument_type_mismatch b/spec/errors/html_style_argument_type_mismatch index 51cb32b88..0d23b859f 100644 --- a/spec/errors/html_style_argument_type_mismatch +++ b/spec/errors/html_style_argument_type_mismatch @@ -8,11 +8,11 @@ component Main { } } -------------------------------------------------------------------------------- -░ ERROR (HTML_STYLE_ARGUMENT_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ +░ ERROR (CALL_ARGUMENT_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ -The 1st argument to a style call is causing a mismatch. +The 1st argument to a function is causing a mismatch. -The style is expecting the 1st argument to be: +The function is expecting the 1st argument to be: String @@ -20,7 +20,7 @@ Instead it is: Bool -The style call in question is here: +The call in question is here: ┌ ./spec/errors/html_style_argument_type_mismatch:7:9 ├──────────────────────────────────────────────────── diff --git a/spec/errors/if_else_type_mismatch b/spec/errors/if_else_type_mismatch index 2adf3a3bf..d32127247 100644 --- a/spec/errors/if_else_type_mismatch +++ b/spec/errors/if_else_type_mismatch @@ -10,8 +10,7 @@ component Main { -------------------------------------------------------------------------------- ░ ERROR (IF_ELSE_TYPE_MISMATCH) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ -The falsy (else) branch of an if expression does not match the type of the -truthy branch. +The else branch of an if expression does not match the type of the main branch. I was expecting: diff --git a/spec/errors/member_access_expected_variable b/spec/errors/member_access_expected_variable deleted file mode 100644 index 294425144..000000000 --- a/spec/errors/member_access_expected_variable +++ /dev/null @@ -1,14 +0,0 @@ -component Main { - fun render : Html { - . --------------------------------------------------------------------------------- -░ ERROR (MEMBER_ACCESS_EXPECTED_VARIABLE) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ - -I was expecting the field of the accessed entity but I found "a space" instead: - - ┌ ./spec/errors/member_access_expected_variable:3:5 - ├────────────────────────────────────────────────── - 1│ component Main { - 2│ fun render : Html { - 3│ . - │ ⌃⌃⌃⌃ diff --git a/spec/errors/operation_or_not_maybe_or_result b/spec/errors/operation_or_not_maybe_or_result index 7b909839b..ebc634f2e 100644 --- a/spec/errors/operation_or_not_maybe_or_result +++ b/spec/errors/operation_or_not_maybe_or_result @@ -1,4 +1,4 @@ -enum Maybe(a) { +type Maybe(a) { Nothing Just(a) } diff --git a/spec/errors/operation_or_type_mismatch b/spec/errors/operation_or_type_mismatch index ce9c05574..c09be3780 100644 --- a/spec/errors/operation_or_type_mismatch +++ b/spec/errors/operation_or_type_mismatch @@ -1,11 +1,11 @@ -enum Maybe(a) { +type Maybe(a) { Nothing Just(a) } component Main { fun render : String { - Maybe::Just(0) or "Hello" + Maybe.Just(0) or "Hello" } } -------------------------------------------------------------------------------- @@ -24,13 +24,13 @@ Instead it is: The operation in question is here: - ┌ ./spec/errors/operation_or_type_mismatch:8:16 + ┌ ./spec/errors/operation_or_type_mismatch:8:15 ├────────────────────────────────────────────── 4│ } 5│ 6│ component Main { 7│ fun render : String { - 8│ Maybe::Just(0) or "Hello" - │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 8│ Maybe.Just(0) or "Hello" + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ 9│ } 10│ } diff --git a/spec/errors/property_with_type_variables b/spec/errors/property_with_type_variables index 9d4046114..4c762fe96 100644 --- a/spec/errors/property_with_type_variables +++ b/spec/errors/property_with_type_variables @@ -4,7 +4,7 @@ type Maybe(a) { } component Test { - property name : Maybe(a) = Maybe::Nothing + property name : Maybe(a) = Maybe.Nothing fun render : Html {
@@ -35,8 +35,8 @@ The property in question is here: 4│ } 5│ 6│ component Test { - 7│ property name : Maybe(a) = Maybe::Nothing - │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ + 7│ property name : Maybe(a) = Maybe.Nothing + │ ⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃⌃ 8│ 9│ fun render : Html { 10│
diff --git a/spec/errors/record_not_found_matching_record_definition b/spec/errors/record_not_found_matching_record_definition index ceffa3971..592fd10e7 100644 --- a/spec/errors/record_not_found_matching_record_definition +++ b/spec/errors/record_not_found_matching_record_definition @@ -3,7 +3,7 @@ component Main { fun render : Html {
- <{ data.name }> + data.name
} } @@ -24,4 +24,4 @@ It was used here: 3│ 4│ fun render : Html { 5│
- 6│ <{ data.name }> + 6│ data.name diff --git a/spec/errors/record_update_not_found_key b/spec/errors/record_update_not_found_key index 9088a2687..90ebcf366 100644 --- a/spec/errors/record_update_not_found_key +++ b/spec/errors/record_update_not_found_key @@ -1,4 +1,4 @@ -record Test { +type Test { a : String, b : Number } diff --git a/spec/errors/record_update_not_updating_record b/spec/errors/record_update_not_updating_record index dd5c7325c..d2d3954ba 100644 --- a/spec/errors/record_update_not_updating_record +++ b/spec/errors/record_update_not_updating_record @@ -1,4 +1,4 @@ -record Test { +type Test { a : String, b : Number } diff --git a/spec/errors/record_update_type_mismatch b/spec/errors/record_update_type_mismatch index 28cfaa571..231299d2e 100644 --- a/spec/errors/record_update_type_mismatch +++ b/spec/errors/record_update_type_mismatch @@ -1,4 +1,4 @@ -record Test { +type Test { a : String, b : Number } diff --git a/spec/errors/record_with_holes b/spec/errors/record_with_holes index 72013224b..e36f5330f 100644 --- a/spec/errors/record_with_holes +++ b/spec/errors/record_with_holes @@ -1,4 +1,4 @@ -record Test { +type Test { a : Array(a), b : Number } @@ -9,7 +9,7 @@ Records with type variables are not allow at this time. I found one here: ┌ ./spec/errors/record_with_holes:1:1 ├──────────────────────────────────── - 1│ record Test { + 1│ type Test { 2│ a : Array(a), 3│ b : Number 4│ } diff --git a/spec/errors/statement_return_type_mismatch b/spec/errors/statement_return_type_mismatch index 9cf3f425d..871abf634 100644 --- a/spec/errors/statement_return_type_mismatch +++ b/spec/errors/statement_return_type_mismatch @@ -1,12 +1,12 @@ -enum Test { +type Test { A(String) B(String) } component Main { fun render : String { - let Test::B(x) = - Test::A("Hello") or return 0 + let Test.B(x) = + Test.A("Hello") or return 0 x } @@ -24,14 +24,14 @@ I was expecting: It return call in question is here: - ┌ ./spec/errors/statement_return_type_mismatch:9:27 + ┌ ./spec/errors/statement_return_type_mismatch:9:26 ├────────────────────────────────────────────────── 5│ 6│ component Main { 7│ fun render : String { - 8│ let Test::B(x) = - 9│ Test::A("Hello") or return 0 - │ ⌃⌃⌃⌃⌃⌃⌃⌃ + 8│ let Test.B(x) = + 9│ Test.A("Hello") or return 0 + │ ⌃⌃⌃⌃⌃⌃⌃⌃ 10│ 11│ x 12│ } @@ -42,8 +42,8 @@ The returned value of the block is here: ┌ ./spec/errors/statement_return_type_mismatch:11:5 ├────────────────────────────────────────────────── 7│ fun render : String { - 8│ let Test::B(x) = - 9│ Test::A("Hello") or return 0 + 8│ let Test.B(x) = + 9│ Test.A("Hello") or return 0 10│ 11│ x │ ⌃ diff --git a/spec/errors/string_literal_interpolation_type_mismatch b/spec/errors/string_literal_interpolation_type_mismatch index d6395a71d..c595e5d99 100644 --- a/spec/errors/string_literal_interpolation_type_mismatch +++ b/spec/errors/string_literal_interpolation_type_mismatch @@ -1,6 +1,6 @@ component Main { fun render : String { - let name = {} + let name = void "Hello There #{name}!" } @@ -14,7 +14,7 @@ An interpolation in string is causing a mismatch. The expected type is: Instead it is: - Unit + Void The interpolation in question is here: @@ -22,7 +22,7 @@ The interpolation in question is here: ├────────────────────────────────────────────────────────────── 1│ component Main { 2│ fun render : String { - 3│ let name = {} + 3│ let name = void 4│ 5│ "Hello There #{name}!" │ ⌃⌃⌃⌃⌃⌃⌃ diff --git a/spec/errors/tuple_destructuring_expected_closing_parenthesis b/spec/errors/tuple_destructuring_expected_closing_parenthesis deleted file mode 100644 index 9b80da1ef..000000000 --- a/spec/errors/tuple_destructuring_expected_closing_parenthesis +++ /dev/null @@ -1,17 +0,0 @@ -component Main { - fun render : String { - case #("a", "b") { - #(a, b, c --------------------------------------------------------------------------------- -░ ERROR (TUPLE_DESTRUCTURING_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░ - -I was expecting the closing parenthesis of a tuple destructuring but I found "a -space" instead: - - ┌ ./spec/errors/tuple_destructuring_expected_closing_parenthesis:4:15 - ├──────────────────────────────────────────────────────────────────── - 1│ component Main { - 2│ fun render : String { - 3│ case #("a", "b") { - 4│ #(a, b, c - │ ⌃⌃⌃⌃ diff --git a/spec/errors/tuple_literal_expected_closing_parenthesis b/spec/errors/tuple_literal_expected_closing_parenthesis index 04ba5cbaf..b8e333f53 100644 --- a/spec/errors/tuple_literal_expected_closing_parenthesis +++ b/spec/errors/tuple_literal_expected_closing_parenthesis @@ -1,6 +1,6 @@ component Main { fun render : String { - {""}[0] + {"", ""}[0] } } --------------------------------------------------------------------------------- \ No newline at end of file +-------------------------------------------------------------------------------- diff --git a/spec/errors/type_definition_not_defined_parameter b/spec/errors/type_definition_not_defined_parameter index 48cf097de..cac6da2a9 100644 --- a/spec/errors/type_definition_not_defined_parameter +++ b/spec/errors/type_definition_not_defined_parameter @@ -1,4 +1,4 @@ -enum A { +type A { B(a) } -------------------------------------------------------------------------------- @@ -9,7 +9,7 @@ parameter was not defined in the type definition: ┌ ./spec/errors/type_definition_not_defined_parameter:2:5 ├──────────────────────────────────────────────────────── - 1│ enum A { + 1│ type A { 2│ B(a) │ ⌃ 3│ } diff --git a/spec/errors/type_definition_unused_parameter b/spec/errors/type_definition_unused_parameter index 9c3ee2d9c..3b3444fac 100644 --- a/spec/errors/type_definition_unused_parameter +++ b/spec/errors/type_definition_unused_parameter @@ -1,4 +1,4 @@ -enum A(a, b, c) { +type A(a, b, c) { B C } @@ -10,7 +10,7 @@ by any of the options: ┌ ./spec/errors/type_definition_unused_parameter:1:8 ├─────────────────────────────────────────────────── - 1│ enum A(a, b, c) { + 1│ type A(a, b, c) { │ ⌃ 2│ B 3│ C diff --git a/spec/errors/type_destructuring_expected_closing_parenthesis b/spec/errors/type_destructuring_expected_closing_parenthesis index 8cc5d0332..fb6f0f290 100644 --- a/spec/errors/type_destructuring_expected_closing_parenthesis +++ b/spec/errors/type_destructuring_expected_closing_parenthesis @@ -1,18 +1,18 @@ module Test { fun toString (status : Status) : String { case (status) { - A::B( + A.B( -------------------------------------------------------------------------------- ░ ERROR (TYPE_DESTRUCTURING_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░ I was expecting the closing parenthesis of an type destructuring but I found "a space" instead: - ┌ ./spec/errors/type_destructuring_expected_closing_parenthesis:4:11 + ┌ ./spec/errors/type_destructuring_expected_closing_parenthesis:4:10 ├─────────────────────────────────────────────────────────────────── 1│ module Test { 2│ fun toString (status : Status) : String { 3│ case (status) { - 4│ A::B( - │ ⌃⌃⌃⌃ + 4│ A.B( + │ ⌃⌃⌃⌃ diff --git a/spec/errors/type_variant_expected_closing_parenthesis b/spec/errors/type_variant_expected_closing_parenthesis index 5b4a61d6b..950d3d599 100644 --- a/spec/errors/type_variant_expected_closing_parenthesis +++ b/spec/errors/type_variant_expected_closing_parenthesis @@ -1,4 +1,4 @@ -enum Test { +type Test { A( -------------------------------------------------------------------------------- ░ ERROR (TYPE_VARIANT_EXPECTED_CLOSING_PARENTHESIS) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░ @@ -8,6 +8,6 @@ instead: ┌ ./spec/errors/type_variant_expected_closing_parenthesis:2:4 ├──────────────────────────────────────────────────────────── - 1│ enum Test { + 1│ type Test { 2│ A( │ ⌃⌃⌃⌃ diff --git a/spec/errors/unkown_builtin b/spec/errors/unkown_builtin new file mode 100644 index 000000000..cfc951e57 --- /dev/null +++ b/spec/errors/unkown_builtin @@ -0,0 +1,22 @@ +component Main { + fun render : Html { + `#{%wtf%}` + +
+ } +} +-------------------------------------------------------------------------------- +░ ERROR (UNKOWN_BUILTIN) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + +There is no builtin with the name: wtf + + ┌ ./spec/errors/unkown_builtin:3:8 + ├───────────────────────────────── + 1│ component Main { + 2│ fun render : Html { + 3│ `#{%wtf%}` + │ ⌃⌃⌃⌃⌃ + 4│ + 5│
+ 6│ } + 7│ } diff --git a/spec/errors/use_condition_mismatch b/spec/errors/use_condition_mismatch index 92c136947..eac4f810d 100644 --- a/spec/errors/use_condition_mismatch +++ b/spec/errors/use_condition_mismatch @@ -1,4 +1,4 @@ -record Provider.Data { +type Provider.Data { a : String, b : String } diff --git a/spec/errors/use_subscription_mismatch b/spec/errors/use_subscription_mismatch index 9658bef43..e165fd7fb 100644 --- a/spec/errors/use_subscription_mismatch +++ b/spec/errors/use_subscription_mismatch @@ -1,9 +1,9 @@ -record Provider.Data { +type Provider.Data { a : String, b : Bool } -record Test { +type Test { a : String, b : String } diff --git a/spec/examples/access b/spec/examples/access index b3cdd33e0..299c738cd 100644 --- a/spec/examples/access +++ b/spec/examples/access @@ -5,9 +5,9 @@ component Main { ----------------------------------------------------------access_expected_field component Main { fun render { - A:: + A. ---------------------------------------------------------access_field_not_found -record Blah { +type Blah { blah : String } @@ -28,7 +28,7 @@ component Main { } } --------------------------------------------------------------access_not_record -record Blah { +type Blah { blah : String } @@ -40,10 +40,6 @@ component Main { blah.blah.blah } } -----------------------------------------------------------access_expected_field -component Main { - fun render : String { - A. --------------------------------------------------------------access_not_record module Test { fun b : Function(String) { @@ -69,11 +65,11 @@ component Main { } } ------------------------------------------------------------------------------- -record Blah1 { +type Blah1 { blah : String } -record Blah { +type Blah { blah : Blah1 } @@ -115,7 +111,7 @@ store Test { } } ------------------------------------------------------------------------------- -record Test { +type Test { test : String } @@ -135,7 +131,7 @@ component Main { } } ------------------------------------------------------------------------------- -record Test { +type Test { test : String } diff --git a/spec/examples/access_call b/spec/examples/access_call index 9436344f0..07d553b8d 100644 --- a/spec/examples/access_call +++ b/spec/examples/access_call @@ -1,4 +1,4 @@ -enum Maybe(value) { +type Maybe(value) { Just(value) Nothing } @@ -16,8 +16,8 @@ component Test { component Main { fun handleClick : String { case (test) { - Maybe::Just(component) => component.something("asd") - Maybe::Nothing => "asd" + Just(component) => component.something("asd") + Nothing => "asd" } } @@ -28,7 +28,7 @@ component Main { } } -------------------------------------------------------------------------------- -enum Maybe(value) { +type Maybe(value) { Just(value) Nothing } @@ -46,8 +46,8 @@ component Test { component Main { fun handleClick : String { case (test) { - Maybe::Just(component) => handleComponent(component) - Maybe::Nothing => "asd" + Just(component) => handleComponent(component) + Nothing => "asd" } } diff --git a/spec/examples/argument b/spec/examples/argument index fad73a51a..bee518528 100644 --- a/spec/examples/argument +++ b/spec/examples/argument @@ -7,6 +7,16 @@ component Main { ------------------------------------------------argument_expected_default_value component Main { fun render (a : String = +---------------------------------------------------------argument_type_mismatch +component Main { + fun test (a : String = 10) : String { + a + } + + fun render : String { + test("") + } +} ------------------------------------------------------------------------------- component Main { fun test (a : String) : String { diff --git a/spec/examples/array_access b/spec/examples/array_access deleted file mode 100644 index 300379e51..000000000 --- a/spec/examples/array_access +++ /dev/null @@ -1,74 +0,0 @@ -----------------------------------------------------array_access_expected_index -component Main { - fun render : String { - array[ -------------------------------------------array_access_expected_closing_bracket -component Main { - fun render : String { - array[0 ---------------------------------------------------array_access_index_not_number -component Main { - fun test : Maybe(String) { - [ - "Hello", - "Blah", - "Joe" - ]["asd"] - } - - fun render : Html { - test() - -
- } -} -------------------------------------------------------array_access_not_an_array -component Main { - fun test : Maybe(String) { - {}[0] - } - - fun render : Html { - test() - -
- } -} ------------------------------------------------------array_access_invalid_tuple -component Main { - fun test : Maybe(String) { - {"Hello"}[1] - } - - fun render : Html { - test() - -
- } -} -------------------------------------------------------------------------------- -component Main { - fun test : Maybe(String) { - [ - "Hello", - "Blah", - "Joe" - ][1] - } - - fun render : String { - "" - } -} --------------------------------------------------------------------------------- -component Main { - fun test : String { - {"Hello"}[0] - } - - fun render : Html { - test() - -
- } -} diff --git a/spec/examples/bracket_access b/spec/examples/bracket_access new file mode 100644 index 000000000..4f681f4d6 --- /dev/null +++ b/spec/examples/bracket_access @@ -0,0 +1,76 @@ +--------------------------------------------------bracket_access_expected_index +component Main { + fun render : String { + array[ +----------------------------------------bracket_access_expected_closing_bracket +component Main { + fun render : String { + array[0 +------------------------------------------------bracket_access_index_not_number +component Main { + fun render : Html { + [ + "Hello", + "Blah", + "Joe" + ]["asd"] + +
+ } +} +--------------------------------------------------bracket_access_not_accessible +component Main { + fun render : Html { + ""[0] + +
+ } +} +---------------------------------------------------bracket_access_invalid_tuple +component Main { + fun render : Html { + {"Hello", ""}[2] + +
+ } +} +--------------------------------------------bracket_access_invalid_tuple_access +component Main { + fun render : Html { + {"Hello", ""}["asd"] + +
+ } +} +---------------------------------------------bracket_access_invalid_tuple_index +component Main { + fun render : Html { + {"Hello", ""}[0.2] + +
+ } +} +-----------------------------------------------bracket_access_index_not_map_key +component Main { + fun render : String { + { 0 => "a" }["a"] + } +} +------------------------------------------------------------------------------- +component Main { + fun render : String { + [ + "Hello", + "Blah", + "Joe" + ][1] or "" + } +} +-------------------------------------------------------------------------------- +component Main { + fun render : Html { + {"Hello", ""}[0] + +
+ } +} diff --git a/spec/examples/html_expression b/spec/examples/builtin similarity index 56% rename from spec/examples/html_expression rename to spec/examples/builtin index 2f9ca1219..81ea9a5cc 100644 --- a/spec/examples/html_expression +++ b/spec/examples/builtin @@ -1,10 +1,15 @@ --------------------------------------------html_expression_expected_closing_tag component Main { fun render : Html { - <{ -------------------------------------------------------------------------------- + `#{%decodeBoolean%}` + +
+ } +} +------------------------------------------------------------------unkown_builtin component Main { fun render : Html { - <{}> + `#{%wtf%}` + +
} } diff --git a/spec/examples/call b/spec/examples/call index d9dd653d0..89263dd19 100644 --- a/spec/examples/call +++ b/spec/examples/call @@ -33,14 +33,14 @@ component Main { } } ----------------------------------------------------call_argument_type_mismatch -enum A { +type A { B(String) C } component Main { fun render : String { - case (A::B(0)) { + case (A.B(0)) { => "" } } @@ -123,16 +123,6 @@ component Main { Test.b() } } -----------------------------------------------------call_argument_type_mismatch -record Test { - test : String -} - -component Main { - fun render : String { - .asd({test: "Hello"}) - } -} ------------------------------------------------------------call_not_a_function component Main { const A = "a" @@ -142,7 +132,7 @@ component Main { A("A is a String constant, but calling it like a function compiles")
- <{ a }> + a
} } diff --git a/spec/examples/case b/spec/examples/case index afd10bc41..71fd04ff2 100644 --- a/spec/examples/case +++ b/spec/examples/case @@ -35,16 +35,16 @@ component Main { } } -----------------------------------------------------------case_unnecessary_all -enum A { +type A { B C } component Main { fun render : String { - case (A::B) { - A::B => "a" - A::C => "c" + case (A.B) { + A.B => "a" + A.C => "c" => "x" } } @@ -58,7 +58,7 @@ component Main { } } ----------------------------------------------------------case_type_not_covered -enum A { +type A { B C D @@ -66,9 +66,9 @@ enum A { component Main { fun render : String { - case (A::B) { - A::B => "a" - A::C => "c" + case (A.B) { + A.B => "a" + A.C => "c" } } } @@ -83,7 +83,7 @@ component Main { } } ------------------------------------------------------------------------------- -enum Maybe(value) { +type Maybe(value) { Just(value) Nothing } @@ -91,8 +91,8 @@ enum Maybe(value) { component Main { fun testCase : Maybe(Number) { case (-1) { - -1 => Maybe::Nothing - => Maybe::Just(2) + -1 => Maybe.Nothing + => Maybe.Just(2) } } @@ -110,7 +110,7 @@ module Test { component Main { fun render : String { case ("x") { - Test:X => "x" + Test.X => "x" "a" => "a" "b" => "b" => "c" diff --git a/spec/examples/decode b/spec/examples/decode index b1f136913..7f7d2076d 100644 --- a/spec/examples/decode +++ b/spec/examples/decode @@ -15,7 +15,7 @@ component Main { fun render : Html { decode as ---------------------------------------------------------decode_expected_object -record X { +type X { name : String } @@ -27,7 +27,7 @@ component Main { } } ------------------------------------------------------------decode_complex_type -record X { +type X { name : Blah } @@ -39,7 +39,7 @@ component Main { } } ------------------------------------------------------------decode_complex_type -record X { +type X { name : Maybe(Blah) } @@ -51,7 +51,7 @@ component Main { } } ------------------------------------------------------------------------------- -record X { +type X { name : String } diff --git a/spec/examples/destructuring b/spec/examples/destructuring index 13cd097ed..fe2692cb4 100644 --- a/spec/examples/destructuring +++ b/spec/examples/destructuring @@ -32,11 +32,6 @@ component Main { } } } --------------------------------tuple_destructuring_expected_closing_parenthesis -component Main { - fun render : String { - case #("a", "b") { - #(a, b, c ----------------------------------------------------destructuring_type_mismatch component Main { fun render : String { @@ -62,14 +57,14 @@ component Main { } } ----------------------------------------------------destructuring_type_mismatch -enum T { +type T { A(String) B } component Main { fun render : String { - if (let T::A(a) = "") { + if (let T.A(a) = "") { a } else { "b" @@ -93,29 +88,29 @@ component Main { -----------------------------------------------------destructuring_type_missing component Main { fun render : String { - let Maybe::Just(a) = "" or return "" + let Maybe.Just(a) = "" or return "" "" } } ---------------------------------------------destructuring_type_variant_missing -enum Maybe { +type Maybe { Nothing } component Main { fun render : String { - let Maybe::Just(a) = "" or return "" + let Maybe.Just(a) = "" or return "" "" } } -----------------------------------------------destructuring_type_field_missing -enum Maybe { +type Maybe { Just(item : String) } component Main { fun render : String { - let Maybe::Just(key) = Maybe::Just(item: "") or return "" + let Maybe.Just(key) = Maybe.Just(item: "") or return "" "" } } @@ -130,7 +125,7 @@ component Main { } } ------------------------------------------------------------------------------- -enum Maybe(a) { +type Maybe(a) { Just(a) Nothing } diff --git a/spec/examples/directives/highlight_file b/spec/examples/directives/highlight_file index b58adf7e1..8f721bd60 100644 --- a/spec/examples/directives/highlight_file +++ b/spec/examples/directives/highlight_file @@ -16,12 +16,6 @@ component Main { @highlight-file(File.mint) } } ------------------------------------------highlight_file_directive_expected_mint -component Main { - fun render : Html { - @highlight-file(../../fixtures/icon-not-svg) - } -} ------------------------------------------------------------------------------- component Main { fun render : Html { diff --git a/spec/examples/encode b/spec/examples/encode index b08b4d8ba..53be30244 100644 --- a/spec/examples/encode +++ b/spec/examples/encode @@ -3,12 +3,12 @@ component Main { fun render : Html { encode ------------------------------------------------------------encode_complex_type -enum Maybe { +type Maybe { Just(String) } component Main { fun render : Html { - encode Maybe::Just("") + encode Maybe.Just("") } } diff --git a/spec/examples/field_access b/spec/examples/field_access new file mode 100644 index 000000000..53ec4e9eb --- /dev/null +++ b/spec/examples/field_access @@ -0,0 +1,36 @@ +-------------------------------------------------field_access_expected_variable +component Main { + fun render : Html { + . +--------------------------------------field_access_expected_opening_parenthesis +component Main { + fun render : Html { + .a +-----------------------------------------------------field_access_expected_type +component Main { + fun render : Html { + .a( +--------------------------------------field_access_expected_closing_parenthesis +component Main { + fun render : Html { + .a(A +---------------------------------------------------field_access_field_not_found +type Test { + test : String +} + +component Main { + fun render : String { + .asd(Test)({test: "Hello"}) + } +} +------------------------------------------------------------------------------- +type Test { + test : String +} + +component Main { + fun render : String { + .test(Test)({test: "Hello"}) + } +} diff --git a/spec/examples/for_expression b/spec/examples/for_expression index 5e49b6142..d391bef18 100644 --- a/spec/examples/for_expression +++ b/spec/examples/for_expression @@ -28,7 +28,7 @@ component Main { fun render : Array(Html) { for (item of "A") {
- <{ item }> + item
} } @@ -38,7 +38,7 @@ component Main { fun render : Array(Html) { for (item, item2, item3 of ["A", "B"]) {
- <{ item }> + item
} } @@ -52,7 +52,7 @@ component Main { fun render : Array(Html) { for (item of map) {
- <{ item }> + item
} } @@ -62,7 +62,7 @@ component Main { fun render : Array(Html) { for (item of ["A", "B"]) {
- <{ item }> + item
} when { item @@ -74,7 +74,7 @@ component Main { fun render : Array(Html) { for (item of ["A", "B"]) {
- <{ item }> + item
} } @@ -84,7 +84,7 @@ component Main { fun render : Array(Html) { for (item, index of ["A", "B"]) {
- <{ item }> + item
} } @@ -94,7 +94,7 @@ component Main { fun render : Array(Html) { for (key, value of `` as Map(String, String)) {
- <{ key }> + key
} } @@ -104,7 +104,7 @@ component Main { fun render : Array(Html) { for (key, value, index of `` as Map(String, String)) {
- <{ key }> + key
} } diff --git a/spec/examples/function b/spec/examples/function index aa36510a5..8593cf51f 100644 --- a/spec/examples/function +++ b/spec/examples/function @@ -72,7 +72,7 @@ component Main { } } ---------------------------------------------------------function_type_mismatch -enum Maybe(value) { +type Maybe(value) { Just(value) Nothing } @@ -80,8 +80,8 @@ enum Maybe(value) { component Main { fun testCase : Maybe(String) { case (-1) { - -1 => Maybe::Nothing - => Maybe::Just(2) + -1 => Maybe.Nothing + => Maybe.Just(2) } } diff --git a/spec/examples/html_element b/spec/examples/html_element index 27c412250..f6c45f27c 100644 --- a/spec/examples/html_element +++ b/spec/examples/html_element @@ -47,17 +47,17 @@ component Main { -----------------------------------------------------html_content_type_mismatch component Main { fun render : Html { -
<{ 0 }>
+
0
} } ------------------------------------------------------------------------------- component Main { fun render : Html { -
<{ "Hello" }>
+
"Hello"
} } ------------------------------------------------------------------------------- -enum Maybe(a) { +type Maybe(a) { Nothing Just(a) } @@ -65,11 +65,11 @@ enum Maybe(a) { component Main { fun render : Html { case test { - Maybe::Just(item) => "" - Maybe::Nothing => "" + Just(item) => "" + Nothing => "" } -
<{ "Hello" }>
+
"Hello"
} } ------------------------------------------------------------------------------- @@ -100,22 +100,22 @@ component Main { } } ------------------------------------------------------------------------------- -enum Maybe(a) { +type Maybe(a) { Nothing Just(a) } component Test { fun render : Html { -
<{ "Hello" }>
+
"Hello"
} } component Main { fun render : Html { case test { - Maybe::Just(item) => { item.test "" } - Maybe::Nothing => "" + Just(item) => { item.test "" } + Nothing => "" } diff --git a/spec/examples/html_style b/spec/examples/html_style index a5ae7364a..3a8015474 100644 --- a/spec/examples/html_style +++ b/spec/examples/html_style @@ -8,7 +8,7 @@ component Main { } } -----------------------------------------------html_style_argument_size_mismatch +----------------------------------------------------call_argument_size_mismatch component Main { style base (name : String, active : Bool) { color: red; @@ -18,7 +18,7 @@ component Main { } } -----------------------------------------------html_style_argument_size_mismatch +----------------------------------------------------call_argument_size_mismatch component Main { style base (name : String, active : Bool) { color: red; @@ -28,7 +28,7 @@ component Main { } } -----------------------------------------------html_style_argument_type_mismatch +----------------------------------------------------call_argument_type_mismatch component Main { style base (name : String, active : Bool) { color: red; diff --git a/spec/examples/if b/spec/examples/if index b958790ed..3d7fb74fc 100644 --- a/spec/examples/if +++ b/spec/examples/if @@ -51,14 +51,14 @@ component Main { } } ----------------------------------------------------------if_else_type_mismatch -enum T { +type T { A(String) B(Number) } component Main { fun render : String { - if (let T::B(a) = T::B(0)) { + if (let T.B(a) = T.B(0)) { a } else { "b" @@ -99,14 +99,14 @@ component Main { } } ------------------------------------------------------------------------------- -enum T { +type T { A(String) B } component Main { fun render : String { - if (let T::A(a) = T::A("")) { + if (let T.A(a) = T.A("")) { a } else { "b" @@ -114,14 +114,14 @@ component Main { } } ------------------------------------------------------------------------------- -enum T { +type T { A(String) B } component Main { fun render : String { - if (let T::A(a) = T::B) { + if (let T.A(a) = T.B) { a } else { "b" @@ -129,7 +129,7 @@ component Main { } } ------------------------------------------------------------------------------- -enum T { +type T { A(String) B } diff --git a/spec/examples/js b/spec/examples/js index d5a11fd41..75798f7e7 100644 --- a/spec/examples/js +++ b/spec/examples/js @@ -1,3 +1,12 @@ +-------------------------------------------------------js_expected_closing_tick +component Main { + fun render : String { + `"Hello" +---------------------------------------------------js_expected_type_or_variable +component Main { + fun render : String { + `"Hello"` as +------------------------------------------------------------------------------- component Main { fun render : String { `"Hello"` diff --git a/spec/examples/map b/spec/examples/map new file mode 100644 index 000000000..3d63a0a42 --- /dev/null +++ b/spec/examples/map @@ -0,0 +1,52 @@ +--------------------------------------------------map_field_expected_expression +component Main { + state data : Map(String, String) = { "name" => +----------------------------------------------------------map_expected_key_type +component Main { + state data : Map(String, String) = { "name" => "value" } of +-------------------------------------------------------------map_expected_arrow +component Main { + state data : Map(String, String) = { "name" => "value" } of String +--------------------------------------------------------map_expected_value_type +component Main { + state data : Map(String, String) = { "name" => "value" } of String => +---------------------------------------------------map_not_matches_defined_type +component Main { + state data : Map(String, String) = { "name" => "value" } of Number => String + + fun render : Html { +
+ data["name"] or "" +
+ } +} +------------------------------------------------------------map_key_not_matches +component Main { + state data : Map(String, String) = { "name" => "value", 0 => "value" } + + fun render : Html { +
+ data["name"] or "" +
+ } +} +----------------------------------------------------------map_value_not_matches +component Main { + state data : Map(String, String) = { "name" => "value", "name" => 0 } + + fun render : Html { +
+ data["name"] or "" +
+ } +} +-------------------------------------------------------------------------------- +component Main { + state data : Map(String, String) = { "name" => "value" } of String => String + + fun render : Html { +
+ data["name"] or "" +
+ } +} diff --git a/spec/examples/member_access b/spec/examples/member_access deleted file mode 100644 index 429575688..000000000 --- a/spec/examples/member_access +++ /dev/null @@ -1,14 +0,0 @@ -------------------------------------------------member_access_expected_variable -component Main { - fun render : Html { - . -------------------------------------------------------------------------------- -record Test { - test : String -} - -component Main { - fun render : String { - .test({test: "Hello"}) - } -} diff --git a/spec/examples/module b/spec/examples/module index 5c02fee46..0ea47851c 100644 --- a/spec/examples/module +++ b/spec/examples/module @@ -46,7 +46,7 @@ module Test { component Main { fun render : String { - Test.greet() + Test:FIRST + Test:SECOND + Test.greet() + Test.FIRST + Test.SECOND } } ------------------------------------------------------------------------------- diff --git a/spec/examples/operation b/spec/examples/operation index 158eeabed..9f0129630 100644 --- a/spec/examples/operation +++ b/spec/examples/operation @@ -50,20 +50,31 @@ component Main { true + "Hello" } } - +---------------------------------------------------operation_bool_type_mismatch +component Main { + fun render : String { + true && "Hello" + } +} +---------------------------------------------------operation_bool_type_mismatch +component Main { + fun render : String { + "Hello" && true + } +} -----------------------------------------------------operation_or_type_mismatch -enum Maybe(a) { +type Maybe(a) { Nothing Just(a) } component Main { fun render : String { - Maybe::Just(0) or "Hello" + Maybe.Just(0) or "Hello" } } -----------------------------------------------operation_or_not_maybe_or_result -enum Maybe(a) { +type Maybe(a) { Nothing Just(a) } @@ -118,14 +129,14 @@ component Main { } } ------------------------------------------------------------------------------- -enum Maybe(a) { +type Maybe(a) { Nothing Just(a) } component Main { fun render : String { - Maybe::Nothing or "Hello" + Maybe.Nothing or "Hello" } } ------------------------------------------------------------------------------- diff --git a/spec/examples/property b/spec/examples/property index 7e6fec593..cdd9e7626 100644 --- a/spec/examples/property +++ b/spec/examples/property @@ -50,7 +50,7 @@ component Main { } } ---------------------------------------------------------property_type_mismatch -record A { +type A { a : String } diff --git a/spec/examples/provider b/spec/examples/provider index 4e09d24d4..454c2c8e3 100644 --- a/spec/examples/provider +++ b/spec/examples/provider @@ -18,7 +18,7 @@ provider Provider : Subscription { } } ------------------------------------------------------------------------------- -record Subscription { +type Subscription { a : Bool } @@ -31,7 +31,7 @@ provider Provider : Subscription { } } ------------------------------------------------------------------------------- -record Subscription { +type Subscription { a : Bool } @@ -42,7 +42,7 @@ provider Provider : Subscription { } } ------------------------------------------------------------------------------- -record Subscription { +type Subscription { a : Bool } diff --git a/spec/examples/record b/spec/examples/record index 041adf06e..d0112a698 100644 --- a/spec/examples/record +++ b/spec/examples/record @@ -1,5 +1,5 @@ --------------------------------------------------------------record_with_holes -record Test { +type Test { a : Array(a), b : Number } @@ -9,7 +9,7 @@ component Main { fun render : Html {
- <{ data.name }> + data.name
} } @@ -19,7 +19,7 @@ component Test { fun render : Html {
- <{ data.name }> + data.name
} } @@ -59,7 +59,7 @@ component Main { } } ------------------------------------------------------------------------------- -record Test { +type Test { string : String } @@ -69,7 +69,7 @@ component Main { } } ------------------------------------------------------------------------------- -record Test { +type Test { a : String, b : Number } @@ -87,7 +87,7 @@ component Main { } } ------------------------------------------------------------------------------- -record A { +type A { name : String } @@ -96,12 +96,12 @@ component Main { fun render : Html {
- <{ data.name }> + data.name
} } ------------------------------------------------------------------------------- -record Test { +type Test { a : String, b : Number } @@ -119,12 +119,12 @@ component Main { } } ------------------------------------------------------------------------------- -record Test { +type Test { a : String, b : Number } -record Test2 { +type Test2 { a : String, b : Number } @@ -142,12 +142,12 @@ component Main { } } -------------------------------------------------------------------------------- -record Test { +type Test { a : String, b : Number } -record Test2 { +type Test2 { a : String, b : Number } diff --git a/spec/examples/record_update b/spec/examples/record_update index 3efd158c4..3daf6ed70 100644 --- a/spec/examples/record_update +++ b/spec/examples/record_update @@ -7,7 +7,7 @@ component Main { get record : Record(String, Bool) { { a | a: "" ----------------------------------------------record_update_not_updating_record -record Test { +type Test { a : String, b : Number } @@ -29,7 +29,7 @@ component Main { } } ----------------------------------------------------record_update_type_mismatch -record Test { +type Test { a : String, b : Number } @@ -55,7 +55,7 @@ component Main { } } ----------------------------------------------------record_update_not_found_key -record Test { +type Test { a : String, b : Number } @@ -81,7 +81,7 @@ component Main { } } ------------------------------------------------------------------------------- -record Test { +type Test { a : String, b : Number } diff --git a/spec/examples/recursion b/spec/examples/recursion index a714f7fbe..345a2d56a 100644 --- a/spec/examples/recursion +++ b/spec/examples/recursion @@ -12,7 +12,7 @@ component Main { } } -----------------------------------------------------------------------recursion +------------------------------------------------------------------------------- component Main { state greeting : String = greeting diff --git a/spec/examples/return_call b/spec/examples/return_call index bc5838c21..f759ee9a9 100644 --- a/spec/examples/return_call +++ b/spec/examples/return_call @@ -17,21 +17,21 @@ component Main { } } ------------------------------------------------------------------------------- -enum Test { +type Test { A(String) B(String) } component Main { fun render : String { - let Test::B(x) = - Test::A("Hello") or return "YES" + let Test.B(x) = + Test.A("Hello") or return "YES" "NO" } } ------------------------------------------------------------------------------- -enum Test { +type Test { A(String) B(String) } @@ -39,8 +39,8 @@ enum Test { component Main { fun render : String { let value = { - let Test::B(x) = - Test::A("Hello") or return "YES" + let Test.B(x) = + Test.A("Hello") or return "YES" "NO" } diff --git a/spec/examples/state b/spec/examples/state index 7f4b33460..ce9733b6b 100644 --- a/spec/examples/state +++ b/spec/examples/state @@ -19,7 +19,7 @@ component Main { } } ------------------------------------------------------------state_type_mismatch -record A { +type A { a : String } diff --git a/spec/examples/state_setter b/spec/examples/state_setter new file mode 100644 index 000000000..e72255d5b --- /dev/null +++ b/spec/examples/state_setter @@ -0,0 +1,27 @@ +-------------------------------------------------state_setter_expected_variable +component Main { + fun render : String { + -> +------------------------------------------------------state_setter_expected_dot +component Main { + fun render : String { + -> Store +-------------------------------------------------state_setter_expected_variable +component Main { + fun render : String { + -> Store. +---------------------------------------------------state_setter_state_not_found +component Main { + fun render : String { + -> asd + } +} +------------------------------------------------------------------------------- +component Main { + state value : String = "" + + fun render : String { + ->value("Hello") + value + } +} diff --git a/spec/examples/statement b/spec/examples/statement index 16823d724..28635615a 100644 --- a/spec/examples/statement +++ b/spec/examples/statement @@ -1,13 +1,13 @@ -------------------------------------------------statement_return_type_mismatch -enum Test { +type Test { A(String) B(String) } component Main { fun render : String { - let Test::B(x) = - Test::A("Hello") or return 0 + let Test.B(x) = + Test.A("Hello") or return 0 x } diff --git a/spec/examples/string_literal b/spec/examples/string_literal index 239f041aa..597e82908 100644 --- a/spec/examples/string_literal +++ b/spec/examples/string_literal @@ -9,7 +9,7 @@ component Main { -------------------------------------string_literal_interpolation_type_mismatch component Main { fun render : String { - let name = {} + let name = void "Hello There #{name}!" } diff --git a/spec/examples/tuple b/spec/examples/tuple index 02b7aae8c..93cfe11f4 100644 --- a/spec/examples/tuple +++ b/spec/examples/tuple @@ -1,7 +1,7 @@ ------------------------------------------------------------------------------- component Main { fun render : String { - {""}[0] + {"", ""}[0] } } ------------------------------------------------------------------------------- @@ -13,18 +13,12 @@ component Main { fun render : String { let x = "" - { x |> pipe }[0] - } -} --------------------------------------tuple_literal_expected_closing_parenthesis -component Main { - fun render : String { - #("a", "b" + { x |> pipe, "" }[0] } } ------------------------------------------------------------------------------- component Main { fun render : String { - #("a", "b")[0] + {"a", "b"}[0] } } diff --git a/spec/examples/type b/spec/examples/type index 28a49be72..ef02d763c 100644 --- a/spec/examples/type +++ b/spec/examples/type @@ -19,20 +19,7 @@ module Test { } } ------------------------------------------------------------------------------- -enum A { - B - C -} - -component Main { - fun render : String { - case (A::B) { - => "" - } - } -} -------------------------------------------------------------------------------- -enum A { +type A { B C } diff --git a/spec/examples/type_definition b/spec/examples/type_definition index 10d4c2618..18e0b3d05 100644 --- a/spec/examples/type_definition +++ b/spec/examples/type_definition @@ -9,29 +9,21 @@ type Maybe(a ---------------------------------------type_definition_expected_closing_bracket type Maybe(a) { Nothing ---------------------------------------------------type_definition_expected_name -enum ------------------------------------type_definition_expected_closing_parenthesis -enum Test ( -------------------------------------------------------------------------------- -enum Test ----------------------------------------type_definition_expected_closing_bracket -enum Test { -----------------------------------------------type_definition_unused_parameter -enum A(a, b, c) { +type A(a, b, c) { B C } ------------------------------------------type_definition_not_defined_parameter -enum A { +type A { B(a) } ------------------------------------------type_definition_not_defined_parameter -enum A { +type A { B(Maybe(a)) } ------------------------------------------------------------------------------- -enum Result(error, value) { +type Result(error, value) { Error(error) Ok(value) } diff --git a/spec/examples/type_destructuring b/spec/examples/type_destructuring index 06c0abee1..cf3da834a 100644 --- a/spec/examples/type_destructuring +++ b/spec/examples/type_destructuring @@ -1,14 +1,7 @@ ---------------------------------------------type_destructuring_expected_variant -module Test { - fun toString (status : Status) : String { - case (status) { - A:: - } -} --------------------------------type_destructuring_expected_closing_parenthesis module Test { fun toString (status : Status) : String { case (status) { - A::B( + A.B( } } diff --git a/spec/examples/type_variant b/spec/examples/type_variant index 371a386ab..7619e70ef 100644 --- a/spec/examples/type_variant +++ b/spec/examples/type_variant @@ -1,3 +1,3 @@ --------------------------------------type_variant_expected_closing_parenthesis -enum Test { +type Test { A( diff --git a/spec/examples/use b/spec/examples/use index 3f926ada2..34606a63e 100644 --- a/spec/examples/use +++ b/spec/examples/use @@ -27,7 +27,7 @@ component Main { } } ---------------------------------------------------------use_condition_mismatch -record Provider.Data { +type Provider.Data { a : String, b : String } @@ -51,12 +51,12 @@ component Main { } } ------------------------------------------------------use_subscription_mismatch -record Provider.Data { +type Provider.Data { a : String, b : Bool } -record Test { +type Test { a : String, b : String } @@ -80,7 +80,7 @@ component Main { } } ------------------------------------------------------------------------------- -record Provider.Data { +type Provider.Data { a : String, b : String } diff --git a/spec/examples/variable b/spec/examples/variable index 3407c4cad..6b507d791 100644 --- a/spec/examples/variable +++ b/spec/examples/variable @@ -37,14 +37,14 @@ suite "Suite 2" { } } ---------------------------------------------------------------variable_missing -enum A { +type A { B(String) C } component Main { fun render : String { - case (A::D(0)) { + case (A.D(0)) { => "" } } @@ -52,7 +52,7 @@ component Main { ---------------------------------------------------------------variable_missing component Main { fun render : String { - case (C::D(0)) { + case (C.D(0)) { => "" } } diff --git a/spec/examples_spec.cr b/spec/examples_spec.cr index bebf2e8be..530cb3149 100644 --- a/spec/examples_spec.cr +++ b/spec/examples_spec.cr @@ -42,13 +42,13 @@ Dir type_checker = Mint::TypeChecker.new(ast) type_checker.check - rescue item : Mint::Error - if item.name.to_s != error - fail item.to_terminal.to_s + rescue exception : Mint::Error + if exception.name.to_s != error + fail exception.to_terminal.to_s end end - item.should be_a(Mint::Error) + exception.should be_a(Mint::Error) else begin ast = Mint::Parser.parse(source, file) @@ -56,10 +56,10 @@ Dir type_checker = Mint::TypeChecker.new(ast) type_checker.check - rescue item : Mint::Error - fail item.to_terminal.to_s - rescue item - fail item.to_s + '\n' + item.backtrace.join('\n') + rescue exception : Mint::Error + fail exception.to_terminal.to_s + rescue exception + fail exception.to_s + '\n' + exception.backtrace.join('\n') end end end diff --git a/spec/fixtures/data.txt b/spec/fixtures/data.txt new file mode 100644 index 000000000..980a0d5f1 --- /dev/null +++ b/spec/fixtures/data.txt @@ -0,0 +1 @@ +Hello World! diff --git a/spec/formatters/array_access b/spec/formatters/bracket_access similarity index 100% rename from spec/formatters/array_access rename to spec/formatters/bracket_access diff --git a/spec/formatters/comment_multiple b/spec/formatters/comment_multiple new file mode 100644 index 000000000..ddbf4f8f6 --- /dev/null +++ b/spec/formatters/comment_multiple @@ -0,0 +1,5 @@ +// Comment A +// Comment B +-------------------------------------------------------------------------------- +// Comment A +// Comment B diff --git a/spec/formatters/comment_multiple_2 b/spec/formatters/comment_multiple_2 new file mode 100644 index 000000000..6ba458ca3 --- /dev/null +++ b/spec/formatters/comment_multiple_2 @@ -0,0 +1,7 @@ +// Comment A + +// Comment B +-------------------------------------------------------------------------------- +// Comment A + +// Comment B diff --git a/spec/formatters/directives/asset b/spec/formatters/directives/asset new file mode 100644 index 000000000..bedca4ce6 --- /dev/null +++ b/spec/formatters/directives/asset @@ -0,0 +1,11 @@ +component Main { + fun render : String { + @asset(../../fixtures/data.txt) + } +} +-------------------------------------------------------------------------------- +component Main { + fun render : String { + @asset(../../fixtures/data.txt) + } +} diff --git a/spec/formatters/directives/format b/spec/formatters/directives/format index 5f6105c9e..3d8cdc8bb 100644 --- a/spec/formatters/directives/format +++ b/spec/formatters/directives/format @@ -7,7 +7,7 @@ component Main { -------------------------------------------------------------------------------- component Main { fun render : String { - let #(result, formatted) = + let {result, formatted} = @format { "Hello" } diff --git a/spec/formatters/directives/inline b/spec/formatters/directives/inline new file mode 100644 index 000000000..98df8ab9b --- /dev/null +++ b/spec/formatters/directives/inline @@ -0,0 +1,11 @@ +component Main { + fun render : String { + @inline(../../fixtures/data.txt) + } +} +-------------------------------------------------------------------------------- +component Main { + fun render : String { + @inline(../../fixtures/data.txt) + } +} diff --git a/spec/formatters/html_expression b/spec/formatters/directives/svg similarity index 50% rename from spec/formatters/html_expression rename to spec/formatters/directives/svg index 78612d18d..9b5a5c28c 100644 --- a/spec/formatters/html_expression +++ b/spec/formatters/directives/svg @@ -1,15 +1,11 @@ -component Test { +component Main { fun render : Html { -
<{ - "Hello There" + "!"}> -
+ @svg(../../fixtures/icon.svg) } } -------------------------------------------------------------------------------- -component Test { +component Main { fun render : Html { -
- <{ "Hello There" + "!" }> -
+ @svg(../../fixtures/icon.svg) } } diff --git a/spec/formatters/member_access b/spec/formatters/field_access similarity index 77% rename from spec/formatters/member_access rename to spec/formatters/field_access index 7336f3aac..1f1614f6b 100644 --- a/spec/formatters/member_access +++ b/spec/formatters/field_access @@ -4,7 +4,7 @@ type Test { component Main { fun render : String { - .test({ test: "Hello" }) + .test(Test)({ test: "Hello" }) } } -------------------------------------------------------------------------------- @@ -14,6 +14,6 @@ type Test { component Main { fun render : String { - .test({ test: "Hello" }) + .test(Test)({ test: "Hello" }) } } diff --git a/spec/formatters/html_attribute_html_expression b/spec/formatters/html_attribute_html_fragment similarity index 69% rename from spec/formatters/html_attribute_html_expression rename to spec/formatters/html_attribute_html_fragment index 22df749bf..fa6689f34 100644 --- a/spec/formatters/html_attribute_html_expression +++ b/spec/formatters/html_attribute_html_fragment @@ -3,8 +3,8 @@ component Test { fun render : Html {
- /> - }>/> + "x"/> + />
} } @@ -14,8 +14,8 @@ component Test { fun render : Html {
- /> - }>/> + "x"/> + />
} } diff --git a/spec/formatters/html_expression_multiline b/spec/formatters/html_expression_multiline deleted file mode 100644 index f93a0ec7c..000000000 --- a/spec/formatters/html_expression_multiline +++ /dev/null @@ -1,18 +0,0 @@ -component Test { - fun render : Html { -
<{ - "Hello ThereHello ThereHello ThereHello " \ "ThereHello ThereHello ThereHello ThereHello ThereHello ThereHello There"}> -
- } -} --------------------------------------------------------------------------------- -component Test { - fun render : Html { -
- <{ - "Hello ThereHello ThereHello ThereHello ThereHello ThereH" \ - "ello ThereHello ThereHello ThereHello ThereHello There" - }> -
- } -} diff --git a/spec/formatters/html_fragment b/spec/formatters/html_fragment index dccf00166..69d6d6b3d 100644 --- a/spec/formatters/html_fragment +++ b/spec/formatters/html_fragment @@ -4,7 +4,7 @@ component Test { "Hello There" <> - <><{"AA"}> + <>"AA" } } @@ -15,7 +15,7 @@ component Test { "Hello There" <> - <><{ "AA" }> + <>"AA" } } diff --git a/spec/formatters/map_multiline b/spec/formatters/map_multiline new file mode 100644 index 000000000..2d3305f82 --- /dev/null +++ b/spec/formatters/map_multiline @@ -0,0 +1,14 @@ +module Test { + fun test : Map(String, String) { + {"a" => "Hello", "b" => "World"} + } +} +-------------------------------------------------------------------------------- +module Test { + fun test : Map(String, String) { + { + "a" => "Hello", + "b" => "World" + } + } +} diff --git a/spec/formatters/map_with_type b/spec/formatters/map_with_type new file mode 100644 index 000000000..77451000f --- /dev/null +++ b/spec/formatters/map_with_type @@ -0,0 +1,11 @@ +module Test { + fun test : Map(String, String) { + {"a" => "Hello" } of String => String + } +} +-------------------------------------------------------------------------------- +module Test { + fun test : Map(String, String) { + { "a" => "Hello" } of String => String + } +} diff --git a/spec/formatters/tuple_destructuring b/spec/formatters/tuple_destructuring index ae1d27805..94e3c8e1e 100644 --- a/spec/formatters/tuple_destructuring +++ b/spec/formatters/tuple_destructuring @@ -9,8 +9,8 @@ module Test { -------------------------------------------------------------------------------- module Test { fun test : String { - let #(a, b) = - #("A", "B") + let {a, b} = + {"A", "B"} a } diff --git a/spec/formatters/tuple_multiple b/spec/formatters/tuple_multiple index 5ec41068f..0e581e3f9 100644 --- a/spec/formatters/tuple_multiple +++ b/spec/formatters/tuple_multiple @@ -9,10 +9,10 @@ module Test { -------------------------------------------------------------------------------- module Test { fun test : Tuple(String, String, String) { - #( + { "Hello", "Blah", "Joe" - ) + } } } diff --git a/spec/formatters/tuple_single b/spec/formatters/tuple_single deleted file mode 100644 index cb4b26616..000000000 --- a/spec/formatters/tuple_single +++ /dev/null @@ -1,13 +0,0 @@ -module Test { - fun test : Tuple(String) { - { - "Hello" - } - } -} --------------------------------------------------------------------------------- -module Test { - fun test : Tuple(String) { - #("Hello") - } -} diff --git a/spec/formatters/type_definition_with_comments b/spec/formatters/type_definition_with_comments index aea803004..bd7775ea6 100644 --- a/spec/formatters/type_definition_with_comments +++ b/spec/formatters/type_definition_with_comments @@ -4,6 +4,7 @@ type Test { /* B */ a : String, + /* C */ b : Blah } diff --git a/spec/formatters/type_definition_with_new_lines b/spec/formatters/type_definition_with_new_lines new file mode 100644 index 000000000..b37cec28a --- /dev/null +++ b/spec/formatters/type_definition_with_new_lines @@ -0,0 +1,11 @@ +type Test { + a:String, + + b:Blah +} +-------------------------------------------------------------------------------- +type Test { + a : String, + + b : Blah +} diff --git a/spec/formatters/type_record b/spec/formatters/type_record index 89255c260..a018d0346 100644 --- a/spec/formatters/type_record +++ b/spec/formatters/type_record @@ -1,13 +1,13 @@ -enum A { +type A { B(name : String, color : String) C } component Main { fun render : String { - case A::B(name: "Joe", color: "Blue") { - A::B(name, color) => "" - A::C => "" + case A.B(name: "Joe", color: "Blue") { + A.B(name, color) => "" + A.C => "" } } } diff --git a/spec/formatters/type_record_multiline b/spec/formatters/type_record_multiline index 7388bd4c5..d70f9fc09 100644 --- a/spec/formatters/type_record_multiline +++ b/spec/formatters/type_record_multiline @@ -1,11 +1,11 @@ -enum A { +type A { B(name : String, color : String) C } component Main { const X = - A::B( + A.B( color: "Blue", name: "Joe", ) diff --git a/spec/language_server/hover/function_provider b/spec/language_server/hover/function_provider index e394d10c4..87ae2d5d3 100644 --- a/spec/language_server/hover/function_provider +++ b/spec/language_server/hover/function_provider @@ -1,4 +1,4 @@ -record Test.Subscription { +type Test.Subscription { test : Test } diff --git a/spec/language_server/hover/module_access b/spec/language_server/hover/module_access index 93df02d38..b1bc37bda 100644 --- a/spec/language_server/hover/module_access +++ b/spec/language_server/hover/module_access @@ -6,8 +6,8 @@ module Test.Module { } component Test { - fun render : Html { - <{ Test.Module.test() }> + fun render : String { + Test.Module.test() } } ------------------------------------------------------------------file test.mint @@ -20,7 +20,7 @@ component Test { }, "position": { "line": 9, - "character": 22 + "character": 19 } } } diff --git a/spec/language_server/hover/type_definition b/spec/language_server/hover/type_definition index d0d65e060..58a79e4cd 100644 --- a/spec/language_server/hover/type_definition +++ b/spec/language_server/hover/type_definition @@ -1,5 +1,5 @@ /* Comment for Status enum. */ -enum Status { +type Status { Error Ok } diff --git a/spec/language_server/hover/type_destructuring b/spec/language_server/hover/type_destructuring index 14793b92c..fe82c919a 100644 --- a/spec/language_server/hover/type_destructuring +++ b/spec/language_server/hover/type_destructuring @@ -1,5 +1,5 @@ /* Comment for Status enum. */ -enum Status { +type Status { Error Ok } @@ -7,8 +7,8 @@ enum Status { module Test { fun toString (status : Status) : String { case (status) { - Status::Error => "Error" - Status::Ok => "Ok" + Status.Error => "Error" + Status.Ok => "Ok" } } } diff --git a/spec/language_server/hover/type_record b/spec/language_server/hover/type_record index 7802a395b..5c1e4f46a 100644 --- a/spec/language_server/hover/type_record +++ b/spec/language_server/hover/type_record @@ -1,4 +1,4 @@ -record Article { +type Article { id : Number, description : String, title : String diff --git a/spec/language_server/hover/type_type b/spec/language_server/hover/type_type index 329814118..7112b381d 100644 --- a/spec/language_server/hover/type_type +++ b/spec/language_server/hover/type_type @@ -1,12 +1,12 @@ /* Comment for Status type. */ -enum Status { +type Status { Error Ok } module Test { fun success : Status { - Status::Ok + Status.Ok } } ------------------------------------------------------------------file test.mint diff --git a/spec/language_server/hover/type_variant b/spec/language_server/hover/type_variant index 469251e85..bfab3697e 100644 --- a/spec/language_server/hover/type_variant +++ b/spec/language_server/hover/type_variant @@ -1,12 +1,12 @@ /* Comment for Status enum. */ -enum Status { +type Status { Error Ok } module Test { fun success : Status { - Status::Ok + Status.Ok } } ------------------------------------------------------------------file test.mint @@ -19,7 +19,7 @@ module Test { }, "position": { "line": 8, - "character": 13 + "character": 12 } } } diff --git a/spec/language_server/hover/type_variant_2 b/spec/language_server/hover/type_variant_2 index 821498f02..ec00a3661 100644 --- a/spec/language_server/hover/type_variant_2 +++ b/spec/language_server/hover/type_variant_2 @@ -1,5 +1,5 @@ /* Comment for Status enum. */ -enum Status { +type Status { Error Ok } diff --git a/spec/language_server/semantic_tokens/component b/spec/language_server/semantic_tokens/component index 0357c4a26..cc5a89b14 100644 --- a/spec/language_server/semantic_tokens/component +++ b/spec/language_server/semantic_tokens/component @@ -71,7 +71,7 @@ component Test { 0, 2, 2, - 48, + 45, 5, 0, 4, diff --git a/spec/language_server/semantic_tokens/record b/spec/language_server/semantic_tokens/record index deadce430..4dd762abb 100644 --- a/spec/language_server/semantic_tokens/record +++ b/spec/language_server/semantic_tokens/record @@ -1,5 +1,5 @@ /* Some comment. */ -record Article { +type Article { id : Number, description : String, title : String @@ -37,16 +37,16 @@ record Article { "data": [ 0, 0, - 20, + 19, 5, 0, 1, 0, - 6, + 4, 4, 0, 0, - 7, + 5, 7, 1, 0, diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index b1ff03063..743e31626 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -4,13 +4,13 @@ ENV["SPEC"] = "TRUE" MINT_ENV["TEST"] = "TRUE" def diff(a, b) - file1 = File.tempfile do |f| - f.puts a.strip - f.flush + file1 = File.tempfile do |file| + file.puts a.strip + file.flush end - file2 = File.tempfile do |f| - f.puts b - f.flush + file2 = File.tempfile do |file| + file.puts b + file.flush end io = IO::Memory.new diff --git a/spec/utils/markd_vdom_renderer2_spec.cr b/spec/utils/markd_vdom_renderer2_spec.cr new file mode 100644 index 000000000..c53b7b86c --- /dev/null +++ b/spec/utils/markd_vdom_renderer2_spec.cr @@ -0,0 +1,140 @@ +require "../spec_helper" + +describe Mint::Compiler2::VDOMRenderer2 do + html_block = + <<-HTML + + + + +
+ hi +
+ HTML + + [ + {"**strong**", "A('p', {}, [A('strong', {}, [`strong`])])"}, + {"> quote", "A('blockquote', {}, [A('p', {}, [`quote`])])"}, + {"`code`", "A('p', {}, [A('code', {}, [`code`])])"}, + {"", "``"}, + {"###### Heading 6", "A('h6', {}, [`Heading 6`])"}, + {"##### Heading 5", "A('h5', {}, [`Heading 5`])"}, + {"#### Heading 4", "A('h4', {}, [`Heading 4`])"}, + {"### Heading 3", "A('h3', {}, [`Heading 3`])"}, + {"## Heading 2", "A('h2', {}, [`Heading 2`])"}, + {"# Heading 1", "A('h1', {}, [`Heading 1`])"}, + {"_em_", "A('p', {}, [A('em', {}, [`em`])])"}, + {"Paragraph", "A('p', {}, [`Paragraph`])"}, + {html_block, %(`#{html_block}`)}, + {"-----", "A('hr', {}, [])"}, + { + "foo\nbaz", + <<-TEXT + A('p', {}, [ + `foo`, + `\n`, + `baz` + ]) + TEXT + }, + { + "foo\\\nbar", + <<-TEXT + A('p', {}, [ + `foo`, + A('br', {}, []), + `bar` + ]) + TEXT + }, + { + "```html\ncode\n```", + <<-TEXT + A('pre', {}, [A('code', { + class: "language-html" + }, [`code`])]) + TEXT + }, + { + "* item 1\n* item 2", + <<-TEXT + A('ul', {}, [ + A('li', {}, [`item 1`]), + A('li', {}, [`item 2`]) + ]) + TEXT + }, + { + "[link](url)", + <<-TEXT + A('p', {}, [A('a', { + href: "url" + }, [`link`])]) + TEXT + }, + { + "![alt](url)", + <<-TEXT + A('p', {}, [A('img', { + src: "url", + alt: "alt" + }, [])]) + TEXT + }, + { + "*foo*", + <<-TEXT + A('p', {}, [ + ``, + A('em', {}, [`foo`]), + `` + ]) + TEXT + }, + ].each do |(markdown, expected)| + context markdown do + it "renders correctly" do + document = + Markd::Parser.parse(markdown, Markd::Options.new) + + renderer = + Mint::Compiler2::VDOMRenderer2.new + + js = + Mint::Compiler2::Js.new(false) + + class_pool = + Mint::NamePool(Mint::Ast::Node | Mint::Compiler2::Builtin, Mint::Ast::Node | Mint::Compiler2::Bundle).new('A'.pred.to_s) + + pool = + Mint::NamePool(Mint::Ast::Node | Mint::Compiler2::Decoder | Mint::Compiler2::Encoder | Mint::Compiler2::Variable | String, Mint::Ast::Node | Mint::Compiler2::Bundle).new + + js_renderer = + Mint::Compiler2::Renderer.new( + deferred_path: ->(_node : Mint::Ast::Node | Mint::Compiler2::Bundle) { "" }, + bundle_path: ->(_node : Mint::Ast::Node | Mint::Compiler2::Bundle) { "" }, + references: Mint::ReferencesTracker.new, + base: Mint::Compiler2::Bundle::Index, + class_pool: class_pool, + pool: pool) + + node = + Mint::Compiler2::VDOMRenderer2 + .render( + node: renderer.render(document, "___SEPARATOR___", false).children.first, + replacements: [] of Mint::Compiler2::Compiled, + separator: "", + js: js) + + result = + js_renderer.render(node) + + begin + result.should eq(expected.strip) + rescue error + fail diff(expected, result) + end + end + end + end +end diff --git a/src/all.cr b/src/all.cr index 93e7bbf4b..60924b4da 100644 --- a/src/all.cr +++ b/src/all.cr @@ -1,10 +1,11 @@ require "baked_file_system" require "ansi-escapes" +require "compress/zip" require "file_utils" require "colorize" require "markd" -require "kemal" require "uuid" +require "http" require "html" require "json" require "ecr" @@ -17,6 +18,7 @@ require "./version" require "./ext/**" require "./errorable" +require "./logger" require "./constants" require "./assets" require "./skippable" @@ -42,6 +44,10 @@ require "./type_checker" require "./formatters/**" require "./formatter" +require "./compilers2/**" +require "./compiler2/**" +require "./compiler2" + require "./compilers/**" require "./compiler" @@ -54,9 +60,10 @@ require "./parser" require "./documentation_generator/**" require "./documentation_generator" -require "./documentation_server" +# require "./documentation_server" require "./semantic_tokenizer" +require "./references_tracker" require "./test_runner/**" require "./test_runner" @@ -65,11 +72,11 @@ require "./lsp/**" require "./ls/**" require "./mint_json" -require "./app_init/scaffold" +require "./scaffold" require "./reactor" -require "./builder" require "./sandbox_server" require "./cli" require "./workspace" require "./debugger" +require "./bundler" require "./artifact_cleaner" diff --git a/src/app_init/app/assets/favicon.png b/src/app_init/app/assets/favicon.png deleted file mode 100644 index ea7514eaf..000000000 Binary files a/src/app_init/app/assets/favicon.png and /dev/null differ diff --git a/src/app_init/app/assets/head.html b/src/app_init/app/assets/head.html deleted file mode 100644 index 53098a83d..000000000 --- a/src/app_init/app/assets/head.html +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/src/app_init/app/assets/style.css b/src/app_init/app/assets/style.css deleted file mode 100644 index 293d3b1f1..000000000 --- a/src/app_init/app/assets/style.css +++ /dev/null @@ -1,3 +0,0 @@ -body { - margin: 0; -} diff --git a/src/app_init/app/source/Info.mint b/src/app_init/app/source/Info.mint deleted file mode 100644 index a9f0f4c8a..000000000 --- a/src/app_init/app/source/Info.mint +++ /dev/null @@ -1,27 +0,0 @@ -component Info { - property mainPath : String - - style info { - font-size: calc(10px + 2vmin); - color: #939DB0; - } - - style path { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; - font-style: italic; - font-weight: 100; - color: #E06C75; - } - - fun render : Html { - - <{ "Edit " }> - - - <{ mainPath }> - - - <{ " and save to reload." }> -

- } -} diff --git a/src/app_init/app/source/Link.mint b/src/app_init/app/source/Link.mint deleted file mode 100644 index d59a01e03..000000000 --- a/src/app_init/app/source/Link.mint +++ /dev/null @@ -1,24 +0,0 @@ -component Link { - property children : Array(Html) = [] - property href : String - - style link { - font-size: calc(10px + 2vmin); - text-decoration: none; - color: #DDDDDD; - - &:hover { - text-decoration: underline; - } - } - - fun render : Html { - - - <{ children }> - - - } -} diff --git a/src/app_init/app/source/Logo.mint b/src/app_init/app/source/Logo.mint deleted file mode 100644 index 2da85c854..000000000 --- a/src/app_init/app/source/Logo.mint +++ /dev/null @@ -1,40 +0,0 @@ -component Logo { - style logo { - svg { - animation: shake 2s infinite ease-in-out; - animation-delay: 1s; - } - - @keyframes shake { - 0% { - transform: translate(1px, 1px) rotate(0deg); - } - - 3% { - transform: translate(-1px, -2px) rotate(-1deg); - } - - 6% { - transform: translate(-3px, 0px) rotate(1deg); - } - - 9% { - transform: translate(3px, 2px) rotate(0deg); - } - - 12% { - transform: translate(1px, -1px) rotate(1deg); - } - - 15% { - transform: translate(0px, 0px) rotate(-1deg); - } - } - } - - fun render : Html { - - <{ @svg(logo.svg) }> -
- } -} diff --git a/src/app_init/app/source/Main.mint b/src/app_init/app/source/Main.mint deleted file mode 100644 index 37bef07cf..000000000 --- a/src/app_init/app/source/Main.mint +++ /dev/null @@ -1,27 +0,0 @@ -component Main { - style app { - justify-content: center; - flex-direction: column; - align-items: center; - display: flex; - - background-color: #282C34; - height: 100vh; - width: 100vw; - - font-family: Open Sans; - font-weight: bold; - } - - fun render : Html { - - - - - - - "Learn Mint" - -
- } -} diff --git a/src/app_init/app/source/logo.svg b/src/app_init/app/source/logo.svg deleted file mode 100644 index c5699c210..000000000 --- a/src/app_init/app/source/logo.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app_init/app/tests/Main.mint b/src/app_init/app/tests/Main.mint deleted file mode 100644 index 0403573f1..000000000 --- a/src/app_init/app/tests/Main.mint +++ /dev/null @@ -1,7 +0,0 @@ -suite "Main" { - test "Greets Mint" { -
- |> Test.Html.start() - |> Test.Html.assertTextOf("a", "Learn Mint") - } -} diff --git a/src/app_init/scaffold.cr b/src/app_init/scaffold.cr deleted file mode 100644 index bff37f3c0..000000000 --- a/src/app_init/scaffold.cr +++ /dev/null @@ -1,108 +0,0 @@ -module Mint - class Scaffold - extend BakedFileSystem - - bake_folder "./app" - - getter path : Path - - def self.run(name : Path | String) - new(Path[name]).run - end - - def initialize(path : Path) - @path = path.expand - end - - def name - path.basename - end - - def run - directory = - name - .colorize(:light_green) - .mode(:bold) - - terminal.puts "#{COG} Creating directory: #{directory}" - - FileUtils.mkdir_p path.to_s - - Dir.cd(path) do - terminal.puts "#{COG} Writing initial files:" - - touch_initial_files - touch_config - - show_created_files(path, indent: 2) - end - end - - private def touch_initial_files - @@files.each do |file| - # The baked files start with a slash "/" - file_path = - file.path.lchop - - FileUtils.mkdir_p File.dirname(file_path) - File.write(file_path, file) - end - end - - private def touch_config - File.write("mint.json", json.to_pretty_json) - end - - private def show_created_files(path : Path, indent : Int32 = 0) - dirs = %w[] - files = %w[] - - Dir.each_child(path) do |child| - child_path = Path[path, child] - case - when File.directory?(child_path) - dirs << child - when File.file?(child_path) - files << child - end - end - - prefix = "#{" " * indent}#{ARROW} " - - dirs.each do |child| - terminal << prefix << child << '\n' - show_created_files(Path[path, child], indent + 2) - end - - files.each do |child| - terminal << prefix << child << '\n' - end - end - - def json - { - "name" => name, - "application" => { - "head" => "assets/head.html", - "title" => name, - "icon" => "assets/favicon.png", - }, - "external" => { - "stylesheets" => [ - "assets/style.css", - ], - }, - "source-directories" => [ - "source", - ], - "test-directories" => [ - "tests", - ], - } - end - - private def terminal - Render::Terminal::STDOUT - end - end -end diff --git a/src/artifact_cleaner.cr b/src/artifact_cleaner.cr index e15c06c90..5683d8df8 100644 --- a/src/artifact_cleaner.cr +++ b/src/artifact_cleaner.cr @@ -1,22 +1,26 @@ module Mint class ArtifactCleaner - def self.clean(clean_global : Bool = false) - artifacts = %w[.mint dist] + def self.clean(clean_packages : Bool = false) + artifacts = + if clean_packages + [MINT_PACKAGES_DIR] + else + %w[.mint dist] + end - if clean_global - safe_delete(MINT_PACKAGES_DIR) + # ameba:disable Performance/AnyInsteadOfEmpty + if artifacts.any?(&->Dir.exists?(String)) + artifacts.each(&->safe_delete(String)) else - artifacts.each do |artifact_path| - safe_delete(artifact_path) - end + terminal.puts "Nothing to delete." end end - private def self.safe_delete(dir_path) - if Dir.exists?(dir_path) - terminal.puts "Deleting: #{dir_path}" - FileUtils.rm_rf(dir_path) - end + private def self.safe_delete(directory) + return unless Dir.exists?(directory) + + terminal.puts "Deleting: #{directory}" + FileUtils.rm_rf(directory) end def self.terminal diff --git a/src/assets/docs-viewer/external-stylesheets.css b/src/assets/docs-viewer/external-stylesheets.css deleted file mode 100644 index 1e255f1e2..000000000 --- a/src/assets/docs-viewer/external-stylesheets.css +++ /dev/null @@ -1,2 +0,0 @@ -/*! modern-normalize v0.6.0 | MIT License | https://github.com/sindresorhus/modern-normalize */ -*,::after,::before{box-sizing:border-box}:root{-moz-tab-size:4;tab-size:4}html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}body{font-family:system-ui,-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji'}hr{height:0}abbr[title]{text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:SFMono-Regular,Consolas,'Liberation Mono',Menlo,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{padding:0}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item} diff --git a/src/assets/docs-viewer/icon-120x120.png b/src/assets/docs-viewer/icon-120x120.png deleted file mode 100644 index 1d88cab08..000000000 Binary files a/src/assets/docs-viewer/icon-120x120.png and /dev/null differ diff --git a/src/assets/docs-viewer/icon-128x128.png b/src/assets/docs-viewer/icon-128x128.png deleted file mode 100644 index 7f1f4c0a2..000000000 Binary files a/src/assets/docs-viewer/icon-128x128.png and /dev/null differ diff --git a/src/assets/docs-viewer/icon-144x144.png b/src/assets/docs-viewer/icon-144x144.png deleted file mode 100644 index cfa571eec..000000000 Binary files a/src/assets/docs-viewer/icon-144x144.png and /dev/null differ diff --git a/src/assets/docs-viewer/icon-152x152.png b/src/assets/docs-viewer/icon-152x152.png deleted file mode 100644 index ea82e8978..000000000 Binary files a/src/assets/docs-viewer/icon-152x152.png and /dev/null differ diff --git a/src/assets/docs-viewer/icon-167x167.png b/src/assets/docs-viewer/icon-167x167.png deleted file mode 100644 index 570925728..000000000 Binary files a/src/assets/docs-viewer/icon-167x167.png and /dev/null differ diff --git a/src/assets/docs-viewer/icon-16x16.png b/src/assets/docs-viewer/icon-16x16.png deleted file mode 100644 index 2adb23f91..000000000 Binary files a/src/assets/docs-viewer/icon-16x16.png and /dev/null differ diff --git a/src/assets/docs-viewer/icon-180x180.png b/src/assets/docs-viewer/icon-180x180.png deleted file mode 100644 index 0cfd446a8..000000000 Binary files a/src/assets/docs-viewer/icon-180x180.png and /dev/null differ diff --git a/src/assets/docs-viewer/icon-192x192.png b/src/assets/docs-viewer/icon-192x192.png deleted file mode 100644 index 72a718efa..000000000 Binary files a/src/assets/docs-viewer/icon-192x192.png and /dev/null differ diff --git a/src/assets/docs-viewer/icon-196x196.png b/src/assets/docs-viewer/icon-196x196.png deleted file mode 100644 index 12f0ea613..000000000 Binary files a/src/assets/docs-viewer/icon-196x196.png and /dev/null differ diff --git a/src/assets/docs-viewer/icon-256x256.png b/src/assets/docs-viewer/icon-256x256.png deleted file mode 100644 index 821e13d6d..000000000 Binary files a/src/assets/docs-viewer/icon-256x256.png and /dev/null differ diff --git a/src/assets/docs-viewer/icon-32x32.png b/src/assets/docs-viewer/icon-32x32.png deleted file mode 100644 index b5722f599..000000000 Binary files a/src/assets/docs-viewer/icon-32x32.png and /dev/null differ diff --git a/src/assets/docs-viewer/icon-36x36.png b/src/assets/docs-viewer/icon-36x36.png deleted file mode 100644 index e70dac366..000000000 Binary files a/src/assets/docs-viewer/icon-36x36.png and /dev/null differ diff --git a/src/assets/docs-viewer/icon-48x48.png b/src/assets/docs-viewer/icon-48x48.png deleted file mode 100644 index 01524c49f..000000000 Binary files a/src/assets/docs-viewer/icon-48x48.png and /dev/null differ diff --git a/src/assets/docs-viewer/icon-512x512.png b/src/assets/docs-viewer/icon-512x512.png deleted file mode 100644 index 30a8f4a65..000000000 Binary files a/src/assets/docs-viewer/icon-512x512.png and /dev/null differ diff --git a/src/assets/docs-viewer/icon-57x57.png b/src/assets/docs-viewer/icon-57x57.png deleted file mode 100644 index d1d2ca9e2..000000000 Binary files a/src/assets/docs-viewer/icon-57x57.png and /dev/null differ diff --git a/src/assets/docs-viewer/icon-72x72.png b/src/assets/docs-viewer/icon-72x72.png deleted file mode 100644 index 148ee9ae3..000000000 Binary files a/src/assets/docs-viewer/icon-72x72.png and /dev/null differ diff --git a/src/assets/docs-viewer/icon-76x76.png b/src/assets/docs-viewer/icon-76x76.png deleted file mode 100644 index 4f3dbeb0d..000000000 Binary files a/src/assets/docs-viewer/icon-76x76.png and /dev/null differ diff --git a/src/assets/docs-viewer/icon-96x96.png b/src/assets/docs-viewer/icon-96x96.png deleted file mode 100644 index 70d354a9c..000000000 Binary files a/src/assets/docs-viewer/icon-96x96.png and /dev/null differ diff --git a/src/assets/docs-viewer/index.html b/src/assets/docs-viewer/index.html deleted file mode 100644 index 1ae19367d..000000000 --- a/src/assets/docs-viewer/index.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - - Documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/docs-viewer/index.js b/src/assets/docs-viewer/index.js deleted file mode 100644 index 5f5757d68..000000000 --- a/src/assets/docs-viewer/index.js +++ /dev/null @@ -1,613 +0,0 @@ -var Mint=function(){"use strict";var t,e,n,r,o,i,a={},s=[],u=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;function c(t,e){for(var n in e)t[n]=e[n];return t}function l(t){var e=t.parentNode;e&&e.removeChild(t)}function h(t,e,n){var r,o=arguments,i={};for(r in e)"key"!==r&&"ref"!==r&&(i[r]=e[r]);if(arguments.length>3)for(n=[n],r=3;r3;)n.pop()();if(n[1]t.original)),r.component=t,r.props=n,customElements.define(e,r)}function ot(t){if(null===t||!0===t||!1===t)return NaN;var e=Number(t);return isNaN(e)?e:e<0?Math.ceil(e):Math.floor(e)}function it(t,e){if(e.length1?"s":"")+" required, but only "+e.length+" present")}function at(t){it(1,arguments);var e=Object.prototype.toString.call(t);return t instanceof Date||"object"==typeof t&&"[object Date]"===e?new Date(t.getTime()):"number"==typeof t||"[object Number]"===e?new Date(t):("string"!=typeof t&&"[object String]"!==e||"undefined"==typeof console||(console.warn("Starting with v2.0.0-beta.1 date-fns doesn't accept strings as date arguments. Please use `parseISO` to parse strings. See: https://git.io/fjule"),console.warn((new Error).stack)),new Date(NaN))}function st(t,e){it(2,arguments);var n=at(t),r=ot(e);if(isNaN(r))return new Date(NaN);if(!r)return n;var o=n.getDate(),i=new Date(n.getTime());i.setMonth(n.getMonth()+r+1,0);var a=i.getDate();return o>=a?i:(n.setFullYear(i.getFullYear(),i.getMonth(),o),n)}function ut(t,e){it(2,arguments);var n=at(t).getTime(),r=ot(e);return new Date(n+r)}function ct(t,e){it(1,arguments);var n=e||{},r=n.locale,o=r&&r.options&&r.options.weekStartsOn,i=null==o?0:ot(o),a=null==n.weekStartsOn?i:ot(n.weekStartsOn);if(!(a>=0&&a<=6))throw new RangeError("weekStartsOn must be between 0 and 6 inclusively");var s=at(t),u=s.getDay(),c=(u0?1:o}function dt(t){return it(1,arguments),t instanceof Date||"object"==typeof t&&"[object Date]"===Object.prototype.toString.call(t)}function pt(t){if(it(1,arguments),!dt(t)&&"number"!=typeof t)return!1;var e=at(t);return!isNaN(Number(e))}function mt(t){it(1,arguments);var e=at(t);return e.setHours(23,59,59,999),e}function yt(t){it(1,arguments);var e=at(t),n=e.getMonth();return e.setFullYear(e.getFullYear(),n+1,0),e.setHours(23,59,59,999),e}function _t(t,e){it(1,arguments);var n=t||{},r=at(n.start),o=at(n.end),i=o.getTime();if(!(r.getTime()<=i))throw new RangeError("Invalid interval");var a=[],s=r;s.setHours(0,0,0,0);var u=e&&"step"in e?Number(e.step):1;if(u<1||isNaN(u))throw new RangeError("`options.step` must be a number greater than 1");for(;s.getTime()<=i;)a.push(at(s)),s.setDate(s.getDate()+u),s.setHours(0,0,0,0);return a}function gt(t){it(1,arguments);var e=at(t);return e.setDate(1),e.setHours(0,0,0,0),e}function vt(t,e){it(1,arguments);var n=e||{},r=n.locale,o=r&&r.options&&r.options.weekStartsOn,i=null==o?0:ot(o),a=null==n.weekStartsOn?i:ot(n.weekStartsOn);if(!(a>=0&&a<=6))throw new RangeError("weekStartsOn must be between 0 and 6 inclusively");var s=at(t),u=s.getDay(),c=6+(u0&&void 0!==arguments[0]?arguments[0]:{},n=e.width?String(e.width):t.defaultWidth,r=t.formats[n]||t.formats[t.defaultWidth];return r}}var kt={date:bt({formats:{full:"EEEE, MMMM do, y",long:"MMMM do, y",medium:"MMM d, y",short:"MM/dd/yyyy"},defaultWidth:"full"}),time:bt({formats:{full:"h:mm:ss a zzzz",long:"h:mm:ss a z",medium:"h:mm:ss a",short:"h:mm a"},defaultWidth:"full"}),dateTime:bt({formats:{full:"{{date}} 'at' {{time}}",long:"{{date}} 'at' {{time}}",medium:"{{date}}, {{time}}",short:"{{date}}, {{time}}"},defaultWidth:"full"})},xt={lastWeek:"'last' eeee 'at' p",yesterday:"'yesterday at' p",today:"'today at' p",tomorrow:"'tomorrow at' p",nextWeek:"eeee 'at' p",other:"P"};function St(t){return function(e,n){var r,o=n||{};if("formatting"===(o.context?String(o.context):"standalone")&&t.formattingValues){var i=t.defaultFormattingWidth||t.defaultWidth,a=o.width?String(o.width):i;r=t.formattingValues[a]||t.formattingValues[i]}else{var s=t.defaultWidth,u=o.width?String(o.width):t.defaultWidth;r=t.values[u]||t.values[s]}return r[t.argumentCallback?t.argumentCallback(e):e]}}var Tt={ordinalNumber:function(t,e){var n=Number(t),r=n%100;if(r>20||r<10)switch(r%10){case 1:return n+"st";case 2:return n+"nd";case 3:return n+"rd"}return n+"th"},era:St({values:{narrow:["B","A"],abbreviated:["BC","AD"],wide:["Before Christ","Anno Domini"]},defaultWidth:"wide"}),quarter:St({values:{narrow:["1","2","3","4"],abbreviated:["Q1","Q2","Q3","Q4"],wide:["1st quarter","2nd quarter","3rd quarter","4th quarter"]},defaultWidth:"wide",argumentCallback:function(t){return t-1}}),month:St({values:{narrow:["J","F","M","A","M","J","J","A","S","O","N","D"],abbreviated:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],wide:["January","February","March","April","May","June","July","August","September","October","November","December"]},defaultWidth:"wide"}),day:St({values:{narrow:["S","M","T","W","T","F","S"],short:["Su","Mo","Tu","We","Th","Fr","Sa"],abbreviated:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],wide:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]},defaultWidth:"wide"}),dayPeriod:St({values:{narrow:{am:"a",pm:"p",midnight:"mi",noon:"n",morning:"morning",afternoon:"afternoon",evening:"evening",night:"night"},abbreviated:{am:"AM",pm:"PM",midnight:"midnight",noon:"noon",morning:"morning",afternoon:"afternoon",evening:"evening",night:"night"},wide:{am:"a.m.",pm:"p.m.",midnight:"midnight",noon:"noon",morning:"morning",afternoon:"afternoon",evening:"evening",night:"night"}},defaultWidth:"wide",formattingValues:{narrow:{am:"a",pm:"p",midnight:"mi",noon:"n",morning:"in the morning",afternoon:"in the afternoon",evening:"in the evening",night:"at night"},abbreviated:{am:"AM",pm:"PM",midnight:"midnight",noon:"noon",morning:"in the morning",afternoon:"in the afternoon",evening:"in the evening",night:"at night"},wide:{am:"a.m.",pm:"p.m.",midnight:"midnight",noon:"noon",morning:"in the morning",afternoon:"in the afternoon",evening:"in the evening",night:"at night"}},defaultFormattingWidth:"wide"})},Ct=Tt;function Pt(t){return function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=n.width,o=r&&t.matchPatterns[r]||t.matchPatterns[t.defaultMatchWidth],i=e.match(o);if(!i)return null;var a,s=i[0],u=r&&t.parsePatterns[r]||t.parsePatterns[t.defaultParseWidth],c=Array.isArray(u)?Dt(u,(function(t){return t.test(s)})):Et(u,(function(t){return t.test(s)}));a=t.valueCallback?t.valueCallback(c):c,a=n.valueCallback?n.valueCallback(a):a;var l=e.slice(s.length);return{value:a,rest:l}}}function Et(t,e){for(var n in t)if(t.hasOwnProperty(n)&&e(t[n]))return n}function Dt(t,e){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{},n=t.match(Mt.matchPattern);if(!n)return null;var r=n[0],o=t.match(Mt.parsePattern);if(!o)return null;var i=Mt.valueCallback?Mt.valueCallback(o[0]):o[0];i=e.valueCallback?e.valueCallback(i):i;var a=t.slice(r.length);return{value:i,rest:a}}),era:Pt({matchPatterns:{narrow:/^(b|a)/i,abbreviated:/^(b\.?\s?c\.?|b\.?\s?c\.?\s?e\.?|a\.?\s?d\.?|c\.?\s?e\.?)/i,wide:/^(before christ|before common era|anno domini|common era)/i},defaultMatchWidth:"wide",parsePatterns:{any:[/^b/i,/^(a|c)/i]},defaultParseWidth:"any"}),quarter:Pt({matchPatterns:{narrow:/^[1234]/i,abbreviated:/^q[1234]/i,wide:/^[1234](th|st|nd|rd)? quarter/i},defaultMatchWidth:"wide",parsePatterns:{any:[/1/i,/2/i,/3/i,/4/i]},defaultParseWidth:"any",valueCallback:function(t){return t+1}}),month:Pt({matchPatterns:{narrow:/^[jfmasond]/i,abbreviated:/^(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)/i,wide:/^(january|february|march|april|may|june|july|august|september|october|november|december)/i},defaultMatchWidth:"wide",parsePatterns:{narrow:[/^j/i,/^f/i,/^m/i,/^a/i,/^m/i,/^j/i,/^j/i,/^a/i,/^s/i,/^o/i,/^n/i,/^d/i],any:[/^ja/i,/^f/i,/^mar/i,/^ap/i,/^may/i,/^jun/i,/^jul/i,/^au/i,/^s/i,/^o/i,/^n/i,/^d/i]},defaultParseWidth:"any"}),day:Pt({matchPatterns:{narrow:/^[smtwf]/i,short:/^(su|mo|tu|we|th|fr|sa)/i,abbreviated:/^(sun|mon|tue|wed|thu|fri|sat)/i,wide:/^(sunday|monday|tuesday|wednesday|thursday|friday|saturday)/i},defaultMatchWidth:"wide",parsePatterns:{narrow:[/^s/i,/^m/i,/^t/i,/^w/i,/^t/i,/^f/i,/^s/i],any:[/^su/i,/^m/i,/^tu/i,/^w/i,/^th/i,/^f/i,/^sa/i]},defaultParseWidth:"any"}),dayPeriod:Pt({matchPatterns:{narrow:/^(a|p|mi|n|(in the|at) (morning|afternoon|evening|night))/i,any:/^([ap]\.?\s?m\.?|midnight|noon|(in the|at) (morning|afternoon|evening|night))/i},defaultMatchWidth:"any",parsePatterns:{any:{am:/^a/i,pm:/^p/i,midnight:/^mi/i,noon:/^no/i,morning:/morning/i,afternoon:/afternoon/i,evening:/evening/i,night:/night/i}},defaultParseWidth:"any"})},Ot={code:"en-US",formatDistance:function(t,e,n){var r,o=wt[t];return r="string"==typeof o?o:1===e?o.one:o.other.replace("{{count}}",e.toString()),null!=n&&n.addSuffix?n.comparison&&n.comparison>0?"in "+r:r+" ago":r},formatLong:kt,formatRelative:function(t,e,n,r){return xt[t]},localize:Ct,match:At,options:{weekStartsOn:0,firstWeekContainsDate:1}};function Nt(t,e){it(2,arguments);var n=ot(e);return ut(t,-n)}function Ut(t,e){for(var n=t<0?"-":"",r=Math.abs(t).toString();r.length0?n:1-n;return Ut("yy"===e?r%100:r,e.length)},Wt=function(t,e){var n=t.getUTCMonth();return"M"===e?String(n+1):Ut(n+1,2)},Lt=function(t,e){return Ut(t.getUTCDate(),e.length)},Rt=function(t,e){return Ut(t.getUTCHours()%12||12,e.length)},Yt=function(t,e){return Ut(t.getUTCHours(),e.length)},Ft=function(t,e){return Ut(t.getUTCMinutes(),e.length)},It=function(t,e){return Ut(t.getUTCSeconds(),e.length)},Ht=function(t,e){var n=e.length,r=t.getUTCMilliseconds();return Ut(Math.floor(r*Math.pow(10,n-3)),e.length)},qt=864e5;function $t(t){it(1,arguments);var e=1,n=at(t),r=n.getUTCDay(),o=(r=o.getTime()?n+1:e.getTime()>=a.getTime()?n:n-1}function Bt(t){it(1,arguments);var e=zt(t),n=new Date(0);n.setUTCFullYear(e,0,4),n.setUTCHours(0,0,0,0);var r=$t(n);return r}var Xt=6048e5;function Gt(t,e){it(1,arguments);var n=e||{},r=n.locale,o=r&&r.options&&r.options.weekStartsOn,i=null==o?0:ot(o),a=null==n.weekStartsOn?i:ot(n.weekStartsOn);if(!(a>=0&&a<=6))throw new RangeError("weekStartsOn must be between 0 and 6 inclusively");var s=at(t),u=s.getUTCDay(),c=(u=1&&u<=7))throw new RangeError("firstWeekContainsDate must be between 1 and 7 inclusively");var c=new Date(0);c.setUTCFullYear(r+1,0,u),c.setUTCHours(0,0,0,0);var l=Gt(c,e),h=new Date(0);h.setUTCFullYear(r,0,u),h.setUTCHours(0,0,0,0);var f=Gt(h,e);return n.getTime()>=l.getTime()?r+1:n.getTime()>=f.getTime()?r:r-1}function Jt(t,e){it(1,arguments);var n=e||{},r=n.locale,o=r&&r.options&&r.options.firstWeekContainsDate,i=null==o?1:ot(o),a=null==n.firstWeekContainsDate?i:ot(n.firstWeekContainsDate),s=Qt(t,e),u=new Date(0);u.setUTCFullYear(s,0,a),u.setUTCHours(0,0,0,0);var c=Gt(u,e);return c}var Vt=6048e5,Kt={G:function(t,e,n){var r=t.getUTCFullYear()>0?1:0;switch(e){case"G":case"GG":case"GGG":return n.era(r,{width:"abbreviated"});case"GGGGG":return n.era(r,{width:"narrow"});default:return n.era(r,{width:"wide"})}},y:function(t,e,n){if("yo"===e){var r=t.getUTCFullYear(),o=r>0?r:1-r;return n.ordinalNumber(o,{unit:"year"})}return jt(t,e)},Y:function(t,e,n,r){var o=Qt(t,r),i=o>0?o:1-o;return"YY"===e?Ut(i%100,2):"Yo"===e?n.ordinalNumber(i,{unit:"year"}):Ut(i,e.length)},R:function(t,e){return Ut(zt(t),e.length)},u:function(t,e){return Ut(t.getUTCFullYear(),e.length)},Q:function(t,e,n){var r=Math.ceil((t.getUTCMonth()+1)/3);switch(e){case"Q":return String(r);case"QQ":return Ut(r,2);case"Qo":return n.ordinalNumber(r,{unit:"quarter"});case"QQQ":return n.quarter(r,{width:"abbreviated",context:"formatting"});case"QQQQQ":return n.quarter(r,{width:"narrow",context:"formatting"});default:return n.quarter(r,{width:"wide",context:"formatting"})}},q:function(t,e,n){var r=Math.ceil((t.getUTCMonth()+1)/3);switch(e){case"q":return String(r);case"qq":return Ut(r,2);case"qo":return n.ordinalNumber(r,{unit:"quarter"});case"qqq":return n.quarter(r,{width:"abbreviated",context:"standalone"});case"qqqqq":return n.quarter(r,{width:"narrow",context:"standalone"});default:return n.quarter(r,{width:"wide",context:"standalone"})}},M:function(t,e,n){var r=t.getUTCMonth();switch(e){case"M":case"MM":return Wt(t,e);case"Mo":return n.ordinalNumber(r+1,{unit:"month"});case"MMM":return n.month(r,{width:"abbreviated",context:"formatting"});case"MMMMM":return n.month(r,{width:"narrow",context:"formatting"});default:return n.month(r,{width:"wide",context:"formatting"})}},L:function(t,e,n){var r=t.getUTCMonth();switch(e){case"L":return String(r+1);case"LL":return Ut(r+1,2);case"Lo":return n.ordinalNumber(r+1,{unit:"month"});case"LLL":return n.month(r,{width:"abbreviated",context:"standalone"});case"LLLLL":return n.month(r,{width:"narrow",context:"standalone"});default:return n.month(r,{width:"wide",context:"standalone"})}},w:function(t,e,n,r){var o=function(t,e){it(1,arguments);var n=at(t),r=Gt(n,e).getTime()-Jt(n,e).getTime();return Math.round(r/Vt)+1}(t,r);return"wo"===e?n.ordinalNumber(o,{unit:"week"}):Ut(o,e.length)},I:function(t,e,n){var r=function(t){it(1,arguments);var e=at(t),n=$t(e).getTime()-Bt(e).getTime();return Math.round(n/Xt)+1}(t);return"Io"===e?n.ordinalNumber(r,{unit:"week"}):Ut(r,e.length)},d:function(t,e,n){return"do"===e?n.ordinalNumber(t.getUTCDate(),{unit:"date"}):Lt(t,e)},D:function(t,e,n){var r=function(t){it(1,arguments);var e=at(t),n=e.getTime();e.setUTCMonth(0,1),e.setUTCHours(0,0,0,0);var r=e.getTime(),o=n-r;return Math.floor(o/qt)+1}(t);return"Do"===e?n.ordinalNumber(r,{unit:"dayOfYear"}):Ut(r,e.length)},E:function(t,e,n){var r=t.getUTCDay();switch(e){case"E":case"EE":case"EEE":return n.day(r,{width:"abbreviated",context:"formatting"});case"EEEEE":return n.day(r,{width:"narrow",context:"formatting"});case"EEEEEE":return n.day(r,{width:"short",context:"formatting"});default:return n.day(r,{width:"wide",context:"formatting"})}},e:function(t,e,n,r){var o=t.getUTCDay(),i=(o-r.weekStartsOn+8)%7||7;switch(e){case"e":return String(i);case"ee":return Ut(i,2);case"eo":return n.ordinalNumber(i,{unit:"day"});case"eee":return n.day(o,{width:"abbreviated",context:"formatting"});case"eeeee":return n.day(o,{width:"narrow",context:"formatting"});case"eeeeee":return n.day(o,{width:"short",context:"formatting"});default:return n.day(o,{width:"wide",context:"formatting"})}},c:function(t,e,n,r){var o=t.getUTCDay(),i=(o-r.weekStartsOn+8)%7||7;switch(e){case"c":return String(i);case"cc":return Ut(i,e.length);case"co":return n.ordinalNumber(i,{unit:"day"});case"ccc":return n.day(o,{width:"abbreviated",context:"standalone"});case"ccccc":return n.day(o,{width:"narrow",context:"standalone"});case"cccccc":return n.day(o,{width:"short",context:"standalone"});default:return n.day(o,{width:"wide",context:"standalone"})}},i:function(t,e,n){var r=t.getUTCDay(),o=0===r?7:r;switch(e){case"i":return String(o);case"ii":return Ut(o,e.length);case"io":return n.ordinalNumber(o,{unit:"day"});case"iii":return n.day(r,{width:"abbreviated",context:"formatting"});case"iiiii":return n.day(r,{width:"narrow",context:"formatting"});case"iiiiii":return n.day(r,{width:"short",context:"formatting"});default:return n.day(r,{width:"wide",context:"formatting"})}},a:function(t,e,n){var r=t.getUTCHours()/12>=1?"pm":"am";switch(e){case"a":case"aa":return n.dayPeriod(r,{width:"abbreviated",context:"formatting"});case"aaa":return n.dayPeriod(r,{width:"abbreviated",context:"formatting"}).toLowerCase();case"aaaaa":return n.dayPeriod(r,{width:"narrow",context:"formatting"});default:return n.dayPeriod(r,{width:"wide",context:"formatting"})}},b:function(t,e,n){var r,o=t.getUTCHours();switch(r=12===o?"noon":0===o?"midnight":o/12>=1?"pm":"am",e){case"b":case"bb":return n.dayPeriod(r,{width:"abbreviated",context:"formatting"});case"bbb":return n.dayPeriod(r,{width:"abbreviated",context:"formatting"}).toLowerCase();case"bbbbb":return n.dayPeriod(r,{width:"narrow",context:"formatting"});default:return n.dayPeriod(r,{width:"wide",context:"formatting"})}},B:function(t,e,n){var r,o=t.getUTCHours();switch(r=o>=17?"evening":o>=12?"afternoon":o>=4?"morning":"night",e){case"B":case"BB":case"BBB":return n.dayPeriod(r,{width:"abbreviated",context:"formatting"});case"BBBBB":return n.dayPeriod(r,{width:"narrow",context:"formatting"});default:return n.dayPeriod(r,{width:"wide",context:"formatting"})}},h:function(t,e,n){if("ho"===e){var r=t.getUTCHours()%12;return 0===r&&(r=12),n.ordinalNumber(r,{unit:"hour"})}return Rt(t,e)},H:function(t,e,n){return"Ho"===e?n.ordinalNumber(t.getUTCHours(),{unit:"hour"}):Yt(t,e)},K:function(t,e,n){var r=t.getUTCHours()%12;return"Ko"===e?n.ordinalNumber(r,{unit:"hour"}):Ut(r,e.length)},k:function(t,e,n){var r=t.getUTCHours();return 0===r&&(r=24),"ko"===e?n.ordinalNumber(r,{unit:"hour"}):Ut(r,e.length)},m:function(t,e,n){return"mo"===e?n.ordinalNumber(t.getUTCMinutes(),{unit:"minute"}):Ft(t,e)},s:function(t,e,n){return"so"===e?n.ordinalNumber(t.getUTCSeconds(),{unit:"second"}):It(t,e)},S:function(t,e){return Ht(t,e)},X:function(t,e,n,r){var o=(r._originalDate||t).getTimezoneOffset();if(0===o)return"Z";switch(e){case"X":return te(o);case"XXXX":case"XX":return ee(o);default:return ee(o,":")}},x:function(t,e,n,r){var o=(r._originalDate||t).getTimezoneOffset();switch(e){case"x":return te(o);case"xxxx":case"xx":return ee(o);default:return ee(o,":")}},O:function(t,e,n,r){var o=(r._originalDate||t).getTimezoneOffset();switch(e){case"O":case"OO":case"OOO":return"GMT"+Zt(o,":");default:return"GMT"+ee(o,":")}},z:function(t,e,n,r){var o=(r._originalDate||t).getTimezoneOffset();switch(e){case"z":case"zz":case"zzz":return"GMT"+Zt(o,":");default:return"GMT"+ee(o,":")}},t:function(t,e,n,r){var o=r._originalDate||t;return Ut(Math.floor(o.getTime()/1e3),e.length)},T:function(t,e,n,r){return Ut((r._originalDate||t).getTime(),e.length)}};function Zt(t,e){var n=t>0?"-":"+",r=Math.abs(t),o=Math.floor(r/60),i=r%60;return 0===i?n+String(o):n+String(o)+e+Ut(i,2)}function te(t,e){return t%60==0?(t>0?"-":"+")+Ut(Math.abs(t)/60,2):ee(t,e)}function ee(t,e){var n=e||"",r=t>0?"-":"+",o=Math.abs(t);return r+Ut(Math.floor(o/60),2)+n+Ut(o%60,2)}var ne=Kt;function re(t,e){switch(t){case"P":return e.date({width:"short"});case"PP":return e.date({width:"medium"});case"PPP":return e.date({width:"long"});default:return e.date({width:"full"})}}function oe(t,e){switch(t){case"p":return e.time({width:"short"});case"pp":return e.time({width:"medium"});case"ppp":return e.time({width:"long"});default:return e.time({width:"full"})}}var ie={p:oe,P:function(t,e){var n,r=t.match(/(P+)(p+)?/)||[],o=r[1],i=r[2];if(!i)return re(t,e);switch(o){case"P":n=e.dateTime({width:"short"});break;case"PP":n=e.dateTime({width:"medium"});break;case"PPP":n=e.dateTime({width:"long"});break;default:n=e.dateTime({width:"full"})}return n.replace("{{date}}",re(o,e)).replace("{{time}}",oe(i,e))}},ae=["D","DD"],se=["YY","YYYY"];function ue(t){return-1!==ae.indexOf(t)}function ce(t){return-1!==se.indexOf(t)}function le(t,e,n){if("YYYY"===t)throw new RangeError("Use `yyyy` instead of `YYYY` (in `".concat(e,"`) for formatting years to the input `").concat(n,"`; see: https://git.io/fxCyr"));if("YY"===t)throw new RangeError("Use `yy` instead of `YY` (in `".concat(e,"`) for formatting years to the input `").concat(n,"`; see: https://git.io/fxCyr"));if("D"===t)throw new RangeError("Use `d` instead of `D` (in `".concat(e,"`) for formatting days of the month to the input `").concat(n,"`; see: https://git.io/fxCyr"));if("DD"===t)throw new RangeError("Use `dd` instead of `DD` (in `".concat(e,"`) for formatting days of the month to the input `").concat(n,"`; see: https://git.io/fxCyr"))}var he=/[yYQqMLwIdDecihHKkms]o|(\w)\1*|''|'(''|[^'])+('|$)|./g,fe=/P+p+|P+|p+|''|'(''|[^'])+('|$)|./g,de=/^'([^]*?)'?$/,pe=/''/g,me=/[a-zA-Z]/;function ye(t,e,n){it(2,arguments);var r=String(e),o=n||{},i=o.locale||Ot,a=i.options&&i.options.firstWeekContainsDate,s=null==a?1:ot(a),u=null==o.firstWeekContainsDate?s:ot(o.firstWeekContainsDate);if(!(u>=1&&u<=7))throw new RangeError("firstWeekContainsDate must be between 1 and 7 inclusively");var c=i.options&&i.options.weekStartsOn,l=null==c?0:ot(c),h=null==o.weekStartsOn?l:ot(o.weekStartsOn);if(!(h>=0&&h<=6))throw new RangeError("weekStartsOn must be between 0 and 6 inclusively");if(!i.localize)throw new RangeError("locale must contain localize property");if(!i.formatLong)throw new RangeError("locale must contain formatLong property");var f=at(t);if(!pt(f))throw new RangeError("Invalid time value");var d=lt(f),p=Nt(f,d),m={firstWeekContainsDate:u,weekStartsOn:h,locale:i,_originalDate:f},y=r.match(fe).map((function(t){var e=t[0];return"p"===e||"P"===e?(0,ie[e])(t,i.formatLong,m):t})).join("").match(he).map((function(n){if("''"===n)return"'";var r=n[0];if("'"===r)return _e(n);var a=ne[r];if(a)return!o.useAdditionalWeekYearTokens&&ce(n)&&le(n,e,t),!o.useAdditionalDayOfYearTokens&&ue(n)&&le(n,e,t),a(p,n,i.localize,m);if(r.match(me))throw new RangeError("Format string contains an unescaped latin alphabet character `"+r+"`");return n})).join("");return y}function _e(t){return t.match(de)[1].replace(pe,"'")}function ge(t){return function(t,e){if(null==t)throw new TypeError("assign requires that input parameter not be null or undefined");for(var n in e=e||{})Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t}({},t)}var ve=6e4,we=1440,be=43200,ke=525600;function xe(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};it(2,arguments);var r=n.locale||Ot;if(!r.formatDistance)throw new RangeError("locale must contain localize.formatDistance property");var o=ft(t,e);if(isNaN(o))throw new RangeError("Invalid time value");var i,a,s=ge(n);s.addSuffix=Boolean(n.addSuffix),s.comparison=o,o>0?(i=at(e),a=at(t)):(i=at(t),a=at(e));var u,c=null==n.roundingMethod?"round":String(n.roundingMethod);if("floor"===c)u=Math.floor;else if("ceil"===c)u=Math.ceil;else{if("round"!==c)throw new RangeError("roundingMethod must be 'floor', 'ceil' or 'round'");u=Math.round}var l,h=a.getTime()-i.getTime(),f=h/ve,d=lt(a)-lt(i),p=(h-d)/ve;if("second"===(l=null==n.unit?f<1?"second":f<60?"minute":fvoid 0===t&&void 0===e||null===t&&null===e||(null!=t&&null!=t&&t[Se]?t[Se](e):null!=e&&null!=e&&e[Se]?e[Se](t):(t&&t.$$typeof===Te||e&&e.$$typeof===Te||console.warn("Comparing entites with === because there is no comparison function defined:",t,e),t===e));class Record{constructor(t){for(let e in t)this[e]=t[e]}[Se](t){if(!(t instanceof Record))return!1;if(Object.keys(this).length!==Object.keys(t).length)return!1;for(let e in this)if(!Ce(t[e],this[e]))return!1;return!0}}const Pe=(t,e)=>n=>{const r=class extends Record{};return r.mappings=n,r.encode=t=>{const e={};for(let r in n){const[o,i,a]=n[r];e[o]=a?a(t[r]):t[r]}return e},r.decode=o=>{const{ok:i,err:a}=e,s={};for(let e in n){const[r,i]=n[e],u=t.field(r,i)(o);if(u instanceof a)return u;s[e]=u._0}return new i(new r(s))},r},Ee=(t,e)=>{const n=Object.assign(Object.create(null),t,e);return t instanceof Record?new t.constructor(n):new Record(n)},De=(t,e=!0)=>{window.location.pathname+window.location.search+window.location.hash!==t&&(e?(window.history.pushState({},"",t),dispatchEvent(new PopStateEvent("popstate"))):window.history.replaceState({},"",t))},Me=t=>{let e=document.createElement("style");document.head.appendChild(e),e.innerHTML=t},Ae=t=>(e,n)=>{const{just:r,nothing:o}=t;return e.length>=n+1&&n>=0?new r(e[n]):new o};class Oe{constructor(){this.effectAllowed="none",this.dropEffect="none",this.files=[],this.types=[],this.cache={}}getData(t){return this.cache[t]||""}setData(t,e){return this.cache[t]=e,null}clearData(){return this.cache={},null}}const Ne=t=>new Proxy(t,{get:function(t,e){if(e in t){const n=t[e];return n instanceof Function?()=>t[e]():n}switch(e){case"clipboardData":return t.clipboardData=new Oe;case"dataTransfer":return t.dataTransfer=new Oe;case"data":case"key":case"locale":case"animationName":case"pseudoElement":case"propertyName":return"";case"altKey":case"ctrlKey":case"metaKey":case"repeat":case"shiftKey":return!1;case"charCode":case"keyCode":case"location":case"which":case"button":case"buttons":case"clientX":case"clientY":case"pageX":case"pageY":case"screenX":case"screenY":case"detail":case"deltaMode":case"deltaX":case"deltaY":case"deltaZ":case"elapsedTime":return-1;default:return}}}),Ue=(t,e)=>{const n=Object.getOwnPropertyDescriptors(Reflect.getPrototypeOf(t));for(let r in n){if(e&&e[r])continue;const o=n[r].value;"function"==typeof o&&(t[r]=o.bind(t))}},je=(t,e)=>{if(!e)return;const n={};Object.keys(e).forEach((t=>{let r=null;n[t]={get:()=>(r||(r=e[t]()),r)}})),Object.defineProperties(t,n)},We=function(){let t=Array.from(arguments);return Array.isArray(t[0])&&1===t.length?t[0]:t},Le=function(t){const e={},n=(t,n)=>{e[t.toString().trim()]=n.toString().trim()};for(let e of t)if("string"==typeof e)e.split(";").forEach((t=>{const[e,r]=t.split(":");e&&r&&n(e,r)}));else if(e instanceof Map)for(let[t,r]of e)n(t,r);else if(e instanceof Array)for(let[t,r]of e)n(t,r);else for(let t in e)n(t,e[t]);return e};class Re extends p{render(){const t=[];for(let e in this.props.globals)t.push(h(this.props.globals[e],{ref:t=>t._persist(),key:e}));return h("div",{},[...t,...this.props.children])}}Re.displayName="Mint.Root";class Ye{constructor(t){t&&t instanceof Node&&t!==document.body?this.root=t:(this.root=document.createElement("div"),document.body.appendChild(this.root))}render(t,e){void 0!==t&&D(h(Re,{globals:e},[h(t,{key:"$MAIN"})]),this.root)}}class Fe{constructor(t,e){this.teardown=e,this.subject=t,this.steps=[]}async run(){let t;try{t=await new Promise(this.next.bind(this))}finally{this.teardown&&this.teardown()}return t}async next(t,e){requestAnimationFrame((async()=>{let n=this.steps.shift();if(n)try{this.subject=await n(this.subject)}catch(t){return e(t)}this.steps.length?this.next(t,e):t(this.subject)}))}step(t){return this.steps.push(t),this}}const Ie=["componentWillMount","render","getSnapshotBeforeUpdate","componentDidMount","componentWillReceiveProps","shouldComponentUpdate","componentWillUpdate","componentDidUpdate","componentWillUnmount","componentDidCatch","setState","forceUpdate","constructor"];class He extends p{constructor(t){super(t),Ue(this,Ie)}_d(t,e){je(this,e);const n={};Object.keys(t).forEach((e=>{const[r,o]=t[e],i=r||e;n[e]={get:()=>i in this.props?this.props[i]:o}})),Object.defineProperties(this,n)}}class qe{constructor(){Ue(this),this.subscriptions=new Map,this.state={}}setState(t,e){this.state=Object.assign({},this.state,t),e()}_d(t){je(this,t)}_subscribe(t,e){const n=this.subscriptions.get(t);null==e||null!=n&&((t,e)=>{if(t instanceof Object&&e instanceof Object){const n=new Set(Object.keys(t).concat(Object.keys(e)));for(let r of n)if(!Ce(t[r],e[r]))return!1;return!0}return console.warn("Comparing entites with === because there is no comparison function defined:",t,e),t===e})(n,e)||(this.subscriptions.set(t,e),this._update())}_unsubscribe(t){this.subscriptions.has(t)&&(this.subscriptions.delete(t),this._update())}_update(){this.update()}get _subscriptions(){return Array.from(this.subscriptions.values())}update(){}}var $e,ze,Be=($e=function(t,e){var n=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,9],n=[1,10],r=[1,11],o=[1,12],i=[5,11,12,13,14,15],a={trace:function(){},yy:{},symbols_:{error:2,root:3,expressions:4,EOF:5,expression:6,optional:7,literal:8,splat:9,param:10,"(":11,")":12,LITERAL:13,SPLAT:14,PARAM:15,$accept:0,$end:1},terminals_:{2:"error",5:"EOF",11:"(",12:")",13:"LITERAL",14:"SPLAT",15:"PARAM"},productions_:[0,[3,2],[3,1],[4,2],[4,1],[6,1],[6,1],[6,1],[6,1],[7,3],[8,1],[9,1],[10,1]],performAction:function(t,e,n,r,o,i,a){var s=i.length-1;switch(o){case 1:return new r.Root({},[i[s-1]]);case 2:return new r.Root({},[new r.Literal({value:""})]);case 3:this.$=new r.Concat({},[i[s-1],i[s]]);break;case 4:case 5:this.$=i[s];break;case 6:this.$=new r.Literal({value:i[s]});break;case 7:this.$=new r.Splat({name:i[s]});break;case 8:this.$=new r.Param({name:i[s]});break;case 9:this.$=new r.Optional({},[i[s-1]]);break;case 10:this.$=t;break;case 11:case 12:this.$=t.slice(1)}},table:[{3:1,4:2,5:[1,3],6:4,7:5,8:6,9:7,10:8,11:e,13:n,14:r,15:o},{1:[3]},{5:[1,13],6:14,7:5,8:6,9:7,10:8,11:e,13:n,14:r,15:o},{1:[2,2]},t(i,[2,4]),t(i,[2,5]),t(i,[2,6]),t(i,[2,7]),t(i,[2,8]),{4:15,6:4,7:5,8:6,9:7,10:8,11:e,13:n,14:r,15:o},t(i,[2,10]),t(i,[2,11]),t(i,[2,12]),{1:[2,1]},t(i,[2,3]),{6:14,7:5,8:6,9:7,10:8,11:e,12:[1,16],13:n,14:r,15:o},t(i,[2,9])],defaultActions:{3:[2,2],13:[2,1]},parseError:function(t,e){if(!e.recoverable){function n(t,e){this.message=t,this.hash=e}throw n.prototype=Error,new n(t,e)}this.trace(t)},parse:function(t){var e=this,n=[0],r=[null],o=[],i=this.table,a="",s=0,u=0,c=2,l=1,h=o.slice.call(arguments,1),f=Object.create(this.lexer),d={yy:{}};for(var p in this.yy)Object.prototype.hasOwnProperty.call(this.yy,p)&&(d.yy[p]=this.yy[p]);f.setInput(t,d.yy),d.yy.lexer=f,d.yy.parser=this,void 0===f.yylloc&&(f.yylloc={});var m=f.yylloc;o.push(m);var y=f.options&&f.options.ranges;"function"==typeof d.yy.parseError?this.parseError=d.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,g,v,w,b,k,x,S,T=function(){var t;return"number"!=typeof(t=f.lex()||l)&&(t=e.symbols_[t]||t),t},C={};;){if(g=n[n.length-1],this.defaultActions[g]?v=this.defaultActions[g]:(null==_&&(_=T()),v=i[g]&&i[g][_]),void 0===v||!v.length||!v[0]){var P="";for(b in S=[],i[g])this.terminals_[b]&&b>c&&S.push("'"+this.terminals_[b]+"'");P=f.showPosition?"Parse error on line "+(s+1)+":\n"+f.showPosition()+"\nExpecting "+S.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(s+1)+": Unexpected "+(_==l?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(P,{text:f.match,token:this.terminals_[_]||_,line:f.yylineno,loc:m,expected:S})}if(v[0]instanceof Array&&v.length>1)throw new Error("Parse Error: multiple actions possible at state: "+g+", token: "+_);switch(v[0]){case 1:n.push(_),r.push(f.yytext),o.push(f.yylloc),n.push(v[1]),_=null,u=f.yyleng,a=f.yytext,s=f.yylineno,m=f.yylloc;break;case 2:if(k=this.productions_[v[1]][1],C.$=r[r.length-k],C._$={first_line:o[o.length-(k||1)].first_line,last_line:o[o.length-1].last_line,first_column:o[o.length-(k||1)].first_column,last_column:o[o.length-1].last_column},y&&(C._$.range=[o[o.length-(k||1)].range[0],o[o.length-1].range[1]]),void 0!==(w=this.performAction.apply(C,[a,u,s,d.yy,v[1],r,o].concat(h))))return w;k&&(n=n.slice(0,-1*k*2),r=r.slice(0,-1*k),o=o.slice(0,-1*k)),n.push(this.productions_[v[1]][0]),r.push(C.$),o.push(C._$),x=i[n[n.length-2]][n[n.length-1]],n.push(x);break;case 3:return!0}}return!0}},s=function(){var t={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var o=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[o[0],o[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,o;if(this.options.backtrack_lexer&&(o={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(o.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var i in o)this[i]=o[i];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var o=this._currentRules(),i=0;ie[0].length)){if(e=n,r=i,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,o[i])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,o[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{},performAction:function(t,e,n,r){switch(n){case 0:return"(";case 1:return")";case 2:return"SPLAT";case 3:return"PARAM";case 4:case 5:return"LITERAL";case 6:return"EOF"}},rules:[/^(?:\()/,/^(?:\))/,/^(?:\*+\w+)/,/^(?::+\w+)/,/^(?:[\w%\-~\n]+)/,/^(?:.)/,/^(?:$)/],conditions:{INITIAL:{rules:[0,1,2,3,4,5,6],inclusive:!0}}};return t}();function u(){this.yy={}}return a.lexer=s,u.prototype=a,a.Parser=u,new u}();e.parser=n,e.Parser=n.Parser,e.parse=function(){return n.parse.apply(n,arguments)}},$e(ze={path:undefined,exports:{},require:function(t,e){return function(){throw new Error("Dynamic requires are not currently supported by @rollup/plugin-commonjs")}(null==e&&ze.path)}},ze.exports),ze.exports);function Xe(t){return function(e,n){return{displayName:t,props:e,children:n||[]}}}var Ge={Root:Xe("Root"),Concat:Xe("Concat"),Literal:Xe("Literal"),Splat:Xe("Splat"),Param:Xe("Param"),Optional:Xe("Optional")},Qe=Be.parser;Qe.yy=Ge;var Je=Qe,Ve=Object.keys(Ge),Ke=function(t){return Ve.forEach((function(e){if(void 0===t[e])throw new Error("No handler defined for "+e.displayName)})),{visit:function(t,e){return this.handlers[t.displayName].call(this,t,e)},handlers:t}},Ze=/[\-{}\[\]+?.,\\\^$|#\s]/g;function tn(t){this.captures=t.captures,this.re=t.re}tn.prototype.match=function(t){var e=this.re.exec(t),n={};if(e)return this.captures.forEach((function(t,r){void 0===e[r+1]?n[t]=void 0:n[t]=decodeURIComponent(e[r+1])})),n};var en=Ke({Concat:function(t){return t.children.reduce(function(t,e){var n=this.visit(e);return{re:t.re+n.re,captures:t.captures.concat(n.captures)}}.bind(this),{re:"",captures:[]})},Literal:function(t){return{re:t.props.value.replace(Ze,"\\$&"),captures:[]}},Splat:function(t){return{re:"([^?]*?)",captures:[t.props.name]}},Param:function(t){return{re:"([^\\/\\?]+)",captures:[t.props.name]}},Optional:function(t){var e=this.visit(t.children[0]);return{re:"(?:"+e.re+")?",captures:e.captures}},Root:function(t){var e=this.visit(t.children[0]);return new tn({re:new RegExp("^"+e.re+"(?=\\?|$)"),captures:e.captures})}}),nn=Ke({Concat:function(t,e){var n=t.children.map(function(t){return this.visit(t,e)}.bind(this));return!n.some((function(t){return!1===t}))&&n.join("")},Literal:function(t){return decodeURI(t.props.value)},Splat:function(t,e){return!!e[t.props.name]&&e[t.props.name]},Param:function(t,e){return!!e[t.props.name]&&e[t.props.name]},Optional:function(t,e){return this.visit(t.children[0],e)||""},Root:function(t,e){e=e||{};var n=this.visit(t.children[0],e);return!!n&&encodeURI(n)}}),rn=nn;function on(t){var e;if(e=this?this:Object.create(on.prototype),void 0===t)throw new Error("A route spec is required");return e.spec=t,e.ast=Je.parse(t),e}on.prototype=Object.create(null),on.prototype.match=function(t){return en.visit(this.ast).match(t)||!1},on.prototype.reverse=function(t){return rn.visit(this.ast,t)};var an=on;Event.prototype.propagationPath=function(){var t=function(){var t=this.target||null,e=[t];if(!t||!t.parentElement)return[];for(;t.parentElement;)t=t.parentElement,e.unshift(t);return e}.bind(this);return this.path||this.composedPath&&this.composedPath()||t()};class sn extends p{handleClick(t,e){if(!t.defaultPrevented&&!t.ctrlKey)for(let e of t.propagationPath())if("A"===e.tagName){if(""!==e.target.trim())return;let n=e.pathname,r=e.origin,o=e.search,i=e.hash;if(r===window.location.origin)for(let e of this.props.routes){let r=n+o+i,a=new an(e.path);if("*"==e.path||a.match(r))return t.preventDefault(),void De(r)}}}render(){const t=[];for(let e in this.props.globals)t.push(h(this.props.globals[e],{ref:t=>t._persist(),key:e}));return h("div",{onClick:this.handleClick.bind(this)},[...t,...this.props.children])}}sn.displayName="Mint.Root";var un=t=>class{constructor(){this.root=document.createElement("div"),document.body.appendChild(this.root),this.firstPageLoad=!0,this.routes=[],this.url=null,window.addEventListener("popstate",(()=>{this.handlePopState()}))}resolvePagePosition(){var t;t=()=>{requestAnimationFrame((()=>{let t;try{t=this.root.querySelector(`a[name="${window.location.hash.slice(1)}"]`)}finally{}window.location.hash&&t?window.location.href=window.location.hash:this.firstPageLoad||window.scrollTo(document.body.scrollTop,0),this.firstPageLoad=!1}))},"function"!=typeof window.queueMicrotask?Promise.resolve().then(t).catch((t=>setTimeout((()=>{throw t})))):window.queueMicrotask(t)}handlePopState(){const e=window.location.pathname+window.location.search+window.location.hash;if(e!==this.url){for(let n of this.routes)if("*"===n.path)n.handler(),this.resolvePagePosition();else{let r=new an(n.path).match(e);if(r)try{let e=n.mapping.map(((e,o)=>{const i=r[e],a=n.decoders[o](i);if(a instanceof t.ok)return a._0;throw""}));n.handler.apply(null,e),this.resolvePagePosition();break}catch(t){}}this.url=e}}render(t,e){void 0!==t&&(D(h(sn,{routes:this.routes,globals:e},[h(t,{key:"$MAIN"})]),this.root),this.handlePopState())}addRoutes(t){this.routes=this.routes.concat(t)}};const cn=t=>{let e=JSON.stringify(t,"",2);return void 0===e&&(e="undefined"),((t,e=1,n)=>{if(n={indent:" ",includeEmptyLines:!1,...n},"string"!=typeof t)throw new TypeError(`Expected \`input\` to be a \`string\`, got \`${typeof t}\``);if("number"!=typeof e)throw new TypeError(`Expected \`count\` to be a \`number\`, got \`${typeof e}\``);if("string"!=typeof n.indent)throw new TypeError(`Expected \`options.indent\` to be a \`string\`, got \`${typeof n.indent}\``);if(0===e)return t;const r=n.includeEmptyLines?/^/gm:/^(?!\s*$)/gm;return t.replace(r,n.indent.repeat(e))})(e)};class ln{constructor(t,e=[]){this.message=t,this.object=null,this.path=e}push(t){this.path.unshift(t)}toString(){const t=this.message.trim(),e=this.path.reduce(((t,e)=>{if(t.length)switch(e.type){case"FIELD":return`${t}.${e.value}`;case"ARRAY":return`${t}[${e.value}]`}else switch(e.type){case"FIELD":return e.value;case"ARRAY":return"[$(item.value)]"}}),"");return e.length&&this.object?t+"\n\n"+hn.trim().replace("{value}",cn(this.object)).replace("{path}",e):t}}const hn="\nThe input is in this object:\n\n{value}\n\nat: {path}\n",fn=t=>e=>{const{ok:n,err:r}=t;return"string"!=typeof e?new r(new ln("\nI was trying to decode the value:\n\n{value}\n\nas a String, but could not.\n".replace("{value}",cn(e)))):new n(e)},dn=t=>e=>{const{ok:n,err:r}=t;let o=NaN;return o="number"==typeof e?new Date(e):Date.parse(e),Number.isNaN(o)?new r(new ln("\nI was trying to decode the value:\n\n{value}\n\nas a Time, but could not.\n".replace("{value}",cn(e)))):new n(new Date(o))},pn=t=>e=>{const{ok:n,err:r}=t;let o=parseFloat(e);return isNaN(o)?new r(new ln("\nI was trying to decode the value:\n\n{value}\n\nas a Number, but could not.\n".replace("{value}",cn(e)))):new n(o)},mn=t=>e=>{const{ok:n,err:r}=t;return"boolean"!=typeof e?new r(new ln("\nI was trying to decode the value:\n\n{value}\n\nas a Bool, but could not.\n".replace("{value}",cn(e)))):new n(e)},yn=t=>(e,n)=>{const{err:r,nothing:o}=t;return t=>{if(null==t||null==t||"object"!=typeof t||Array.isArray(t)){const n='\nI was trying to decode the field "{field}" from the object:\n\n{value}\n\nbut I could not because it\'s not an object.\n'.replace("{field}",e).replace("{value}",cn(t));return new r(new ln(n))}{const o=t[e],i=n(o);return i instanceof r&&(i._0.push({type:"FIELD",value:e}),i._0.object=t),i}}},_n=t=>e=>n=>{const{ok:r,err:o}=t;if(!Array.isArray(n))return new o(new ln("\nI was trying to decode the value:\n\n{value}\n\nas an Array, but could not.\n".replace("{value}",cn(n))));let i=[],a=0;for(let t of n){let r=e(t);if(r instanceof o)return r._0.push({type:"ARRAY",value:a}),r._0.object=n,r;i.push(r._0),a++}return new r(i)},gn=t=>e=>n=>{const{ok:r,just:o,nothing:i,err:a}=t;if(null==n||null==n)return new r(new i);{const t=e(n);return t instanceof a?t:new r(new o(t._0))}},vn=t=>e=>n=>{const{ok:r,err:o}=t;if(!Array.isArray(n))return new o(new ln("\nI was trying to decode the value:\n\n{value}\n\nas an Tuple, but could not.\n".replace("{value}",cn(n))));let i=[],a=0;for(let t of e){if(void 0===n[a]||null===n[a])return new o(new ln("\nI was trying to decode one of the values of a tuple:\n\n{value}\n\nbut could not.\n".replace("{value}",cn(n[a]))));{let e=t(n[a]);if(e instanceof o)return e._0.push({type:"ARRAY",value:a}),e._0.object=n,e;i.push(e._0)}a++}return new r(i)},wn=t=>e=>n=>{const{ok:r,err:o}=t;if(null==n||null==n||"object"!=typeof n||Array.isArray(n)){const t="\nI was trying to decode the value:\n\n{value}\n\nas a Map, but could not.\n".replace("{value}",cn(n));return new o(new ln(t))}{const t=[];for(let r in n){const i=e(n[r]);if(i instanceof o)return i;t.push([r,i._0])}return new r(t)}},bn=t=>e=>new t.ok(e),kn=t=>t,xn=t=>t.toISOString(),Sn=t=>e=>e.map((e=>t?t(e):e)),Tn=t=>e=>{const n={};for(let r of e)n[r[0]]=t?t(r[1]):r[1];return n},Cn=t=>e=>n=>n instanceof t.just?e?e(n._0):n._0:null,Pn=t=>e=>e.map(((e,n)=>{const r=t[n];return r?r(e):e}));var En=t=>({maybe:Cn(t),identity:kn,tuple:Pn,array:Sn,time:xn,map:Tn});class Dn{constructor(){Ue(this)}_d(t){je(this,t)}}class Mn{constructor(){Ue(this),this.listeners=new Set,this.state={}}setState(t,e){this.state=Object.assign({},this.state,t);for(let t of this.listeners)t.forceUpdate();e()}_d(t){je(this,t)}_subscribe(t){this.listeners.add(t)}_unsubscribe(t){this.listeners.delete(t)}}class An{[Se](t){if(!(t instanceof this.constructor))return!1;if(t.length!==this.length)return!1;for(let e=0;e{const e=(t=>({boolean:mn(t),object:bn(t),number:pn(t),string:fn(t),field:yn(t),array:_n(t),maybe:gn(t),tuple:vn(t),time:dn(t),map:wn(t)}))(t);return{program:new(un(t)),normalizeEvent:Ne,insertStyles:Me,navigate:De,compare:Ce,update:Ee,array:We,style:Le,at:Ae(t),EmbeddedProgram:Ye,TestContext:Fe,Component:He,Provider:qe,Module:Dn,Store:Mn,Decoder:e,Encoder:En(t),DateFNS:{format:ye,startOfMonth:gt,startOfWeek:ct,startOfDay:ht,endOfMonth:yt,endOfWeek:vt,endOfDay:mt,addMonths:st,eachDay:_t,distanceInWordsStrict:xe},Record:Record,Enum:An,Nothing:t.nothing,Just:t.just,Err:t.err,Ok:t.ok,createRecord:Pe(e,t),createPortal:Q,register:rt,createElement:h,React:{Fragment:d},ReactDOM:{unmountComponentAtNode:t=>D(null,t),render:D},Symbols:{Equals:Se}}}}(); -(() => { - const _enums = {} - const mint = Mint(_enums) - - const _normalizeEvent = (event) => { - return DB.gb(mint.normalizeEvent(event)) - } - - const _R = mint.createRecord - const _h = mint.createElement - const _createPortal = mint.createPortal - const _insertStyles = mint.insertStyles - const _navigate = mint.navigate - const _compare = mint.compare - const _program = mint.program - const _encode = mint.encode - const _style = mint.style - const _array = mint.array - const _wc = mint.register - const _u = mint.update - const _at = mint.at - - window.TestContext = mint.TestContext - const TestContext = mint.TestContext - const ReactDOM = mint.ReactDOM - const Decoder = mint.Decoder - const Encoder = mint.Encoder - const DateFNS = mint.DateFNS - const Record = mint.Record - const React = mint.React - - const _C = mint.Component - const _P = mint.Provider - const _M = mint.Module - const _S = mint.Store - const _E = mint.Enum - - const _m = (method) => { - let value - return () => { - if (value) { return value } - value = method() - return value - } - } - - const _o = (item, value) => { - if (item !== undefined && item !== null) { - return item; - } else { - return value; - } - } - - const _s = (item, callback) => { - if (item instanceof BT) { - return item - } else if (item instanceof BR) { - return new BR(callback(item._0)) - } else { - return callback(item) - } - } - - class DoError extends Error {} - - class CV extends _E{constructor(){super();this.length = 0}};class CX extends _E{constructor(){super();this.length = 0}};class CW extends _E{constructor(){super();this.length = 0}};class CU extends _E{constructor(){super();this.length = 0}};class CR extends _E{constructor(_0){super();this._0 = _0;this.length = 1}};class CQ extends _E{constructor(_0){super();this._0 = _0;this.length = 1}};class BR extends _E{constructor(_0){super();this._0 = _0;this.length = 1}};class BT extends _E{constructor(){super();this.length = 0}};class CC extends _E{constructor(){super();this.length = 0}};class CE extends _E{constructor(){super();this.length = 0}};class BQ extends _E{constructor(){super();this.length = 0}};class BC extends _E{constructor(){super();this.length = 0}};class CJ extends _E{constructor(){super();this.length = 0}};class CK extends _E{constructor(){super();this.length = 0}};class CH extends _E{constructor(){super();this.length = 0}};class CI extends _E{constructor(){super();this.length = 0}};class CL extends _E{constructor(){super();this.length = 0}};class BW extends _E{constructor(){super();this.length = 0}};class BX extends _E{constructor(){super();this.length = 0}};class BV extends _E{constructor(){super();this.length = 0}};class BY extends _E{constructor(){super();this.length = 0}};class BZ extends _E{constructor(){super();this.length = 0}};const B = _R({});const C = _R({});const D = _R({});const E = _R({});const F = _R({});const G = _R({});const H = _R({});const I = _R({});const J = _R({});const K = _R({});const L = _R({});const M = _R({});const N = _R({});const O = _R({});const P = _R({});const Q = _R({});const R = _R({});const S = _R({caseInsensitive:["caseInsensitive",Decoder.boolean],multiline:["multiline",Decoder.boolean],unicode:["unicode",Decoder.boolean],global:["global",Decoder.boolean],sticky:["sticky",Decoder.boolean]});const T = _R({submatches:["submatches",Decoder.array(Decoder.string),Encoder.array()],match:["match",Decoder.string],index:["index",Decoder.number]});const U = _R({});const V = _R({});const W = _R({key:["key",Decoder.string],value:["value",Decoder.string]});const X = _R({});const Y = _R({status:["status",Decoder.number],body:["body",Decoder.string]});const Z = _R({});const AA = _R({});const AB = _R({hostname:["hostname",Decoder.string],protocol:["protocol",Decoder.string],origin:["origin",Decoder.string],search:["search",Decoder.string],path:["path",Decoder.string],hash:["hash",Decoder.string],host:["host",Decoder.string],port:["port",Decoder.string]});const AC = _R({height:["height",Decoder.number],bottom:["bottom",Decoder.number],width:["width",Decoder.number],right:["right",Decoder.number],left:["left",Decoder.number],top:["top",Decoder.number],x:["x",Decoder.number],y:["y",Decoder.number]});const AD = _R({});const AE = _R({});const AF = _R({defaultValue:["default",Decoder.maybe(Decoder.string),Encoder.maybe()],description:["description",Decoder.maybe(Decoder.string),Encoder.maybe()],type:["type",Decoder.maybe(Decoder.string),Encoder.maybe()],name:["name",Decoder.string]});const AG = _R({description:["description",Decoder.maybe(Decoder.string),Encoder.maybe()],type:["type",Decoder.maybe(Decoder.string),Encoder.maybe()],source:["source",Decoder.string],name:["name",Decoder.string]});const AH = _R({keys:["keys",Decoder.array(Decoder.string),Encoder.array()],store:["store",Decoder.string]});const AI = _R({computedProperties:["computed-properties",Decoder.array(((_)=>AG.decode(_))),Encoder.array(((_)=>AG.encode(_)))],states:["states",Decoder.array(((_)=>AF.decode(_))),Encoder.array(((_)=>AF.encode(_)))],properties:["properties",Decoder.array(((_)=>AF.decode(_))),Encoder.array(((_)=>AF.encode(_)))],description:["description",Decoder.maybe(Decoder.string),Encoder.maybe()],connects:["connects",Decoder.array(((_)=>AH.decode(_))),Encoder.array(((_)=>AH.encode(_)))],functions:["functions",Decoder.array(((_)=>AK.decode(_))),Encoder.array(((_)=>AK.encode(_)))],providers:["providers",Decoder.array(((_)=>AL.decode(_))),Encoder.array(((_)=>AL.encode(_)))],name:["name",Decoder.string]});const AL = _R({condition:["condition",Decoder.maybe(Decoder.string),Encoder.maybe()],provider:["provider",Decoder.string],data:["data",Decoder.string]});const AM = _R({computedProperties:["computed-properties",Decoder.array(((_)=>AG.decode(_))),Encoder.array(((_)=>AG.encode(_)))],states:["states",Decoder.array(((_)=>AF.decode(_))),Encoder.array(((_)=>AF.encode(_)))],description:["description",Decoder.maybe(Decoder.string),Encoder.maybe()],functions:["functions",Decoder.array(((_)=>AK.decode(_))),Encoder.array(((_)=>AK.encode(_)))],name:["name",Decoder.string]});const AK = _R({arguments:["arguments",Decoder.array(((_)=>AJ.decode(_))),Encoder.array(((_)=>AJ.encode(_)))],description:["description",Decoder.maybe(Decoder.string),Encoder.maybe()],type:["type",Decoder.maybe(Decoder.string),Encoder.maybe()],source:["source",Decoder.string],name:["name",Decoder.string]});const AN = _R({description:["description",Decoder.maybe(Decoder.string),Encoder.maybe()],functions:["functions",Decoder.array(((_)=>AK.decode(_))),Encoder.array(((_)=>AK.encode(_)))],subscription:["subscription",Decoder.string],name:["name",Decoder.string]});const AJ = _R({name:["name",Decoder.string],type:["type",Decoder.string]});const AO = _R({description:["description",Decoder.maybe(Decoder.string),Encoder.maybe()],functions:["functions",Decoder.array(((_)=>AK.decode(_))),Encoder.array(((_)=>AK.encode(_)))],name:["name",Decoder.string]});const AP = _R({computedProperties:["computedProperties",Decoder.array(((_)=>AG.decode(_))),Encoder.array(((_)=>AG.encode(_)))],properties:["properties",Decoder.array(((_)=>AF.decode(_))),Encoder.array(((_)=>AF.encode(_)))],fields:["fields",Decoder.array(((_)=>AQ.decode(_))),Encoder.array(((_)=>AQ.encode(_)))],options:["options",Decoder.array(((_)=>AR.decode(_))),Encoder.array(((_)=>AR.encode(_)))],parameters:["parameters",Decoder.array(Decoder.string),Encoder.array()],connects:["connects",Decoder.array(((_)=>AH.decode(_))),Encoder.array(((_)=>AH.encode(_)))],functions:["functions",Decoder.array(((_)=>AK.decode(_))),Encoder.array(((_)=>AK.encode(_)))],states:["states",Decoder.array(((_)=>AF.decode(_))),Encoder.array(((_)=>AF.encode(_)))],subscription:["subscription",Decoder.string],description:["description",Decoder.string],uses:["uses",Decoder.array(((_)=>AL.decode(_))),Encoder.array(((_)=>AL.encode(_)))],name:["name",Decoder.string]});const AS = _R({dependencies:["dependencies",Decoder.array(((_)=>AT.decode(_))),Encoder.array(((_)=>AT.encode(_)))],components:["components",Decoder.array(((_)=>AI.decode(_))),Encoder.array(((_)=>AI.encode(_)))],providers:["providers",Decoder.array(((_)=>AN.decode(_))),Encoder.array(((_)=>AN.encode(_)))],records:["records",Decoder.array(((_)=>AU.decode(_))),Encoder.array(((_)=>AU.encode(_)))],modules:["modules",Decoder.array(((_)=>AO.decode(_))),Encoder.array(((_)=>AO.encode(_)))],stores:["stores",Decoder.array(((_)=>AM.decode(_))),Encoder.array(((_)=>AM.encode(_)))],enums:["enums",Decoder.array(((_)=>AV.decode(_))),Encoder.array(((_)=>AV.encode(_)))],name:["name",Decoder.string]});const AW = _R({packages:["packages",Decoder.array(((_)=>AS.decode(_))),Encoder.array(((_)=>AS.encode(_)))]});const AT = _R({repository:["repository",Decoder.string],constraint:["constraint",Decoder.string],name:["name",Decoder.string]});const AQ = _R({mapping:["mapping",Decoder.maybe(Decoder.string),Encoder.maybe()],type:["type",Decoder.string],key:["key",Decoder.string]});const AU = _R({fields:["fields",Decoder.array(((_)=>AQ.decode(_))),Encoder.array(((_)=>AQ.encode(_)))],description:["description",Decoder.maybe(Decoder.string),Encoder.maybe()],name:["name",Decoder.string]});const AV = _R({description:["description",Decoder.maybe(Decoder.string),Encoder.maybe()],options:["options",Decoder.array(((_)=>AR.decode(_))),Encoder.array(((_)=>AR.encode(_)))],parameters:["parameters",Decoder.array(Decoder.string),Encoder.array()],name:["name",Decoder.string]});const AR = _R({description:["description",Decoder.maybe(Decoder.string),Encoder.maybe()],parameters:["parameters",Decoder.array(Decoder.string),Encoder.array()],name:["name",Decoder.string]});const CO=new(class extends _M{dw(dx){return (dx.toString())}});const BK=new(class extends _M{az(dy){return _compare(dy, ``)}aw(dz,ea){return (dz.join(ea))}});const CP=new(class extends _M{eb(ec){return ((() => { - try { - return new CQ((JSON.parse(ec))) - } catch (error) { - return new CR((error.message)) - } - })())}});const CS=new(class extends _M{ed(){return new X({withCredentials:false,method:`GET`,body:(null),headers:[],url:``})}ee(ef){return CS.eg(CS.eh(CS.ed(), `GET`), ef)}eh(ei,ej){return _u(ei, {method:ej})}ek(el){return CS.em(el, CT.en())}em(eo,ep){return (new Promise((resolve, reject) => { - if (!this._requests) { this._requests = {} } - - let xhr = new XMLHttpRequest() - - this._requests[ep] = xhr - - xhr.withCredentials = eo.withCredentials - - try { - xhr.open(eo.method.toUpperCase(), eo.url, true) - } catch (error) { - delete this._requests[ep] - - resolve(new CR(new Z({type:new CU(),status:(xhr.status),url:eo.url}))) - } - - eo.headers.forEach((item) => { - xhr.setRequestHeader(item.key, item.value) - }) - - xhr.addEventListener('error', (event) => { - delete this._requests[ep] - - resolve(new CR(new Z({type:new CV(),status:(xhr.status),url:eo.url}))) - }) - - xhr.addEventListener('timeout', (event) => { - delete this._requests[ep] - - resolve(new CR(new Z({type:new CW(),status:(xhr.status),url:eo.url}))) - }) - - xhr.addEventListener('load', (event) => { - delete this._requests[ep] - - resolve(new CQ(new Y({body:(xhr.responseText),status:(xhr.status)}))) - }) - - xhr.addEventListener('abort', (event) => { - delete this._requests[ep] - - resolve(new CR(new Z({type:new CX(),status:(xhr.status),url:eo.url}))) - }) - - xhr.send(eo.body) - }))}eg(eq,er){return _u(eq, {url:er})}});const BE=new(class extends _M{es(et,eu){return BE.ev((()=>{const _0 = [];const _1 = et;let _i = -1;for(let ew of _1){_i++;const _2 = eu(ew) -if (!_2) { continue };_0.push(ew)};return _0})())}ev(ex){return _at(ex, 0)}ax(ey){return _compare(BE.ez(ey), 0)}n(fa,fb){return (()=>{const _0 = [];const _1 = fa;let _i = -1;for(let fc of _1){_i++;_0.push(fb(fc))};return _0})()}ez(fd){return (fd.length)}});const CT=new(class extends _M{en(){return (([1e7] + -1e3 + -4e3 + -8e3 + -1e11) - .replace(/[018]/g, c => - (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4) - .toString(16)))}});const CY=new(class extends _M{fe(ff){return new CR(ff)}fg(fh){return new CQ(fh)}});const CZ=new(class extends _M{fi(fj){return (_navigate(fj))}fk(){return (window.pageYOffset)}fl(fm){return (window.scrollTo(CZ.fk(), fm))}});const CM=new(class extends _M{dp(){return (false)}});const DA=new(class extends _M{fn(fo){return ((() => { - if (window.DEBUG) { - window.DEBUG.log(fo) - } else { - console.log(fo) - } - - return fo - })())}});const BN=new(class extends _M{fp(fq){return (()=>{let fr = fq;if(fr instanceof BT){return new BT()} else if(fr instanceof BR){const fs = fr._0;return fs}})()}bc(ft){return !_compare(ft, new BT())}fu(fv){return new BR(fv)}fw(fx,fy){return (()=>{let fz = fx;if(fz instanceof BR){const ga = fz._0;return new BR(fy(ga))} else if(fz instanceof BT){return new BT()}})()}bd(){return new BT()}});const DB=new(class extends _M{gb(gc){return new AE({bubbles:(gc.bubbles),cancelable:(gc.cancelable),currentTarget:(gc.currentTarget),defaultPrevented:(gc.defaultPrevented),dataTransfer:(gc.dataTransfer),clipboardData:(gc.clipboardData),eventPhase:(gc.eventPhase),isTrusted:(gc.isTrusted),target:(gc.target),timeStamp:(gc.timeStamp),type:(gc.type),data:(gc.data),altKey:(gc.altKey),charCode:(gc.charCode),ctrlKey:(gc.ctrlKey),key:(gc.key),keyCode:(gc.keyCode),locale:(gc.locale),location:(gc.location),metaKey:(gc.metaKey),repeat:(gc.repeat),shiftKey:(gc.shiftKey),which:(gc.which),button:(gc.button),buttons:(gc.buttons),clientX:(gc.clientX),clientY:(gc.clientY),pageX:(gc.pageX),pageY:(gc.pageY),screenX:(gc.screenX),screenY:(gc.screenY),detail:(gc.detail),deltaMode:(gc.deltaMode),deltaX:(gc.deltaX),deltaY:(gc.deltaY),deltaZ:(gc.deltaZ),animationName:(gc.animationName),pseudoElement:(gc.pseudoElement),propertyName:(gc.propertyName),elapsedTime:(gc.elapsedTime),event:gc})}});const CG=new(class extends _M{ck(){return _h("svg", {"xmlns":`http://www.w3.org/2000/svg`,"width":`24`,"height":`24`,"viewBox":`0 0 24 24`}, [_h("path", {"d":`M16.677 17.868l-.343.195v-1.717l.343-.195v1.717zm2.823-3.325l-.342.195v1.717l.342-.195v-1.717zm3.5-7.602v11.507l-9.75 5.552-12.25-6.978v-11.507l9.767-5.515 12.233 6.941zm-13.846-3.733l9.022 5.178 1.7-.917-9.113-5.17-1.609.909zm2.846 9.68l-9-5.218v8.19l9 5.126v-8.098zm3.021-2.809l-8.819-5.217-2.044 1.167 8.86 5.138 2.003-1.088zm5.979-.943l-2 1.078v2.786l-3 1.688v-2.856l-2 1.078v8.362l7-3.985v-8.151zm-4.907 7.348l-.349.199v1.713l.349-.195v-1.717zm1.405-.8l-.344.196v1.717l.344-.196v-1.717zm.574-.327l-.343.195v1.717l.343-.195v-1.717zm.584-.333l-.35.199v1.717l.35-.199v-1.717z`})])}});const DC=new(class extends _M{gd(ge){return new AP({computedProperties:ge.computedProperties,description:_o(ge.description._0, ``),properties:ge.properties,functions:ge.functions,connects:ge.connects,uses:ge.providers,states:ge.states,subscription:``,name:ge.name,parameters:[],options:[],fields:[]})}gf(gg){return new AP({description:_o(gg.description._0, ``),computedProperties:[],fields:gg.fields,subscription:``,name:gg.name,properties:[],parameters:[],functions:[],connects:[],options:[],states:[],uses:[]})}gh(gi){return new AP({description:_o(gi.description._0, ``),parameters:gi.parameters,computedProperties:[],options:gi.options,subscription:``,name:gi.name,properties:[],functions:[],connects:[],fields:[],states:[],uses:[]})}gj(gk){return new AP({description:_o(gk.description._0, ``),subscription:gk.subscription,functions:gk.functions,computedProperties:[],name:gk.name,parameters:[],properties:[],connects:[],options:[],fields:[],states:[],uses:[]})}gl(gm){return new AP({computedProperties:gm.computedProperties,description:_o(gm.description._0, ``),functions:gm.functions,states:gm.states,subscription:``,name:gm.name,parameters:[],properties:[],connects:[],options:[],fields:[],uses:[]})}gn(go){return new AP({description:_o(go.description._0, ``),functions:go.functions,computedProperties:[],subscription:``,name:go.name,parameters:[],properties:[],connects:[],options:[],states:[],fields:[],uses:[]})}gp(){return new AP({computedProperties:[],subscription:``,description:``,parameters:[],properties:[],functions:[],connects:[],options:[],fields:[],states:[],uses:[],name:``})}});const BA=new(class extends _M{gq(gr){return (()=>{let gs = gr;if(_compare(gs, `component`)){return CY.fg(new BC())} else if(_compare(gs, `provider`)){return CY.fg(new CJ())} else if(_compare(gs, `record`)){return CY.fg(new CK())} else if(_compare(gs, `module`)){return CY.fg(new CH())} else if(_compare(gs, `store`)){return CY.fg(new CI())} else if(_compare(gs, `enum`)){return CY.fg(new CL())} else{return CY.fe(`Cannot find tab!`)}})()}g(gt){return (()=>{let gu = gt;if(gu instanceof BC){return `C`} else if(gu instanceof CJ){return `P`} else if(gu instanceof CK){return `R`} else if(gu instanceof CH){return `M`} else if(gu instanceof CI){return `S`} else if(gu instanceof CL){return `E`}})()}e(gv){return (()=>{let gw = gv;if(gw instanceof BC){return `#369e58`} else if(gw instanceof CJ){return `#ff7b00`} else if(gw instanceof CK){return `#673ab7`} else if(gw instanceof CH){return `#be08d0`} else if(gw instanceof CI){return `#d02e2e`} else if(gw instanceof CL){return `#00bbb5`}})()}j(gx){return (()=>{let gy = gx;if(gy instanceof BC){return `component`} else if(gy instanceof CJ){return `provider`} else if(gy instanceof CK){return `record`} else if(gy instanceof CH){return `module`} else if(gy instanceof CI){return `store`} else if(gy instanceof CL){return `enum`}})()}bk(gz){return (()=>{let ha = gz;if(ha instanceof BC){return `Components`} else if(ha instanceof CJ){return `Providers`} else if(ha instanceof CK){return `Records`} else if(ha instanceof CH){return `Modules`} else if(ha instanceof CI){return `Stores`} else if(ha instanceof CL){return `Enums`}})()}bn(hb){return (()=>{let hc = hb;if(hc instanceof BC){return _h("svg", {"xmlns":`http://www.w3.org/2000/svg`,"viewBox":`0 0 24 24`,"height":`24`,"width":`24`}, [_h("path", {"d":`M4.759 5.753h-.013v.958c-.035 1.614 4.405 1.618 4.351 0v-.957c-.129-1.528-4.226-1.536-4.338-.001zm3.545.147c0 .314-.614.571-1.37.571-.755 0-1.37-.256-1.37-.571s.615-.57 1.37-.57c.756 0 1.37.256 1.37.57zm-8.304.179l.009.005-.009-.019 11.5-6.065 11.5 6.142v5.231l-11 5.798v-5.311l9.864-5.19-10.367-5.517-10.331 5.454 9.834 5.229v5.331l-11-5.858v-5.23zm23 6.434v5.813l-11 5.674v-5.689l11-5.798zm-13.692-3.37c-.035 1.615 4.406 1.618 4.351 0v-.957c-.129-1.528-4.225-1.536-4.337-.001h-.014v.958zm2.188-1.381c.755 0 1.37.255 1.37.57 0 .314-.615.57-1.37.57s-1.37-.255-1.37-.57c0-.315.615-.57 1.37-.57zm2.162-3.354v-.956c-.13-1.527-4.225-1.535-4.337-.001h-.013v.957c-.036 1.615 4.406 1.618 4.35 0zm-2.161-1.381c.754 0 1.37.256 1.37.571 0 .314-.616.571-1.37.571-.756 0-1.37-.257-1.37-.571 0-.314.614-.571 1.37-.571zm6.712 3.684v-.957c-.13-1.528-4.226-1.536-4.336-.001h-.014v.958c-.037 1.615 4.405 1.618 4.35 0zm-3.532-.81c0-.314.615-.57 1.37-.57.756 0 1.371.256 1.371.57s-.615.57-1.371.57c-.755 0-1.37-.256-1.37-.57zm-3.677 12.408v5.691l-11-5.673v-5.875l11 5.857z`})])} else if(hc instanceof CJ){return _h("svg", {"xmlns":`http://www.w3.org/2000/svg`,"width":`24`,"height":`24`,"viewBox":`0 0 24 24`}, [_h("path", {"d":`M15.929 11.517c.848-1.003 1.354-2.25 1.354-3.601s-.506-2.598-1.354-3.601l1.57-1.439c1.257 1.375 2.022 3.124 2.022 5.04s-.766 3.664-2.022 5.041l-1.57-1.44zm-10.992-10.076l-1.572-1.441c-2.086 2.113-3.365 4.876-3.365 7.916s1.279 5.802 3.364 7.916l1.572-1.441c-1.672-1.747-2.697-4.001-2.697-6.475s1.026-4.728 2.698-6.475zm1.564 11.515l1.57-1.439c-.848-1.003-1.354-2.25-1.354-3.601s.506-2.598 1.354-3.601l-1.57-1.439c-1.257 1.375-2.022 3.124-2.022 5.04s.765 3.664 2.022 5.04zm14.134-12.956l-1.571 1.441c1.672 1.747 2.697 4.001 2.697 6.475s-1.025 4.728-2.697 6.475l1.572 1.441c2.085-2.115 3.364-4.877 3.364-7.916s-1.279-5.803-3.365-7.916zm-2.552 24h-2.154c-.85-2.203-2.261-3.066-3.929-3.066-1.692 0-3.088.886-3.929 3.066h-2.113l5.042-13.268c-1.162-.414-2-1.512-2-2.816 0-1.657 1.344-3 3-3s3 1.343 3 3c0 1.304-.838 2.403-2 2.816l5.083 13.268zm-4.077-5l-2.006-5.214-2.006 5.214h4.012z`})])} else if(hc instanceof CK){return _h("svg", {"xmlns":`http://www.w3.org/2000/svg`,"viewBox":`0 0 24 24`,"height":`24`,"width":`24`}, [_h("path", {"d":`M5.485 3.567l6.488-3.279c.448-.199.904-.288 1.344-.288 1.863 0 3.477 1.629 3.287 3.616l-7.881 4.496c.118-2.088-1.173-4.035-3.238-4.545zm16.515 10.912c0 1.08-.523 2.185-1.502 2.827-.164.107.84-.506-7.997 5.065.02-.91-.293-1.836-1.061-2.71-1.422-1.623-8.513-9.85-8.531-9.873-.646-.812-.909-1.571-.909-2.225 0-2.167 2.891-3.172 4.274-1.129.799 1.18.528 3.042-.632 3.799l1.083 1.354 8.855-5.069c1.213 1.478 4.834 4.909 5.762 6.045.444.544.658 1.225.658 1.916zm-12.614-.25l6.883-4.062-.718-.737-6.83 4.031.665.768zm8.536-2.359l-.717-.738-6.951 4.101.665.768 7.003-4.131zm1.64 1.689l-.716-.737-7.07 4.171.665.769 7.121-4.203zm-11.782 4.941c-2.148 1.09-2.38 3.252-1.222 4.598.545.632 1.265.902 1.943.902 1.476 0 2.821-1.337 1.567-2.877-1.3-1.599-2.288-2.623-2.288-2.623z`})])} else if(hc instanceof CH){return _h("svg", {"xmlns":`http://www.w3.org/2000/svg`,"viewBox":`0 0 24 24`,"height":`24`,"width":`24`}, [_h("path", {"d":`M12 0l-11 6v12.131l11 5.869 11-5.869v-12.066l-11-6.065zm7.91 6.646l-7.905 4.218-7.872-4.294 7.862-4.289 7.915 4.365zm-16.91 1.584l8 4.363v8.607l-8-4.268v-8.702zm10 12.97v-8.6l8-4.269v8.6l-8 4.269zm6.678-5.315c.007.332-.256.605-.588.612-.332.007-.604-.256-.611-.588-.006-.331.256-.605.588-.612.331-.007.605.256.611.588zm-2.71-1.677c-.332.006-.595.28-.588.611.006.332.279.595.611.588s.594-.28.588-.612c-.007-.331-.279-.594-.611-.587zm-2.132-1.095c-.332.007-.595.281-.588.612.006.332.279.594.611.588.332-.007.594-.28.588-.612-.007-.331-.279-.594-.611-.588zm-9.902 2.183c.332.007.594.281.588.612-.007.332-.279.595-.611.588-.332-.006-.595-.28-.588-.612.005-.331.279-.594.611-.588zm1.487-.5c-.006.332.256.605.588.612s.605-.257.611-.588c.007-.332-.256-.605-.588-.611-.332-.008-.604.255-.611.587zm2.132-1.094c-.006.332.256.605.588.612.332.006.605-.256.611-.588.007-.332-.256-.605-.588-.612-.332-.007-.604.256-.611.588zm3.447-5.749c-.331 0-.6.269-.6.6s.269.6.6.6.6-.269.6-.6-.269-.6-.6-.6zm0-2.225c-.331 0-.6.269-.6.6s.269.6.6.6.6-.269.6-.6-.269-.6-.6-.6zm0-2.031c-.331 0-.6.269-.6.6s.269.6.6.6.6-.269.6-.6-.269-.6-.6-.6z`})])} else if(hc instanceof CI){return _h("svg", {"xmlns":`http://www.w3.org/2000/svg`,"viewBox":`0 0 24 24`,"height":`24`,"width":`24`}, [_h("path", {"d":`M22 18.055v2.458c0 1.925-4.655 3.487-10 3.487-5.344 0-10-1.562-10-3.487v-2.458c2.418 1.738 7.005 2.256 10 2.256 3.006 0 7.588-.523 10-2.256zm-10-3.409c-3.006 0-7.588-.523-10-2.256v2.434c0 1.926 4.656 3.487 10 3.487 5.345 0 10-1.562 10-3.487v-2.434c-2.418 1.738-7.005 2.256-10 2.256zm0-14.646c-5.344 0-10 1.562-10 3.488s4.656 3.487 10 3.487c5.345 0 10-1.562 10-3.487 0-1.926-4.655-3.488-10-3.488zm0 8.975c-3.006 0-7.588-.523-10-2.256v2.44c0 1.926 4.656 3.487 10 3.487 5.345 0 10-1.562 10-3.487v-2.44c-2.418 1.738-7.005 2.256-10 2.256z`})])} else if(hc instanceof CL){return _h("svg", {"xmlns":`http://www.w3.org/2000/svg`,"width":`24`,"height":`24`,"viewBox":`0 0 24 24`}, [_h("path", {"d":`M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm6 17h-12v-2h12v2zm0-4h-12v-2h12v2zm0-4h-12v-2h12v2z`})])}})()}});const DD=new(class extends _M{hd(){return new AS({dependencies:[],components:[],providers:[],modules:[],records:[],stores:[],enums:[],name:``})}});_program.addRoutes([{handler:((ik, il, im)=>{BB.hr(ik, il, BN.fu(im))}),decoders:[Decoder.string,Decoder.string,Decoder.string],mapping:['package','tab','selected'],path:`/:package/:tab/:selected`},{handler:((io, ip)=>{BB.hr(io, ip, BN.bd())}),decoders:[Decoder.string,Decoder.string],mapping:['package','tab'],path:`/:package/:tab`},{handler:((iq)=>{BB.hm(iq)}),decoders:[Decoder.string],mapping:['package'],path:`/:package`},{handler:(()=>{BB.hl()}),decoders:[],mapping:[],path:`/`},{handler:(()=>{BB.hr(``, `component`, BN.bd())}),decoders:[],mapping:[],path:`*`}]);class AX extends _C{constructor(props){super(props);this._d({b:["children",[]],a:[null,true]})}render(){return (!this.a ? this.b : [])}};;class AY extends _C{constructor(props){super(props);this._d({d:["children",[]],c:[null,true]})}render(){return (this.c ? this.d : [])}};;class AZ extends _C{constructor(props){super(props);this._d({m:[null,new BC()],h:[null,``]})}$c(){const _={[`--a-a`]:BA.e(this.f)};return _}get f(){return BB.k;}get i(){return BB.l;}componentWillUnmount(){BB._unsubscribe(this)}componentDidMount(){BB._subscribe(this)}render(){return _h("a", {"href":`/` + this.i.name + `/` + BA.j(this.f) + `/` + this.h,className:`a`}, [_h("div", {className:`c`,style:_style([this.$c()])}, [BA.g(this.f)]),_h("span", {className:`b`}, [this.h])])}};;class BD extends _C{get o(){return BB.ba;}componentWillUnmount(){BB._unsubscribe(this)}componentDidMount(){BB._subscribe(this)}render(){const u=BE.n(this.o.computedProperties, ((p)=>{return _h(BF, {"key":this.o.name + p.name,q:p.description,r:p.source,s:p.name,t:p.type})}));const x=BE.n(this.o.properties, ((v)=>{return _h(BF, {w:_o(v.defaultValue._0, ``),"key":this.o.name + v.name,q:v.description,s:v.name,t:v.type})}));const aa=BE.n(this.o.functions, ((y)=>{return _h(BF, {"key":this.o.name + y.name,q:y.description,z:y.arguments,r:y.source,s:y.name,t:y.type})}));const ae=BE.n(this.o.connects, ((ab)=>{return _h(BG, {ac:ab.store,ad:ab.keys})}));const aj=BE.n(this.o.fields, ((af)=>{return _h(BH, {ag:af.mapping,ah:af.type,ai:af.key})}));const al=BE.n(this.o.states, ((ak)=>{return _h(BF, {w:_o(ak.defaultValue._0, ``),"key":this.o.name + ak.name,q:ak.description,s:ak.name,t:ak.type})}));const aq=BE.n(this.o.options, ((am)=>{return _h(BI, {an:am.description,ao:am.parameters,ap:am.name})}));const av=BE.n(this.o.uses, ((ar)=>{return _h(BJ, {as:ar.condition,at:ar.provider,au:ar.data})}));return _h("div", {className:`d`}, [_h("div", {className:`e`}, [this.o.name,_h(AX, {a:BE.ax(this.o.parameters)}, _array(_h("div", {className:`i`}, [BK.aw(this.o.parameters, `, `)])))]),_h("div", {className:`f`}, [_h(BL, {ay:this.o.description})]),_h(AX, {a:BE.ax(ae)}, _array(_h("div", {className:`g`}, [`Connected Stores`]), _h("div", {}, [ae]))),_h(AX, {a:BE.ax(al)}, _array(_h("div", {className:`g`}, [`States`]), _h("div", {}, [al]))),_h(AX, {a:BK.az(this.o.subscription)}, _array(_h("div", {className:`g`}, [`Subscription`]), _h("div", {className:`h`}, [this.o.subscription]))),_h(AX, {a:BE.ax(av)}, _array(_h("div", {className:`g`}, [`Using Providers`]), _h("div", {}, [av]))),_h(AX, {a:BE.ax(aj)}, _array(_h("div", {className:`g`}, [`Fields`]), _h("div", {}, [aj]))),_h(AX, {a:BE.ax(aq)}, _array(_h("div", {className:`g`}, [`Options`]), _h("div", {}, [aq]))),_h(AX, {a:BE.ax(x)}, _array(_h("div", {className:`g`}, [`Properties`]), _h("div", {}, [x]))),_h(AX, {a:BE.ax(u)}, _array(_h("div", {className:`g`}, [`Computed Properties`]), _h("div", {}, [u]))),_h(AX, {a:BE.ax(aa)}, _array(_h("div", {className:`g`}, [`Functions`]), _h("div", {}, [aa])))])}};;class BJ extends _C{constructor(props){super(props);this._d({as:[null,BN.bd()],at:[null,``],au:[null,``]})}render(){return _h("div", {className:`j`}, [_h("div", {className:`k`}, [this.at]),_h("div", {className:`l`}, [_h(BM, {bb:this.au})]),_h(AY, {c:BN.bc(this.as)}, _array(_h("div", {className:`m`}, [`only when:`]), _h("div", {className:`l`}, [_h(BM, {bb:_o(this.as._0, ``)})])))])}};;class BO extends _C{constructor(props){super(props);this._d({bf:[null,new BC()]})}get bh(){return BB.k;}get be(){return BB.l;}get bi(){return BB.bp;}componentWillUnmount(){BB._unsubscribe(this)}componentDidMount(){BB._subscribe(this)}render(){return _h(BP, {bg:`/` + this.be.name + `/` + BA.j(this.bf),bj:_compare(this.bf, this.bh) && _compare(this.bi, new BQ()),bl:BA.bk(this.bf),bm:BA.e(this.bf),bo:BA.bn(this.bf)})}};;class BH extends _C{constructor(props){super(props);this._d({ag:[null,BN.bd()],ah:[null,``],ai:[null,``]})}render(){return _h("div", {className:`n`}, [_h("div", {className:`p`}, [this.ai]),_h("div", {className:`o`}, [this.ah])])}};;class BF extends _C{constructor(props){super(props);this._d({q:[null,BN.bd()],z:[null,[]],w:[null,``],r:[null,``],s:[null,``],t:[null,new BT()]})}bq(br){return _h("div", {className:`v`}, [_h("strong", {}, [br.name]),_h("span", {className:`s`}, [br.type])])}render(){return _h("div", {className:`t`}, [_h("div", {className:`q`}, [_h("div", {className:`r`}, [this.s]),_h(AX, {a:BE.ax(this.z)}, _array(_h("div", {className:`u`}, [BE.n(this.z, this.bq)]))),(()=>{let bs = this.t;if(bs instanceof BR){const bt = bs._0;return _h("div", {className:`s`}, [bt])} else{return null}})(),_h(AX, {a:BK.az(this.w)}, _array(_h("div", {className:`x`}, [_h(BM, {bb:this.w})])))]),_h(AY, {c:BN.bc(this.q)}, _array(_h("div", {className:`w`}, [_h(BL, {ay:_o(this.q._0, ``)})]))),_h(AX, {a:BK.az(this.r)}, _array(_h(BS, {bu:this.r})))])}};;class BG extends _C{constructor(props){super(props);this._d({ad:[null,[]],ac:[null,``]})}bv(bw){return _h("div", {className:`ab`}, [bw])}render(){return _h("div", {className:`y`}, [_h("div", {className:`z`}, [this.ac]),_h("span", {}, [` exposing {`]),_h("div", {className:`aa`}, [BE.n(this.ad, this.bv)]),_h("div", {}, [`}`])])}};;class A extends _C{get ca(){return _h("div", {className:`ac`}, [$d(),this.cb])}get cb(){return (()=>{let cd = this.cc;if(cd instanceof CC){return $e()} else if(cd instanceof CE){return $f()} else if(cd instanceof BQ){return _h("div", {className:`ad`}, [$g(),$h()])}})()}get ce(){return BB.ba;}get bx(){return BB.cf;}ch (...params) { return BB.cg(...params); }get cc(){return BB.bp;}componentWillUnmount(){BB._unsubscribe(this)}componentDidMount(){BB._subscribe(this)}render(){return (()=>{let by = this.bx;if(by instanceof BV){return $a()} else if(by instanceof BW){return $b()} else if(by instanceof BX){return $c()} else if(by instanceof BY){return _h("div", {})} else if(by instanceof BZ){return this.ca}})()}};;class CB extends _C{get ci(){return BB.cn;}componentWillUnmount(){BB._unsubscribe(this)}componentDidMount(){BB._subscribe(this)}render(){const cm=BE.n(BE.n(this.ci, ((cj)=>{return cj.name})), ((cl)=>{return _h("a", {"href":`/` + cl,className:`af`}, [CG.ck(),cl])}));return _h("div", {className:`ae`}, [_h("div", {className:`ag`}, [`Dashboard`]),_h("div", {}, [cm])])}};;class BI extends _C{constructor(props){super(props);this._d({an:[null,BN.bd()],ao:[null,[]],ap:[null,``]})}render(){return _h("div", {className:`ah`}, [_h("div", {className:`ai`}, [this.ap,_h(AX, {a:BE.ax(this.ao)}, _array(_h("div", {className:`ak`}, [BK.aw(this.ao, `, `)])))]),_h(AY, {c:BN.bc(this.an)}, _array(_h("div", {className:`aj`}, [_h(BL, {ay:_o(this.an._0, ``)})])))])}};;class BS extends _C{constructor(props){super(props);this._d({bu:[null,``]});this.state = new Record({cr:false})}$am(){const _={[`--b-a`]:this.co};return _}get cs(){return _h("svg", {"xmlns":`http://www.w3.org/2000/svg`,"viewBox":`0 0 24 24`,"height":`9`,"width":`9`,className:`am`,style:_style([this.$am()])}, [_h("path", {"d":`M5 3l3.057-3 11.943 12-11.943 12-3.057-3 9-9z`})])}get ct(){return (this.cr ? `Hide source ` : `Show source`)}get co(){return (this.cr ? `rotate(90deg)` : ``)}get cr(){return this.state.cr;}cp(cq){return new Promise(((_resolve)=>{this.setState(_u(this.state, new Record({cr:!this.cr})), _resolve) -}))}render(){return _h("div", {}, [_h("div", {"onClick":(event => (this.cp)(_normalizeEvent(event))),className:`al`}, [this.cs,_h("div", {}, [this.ct])]),_h(AY, {c:this.cr}, _array(_h("div", {className:`an`}, [_h(BM, {bb:this.bu})])))])}};;class BU extends _C{constructor(props){super(props);this._d({bz:[null,``]})}get cu(){return _h("svg", {"xmlns":`http://www.w3.org/2000/svg`,"viewBox":`0 0 24 24`,"height":`100`,"width":`100`,className:`ap`}, [_h("path", {"d":`M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm-1.31 7.526c-.099-.807.528-1.526 1.348-1.526.771 0 1.377.676 1.28 1.451l-.757 6.053c-.035.283-.276.496-.561.496s-.526-.213-.562-.496l-.748-5.978zm1.31 10.724c-.69 0-1.25-.56-1.25-1.25s.56-1.25 1.25-1.25 1.25.56 1.25 1.25-.56 1.25-1.25 1.25z`})])}render(){return _h("div", {className:`ao`}, [this.cu,this.bz])}};;class CA extends _C{$aq(){const _={[`--c-a`]:`5px solid ` + this.cv};return _}get cv(){return (()=>{let cz = this.cw;if(cz instanceof CC){return `#666`} else if(cz instanceof CE){return `#666`} else{return BA.e(this.da)}})()}get cx(){return _h("svg", {"xmlns":`http://www.w3.org/2000/svg`,"viewBox":`0 0 24 24`,"height":`24`,"width":`24`}, [_h("path", {"d":`M12 2c-6.627 0-12 5.373-12 12 0 2.583.816 5.042 2.205 7h19.59c1.389-1.958 2.205-4.417 2.205-7 0-6.627-5.373-12-12-12zm-.758 2.14c.256-.02.51-.029.758-.029s.502.01.758.029v3.115c-.252-.027-.506-.042-.758-.042s-.506.014-.758.042v-3.115zm-5.763 7.978l-2.88-1.193c.157-.479.351-.948.581-1.399l2.879 1.192c-.247.444-.441.913-.58 1.4zm1.216-2.351l-2.203-2.203c.329-.383.688-.743 1.071-1.071l2.203 2.203c-.395.316-.754.675-1.071 1.071zm.793-4.569c.449-.231.919-.428 1.396-.586l1.205 2.875c-.485.141-.953.338-1.396.585l-1.205-2.874zm1.408 13.802c.019-1.151.658-2.15 1.603-2.672l1.501-7.041 1.502 7.041c.943.522 1.584 1.521 1.603 2.672h-6.209zm4.988-11.521l1.193-2.879c.479.156.948.352 1.399.581l-1.193 2.878c-.443-.246-.913-.44-1.399-.58zm2.349 1.217l2.203-2.203c.383.329.742.688 1.071 1.071l-2.203 2.203c-.316-.396-.675-.755-1.071-1.071zm2.259 3.32c-.147-.483-.35-.95-.603-1.39l2.86-1.238c.235.445.438.912.602 1.39l-2.859 1.238z`})])}get db(){return BB.cn;}get cy(){return BB.l;}get da(){return BB.k;}get cw(){return BB.bp;}componentWillUnmount(){BB._unsubscribe(this)}componentDidMount(){BB._subscribe(this)}render(){return _h("div", {className:`aq`,style:_style([this.$aq()])}, [_h(BP, {bj:_compare(this.cw, new CC()),bo:this.cx,bm:`#666`,bg:`/`}),_h(AY, {c:!_compare(this.cy.name, ``)}, _array(_h(BP, {bj:_compare(this.cw, new CE()),bg:`/` + this.cy.name,bl:this.cy.name,bo:CG.ck(),bm:`#666`}))),_h(AX, {a:BE.ax(this.cy.components)}, _array(_h(BO, {bf:new BC()}))),_h(AX, {a:BE.ax(this.cy.modules)}, _array(_h(BO, {bf:new CH()}))),_h(AX, {a:BE.ax(this.cy.stores)}, _array(_h(BO, {bf:new CI()}))),_h(AX, {a:BE.ax(this.cy.providers)}, _array(_h(BO, {bf:new CJ()}))),_h(AX, {a:BE.ax(this.cy.records)}, _array(_h(BO, {bf:new CK()}))),_h(AX, {a:BE.ax(this.cy.enums)}, _array(_h(BO, {bf:new CL()})))])}};;class BL extends _C{constructor(props){super(props);this._d({ay:[null,``]})}render(){return _h("div", {"dangerouslySetInnerHTML":({__html: this.ay}),className:`ar`})}};;class CF extends _C{get dc(){return (()=>{let de = this.dd;if(de instanceof BC){return BE.n(this.df.components, ((dg)=>{return _h(AZ, {m:new BC(),h:dg.name})}))} else if(de instanceof CJ){return BE.n(this.df.providers, ((dh)=>{return _h(AZ, {m:new CJ(),h:dh.name})}))} else if(de instanceof CI){return BE.n(this.df.stores, ((di)=>{return _h(AZ, {m:new CI(),h:di.name})}))} else if(de instanceof CK){return BE.n(this.df.records, ((dj)=>{return _h(AZ, {m:new CK(),h:dj.name})}))} else if(de instanceof CH){return BE.n(this.df.modules, ((dk)=>{return _h(AZ, {m:new CH(),h:dk.name})}))} else if(de instanceof CL){return BE.n(this.df.enums, ((dl)=>{return _h(AZ, {m:new CL(),h:dl.name})}))}})()}get df(){return BB.l;}get dd(){return BB.k;}componentWillUnmount(){BB._unsubscribe(this)}componentDidMount(){BB._subscribe(this)}render(){return _h("div", {className:`as`}, [this.dc])}};;class BP extends _C{constructor(props){super(props);this._d({bo:[null,CM.dp()],bj:[null,false],bl:[null,``],bm:[null,``],bg:[null,``]})}$at(){const _={[`--d-a`]:this.dm,[`--e-a`]:this.dn};return _}get dm(){return (this.bj ? this.bm : `transparent`)}get dn(){return (this.bj ? `linear-gradient(rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.1)), ` + this.dm : `#444`)}render(){return _h("a", {"href":this.bg,className:`at`,style:_style([this.$at()])}, [this.bo,_h(AY, {c:!_compare(this.bl, ``)}, _array(_h("span", {className:`au`}, [this.bl])))])}};;class CN extends _C{constructor(props){super(props);this._d({ds:[null,``],dr:[null,``],dq:[null,``]})}render(){return _h("div", {}, [_h("div", {className:`av`}, [_h("div", {className:`aw`}, [this.dq]),_h("div", {className:`ay`}, [this.dr])]),_h("div", {className:`ax`}, [this.ds])])}};;class CD extends _C{get dt(){return BB.l;}componentWillUnmount(){BB._unsubscribe(this)}componentDidMount(){BB._subscribe(this)}render(){const dv=BE.n(this.dt.dependencies, ((du)=>{return _h(CN, {dr:du.constraint,ds:du.repository,dq:du.name})}));return _h("div", {className:`az`}, [_h("div", {className:`ba`}, [this.dt.name]),_h(AX, {a:BE.ax(dv)}, _array(_h("div", {className:`bb`}, [`Dependencies`]), _h("div", {}, [dv])))])}};;class BM extends _C{constructor(props){super(props);this._d({bb:[null,``]})}render(){return _h("pre", {className:`bc`}, [this.bb])}};;const $a=_m(() => _h(BU, {bz:`Could not parse the documentation json!`}));const $b=_m(() => _h(BU, {bz:`Could not decode the documentation!`}));const $c=_m(() => _h(BU, {bz:`Could not load the documentation!`}));const $d=_m(() => _h(CA, {}));const $e=_m(() => _h(CB, {}));const $f=_m(() => _h(CD, {}));const $g=_m(() => _h(CF, {}));const $h=_m(() => _h(BD, {}));const BB=new(class extends _S{constructor(){super();this.state={ba:DC.gp(),cf:new BY(),k:new BC(),cn:[],l:DD.hd(),bp:new CC()}}get ba(){return this.state.ba;}get cf(){return this.state.cf;}get k(){return this.state.k;}get cn(){return this.state.cn;}get l(){return this.state.l;}get bp(){return this.state.bp;}cg(){return (_compare(this.cf, new BY()) ? (async()=>{let he = await CS.ek(CS.ee(`http://localhost:3002/documentation.json`));if(he instanceof CR){return new Promise(((_resolve)=>{this.setState(_u(this.state, new Record({cf:new BX()})), _resolve) -}))} else if(he instanceof CQ){const hf = he._0;return (()=>{let hg = CP.eb(hf.body);if(hg instanceof CR){return new Promise(((_resolve)=>{this.setState(_u(this.state, new Record({cf:new BV()})), _resolve) -}))} else if(hg instanceof CQ){const hh = hg._0;return (()=>{let hi = ((_)=>AW.decode(_))(hh);if(hi instanceof CR){const hj = hi._0;return (()=>{DA.fn(CO.dw(hj));return new Promise(((_resolve)=>{this.setState(_u(this.state, new Record({cf:new BW()})), _resolve) -}))})()} else if(hi instanceof CQ){const hk = hi._0;return new Promise(((_resolve)=>{this.setState(_u(this.state, new Record({cn:hk.packages,cf:new BZ()})), _resolve) -}))}})()}})()}})() : new Promise(((_resolve)=>{this.setState(_u(this.state, new Record({})), _resolve) -})))}async hl(){await BB.cg();await new Promise(((_resolve)=>{this.setState(_u(this.state, new Record({l:DD.hd(),ba:DC.gp(),bp:new CC()})), _resolve) -}));return CZ.fl(0)}async hm(hn){await BB.cg();return (()=>{let hp = BE.es(this.cn, ((ho)=>{return _compare(ho.name, hn)}));if(hp instanceof BT){return CZ.fi(`/`)} else if(hp instanceof BR){const hq = hp._0;return (()=>{new Promise(((_resolve)=>{this.setState(_u(this.state, new Record({l:hq,bp:new CE()})), _resolve) -}));return CZ.fl(0)})()}})()}async hr(hs,ht,hu){await BB.cg();return (()=>{let hw = BE.es(this.cn, ((hv)=>{return _compare(hv.name, hs)}));if(hw instanceof BT){return CZ.fi(`/`)} else if(hw instanceof BR){const hy = hw._0;return (()=>{let hx = BA.gq(ht);if(hx instanceof CR){return CZ.fi(`/` + hy.name)} else if(hx instanceof CQ){const hz = hx._0;return (()=>{const ib=(()=>{let ia = hz;if(ia instanceof BC){return BE.n(hy.components, DC.gd)} else if(ia instanceof CJ){return BE.n(hy.providers, DC.gj)} else if(ia instanceof CK){return BE.n(hy.records, DC.gf)} else if(ia instanceof CH){return BE.n(hy.modules, DC.gn)} else if(ia instanceof CI){return BE.n(hy.stores, DC.gl)} else if(ia instanceof CL){return BE.n(hy.enums, DC.gh)}})();const ie=BN.fp(BN.fw(hu, ((id)=>{return BE.es(ib, ((ic)=>{return _compare(ic.name, id)}))})));return (()=>{let ig = ie;if(ig instanceof BR){const ih = ig._0;return (async()=>{await new Promise(((_resolve)=>{this.setState(_u(this.state, new Record({l:hy,ba:ih,bp:new BQ(),k:hz})), _resolve) -}));return CZ.fl(0)})()} else if(ig instanceof BT){return (()=>{let ii = BE.ev(ib);if(ii instanceof BT){return CZ.fi(`/` + hy.name)} else if(ii instanceof BR){const ij = ii._0;return CZ.fi(`/` + hy.name + `/` + BA.j(hz) + `/` + ij.name)}})()}})()})()}})()}})()}});_insertStyles(` -.a { - text-decoration: none; - align-items: center; - margin-bottom: 5px; - cursor: pointer; - color: inherit; - display: flex; -} - -.a:hover span { - text-decoration: underline; -} - -.b { - line-height: 13px; -} - -.c { - background-color: var(--a-a); - justify-content: center; - display: inline-flex; - align-items: center; - margin-right: 7px; - border-radius: 2px; - font-weight: bold; - font-size: 12px; - height: 20px; - width: 20px; - color: #FFF; -} - -.d { - flex: 1; - padding: 30px; - padding-bottom: 150px; -} - -.e { - border-bottom: 2px solid #EEE; - padding-bottom: 10px; - font-size: 30px; - display: flex; -} - -.f { - margin-top: 20px; - opacity: 0.8; -} - -.g { - border-bottom: 1px solid #EEE; - text-transform: uppercase; - padding-bottom: 10px; - font-weight: 600; - margin-top: 40px; - font-size: 14px; - opacity: 0.6; -} - -.h { - font-family: Source Code Pro; - margin-top: 15px; - font-size: 18px; - color: #2e894e; -} - -.i { - font-weight: normal; - color: #2e894e; -} - -.i::before { - content: "("; - color: #333; -} - -.i::after { - content: ")"; - color: #333; -} - -.j { - font-family: Source Code Pro; - flex-direction: column; - padding-top: 15px; - font-size: 18px; - display: flex; -} - -.k { - color: #2e894e; -} - -.l { - align-self: flex-start; - margin-left: 20px; - margin-top: 20px; -} - -.m { - font-family: sans-serif; - margin-top: 20px; -} - -.n { - font-family: Source Code Pro; - padding-top: 15px; - font-size: 18px; - display: flex; -} - -.o { - color: #2e894e; -} - -.o:before { - font-weight: 300; - margin: 0 5px; - content: ":"; - color: #999; -} - -.p { - font-weight: bold; -} - -.q { - font-family: Source Code Pro; - white-space: nowrap; - align-items: center; - font-size: 18px; - display: flex; -} - -.r { - align-items: center; - font-weight: bold; - display: flex; -} - -.s { - color: #2e894e; -} - -.s:before { - font-weight: 300; - margin: 0 5px; - content: ":"; - color: #999; -} - -.t { - padding: 15px 0; -} - -.t + * { - border-top: 1px dashed #DDD; -} - -.u { - display: flex; -} - -.u:before { - content: "("; - opacity: 0.75; -} - -.u:after { - content: ")"; - opacity: 0.75; -} - -.v + *:before { - content: ", "; -} - -.w { - padding: 18px 0; - padding-left: 20px; - opacity: 0.8; -} - -.x { - align-items: center; - display: flex; -} - -.x:before { - font-weight: 300; - margin: 0 5px; - content: "="; - color: #999; -} - -.y { - font-family: Source Code Pro; - font-weight: bold; - padding-top: 15px; - font-size: 18px; -} - -.z { - display: inline; - color: #2e894e; -} - -.aa { - font-weight: normal; - padding-left: 20px; -} - -.ab:not(:last-child):after { - content: ", "; -} - -.ac { - font-family: sans-serif; - flex-direction: column; - min-height: 100vh; - display: flex; - color: #333; -} - -.ad { - display: flex; - flex: 1; -} - -.ae { - padding: 30px; -} - -.af { - align-items: center; - font-size: 18px; - padding: 10px 0; - color: #2e894e; - display: flex; -} - -.af svg { - fill: currentColor; - margin-right: 5px; - height: 20px; - width: 20px; -} - -.ag { - border-bottom: 3px solid #EEE; - padding-bottom: 5px; - margin-bottom: 20px; - font-size: 36px; -} - -.ah { - flex-direction: column; - padding-top: 15px; - display: flex; -} - -.ai { - font-family: Source Code Pro; - font-weight: bold; - font-size: 18px; - display: flex; -} - -.aj { - padding: 20px 0; - padding-left: 20px; - opacity: 0.8; -} - -.ak { - font-weight: normal; - color: #2e894e; -} - -.ak::before { - content: "("; - color: #333; -} - -.ak::after { - content: ")"; - color: #333; -} - -.al { - text-transform: uppercase; - align-items: center; - margin-top: 10px; - font-size: 10px; - cursor: pointer; - display: flex; - opacity: 0.33; -} - -.al:hover { - opacity: 1; -} - -.am { - transform: var(--b-a); - position: relative; - fill: currentColor; - margin-right: 5px; - top: -1px; -} - -.an { - margin-top: 10px; -} - -.ao { - justify-content: center; - font-family: sans-serif; - flex-direction: column; - align-items: center; - font-size: 30px; - display: flex; - height: 100vh; - color: #444; -} - -.ap { - margin-bottom: 30px; - fill: currentColor; -} - -.aq { - border-bottom: var(--c-a); - font-weight: bold; - background: #333; - display: flex; - color: #EEE; -} - -.ar *:first-child { - margin-top: 0; -} - -.ar *:last-child { - margin-bottom: 0; -} - -.ar li { - line-height: 2; -} - -.ar pre { - font-family: Source Code Pro; - background: #F2F2F2; - border-radius: 2px; - padding: 5px 7px; - font-size: 14px; - margin: 0; -} - -.ar p code { - font-family: Source Code Pro; - background: #F2F2F2; - border-radius: 2px; - padding: 5px 7px; - font-size: 14px; - margin: 0; -} - -.ar li code { - font-family: Source Code Pro; - background: #F2F2F2; - border-radius: 2px; - padding: 5px 7px; - font-size: 14px; - margin: 0; -} - -.as { - background: #F5F5F5; - color: #444; - padding: 20px; - padding-right: 40px; -} - -.at { - background: var(--d-a); - text-decoration: none; - align-items: center; - padding: 0 15px; - cursor: pointer; - color: inherit; - display: flex; - height: 50px; -} - -.at:hover { - background: var(--e-a); -} - -.at svg { - filter: drop-shadow(0 1px 0 rgba(0,0,0,0.333)); - fill: currentColor; - height: 18px; - width: 18px; -} - -.au { - text-shadow: 0 1px 0 rgba(0,0,0,0.333); - text-transform: uppercase; - margin-left: 10px; - font-size: 14px; -} - -.av { - font-size: 20px; - display: flex; -} - -.aw { - font-weight: bold; -} - -.ax { - opacity: 0.5; -} - -.ay:before { - margin: 0 5px; - content: "-"; -} - -.az { - padding: 30px; -} - -.ba { - border-bottom: 3px solid #EEE; - padding-bottom: 5px; - margin-bottom: 20px; - font-size: 36px; -} - -.bb { - margin-bottom: 5px; - font-size: 20px; -} - -.bc { - font-family: Source Code Pro; - border: 1px dashed #DDD; - background: #FAFAFA; - font-size: 14px; - padding: 10px; - margin: 0; -} -`) - - const Nothing = BT - const Just = BR - const Err = CR - const Ok = CQ - - _enums.nothing = BT - _enums.just = BR - _enums.err = CR - _enums.ok = CQ - - - -_program.render(A, {}) -})() \ No newline at end of file diff --git a/src/assets/docs-viewer/manifest.webmanifest b/src/assets/docs-viewer/manifest.webmanifest deleted file mode 100644 index 82d5d5751..000000000 --- a/src/assets/docs-viewer/manifest.webmanifest +++ /dev/null @@ -1,101 +0,0 @@ -{ - "name": "", - "short_name": "", - "background_color": "", - "theme_color": "", - "display": "", - "orientation": "", - "start_url": "/", - "icons": [ - { - "src": "icon-16x16.png", - "sizes": "16x16", - "type": "image/png" - }, - { - "src": "icon-32x32.png", - "sizes": "32x32", - "type": "image/png" - }, - { - "src": "icon-36x36.png", - "sizes": "36x36", - "type": "image/png" - }, - { - "src": "icon-48x48.png", - "sizes": "48x48", - "type": "image/png" - }, - { - "src": "icon-57x57.png", - "sizes": "57x57", - "type": "image/png" - }, - { - "src": "icon-72x72.png", - "sizes": "72x72", - "type": "image/png" - }, - { - "src": "icon-76x76.png", - "sizes": "76x76", - "type": "image/png" - }, - { - "src": "icon-96x96.png", - "sizes": "96x96", - "type": "image/png" - }, - { - "src": "icon-120x120.png", - "sizes": "120x120", - "type": "image/png" - }, - { - "src": "icon-128x128.png", - "sizes": "128x128", - "type": "image/png" - }, - { - "src": "icon-144x144.png", - "sizes": "144x144", - "type": "image/png" - }, - { - "src": "icon-152x152.png", - "sizes": "152x152", - "type": "image/png" - }, - { - "src": "icon-167x167.png", - "sizes": "167x167", - "type": "image/png" - }, - { - "src": "icon-180x180.png", - "sizes": "180x180", - "type": "image/png" - }, - { - "src": "icon-192x192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icon-196x196.png", - "sizes": "196x196", - "type": "image/png" - }, - { - "src": "icon-256x256.png", - "sizes": "256x256", - "type": "image/png" - }, - { - "src": "icon-512x512.png", - "sizes": "512x512", - "type": "image/png" - } - ] -} \ No newline at end of file diff --git a/src/assets/runtime.js b/src/assets/runtime.js index c2340a738..0751cabdf 100644 --- a/src/assets/runtime.js +++ b/src/assets/runtime.js @@ -1 +1,68 @@ -var Mint=function(){"use strict";var t,e,n,r,o,i,a={},s=[],u=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;function l(t,e){for(var n in e)t[n]=e[n];return t}function c(t){var e=t.parentNode;e&&e.removeChild(t)}function h(t,e,n){var r,o=arguments,i={};for(r in e)"key"!==r&&"ref"!==r&&(i[r]=e[r]);if(arguments.length>3)for(n=[n],r=3;r3;)n.pop()();if(n[1]t.original)),r.component=t,r.props=n,customElements.define(e,r)}function ot(t){if(null===t||!0===t||!1===t)return NaN;var e=Number(t);return isNaN(e)?e:e<0?Math.ceil(e):Math.floor(e)}function it(t,e){if(e.length1?"s":"")+" required, but only "+e.length+" present")}function at(t){it(1,arguments);var e=Object.prototype.toString.call(t);return t instanceof Date||"object"==typeof t&&"[object Date]"===e?new Date(t.getTime()):"number"==typeof t||"[object Number]"===e?new Date(t):("string"!=typeof t&&"[object String]"!==e||"undefined"==typeof console||(console.warn("Starting with v2.0.0-beta.1 date-fns doesn't accept strings as date arguments. Please use `parseISO` to parse strings. See: https://github.com/date-fns/date-fns/blob/master/docs/upgradeGuide.md#string-arguments"),console.warn((new Error).stack)),new Date(NaN))}function st(t,e){it(2,arguments);var n=at(t),r=ot(e);if(isNaN(r))return new Date(NaN);if(!r)return n;var o=n.getDate(),i=new Date(n.getTime());i.setMonth(n.getMonth()+r+1,0);var a=i.getDate();return o>=a?i:(n.setFullYear(i.getFullYear(),i.getMonth(),o),n)}function ut(t,e){it(2,arguments);var n=at(t).getTime(),r=ot(e);return new Date(n+r)}var lt={};function ct(){return lt}function ht(t,e){var n,r,o,i,a,s,u,l;it(1,arguments);var c=ct(),h=ot(null!==(n=null!==(r=null!==(o=null!==(i=null==e?void 0:e.weekStartsOn)&&void 0!==i?i:null==e||null===(a=e.locale)||void 0===a||null===(s=a.options)||void 0===s?void 0:s.weekStartsOn)&&void 0!==o?o:c.weekStartsOn)&&void 0!==r?r:null===(u=c.locale)||void 0===u||null===(l=u.options)||void 0===l?void 0:l.weekStartsOn)&&void 0!==n?n:0);if(!(h>=0&&h<=6))throw new RangeError("weekStartsOn must be between 0 and 6 inclusively");var f=at(t),d=f.getDay(),p=(d0?1:o}function mt(t){return it(1,arguments),t instanceof Date||"object"==typeof t&&"[object Date]"===Object.prototype.toString.call(t)}function vt(t){if(it(1,arguments),!mt(t)&&"number"!=typeof t)return!1;var e=at(t);return!isNaN(Number(e))}function yt(t){it(1,arguments);var e=at(t);return e.setHours(23,59,59,999),e}function _t(t){it(1,arguments);var e=at(t),n=e.getMonth();return e.setFullYear(e.getFullYear(),n+1,0),e.setHours(23,59,59,999),e}function gt(t,e){var n;it(1,arguments);var r=t||{},o=at(r.start),i=at(r.end),a=i.getTime();if(!(o.getTime()<=a))throw new RangeError("Invalid interval");var s=[],u=o;u.setHours(0,0,0,0);var l=Number(null!==(n=null==e?void 0:e.step)&&void 0!==n?n:1);if(l<1||isNaN(l))throw new RangeError("`options.step` must be a number greater than 1");for(;u.getTime()<=a;)s.push(at(u)),u.setDate(u.getDate()+l),u.setHours(0,0,0,0);return s}function wt(t){it(1,arguments);var e=at(t);return e.setDate(1),e.setHours(0,0,0,0),e}function bt(t,e){var n,r,o,i,a,s,u,l;it(1,arguments);var c=ct(),h=ot(null!==(n=null!==(r=null!==(o=null!==(i=null==e?void 0:e.weekStartsOn)&&void 0!==i?i:null==e||null===(a=e.locale)||void 0===a||null===(s=a.options)||void 0===s?void 0:s.weekStartsOn)&&void 0!==o?o:c.weekStartsOn)&&void 0!==r?r:null===(u=c.locale)||void 0===u||null===(l=u.options)||void 0===l?void 0:l.weekStartsOn)&&void 0!==n?n:0);if(!(h>=0&&h<=6))throw new RangeError("weekStartsOn must be between 0 and 6 inclusively");var f=at(t),d=f.getDay(),p=6+(d=o.getTime()?n+1:e.getTime()>=a.getTime()?n:n-1}function Tt(t){it(1,arguments);var e=xt(t),n=new Date(0);n.setUTCFullYear(e,0,4),n.setUTCHours(0,0,0,0);var r=Et(n);return r}var Ct=6048e5;function Dt(t,e){var n,r,o,i,a,s,u,l;it(1,arguments);var c=ct(),h=ot(null!==(n=null!==(r=null!==(o=null!==(i=null==e?void 0:e.weekStartsOn)&&void 0!==i?i:null==e||null===(a=e.locale)||void 0===a||null===(s=a.options)||void 0===s?void 0:s.weekStartsOn)&&void 0!==o?o:c.weekStartsOn)&&void 0!==r?r:null===(u=c.locale)||void 0===u||null===(l=u.options)||void 0===l?void 0:l.weekStartsOn)&&void 0!==n?n:0);if(!(h>=0&&h<=6))throw new RangeError("weekStartsOn must be between 0 and 6 inclusively");var f=at(t),d=f.getUTCDay(),p=(d=1&&d<=7))throw new RangeError("firstWeekContainsDate must be between 1 and 7 inclusively");var p=new Date(0);p.setUTCFullYear(h+1,0,d),p.setUTCHours(0,0,0,0);var m=Dt(p,e),v=new Date(0);v.setUTCFullYear(h,0,d),v.setUTCHours(0,0,0,0);var y=Dt(v,e);return c.getTime()>=m.getTime()?h+1:c.getTime()>=y.getTime()?h:h-1}function Mt(t,e){var n,r,o,i,a,s,u,l;it(1,arguments);var c=ct(),h=ot(null!==(n=null!==(r=null!==(o=null!==(i=null==e?void 0:e.firstWeekContainsDate)&&void 0!==i?i:null==e||null===(a=e.locale)||void 0===a||null===(s=a.options)||void 0===s?void 0:s.firstWeekContainsDate)&&void 0!==o?o:c.firstWeekContainsDate)&&void 0!==r?r:null===(u=c.locale)||void 0===u||null===(l=u.options)||void 0===l?void 0:l.firstWeekContainsDate)&&void 0!==n?n:1),f=Pt(t,e),d=new Date(0);d.setUTCFullYear(f,0,h),d.setUTCHours(0,0,0,0);var p=Dt(d,e);return p}var Ot=6048e5;function At(t,e){for(var n=t<0?"-":"",r=Math.abs(t).toString();r.length0?n:1-n;return At("yy"===e?r%100:r,e.length)},Nt=function(t,e){var n=t.getUTCMonth();return"M"===e?String(n+1):At(n+1,2)},Ut=function(t,e){return At(t.getUTCDate(),e.length)},qt=function(t,e){return At(t.getUTCHours()%12||12,e.length)},Wt=function(t,e){return At(t.getUTCHours(),e.length)},Rt=function(t,e){return At(t.getUTCMinutes(),e.length)},It=function(t,e){return At(t.getUTCSeconds(),e.length)},Lt=function(t,e){var n=e.length,r=t.getUTCMilliseconds();return At(Math.floor(r*Math.pow(10,n-3)),e.length)},Yt={G:function(t,e,n){var r=t.getUTCFullYear()>0?1:0;switch(e){case"G":case"GG":case"GGG":return n.era(r,{width:"abbreviated"});case"GGGGG":return n.era(r,{width:"narrow"});default:return n.era(r,{width:"wide"})}},y:function(t,e,n){if("yo"===e){var r=t.getUTCFullYear(),o=r>0?r:1-r;return n.ordinalNumber(o,{unit:"year"})}return jt(t,e)},Y:function(t,e,n,r){var o=Pt(t,r),i=o>0?o:1-o;return"YY"===e?At(i%100,2):"Yo"===e?n.ordinalNumber(i,{unit:"year"}):At(i,e.length)},R:function(t,e){return At(xt(t),e.length)},u:function(t,e){return At(t.getUTCFullYear(),e.length)},Q:function(t,e,n){var r=Math.ceil((t.getUTCMonth()+1)/3);switch(e){case"Q":return String(r);case"QQ":return At(r,2);case"Qo":return n.ordinalNumber(r,{unit:"quarter"});case"QQQ":return n.quarter(r,{width:"abbreviated",context:"formatting"});case"QQQQQ":return n.quarter(r,{width:"narrow",context:"formatting"});default:return n.quarter(r,{width:"wide",context:"formatting"})}},q:function(t,e,n){var r=Math.ceil((t.getUTCMonth()+1)/3);switch(e){case"q":return String(r);case"qq":return At(r,2);case"qo":return n.ordinalNumber(r,{unit:"quarter"});case"qqq":return n.quarter(r,{width:"abbreviated",context:"standalone"});case"qqqqq":return n.quarter(r,{width:"narrow",context:"standalone"});default:return n.quarter(r,{width:"wide",context:"standalone"})}},M:function(t,e,n){var r=t.getUTCMonth();switch(e){case"M":case"MM":return Nt(t,e);case"Mo":return n.ordinalNumber(r+1,{unit:"month"});case"MMM":return n.month(r,{width:"abbreviated",context:"formatting"});case"MMMMM":return n.month(r,{width:"narrow",context:"formatting"});default:return n.month(r,{width:"wide",context:"formatting"})}},L:function(t,e,n){var r=t.getUTCMonth();switch(e){case"L":return String(r+1);case"LL":return At(r+1,2);case"Lo":return n.ordinalNumber(r+1,{unit:"month"});case"LLL":return n.month(r,{width:"abbreviated",context:"standalone"});case"LLLLL":return n.month(r,{width:"narrow",context:"standalone"});default:return n.month(r,{width:"wide",context:"standalone"})}},w:function(t,e,n,r){var o=function(t,e){it(1,arguments);var n=at(t),r=Dt(n,e).getTime()-Mt(n,e).getTime();return Math.round(r/Ot)+1}(t,r);return"wo"===e?n.ordinalNumber(o,{unit:"week"}):At(o,e.length)},I:function(t,e,n){var r=function(t){it(1,arguments);var e=at(t),n=Et(e).getTime()-Tt(e).getTime();return Math.round(n/Ct)+1}(t);return"Io"===e?n.ordinalNumber(r,{unit:"week"}):At(r,e.length)},d:function(t,e,n){return"do"===e?n.ordinalNumber(t.getUTCDate(),{unit:"date"}):Ut(t,e)},D:function(t,e,n){var r=function(t){it(1,arguments);var e=at(t),n=e.getTime();e.setUTCMonth(0,1),e.setUTCHours(0,0,0,0);var r=e.getTime(),o=n-r;return Math.floor(o/St)+1}(t);return"Do"===e?n.ordinalNumber(r,{unit:"dayOfYear"}):At(r,e.length)},E:function(t,e,n){var r=t.getUTCDay();switch(e){case"E":case"EE":case"EEE":return n.day(r,{width:"abbreviated",context:"formatting"});case"EEEEE":return n.day(r,{width:"narrow",context:"formatting"});case"EEEEEE":return n.day(r,{width:"short",context:"formatting"});default:return n.day(r,{width:"wide",context:"formatting"})}},e:function(t,e,n,r){var o=t.getUTCDay(),i=(o-r.weekStartsOn+8)%7||7;switch(e){case"e":return String(i);case"ee":return At(i,2);case"eo":return n.ordinalNumber(i,{unit:"day"});case"eee":return n.day(o,{width:"abbreviated",context:"formatting"});case"eeeee":return n.day(o,{width:"narrow",context:"formatting"});case"eeeeee":return n.day(o,{width:"short",context:"formatting"});default:return n.day(o,{width:"wide",context:"formatting"})}},c:function(t,e,n,r){var o=t.getUTCDay(),i=(o-r.weekStartsOn+8)%7||7;switch(e){case"c":return String(i);case"cc":return At(i,e.length);case"co":return n.ordinalNumber(i,{unit:"day"});case"ccc":return n.day(o,{width:"abbreviated",context:"standalone"});case"ccccc":return n.day(o,{width:"narrow",context:"standalone"});case"cccccc":return n.day(o,{width:"short",context:"standalone"});default:return n.day(o,{width:"wide",context:"standalone"})}},i:function(t,e,n){var r=t.getUTCDay(),o=0===r?7:r;switch(e){case"i":return String(o);case"ii":return At(o,e.length);case"io":return n.ordinalNumber(o,{unit:"day"});case"iii":return n.day(r,{width:"abbreviated",context:"formatting"});case"iiiii":return n.day(r,{width:"narrow",context:"formatting"});case"iiiiii":return n.day(r,{width:"short",context:"formatting"});default:return n.day(r,{width:"wide",context:"formatting"})}},a:function(t,e,n){var r=t.getUTCHours()/12>=1?"pm":"am";switch(e){case"a":case"aa":return n.dayPeriod(r,{width:"abbreviated",context:"formatting"});case"aaa":return n.dayPeriod(r,{width:"abbreviated",context:"formatting"}).toLowerCase();case"aaaaa":return n.dayPeriod(r,{width:"narrow",context:"formatting"});default:return n.dayPeriod(r,{width:"wide",context:"formatting"})}},b:function(t,e,n){var r,o=t.getUTCHours();switch(r=12===o?"noon":0===o?"midnight":o/12>=1?"pm":"am",e){case"b":case"bb":return n.dayPeriod(r,{width:"abbreviated",context:"formatting"});case"bbb":return n.dayPeriod(r,{width:"abbreviated",context:"formatting"}).toLowerCase();case"bbbbb":return n.dayPeriod(r,{width:"narrow",context:"formatting"});default:return n.dayPeriod(r,{width:"wide",context:"formatting"})}},B:function(t,e,n){var r,o=t.getUTCHours();switch(r=o>=17?"evening":o>=12?"afternoon":o>=4?"morning":"night",e){case"B":case"BB":case"BBB":return n.dayPeriod(r,{width:"abbreviated",context:"formatting"});case"BBBBB":return n.dayPeriod(r,{width:"narrow",context:"formatting"});default:return n.dayPeriod(r,{width:"wide",context:"formatting"})}},h:function(t,e,n){if("ho"===e){var r=t.getUTCHours()%12;return 0===r&&(r=12),n.ordinalNumber(r,{unit:"hour"})}return qt(t,e)},H:function(t,e,n){return"Ho"===e?n.ordinalNumber(t.getUTCHours(),{unit:"hour"}):Wt(t,e)},K:function(t,e,n){var r=t.getUTCHours()%12;return"Ko"===e?n.ordinalNumber(r,{unit:"hour"}):At(r,e.length)},k:function(t,e,n){var r=t.getUTCHours();return 0===r&&(r=24),"ko"===e?n.ordinalNumber(r,{unit:"hour"}):At(r,e.length)},m:function(t,e,n){return"mo"===e?n.ordinalNumber(t.getUTCMinutes(),{unit:"minute"}):Rt(t,e)},s:function(t,e,n){return"so"===e?n.ordinalNumber(t.getUTCSeconds(),{unit:"second"}):It(t,e)},S:function(t,e){return Lt(t,e)},X:function(t,e,n,r){var o=(r._originalDate||t).getTimezoneOffset();if(0===o)return"Z";switch(e){case"X":return Ft(o);case"XXXX":case"XX":return Ht(o);default:return Ht(o,":")}},x:function(t,e,n,r){var o=(r._originalDate||t).getTimezoneOffset();switch(e){case"x":return Ft(o);case"xxxx":case"xx":return Ht(o);default:return Ht(o,":")}},O:function(t,e,n,r){var o=(r._originalDate||t).getTimezoneOffset();switch(e){case"O":case"OO":case"OOO":return"GMT"+$t(o,":");default:return"GMT"+Ht(o,":")}},z:function(t,e,n,r){var o=(r._originalDate||t).getTimezoneOffset();switch(e){case"z":case"zz":case"zzz":return"GMT"+$t(o,":");default:return"GMT"+Ht(o,":")}},t:function(t,e,n,r){var o=r._originalDate||t;return At(Math.floor(o.getTime()/1e3),e.length)},T:function(t,e,n,r){return At((r._originalDate||t).getTime(),e.length)}};function $t(t,e){var n=t>0?"-":"+",r=Math.abs(t),o=Math.floor(r/60),i=r%60;if(0===i)return n+String(o);var a=e||"";return n+String(o)+a+At(i,2)}function Ft(t,e){return t%60==0?(t>0?"-":"+")+At(Math.abs(t)/60,2):Ht(t,e)}function Ht(t,e){var n=e||"",r=t>0?"-":"+",o=Math.abs(t);return r+At(Math.floor(o/60),2)+n+At(o%60,2)}var zt=Yt,Bt=function(t,e){switch(t){case"P":return e.date({width:"short"});case"PP":return e.date({width:"medium"});case"PPP":return e.date({width:"long"});default:return e.date({width:"full"})}},Xt=function(t,e){switch(t){case"p":return e.time({width:"short"});case"pp":return e.time({width:"medium"});case"ppp":return e.time({width:"long"});default:return e.time({width:"full"})}},Gt={p:Xt,P:function(t,e){var n,r=t.match(/(P+)(p+)?/)||[],o=r[1],i=r[2];if(!i)return Bt(t,e);switch(o){case"P":n=e.dateTime({width:"short"});break;case"PP":n=e.dateTime({width:"medium"});break;case"PPP":n=e.dateTime({width:"long"});break;default:n=e.dateTime({width:"full"})}return n.replace("{{date}}",Bt(o,e)).replace("{{time}}",Xt(i,e))}},Qt=["D","DD"],Jt=["YY","YYYY"];function Vt(t){return-1!==Qt.indexOf(t)}function Kt(t){return-1!==Jt.indexOf(t)}function Zt(t,e,n){if("YYYY"===t)throw new RangeError("Use `yyyy` instead of `YYYY` (in `".concat(e,"`) for formatting years to the input `").concat(n,"`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md"));if("YY"===t)throw new RangeError("Use `yy` instead of `YY` (in `".concat(e,"`) for formatting years to the input `").concat(n,"`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md"));if("D"===t)throw new RangeError("Use `d` instead of `D` (in `".concat(e,"`) for formatting days of the month to the input `").concat(n,"`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md"));if("DD"===t)throw new RangeError("Use `dd` instead of `DD` (in `".concat(e,"`) for formatting days of the month to the input `").concat(n,"`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md"))}var te={lessThanXSeconds:{one:"less than a second",other:"less than {{count}} seconds"},xSeconds:{one:"1 second",other:"{{count}} seconds"},halfAMinute:"half a minute",lessThanXMinutes:{one:"less than a minute",other:"less than {{count}} minutes"},xMinutes:{one:"1 minute",other:"{{count}} minutes"},aboutXHours:{one:"about 1 hour",other:"about {{count}} hours"},xHours:{one:"1 hour",other:"{{count}} hours"},xDays:{one:"1 day",other:"{{count}} days"},aboutXWeeks:{one:"about 1 week",other:"about {{count}} weeks"},xWeeks:{one:"1 week",other:"{{count}} weeks"},aboutXMonths:{one:"about 1 month",other:"about {{count}} months"},xMonths:{one:"1 month",other:"{{count}} months"},aboutXYears:{one:"about 1 year",other:"about {{count}} years"},xYears:{one:"1 year",other:"{{count}} years"},overXYears:{one:"over 1 year",other:"over {{count}} years"},almostXYears:{one:"almost 1 year",other:"almost {{count}} years"}};function ee(t){return function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.width?String(e.width):t.defaultWidth,r=t.formats[n]||t.formats[t.defaultWidth];return r}}var ne={date:ee({formats:{full:"EEEE, MMMM do, y",long:"MMMM do, y",medium:"MMM d, y",short:"MM/dd/yyyy"},defaultWidth:"full"}),time:ee({formats:{full:"h:mm:ss a zzzz",long:"h:mm:ss a z",medium:"h:mm:ss a",short:"h:mm a"},defaultWidth:"full"}),dateTime:ee({formats:{full:"{{date}} 'at' {{time}}",long:"{{date}} 'at' {{time}}",medium:"{{date}}, {{time}}",short:"{{date}}, {{time}}"},defaultWidth:"full"})},re={lastWeek:"'last' eeee 'at' p",yesterday:"'yesterday at' p",today:"'today at' p",tomorrow:"'tomorrow at' p",nextWeek:"eeee 'at' p",other:"P"};function oe(t){return function(e,n){var r;if("formatting"===(null!=n&&n.context?String(n.context):"standalone")&&t.formattingValues){var o=t.defaultFormattingWidth||t.defaultWidth,i=null!=n&&n.width?String(n.width):o;r=t.formattingValues[i]||t.formattingValues[o]}else{var a=t.defaultWidth,s=null!=n&&n.width?String(n.width):t.defaultWidth;r=t.values[s]||t.values[a]}return r[t.argumentCallback?t.argumentCallback(e):e]}}var ie={ordinalNumber:function(t,e){var n=Number(t),r=n%100;if(r>20||r<10)switch(r%10){case 1:return n+"st";case 2:return n+"nd";case 3:return n+"rd"}return n+"th"},era:oe({values:{narrow:["B","A"],abbreviated:["BC","AD"],wide:["Before Christ","Anno Domini"]},defaultWidth:"wide"}),quarter:oe({values:{narrow:["1","2","3","4"],abbreviated:["Q1","Q2","Q3","Q4"],wide:["1st quarter","2nd quarter","3rd quarter","4th quarter"]},defaultWidth:"wide",argumentCallback:function(t){return t-1}}),month:oe({values:{narrow:["J","F","M","A","M","J","J","A","S","O","N","D"],abbreviated:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],wide:["January","February","March","April","May","June","July","August","September","October","November","December"]},defaultWidth:"wide"}),day:oe({values:{narrow:["S","M","T","W","T","F","S"],short:["Su","Mo","Tu","We","Th","Fr","Sa"],abbreviated:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],wide:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]},defaultWidth:"wide"}),dayPeriod:oe({values:{narrow:{am:"a",pm:"p",midnight:"mi",noon:"n",morning:"morning",afternoon:"afternoon",evening:"evening",night:"night"},abbreviated:{am:"AM",pm:"PM",midnight:"midnight",noon:"noon",morning:"morning",afternoon:"afternoon",evening:"evening",night:"night"},wide:{am:"a.m.",pm:"p.m.",midnight:"midnight",noon:"noon",morning:"morning",afternoon:"afternoon",evening:"evening",night:"night"}},defaultWidth:"wide",formattingValues:{narrow:{am:"a",pm:"p",midnight:"mi",noon:"n",morning:"in the morning",afternoon:"in the afternoon",evening:"in the evening",night:"at night"},abbreviated:{am:"AM",pm:"PM",midnight:"midnight",noon:"noon",morning:"in the morning",afternoon:"in the afternoon",evening:"in the evening",night:"at night"},wide:{am:"a.m.",pm:"p.m.",midnight:"midnight",noon:"noon",morning:"in the morning",afternoon:"in the afternoon",evening:"in the evening",night:"at night"}},defaultFormattingWidth:"wide"})},ae=ie;function se(t){return function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=n.width,o=r&&t.matchPatterns[r]||t.matchPatterns[t.defaultMatchWidth],i=e.match(o);if(!i)return null;var a,s=i[0],u=r&&t.parsePatterns[r]||t.parsePatterns[t.defaultParseWidth],l=Array.isArray(u)?le(u,(function(t){return t.test(s)})):ue(u,(function(t){return t.test(s)}));a=t.valueCallback?t.valueCallback(l):l,a=n.valueCallback?n.valueCallback(a):a;var c=e.slice(s.length);return{value:a,rest:c}}}function ue(t,e){for(var n in t)if(t.hasOwnProperty(n)&&e(t[n]))return n}function le(t,e){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{},n=t.match(ce.matchPattern);if(!n)return null;var r=n[0],o=t.match(ce.parsePattern);if(!o)return null;var i=ce.valueCallback?ce.valueCallback(o[0]):o[0];i=e.valueCallback?e.valueCallback(i):i;var a=t.slice(r.length);return{value:i,rest:a}}),era:se({matchPatterns:{narrow:/^(b|a)/i,abbreviated:/^(b\.?\s?c\.?|b\.?\s?c\.?\s?e\.?|a\.?\s?d\.?|c\.?\s?e\.?)/i,wide:/^(before christ|before common era|anno domini|common era)/i},defaultMatchWidth:"wide",parsePatterns:{any:[/^b/i,/^(a|c)/i]},defaultParseWidth:"any"}),quarter:se({matchPatterns:{narrow:/^[1234]/i,abbreviated:/^q[1234]/i,wide:/^[1234](th|st|nd|rd)? quarter/i},defaultMatchWidth:"wide",parsePatterns:{any:[/1/i,/2/i,/3/i,/4/i]},defaultParseWidth:"any",valueCallback:function(t){return t+1}}),month:se({matchPatterns:{narrow:/^[jfmasond]/i,abbreviated:/^(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)/i,wide:/^(january|february|march|april|may|june|july|august|september|october|november|december)/i},defaultMatchWidth:"wide",parsePatterns:{narrow:[/^j/i,/^f/i,/^m/i,/^a/i,/^m/i,/^j/i,/^j/i,/^a/i,/^s/i,/^o/i,/^n/i,/^d/i],any:[/^ja/i,/^f/i,/^mar/i,/^ap/i,/^may/i,/^jun/i,/^jul/i,/^au/i,/^s/i,/^o/i,/^n/i,/^d/i]},defaultParseWidth:"any"}),day:se({matchPatterns:{narrow:/^[smtwf]/i,short:/^(su|mo|tu|we|th|fr|sa)/i,abbreviated:/^(sun|mon|tue|wed|thu|fri|sat)/i,wide:/^(sunday|monday|tuesday|wednesday|thursday|friday|saturday)/i},defaultMatchWidth:"wide",parsePatterns:{narrow:[/^s/i,/^m/i,/^t/i,/^w/i,/^t/i,/^f/i,/^s/i],any:[/^su/i,/^m/i,/^tu/i,/^w/i,/^th/i,/^f/i,/^sa/i]},defaultParseWidth:"any"}),dayPeriod:se({matchPatterns:{narrow:/^(a|p|mi|n|(in the|at) (morning|afternoon|evening|night))/i,any:/^([ap]\.?\s?m\.?|midnight|noon|(in the|at) (morning|afternoon|evening|night))/i},defaultMatchWidth:"any",parsePatterns:{any:{am:/^a/i,pm:/^p/i,midnight:/^mi/i,noon:/^no/i,morning:/morning/i,afternoon:/afternoon/i,evening:/evening/i,night:/night/i}},defaultParseWidth:"any"})},fe={code:"en-US",formatDistance:function(t,e,n){var r,o=te[t];return r="string"==typeof o?o:1===e?o.one:o.other.replace("{{count}}",e.toString()),null!=n&&n.addSuffix?n.comparison&&n.comparison>0?"in "+r:r+" ago":r},formatLong:ne,formatRelative:function(t,e,n,r){return re[t]},localize:ae,match:he,options:{weekStartsOn:0,firstWeekContainsDate:1}},de=/[yYQqMLwIdDecihHKkms]o|(\w)\1*|''|'(''|[^'])+('|$)|./g,pe=/P+p+|P+|p+|''|'(''|[^'])+('|$)|./g,me=/^'([^]*?)'?$/,ve=/''/g,ye=/[a-zA-Z]/;function _e(t,e,n){var r,o,i,a,s,u,l,c,h,f,d,p,m,v,y,_,g,w;it(2,arguments);var b=String(e),k=ct(),S=null!==(r=null!==(o=null==n?void 0:n.locale)&&void 0!==o?o:k.locale)&&void 0!==r?r:fe,E=ot(null!==(i=null!==(a=null!==(s=null!==(u=null==n?void 0:n.firstWeekContainsDate)&&void 0!==u?u:null==n||null===(l=n.locale)||void 0===l||null===(c=l.options)||void 0===c?void 0:c.firstWeekContainsDate)&&void 0!==s?s:k.firstWeekContainsDate)&&void 0!==a?a:null===(h=k.locale)||void 0===h||null===(f=h.options)||void 0===f?void 0:f.firstWeekContainsDate)&&void 0!==i?i:1);if(!(E>=1&&E<=7))throw new RangeError("firstWeekContainsDate must be between 1 and 7 inclusively");var x=ot(null!==(d=null!==(p=null!==(m=null!==(v=null==n?void 0:n.weekStartsOn)&&void 0!==v?v:null==n||null===(y=n.locale)||void 0===y||null===(_=y.options)||void 0===_?void 0:_.weekStartsOn)&&void 0!==m?m:k.weekStartsOn)&&void 0!==p?p:null===(g=k.locale)||void 0===g||null===(w=g.options)||void 0===w?void 0:w.weekStartsOn)&&void 0!==d?d:0);if(!(x>=0&&x<=6))throw new RangeError("weekStartsOn must be between 0 and 6 inclusively");if(!S.localize)throw new RangeError("locale must contain localize property");if(!S.formatLong)throw new RangeError("locale must contain formatLong property");var T=at(t);if(!vt(T))throw new RangeError("Invalid time value");var C=ft(T),D=kt(T,C),P={firstWeekContainsDate:E,weekStartsOn:x,locale:S,_originalDate:T},M=b.match(pe).map((function(t){var e=t[0];return"p"===e||"P"===e?(0,Gt[e])(t,S.formatLong):t})).join("").match(de).map((function(r){if("''"===r)return"'";var o=r[0];if("'"===o)return ge(r);var i=zt[o];if(i)return null!=n&&n.useAdditionalWeekYearTokens||!Kt(r)||Zt(r,e,String(t)),null!=n&&n.useAdditionalDayOfYearTokens||!Vt(r)||Zt(r,e,String(t)),i(D,r,S.localize,P);if(o.match(ye))throw new RangeError("Format string contains an unescaped latin alphabet character `"+o+"`");return r})).join("");return M}function ge(t){var e=t.match(me);return e?e[1].replace(ve,"'"):t}function we(t,e){if(null==t)throw new TypeError("assign requires that input parameter not be null or undefined");for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t}function be(t){return we({},t)}var ke=6e4,Se=1440,Ee=43200,xe=525600;function Te(t,e,n){var r,o,i;it(2,arguments);var a=ct(),s=null!==(r=null!==(o=null==n?void 0:n.locale)&&void 0!==o?o:a.locale)&&void 0!==r?r:fe;if(!s.formatDistance)throw new RangeError("locale must contain localize.formatDistance property");var u=pt(t,e);if(isNaN(u))throw new RangeError("Invalid time value");var l,c,h=we(be(n),{addSuffix:Boolean(null==n?void 0:n.addSuffix),comparison:u});u>0?(l=at(e),c=at(t)):(l=at(t),c=at(e));var f,d=String(null!==(i=null==n?void 0:n.roundingMethod)&&void 0!==i?i:"round");if("floor"===d)f=Math.floor;else if("ceil"===d)f=Math.ceil;else{if("round"!==d)throw new RangeError("roundingMethod must be 'floor', 'ceil' or 'round'");f=Math.round}var p,m=c.getTime()-l.getTime(),v=m/ke,y=ft(c)-ft(l),_=(m-y)/ke,g=null==n?void 0:n.unit;if("second"===(p=g?String(g):v<1?"second":v<60?"minute":vvoid 0===t&&void 0===e||null===t&&null===e||(null!=t&&null!=t&&t[Ce]?t[Ce](e):null!=e&&null!=e&&e[Ce]?e[Ce](t):(t&&t.$$typeof===De||e&&e.$$typeof===De||console.warn("Comparing entites with === because there is no comparison function defined:",t,e),t===e));class Record{constructor(t){for(let e in t)this[e]=t[e]}[Ce](t){if(!(t instanceof Record))return!1;if(Object.keys(this).length!==Object.keys(t).length)return!1;for(let e in this)if(!Pe(t[e],this[e]))return!1;return!0}}const Me=(t,e)=>n=>{const r=class extends Record{};return r.mappings=n,r.encode=t=>{const e={};for(let r in n){const[o,i,a]=n[r];e[o]=a?a(t[r]):t[r]}return e},r.decode=o=>{const{ok:i,err:a}=e,s={};for(let e in n){const[r,i]=n[e],u=t.field(r,i)(o);if(u instanceof a)return u;s[e]=u._0}return new i(new r(s))},r},Oe=(t,e)=>{const n=Object.assign(Object.create(null),t,e);return t instanceof Record?new t.constructor(n):new Record(n)},Ae=(t,e=!0,n=!0,r=null)=>{if(window.location.pathname+window.location.search+window.location.hash!==t&&(e?window.history.pushState({},"",t):window.history.replaceState({},"",t)),e){let t=new PopStateEvent("popstate");t.triggerJump=n,t.routeInfo=r,dispatchEvent(t)}},je=t=>{let e=document.createElement("style");document.head.appendChild(e),e.innerHTML=t},Ne=t=>(e,n)=>{const{just:r,nothing:o}=t;return e.length>=n+1&&n>=0?new r(e[n]):new o};class Ue{constructor(){this.effectAllowed="none",this.dropEffect="none",this.files=[],this.types=[],this.cache={}}getData(t){return this.cache[t]||""}setData(t,e){return this.cache[t]=e,null}clearData(){return this.cache={},null}}const qe=t=>new Proxy(t,{get:function(t,e){if(e in t){const n=t[e];return n instanceof Function?()=>t[e]():n}switch(e){case"clipboardData":return t.clipboardData=new Ue;case"dataTransfer":return t.dataTransfer=new Ue;case"data":case"key":case"locale":case"animationName":case"pseudoElement":case"propertyName":return"";case"altKey":case"ctrlKey":case"metaKey":case"repeat":case"shiftKey":return!1;case"charCode":case"keyCode":case"location":case"which":case"button":case"buttons":case"clientX":case"clientY":case"pageX":case"pageY":case"screenX":case"screenY":case"detail":case"deltaMode":case"deltaX":case"deltaY":case"deltaZ":case"elapsedTime":return-1;default:return}}}),We=(t,e)=>{const n=Object.getOwnPropertyDescriptors(Reflect.getPrototypeOf(t));for(let r in n){if(e&&e[r])continue;const o=n[r].value;"function"==typeof o&&(t[r]=o.bind(t))}},Re=(t,e)=>{if(!e)return;const n={};Object.keys(e).forEach((t=>{let r=null;n[t]={get:()=>(r||(r=e[t]()),r)}})),Object.defineProperties(t,n)},Ie=function(){let t=Array.from(arguments);return Array.isArray(t[0])&&1===t.length?t[0]:t},Le=function(t){const e={},n=(t,n)=>{e[t.toString().trim()]=n.toString().trim()};for(let e of t)if("string"==typeof e)e.split(";").forEach((t=>{const[e,r]=t.split(":");e&&r&&n(e,r)}));else if(e instanceof Map)for(let[t,r]of e)n(t,r);else if(e instanceof Array)for(let[t,r]of e)n(t,r);else for(let t in e)n(t,e[t]);return e};class Ye extends p{render(){const t=[];for(let e in this.props.globals)t.push(h(this.props.globals[e],{ref:t=>t._persist(),key:e}));return h("div",{},[...t,...this.props.children])}}Ye.displayName="Mint.Root";class $e{constructor(t){t&&t instanceof Node&&t!==document.body?this.root=t:(this.root=document.createElement("div"),document.body.appendChild(this.root))}render(t,e){void 0!==t&&P(h(Ye,{globals:e},[h(t,{key:"$MAIN"})]),this.root)}}class Fe{constructor(t,e){this.teardown=e,this.subject=t,this.steps=[]}async run(){let t;try{t=await new Promise(this.next.bind(this))}finally{this.teardown&&this.teardown()}return t}async next(t,e){requestAnimationFrame((async()=>{let n=this.steps.shift();if(n)try{this.subject=await n(this.subject)}catch(t){return e(t)}this.steps.length?this.next(t,e):t(this.subject)}))}step(t){return this.steps.push(t),this}}const He=["componentWillMount","render","getSnapshotBeforeUpdate","componentDidMount","componentWillReceiveProps","shouldComponentUpdate","componentWillUpdate","componentDidUpdate","componentWillUnmount","componentDidCatch","setState","forceUpdate","constructor"];class ze extends p{constructor(t){super(t),We(this,He)}_d(t,e){Re(this,e);const n={};Object.keys(t).forEach((e=>{const[r,o]=t[e],i=r||e;n[e]={get:()=>i in this.props?this.props[i]:o}})),Object.defineProperties(this,n)}}class Be{constructor(){We(this),this.subscriptions=new Map,this.state={}}setState(t,e){this.state=Object.assign({},this.state,t),e()}_d(t){Re(this,t)}_subscribe(t,e){const n=this.subscriptions.get(t);null==e||null!=n&&((t,e)=>{if(t instanceof Object&&e instanceof Object){const n=new Set(Object.keys(t).concat(Object.keys(e)));for(let r of n)if(!Pe(t[r],e[r]))return!1;return!0}return console.warn("Comparing entites with === because there is no comparison function defined:",t,e),t===e})(n,e)||(this.subscriptions.set(t,e),this._update())}_unsubscribe(t){this.subscriptions.has(t)&&(this.subscriptions.delete(t),this._update())}_update(){this.update()}get _subscriptions(){return Array.from(this.subscriptions.values())}update(){}}var Xe,Ge,Qe=(Xe=function(t,e){var n=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,9],n=[1,10],r=[1,11],o=[1,12],i=[5,11,12,13,14,15],a={trace:function(){},yy:{},symbols_:{error:2,root:3,expressions:4,EOF:5,expression:6,optional:7,literal:8,splat:9,param:10,"(":11,")":12,LITERAL:13,SPLAT:14,PARAM:15,$accept:0,$end:1},terminals_:{2:"error",5:"EOF",11:"(",12:")",13:"LITERAL",14:"SPLAT",15:"PARAM"},productions_:[0,[3,2],[3,1],[4,2],[4,1],[6,1],[6,1],[6,1],[6,1],[7,3],[8,1],[9,1],[10,1]],performAction:function(t,e,n,r,o,i,a){var s=i.length-1;switch(o){case 1:return new r.Root({},[i[s-1]]);case 2:return new r.Root({},[new r.Literal({value:""})]);case 3:this.$=new r.Concat({},[i[s-1],i[s]]);break;case 4:case 5:this.$=i[s];break;case 6:this.$=new r.Literal({value:i[s]});break;case 7:this.$=new r.Splat({name:i[s]});break;case 8:this.$=new r.Param({name:i[s]});break;case 9:this.$=new r.Optional({},[i[s-1]]);break;case 10:this.$=t;break;case 11:case 12:this.$=t.slice(1)}},table:[{3:1,4:2,5:[1,3],6:4,7:5,8:6,9:7,10:8,11:e,13:n,14:r,15:o},{1:[3]},{5:[1,13],6:14,7:5,8:6,9:7,10:8,11:e,13:n,14:r,15:o},{1:[2,2]},t(i,[2,4]),t(i,[2,5]),t(i,[2,6]),t(i,[2,7]),t(i,[2,8]),{4:15,6:4,7:5,8:6,9:7,10:8,11:e,13:n,14:r,15:o},t(i,[2,10]),t(i,[2,11]),t(i,[2,12]),{1:[2,1]},t(i,[2,3]),{6:14,7:5,8:6,9:7,10:8,11:e,12:[1,16],13:n,14:r,15:o},t(i,[2,9])],defaultActions:{3:[2,2],13:[2,1]},parseError:function(t,e){if(!e.recoverable){function n(t,e){this.message=t,this.hash=e}throw n.prototype=Error,new n(t,e)}this.trace(t)},parse:function(t){var e=this,n=[0],r=[null],o=[],i=this.table,a="",s=0,u=0,l=2,c=1,h=o.slice.call(arguments,1),f=Object.create(this.lexer),d={yy:{}};for(var p in this.yy)Object.prototype.hasOwnProperty.call(this.yy,p)&&(d.yy[p]=this.yy[p]);f.setInput(t,d.yy),d.yy.lexer=f,d.yy.parser=this,void 0===f.yylloc&&(f.yylloc={});var m=f.yylloc;o.push(m);var v=f.options&&f.options.ranges;"function"==typeof d.yy.parseError?this.parseError=d.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var y,_,g,w,b,k,S,E,x=function(){var t;return"number"!=typeof(t=f.lex()||c)&&(t=e.symbols_[t]||t),t},T={};;){if(_=n[n.length-1],this.defaultActions[_]?g=this.defaultActions[_]:(null==y&&(y=x()),g=i[_]&&i[_][y]),void 0===g||!g.length||!g[0]){var C="";for(b in E=[],i[_])this.terminals_[b]&&b>l&&E.push("'"+this.terminals_[b]+"'");C=f.showPosition?"Parse error on line "+(s+1)+":\n"+f.showPosition()+"\nExpecting "+E.join(", ")+", got '"+(this.terminals_[y]||y)+"'":"Parse error on line "+(s+1)+": Unexpected "+(y==c?"end of input":"'"+(this.terminals_[y]||y)+"'"),this.parseError(C,{text:f.match,token:this.terminals_[y]||y,line:f.yylineno,loc:m,expected:E})}if(g[0]instanceof Array&&g.length>1)throw new Error("Parse Error: multiple actions possible at state: "+_+", token: "+y);switch(g[0]){case 1:n.push(y),r.push(f.yytext),o.push(f.yylloc),n.push(g[1]),y=null,u=f.yyleng,a=f.yytext,s=f.yylineno,m=f.yylloc;break;case 2:if(k=this.productions_[g[1]][1],T.$=r[r.length-k],T._$={first_line:o[o.length-(k||1)].first_line,last_line:o[o.length-1].last_line,first_column:o[o.length-(k||1)].first_column,last_column:o[o.length-1].last_column},v&&(T._$.range=[o[o.length-(k||1)].range[0],o[o.length-1].range[1]]),void 0!==(w=this.performAction.apply(T,[a,u,s,d.yy,g[1],r,o].concat(h))))return w;k&&(n=n.slice(0,-1*k*2),r=r.slice(0,-1*k),o=o.slice(0,-1*k)),n.push(this.productions_[g[1]][0]),r.push(T.$),o.push(T._$),S=i[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},s=function(){var t={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var o=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[o[0],o[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,o;if(this.options.backtrack_lexer&&(o={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(o.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var i in o)this[i]=o[i];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var o=this._currentRules(),i=0;ie[0].length)){if(e=n,r=i,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,o[i])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,o[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{},performAction:function(t,e,n,r){switch(n){case 0:return"(";case 1:return")";case 2:return"SPLAT";case 3:return"PARAM";case 4:case 5:return"LITERAL";case 6:return"EOF"}},rules:[/^(?:\()/,/^(?:\))/,/^(?:\*+\w+)/,/^(?::+\w+)/,/^(?:[\w%\-~\n]+)/,/^(?:.)/,/^(?:$)/],conditions:{INITIAL:{rules:[0,1,2,3,4,5,6],inclusive:!0}}};return t}();function u(){this.yy={}}return a.lexer=s,u.prototype=a,a.Parser=u,new u}();e.parser=n,e.Parser=n.Parser,e.parse=function(){return n.parse.apply(n,arguments)}},Xe(Ge={path:undefined,exports:{},require:function(t,e){return function(){throw new Error("Dynamic requires are not currently supported by @rollup/plugin-commonjs")}(null==e&&Ge.path)}},Ge.exports),Ge.exports);function Je(t){return function(e,n){return{displayName:t,props:e,children:n||[]}}}var Ve={Root:Je("Root"),Concat:Je("Concat"),Literal:Je("Literal"),Splat:Je("Splat"),Param:Je("Param"),Optional:Je("Optional")},Ke=Qe.parser;Ke.yy=Ve;var Ze=Ke,tn=Object.keys(Ve),en=function(t){return tn.forEach((function(e){if(void 0===t[e])throw new Error("No handler defined for "+e.displayName)})),{visit:function(t,e){return this.handlers[t.displayName].call(this,t,e)},handlers:t}},nn=/[\-{}\[\]+?.,\\\^$|#\s]/g;function rn(t){this.captures=t.captures,this.re=t.re}rn.prototype.match=function(t){var e=this.re.exec(t),n={};return!!e&&(this.captures.forEach((function(t,r){void 0===e[r+1]?n[t]=void 0:n[t]=decodeURIComponent(e[r+1])})),n)};var on=en({Concat:function(t){return t.children.reduce(function(t,e){var n=this.visit(e);return{re:t.re+n.re,captures:t.captures.concat(n.captures)}}.bind(this),{re:"",captures:[]})},Literal:function(t){return{re:t.props.value.replace(nn,"\\$&"),captures:[]}},Splat:function(t){return{re:"([^?#]*?)",captures:[t.props.name]}},Param:function(t){return{re:"([^\\/\\?#]+)",captures:[t.props.name]}},Optional:function(t){var e=this.visit(t.children[0]);return{re:"(?:"+e.re+")?",captures:e.captures}},Root:function(t){var e=this.visit(t.children[0]);return new rn({re:new RegExp("^"+e.re+"(?=\\?|#|$)"),captures:e.captures})}}),an=en({Concat:function(t,e){var n=t.children.map(function(t){return this.visit(t,e)}.bind(this));return!n.some((function(t){return!1===t}))&&n.join("")},Literal:function(t){return decodeURI(t.props.value)},Splat:function(t,e){return void 0!==e[t.props.name]&&e[t.props.name]},Param:function(t,e){return void 0!==e[t.props.name]&&e[t.props.name]},Optional:function(t,e){return this.visit(t.children[0],e)||""},Root:function(t,e){e=e||{};var n=this.visit(t.children[0],e);return!1!==n&&void 0!==n&&encodeURI(n)}}),sn=an;function un(t){var e;if(e=this?this:Object.create(un.prototype),void 0===t)throw new Error("A route spec is required");return e.spec=t,e.ast=Ze.parse(t),e}un.prototype=Object.create(null),un.prototype.match=function(t){var e=on.visit(this.ast).match(t);return null!==e&&e},un.prototype.reverse=function(t){return sn.visit(this.ast,t)};var ln=un,cn=Object.getOwnPropertyNames,hn=Object.getOwnPropertySymbols,fn=Object.prototype.hasOwnProperty;function dn(t,e){return function(n,r,o){return t(n,r,o)&&e(n,r,o)}}function pn(t){return function(e,n,r){if(!e||!n||"object"!=typeof e||"object"!=typeof n)return t(e,n,r);var o=r.cache,i=o.get(e),a=o.get(n);if(i&&a)return i===n&&a===e;o.set(e,n),o.set(n,e);var s=t(e,n,r);return o.delete(e),o.delete(n),s}}function mn(t){return cn(t).concat(hn(t))}var vn=Object.hasOwn||function(t,e){return fn.call(t,e)};function yn(t,e){return t||e?t===e:t===e||t!=t&&e!=e}var _n="_owner",gn=Object.getOwnPropertyDescriptor,wn=Object.keys;function bn(t,e,n){var r=t.length;if(e.length!==r)return!1;for(;r-- >0;)if(!n.equals(t[r],e[r],r,r,t,e,n))return!1;return!0}function kn(t,e){return yn(t.getTime(),e.getTime())}function Sn(t,e,n){if(t.size!==e.size)return!1;for(var r,o,i={},a=t.entries(),s=0;(r=a.next())&&!r.done;){for(var u=e.entries(),l=!1,c=0;(o=u.next())&&!o.done;){var h=r.value,f=h[0],d=h[1],p=o.value,m=p[0],v=p[1];l||i[c]||!(l=n.equals(f,m,s,c,t,e,n)&&n.equals(d,v,f,m,t,e,n))||(i[c]=!0),c++}if(!l)return!1;s++}return!0}function En(t,e,n){var r,o=wn(t),i=o.length;if(wn(e).length!==i)return!1;for(;i-- >0;){if((r=o[i])===_n&&(t.$$typeof||e.$$typeof)&&t.$$typeof!==e.$$typeof)return!1;if(!vn(e,r)||!n.equals(t[r],e[r],r,r,t,e,n))return!1}return!0}function xn(t,e,n){var r,o,i,a=mn(t),s=a.length;if(mn(e).length!==s)return!1;for(;s-- >0;){if((r=a[s])===_n&&(t.$$typeof||e.$$typeof)&&t.$$typeof!==e.$$typeof)return!1;if(!vn(e,r))return!1;if(!n.equals(t[r],e[r],r,r,t,e,n))return!1;if(o=gn(t,r),i=gn(e,r),(o||i)&&(!o||!i||o.configurable!==i.configurable||o.enumerable!==i.enumerable||o.writable!==i.writable))return!1}return!0}function Tn(t,e){return yn(t.valueOf(),e.valueOf())}function Cn(t,e){return t.source===e.source&&t.flags===e.flags}function Dn(t,e,n){if(t.size!==e.size)return!1;for(var r,o,i={},a=t.values();(r=a.next())&&!r.done;){for(var s=e.values(),u=!1,l=0;(o=s.next())&&!o.done;)u||i[l]||!(u=n.equals(r.value,o.value,r.value,o.value,t,e,n))||(i[l]=!0),l++;if(!u)return!1}return!0}function Pn(t,e){var n=t.length;if(e.length!==n)return!1;for(;n-- >0;)if(t[n]!==e[n])return!1;return!0}var Mn=Array.isArray,On="function"==typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView:null,An=Object.assign,jn=Object.prototype.toString.call.bind(Object.prototype.toString),Nn=Un();function Un(t){void 0===t&&(t={});var e=t.circular,n=void 0!==e&&e,r=t.createInternalComparator,o=t.createState,i=t.strict,a=void 0!==i&&i,s=function(t){var e=t.circular,n=t.createCustomConfig,r=t.strict,o={areArraysEqual:r?xn:bn,areDatesEqual:kn,areMapsEqual:r?dn(Sn,xn):Sn,areObjectsEqual:r?xn:En,arePrimitiveWrappersEqual:Tn,areRegExpsEqual:Cn,areSetsEqual:r?dn(Dn,xn):Dn,areTypedArraysEqual:r?xn:Pn};if(n&&(o=An({},o,n(o))),e){var i=pn(o.areArraysEqual),a=pn(o.areMapsEqual),s=pn(o.areObjectsEqual),u=pn(o.areSetsEqual);o=An({},o,{areArraysEqual:i,areMapsEqual:a,areObjectsEqual:s,areSetsEqual:u})}return o}(t),u=function(t){var e=t.areArraysEqual,n=t.areDatesEqual,r=t.areMapsEqual,o=t.areObjectsEqual,i=t.arePrimitiveWrappersEqual,a=t.areRegExpsEqual,s=t.areSetsEqual,u=t.areTypedArraysEqual;return function(t,l,c){if(t===l)return!0;if(null==t||null==l||"object"!=typeof t||"object"!=typeof l)return t!=t&&l!=l;var h=t.constructor;if(h!==l.constructor)return!1;if(h===Object)return o(t,l,c);if(Mn(t))return e(t,l,c);if(null!=On&&On(t))return u(t,l,c);if(h===Date)return n(t,l,c);if(h===RegExp)return a(t,l,c);if(h===Map)return r(t,l,c);if(h===Set)return s(t,l,c);var f=jn(t);return"[object Date]"===f?n(t,l,c):"[object RegExp]"===f?a(t,l,c):"[object Map]"===f?r(t,l,c):"[object Set]"===f?s(t,l,c):"[object Object]"===f?"function"!=typeof t.then&&"function"!=typeof l.then&&o(t,l,c):"[object Arguments]"===f?o(t,l,c):("[object Boolean]"===f||"[object Number]"===f||"[object String]"===f)&&i(t,l,c)}}(s),l=r?r(u):function(t){return function(e,n,r,o,i,a,s){return t(e,n,s)}}(u);return function(t){var e=t.circular,n=t.comparator,r=t.createState,o=t.equals,i=t.strict;if(r)return function(t,a){var s=r(),u=s.cache,l=void 0===u?e?new WeakMap:void 0:u,c=s.meta;return n(t,a,{cache:l,equals:o,meta:c,strict:i})};if(e)return function(t,e){return n(t,e,{cache:new WeakMap,equals:o,meta:void 0,strict:i})};var a={cache:void 0,equals:o,meta:void 0,strict:i};return function(t,e){return n(t,e,a)}}({circular:n,comparator:u,createState:o,equals:l,strict:a})}Un({strict:!0}),Un({circular:!0}),Un({circular:!0,strict:!0}),Un({createInternalComparator:function(){return yn}}),Un({strict:!0,createInternalComparator:function(){return yn}}),Un({circular:!0,createInternalComparator:function(){return yn}}),Un({circular:!0,createInternalComparator:function(){return yn},strict:!0}),Event.prototype.propagationPath=function(){var t=function(){var t=this.target||null,e=[t];if(!t||!t.parentElement)return[];for(;t.parentElement;)t=t.parentElement,e.unshift(t);return e}.bind(this);return this.path||this.composedPath&&this.composedPath()||t()};class qn extends Error{}const Wn=(t,e)=>{for(let n of e){if("*"===n.path)return{route:n,vars:!1};{let e=new ln(n.path).match(t);if(e)return{route:n,vars:e}}}return null};class Rn extends p{handleClick(t){if(!t.defaultPrevented&&!t.ctrlKey)for(let e of t.propagationPath())if("A"===e.tagName){if(""!==e.target.trim())return;if(e.origin===window.location.origin){const n=e.pathname+e.search+e.hash,r=this.props.routes,o=Wn(n,r);if(o)return t.preventDefault(),void Ae(n,!0,!0,o)}}}render(){const t=[];for(let e in this.props.globals)t.push(h(this.props.globals[e],{ref:t=>t._persist(),key:e}));return h("div",{onClick:this.handleClick.bind(this)},[...t,...this.props.children])}}Rn.displayName="Mint.Root";var In=t=>class{constructor(){this.root=document.createElement("div"),document.body.appendChild(this.root),this.routes=[],this.routeInfo=null,window.addEventListener("popstate",(t=>{this.handlePopState(t)}))}resolvePagePosition(t){var e;e=()=>{requestAnimationFrame((()=>{const e=window.location.hash;if(e){let n=null;try{n=this.root.querySelector(e)||this.root.querySelector(`a[name="${e.slice(1)}"]`)}finally{}n?t&&n.scrollIntoView():console.warn(`${e} matches no element with an id and no link with a name`)}else t&&window.scrollTo(0,0)}))},"function"!=typeof window.queueMicrotask?Promise.resolve().then(e).catch((t=>setTimeout((()=>{throw t})))):window.queueMicrotask(e)}handlePopState(t){const e=window.location.pathname+window.location.search+window.location.hash,n=t?.routeInfo||Wn(e,this.routes);n&&(null!==this.routeInfo&&n.route.path===this.routeInfo.route.path&&((t,e)=>t instanceof Object?e instanceof Object&&Nn(t,e):!e instanceof Object&&t===e)(n.vars,this.routeInfo.vars)||this.runRouteHandler(n),this.resolvePagePosition(!!t?.triggerJump)),this.routeInfo=n}runRouteHandler(e){const{route:n}=e;if("*"===n.path)n.handler();else{const{vars:r}=e;try{let e=n.mapping.map(((e,o)=>{const i=r[e],a=n.decoders[o](i);if(a instanceof t.ok)return a._0;throw new qn}));n.handler.apply(null,e)}catch(t){if(t.constructor!==qn)throw t}}}render(t,e){void 0!==t&&(P(h(Rn,{routes:this.routes,globals:e},[h(t,{key:"$MAIN"})]),this.root),this.handlePopState())}addRoutes(t){this.routes=this.routes.concat(t)}};const Ln=t=>{let e=JSON.stringify(t,"",2);return void 0===e&&(e="undefined"),((t,e=1,n)=>{if(n={indent:" ",includeEmptyLines:!1,...n},"string"!=typeof t)throw new TypeError(`Expected \`input\` to be a \`string\`, got \`${typeof t}\``);if("number"!=typeof e)throw new TypeError(`Expected \`count\` to be a \`number\`, got \`${typeof e}\``);if("string"!=typeof n.indent)throw new TypeError(`Expected \`options.indent\` to be a \`string\`, got \`${typeof n.indent}\``);if(0===e)return t;const r=n.includeEmptyLines?/^/gm:/^(?!\s*$)/gm;return t.replace(r,n.indent.repeat(e))})(e)};class Yn{constructor(t,e=[]){this.message=t,this.object=null,this.path=e}push(t){this.path.unshift(t)}toString(){const t=this.message.trim(),e=this.path.reduce(((t,e)=>{if(t.length)switch(e.type){case"FIELD":return`${t}.${e.value}`;case"ARRAY":return`${t}[${e.value}]`}else switch(e.type){case"FIELD":return e.value;case"ARRAY":return"[$(item.value)]"}}),"");return e.length&&this.object?t+"\n\n"+$n.trim().replace("{value}",Ln(this.object)).replace("{path}",e):t}}const $n="\nThe input is in this object:\n\n{value}\n\nat: {path}\n",Fn=t=>e=>{const{ok:n,err:r}=t;return"string"!=typeof e?new r(new Yn("\nI was trying to decode the value:\n\n{value}\n\nas a String, but could not.\n".replace("{value}",Ln(e)))):new n(e)},Hn=t=>e=>{const{ok:n,err:r}=t;let o=NaN;return o="number"==typeof e?new Date(e):Date.parse(e),Number.isNaN(o)?new r(new Yn("\nI was trying to decode the value:\n\n{value}\n\nas a Time, but could not.\n".replace("{value}",Ln(e)))):new n(new Date(o))},zn=t=>e=>{const{ok:n,err:r}=t;let o=parseFloat(e);return isNaN(o)?new r(new Yn("\nI was trying to decode the value:\n\n{value}\n\nas a Number, but could not.\n".replace("{value}",Ln(e)))):new n(o)},Bn=t=>e=>{const{ok:n,err:r}=t;return"boolean"!=typeof e?new r(new Yn("\nI was trying to decode the value:\n\n{value}\n\nas a Bool, but could not.\n".replace("{value}",Ln(e)))):new n(e)},Xn=t=>(e,n)=>{const{err:r,nothing:o}=t;return t=>{if(null==t||null==t||"object"!=typeof t||Array.isArray(t)){const n='\nI was trying to decode the field "{field}" from the object:\n\n{value}\n\nbut I could not because it\'s not an object.\n'.replace("{field}",e).replace("{value}",Ln(t));return new r(new Yn(n))}{const o=t[e],i=n(o);return i instanceof r&&(i._0.push({type:"FIELD",value:e}),i._0.object=t),i}}},Gn=t=>e=>n=>{const{ok:r,err:o}=t;if(!Array.isArray(n))return new o(new Yn("\nI was trying to decode the value:\n\n{value}\n\nas an Array, but could not.\n".replace("{value}",Ln(n))));let i=[],a=0;for(let t of n){let r=e(t);if(r instanceof o)return r._0.push({type:"ARRAY",value:a}),r._0.object=n,r;i.push(r._0),a++}return new r(i)},Qn=t=>e=>n=>{const{ok:r,just:o,nothing:i,err:a}=t;if(null==n||null==n)return new r(new i);{const t=e(n);return t instanceof a?t:new r(new o(t._0))}},Jn=t=>e=>n=>{const{ok:r,err:o}=t;if(!Array.isArray(n))return new o(new Yn("\nI was trying to decode the value:\n\n{value}\n\nas an Tuple, but could not.\n".replace("{value}",Ln(n))));let i=[],a=0;for(let t of e){if(void 0===n[a]||null===n[a])return new o(new Yn("\nI was trying to decode one of the values of a tuple:\n\n{value}\n\nbut could not.\n".replace("{value}",Ln(n[a]))));{let e=t(n[a]);if(e instanceof o)return e._0.push({type:"ARRAY",value:a}),e._0.object=n,e;i.push(e._0)}a++}return new r(i)},Vn=t=>e=>n=>{const{ok:r,err:o}=t;if(null==n||null==n||"object"!=typeof n||Array.isArray(n)){const t="\nI was trying to decode the value:\n\n{value}\n\nas a Map, but could not.\n".replace("{value}",Ln(n));return new o(new Yn(t))}{const t=[];for(let r in n){const i=e(n[r]);if(i instanceof o)return i;t.push([r,i._0])}return new r(t)}},Kn=t=>e=>new t.ok(e),Zn=t=>t,tr=t=>t.toISOString(),er=t=>e=>e.map((e=>t?t(e):e)),nr=t=>e=>{const n={};for(let r of e)n[r[0]]=t?t(r[1]):r[1];return n},rr=t=>e=>n=>n instanceof t.just?e?e(n._0):n._0:null,or=t=>e=>e.map(((e,n)=>{const r=t[n];return r?r(e):e}));var ir=t=>({maybe:rr(t),identity:Zn,tuple:or,array:er,time:tr,map:nr});class ar{constructor(){We(this)}_d(t){Re(this,t)}}class sr{constructor(){We(this),this.listeners=new Set,this.state={}}setState(t,e){this.state=Object.assign({},this.state,t);for(let t of this.listeners)t.forceUpdate();e()}_d(t){Re(this,t)}_subscribe(t){this.listeners.add(t)}_unsubscribe(t){this.listeners.delete(t)}}class ur{[Ce](t){if(!(t instanceof this.constructor))return!1;if(t.length!==this.length)return!1;for(let e=0;e{const e=(t=>({boolean:Bn(t),object:Kn(t),number:zn(t),string:Fn(t),field:Xn(t),array:Gn(t),maybe:Qn(t),tuple:Jn(t),time:Hn(t),map:Vn(t)}))(t);return{program:new(In(t)),normalizeEvent:qe,insertStyles:je,navigate:Ae,compare:Pe,update:Oe,array:Ie,style:Le,at:Ne(t),EmbeddedProgram:$e,TestContext:Fe,Component:ze,Provider:Be,Module:ar,Store:sr,Decoder:e,Encoder:ir(t),DateFNS:{format:_e,startOfMonth:wt,startOfWeek:ht,startOfDay:dt,endOfMonth:_t,endOfWeek:bt,endOfDay:yt,addMonths:st,eachDay:gt,distanceInWordsStrict:Te},Record:Record,Enum:ur,Nothing:t.nothing,Just:t.just,Err:t.err,Ok:t.ok,createRecord:Me(e,t),createPortal:Q,register:rt,createElement:h,React:{Fragment:d},ReactDOM:{unmountComponentAtNode:t=>P(null,t),render:P},Symbols:{Equals:Ce}}}}(); +var br=Object.create;var st=Object.defineProperty;var kr=Object.getOwnPropertyDescriptor;var Sr=Object.getOwnPropertyNames;var Ar=Object.getPrototypeOf,qr=Object.prototype.hasOwnProperty;var me=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,r)=>(typeof require<"u"?require:e)[r]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var N=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var Tr=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Sr(e))!qr.call(t,i)&&i!==r&&st(t,i,{get:()=>e[i],enumerable:!(n=kr(e,i))||n.enumerable});return t};var at=(t,e,r)=>(r=t!=null?br(Ar(t)):{},Tr(e||!t||!t.__esModule?st(r,"default",{value:t,enumerable:!0}):r,t));var Ht=N(()=>{});var Wt=N((Ni,Qe)=>{"use strict";(function(){var t,e=0,r=[],n;for(n=0;n<256;n++)r[n]=(n+256).toString(16).substr(1);c.BUFFER_SIZE=4096,c.bin=a,c.clearBuffer=function(){t=null,e=0},c.test=function(l){return typeof l=="string"?/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(l):!1};var i;typeof crypto<"u"?i=crypto:typeof window<"u"&&typeof window.msCrypto<"u"&&(i=window.msCrypto),typeof Qe<"u"&&typeof me=="function"?(i=i||Ht(),Qe.exports=c):typeof window<"u"&&(window.uuid=c),c.randomBytes=function(){if(i){if(i.randomBytes)return i.randomBytes;if(i.getRandomValues)return typeof Uint8Array.prototype.slice!="function"?function(l){var _=new Uint8Array(l);return i.getRandomValues(_),Array.from(_)}:function(l){var _=new Uint8Array(l);return i.getRandomValues(_),_}}return function(l){var _,u=[];for(_=0;_c.BUFFER_SIZE)&&(e=0,t=c.randomBytes(c.BUFFER_SIZE)),t.slice(e,e+=l)}function a(){var l=o(16);return l[6]=l[6]&15|64,l[8]=l[8]&63|128,l}function c(){var l=a();return r[l[0]]+r[l[1]]+r[l[2]]+r[l[3]]+"-"+r[l[4]]+r[l[5]]+"-"+r[l[6]]+r[l[7]]+"-"+r[l[8]]+r[l[9]]+"-"+r[l[10]]+r[l[11]]+r[l[12]]+r[l[13]]+r[l[14]]+r[l[15]]}})()});var ir=N(pe=>{var Ne=function(){var t=function(_,u,s,h){for(s=s||{},h=_.length;h--;s[_[h]]=u);return s},e=[1,9],r=[1,10],n=[1,11],i=[1,12],o=[5,11,12,13,14,15],a={trace:function(){},yy:{},symbols_:{error:2,root:3,expressions:4,EOF:5,expression:6,optional:7,literal:8,splat:9,param:10,"(":11,")":12,LITERAL:13,SPLAT:14,PARAM:15,$accept:0,$end:1},terminals_:{2:"error",5:"EOF",11:"(",12:")",13:"LITERAL",14:"SPLAT",15:"PARAM"},productions_:[0,[3,2],[3,1],[4,2],[4,1],[6,1],[6,1],[6,1],[6,1],[7,3],[8,1],[9,1],[10,1]],performAction:function(u,s,h,f,p,d,g){var y=d.length-1;switch(p){case 1:return new f.Root({},[d[y-1]]);case 2:return new f.Root({},[new f.Literal({value:""})]);case 3:this.$=new f.Concat({},[d[y-1],d[y]]);break;case 4:case 5:this.$=d[y];break;case 6:this.$=new f.Literal({value:d[y]});break;case 7:this.$=new f.Splat({name:d[y]});break;case 8:this.$=new f.Param({name:d[y]});break;case 9:this.$=new f.Optional({},[d[y-1]]);break;case 10:this.$=u;break;case 11:case 12:this.$=u.slice(1);break}},table:[{3:1,4:2,5:[1,3],6:4,7:5,8:6,9:7,10:8,11:e,13:r,14:n,15:i},{1:[3]},{5:[1,13],6:14,7:5,8:6,9:7,10:8,11:e,13:r,14:n,15:i},{1:[2,2]},t(o,[2,4]),t(o,[2,5]),t(o,[2,6]),t(o,[2,7]),t(o,[2,8]),{4:15,6:4,7:5,8:6,9:7,10:8,11:e,13:r,14:n,15:i},t(o,[2,10]),t(o,[2,11]),t(o,[2,12]),{1:[2,1]},t(o,[2,3]),{6:14,7:5,8:6,9:7,10:8,11:e,12:[1,16],13:r,14:n,15:i},t(o,[2,9])],defaultActions:{3:[2,2],13:[2,1]},parseError:function(u,s){if(s.recoverable)this.trace(u);else{let f=function(p,d){this.message=p,this.hash=d};var h=f;throw f.prototype=Error,new f(u,s)}},parse:function(u){var s=this,h=[0],f=[],p=[null],d=[],g=this.table,y="",w=0,P=0,H=0,W=2,ie=1,X=d.slice.call(arguments,1),x=Object.create(this.lexer),E={yy:{}};for(var U in this.yy)Object.prototype.hasOwnProperty.call(this.yy,U)&&(E.yy[U]=this.yy[U]);x.setInput(u,E.yy),E.yy.lexer=x,E.yy.parser=this,typeof x.yylloc>"u"&&(x.yylloc={});var $e=x.yylloc;d.push($e);var xr=x.options&&x.options.ranges;typeof E.yy.parseError=="function"?this.parseError=E.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function Hn(C){h.length=h.length-2*C,p.length=p.length-C,d.length=d.length-C}for(var Er=function(){var C;return C=x.lex()||ie,typeof C!="number"&&(C=s.symbols_[C]||C),C},A,je,G,O,Wn,Me,Z={},ye,D,ot,ve;;){if(G=h[h.length-1],this.defaultActions[G]?O=this.defaultActions[G]:((A===null||typeof A>"u")&&(A=Er()),O=g[G]&&g[G][A]),typeof O>"u"||!O.length||!O[0]){var De="";ve=[];for(ye in g[G])this.terminals_[ye]&&ye>W&&ve.push("'"+this.terminals_[ye]+"'");x.showPosition?De="Parse error on line "+(w+1)+`: +`+x.showPosition()+` +Expecting `+ve.join(", ")+", got '"+(this.terminals_[A]||A)+"'":De="Parse error on line "+(w+1)+": Unexpected "+(A==ie?"end of input":"'"+(this.terminals_[A]||A)+"'"),this.parseError(De,{text:x.match,token:this.terminals_[A]||A,line:x.yylineno,loc:$e,expected:ve})}if(O[0]instanceof Array&&O.length>1)throw new Error("Parse Error: multiple actions possible at state: "+G+", token: "+A);switch(O[0]){case 1:h.push(A),p.push(x.yytext),d.push(x.yylloc),h.push(O[1]),A=null,je?(A=je,je=null):(P=x.yyleng,y=x.yytext,w=x.yylineno,$e=x.yylloc,H>0&&H--);break;case 2:if(D=this.productions_[O[1]][1],Z.$=p[p.length-D],Z._$={first_line:d[d.length-(D||1)].first_line,last_line:d[d.length-1].last_line,first_column:d[d.length-(D||1)].first_column,last_column:d[d.length-1].last_column},xr&&(Z._$.range=[d[d.length-(D||1)].range[0],d[d.length-1].range[1]]),Me=this.performAction.apply(Z,[y,P,w,E.yy,O[1],p,d].concat(X)),typeof Me<"u")return Me;D&&(h=h.slice(0,-1*D*2),p=p.slice(0,-1*D),d=d.slice(0,-1*D)),h.push(this.productions_[O[1]][0]),p.push(Z.$),d.push(Z._$),ot=g[h[h.length-2]][h[h.length-1]],h.push(ot);break;case 3:return!0}}return!0}},c=function(){var _={EOF:1,parseError:function(s,h){if(this.yy.parser)this.yy.parser.parseError(s,h);else throw new Error(s)},setInput:function(u,s){return this.yy=s||this.yy||{},this._input=u,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var u=this._input[0];this.yytext+=u,this.yyleng++,this.offset++,this.match+=u,this.matched+=u;var s=u.match(/(?:\r\n?|\n).*/g);return s?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),u},unput:function(u){var s=u.length,h=u.split(/(?:\r\n?|\n)/g);this._input=u+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-s),this.offset-=s;var f=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),h.length-1&&(this.yylineno-=h.length-1);var p=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:h?(h.length===f.length?this.yylloc.first_column:0)+f[f.length-h.length].length-h[0].length:this.yylloc.first_column-s},this.options.ranges&&(this.yylloc.range=[p[0],p[0]+this.yyleng-s]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). +`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},less:function(u){this.unput(this.match.slice(u))},pastInput:function(){var u=this.matched.substr(0,this.matched.length-this.match.length);return(u.length>20?"...":"")+u.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var u=this.match;return u.length<20&&(u+=this._input.substr(0,20-u.length)),(u.substr(0,20)+(u.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var u=this.pastInput(),s=new Array(u.length+1).join("-");return u+this.upcomingInput()+` +`+s+"^"},test_match:function(u,s){var h,f,p;if(this.options.backtrack_lexer&&(p={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(p.yylloc.range=this.yylloc.range.slice(0))),f=u[0].match(/(?:\r\n?|\n).*/g),f&&(this.yylineno+=f.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:f?f[f.length-1].length-f[f.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+u[0].length},this.yytext+=u[0],this.match+=u[0],this.matches=u,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(u[0].length),this.matched+=u[0],h=this.performAction.call(this,this.yy,this,s,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),h)return h;if(this._backtrack){for(var d in p)this[d]=p[d];return!1}return!1},next:function(){if(this.done)return this.EOF;this._input||(this.done=!0);var u,s,h,f;this._more||(this.yytext="",this.match="");for(var p=this._currentRules(),d=0;ds[0].length)){if(s=h,f=d,this.options.backtrack_lexer){if(u=this.test_match(h,p[d]),u!==!1)return u;if(this._backtrack){s=!1;continue}else return!1}else if(!this.options.flex)break}return s?(u=this.test_match(s,p[f]),u!==!1?u:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text. +`+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var s=this.next();return s||this.lex()},begin:function(s){this.conditionStack.push(s)},popState:function(){var s=this.conditionStack.length-1;return s>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(s){return s=this.conditionStack.length-1-Math.abs(s||0),s>=0?this.conditionStack[s]:"INITIAL"},pushState:function(s){this.begin(s)},stateStackSize:function(){return this.conditionStack.length},options:{},performAction:function(s,h,f,p){var d=p;switch(f){case 0:return"(";case 1:return")";case 2:return"SPLAT";case 3:return"PARAM";case 4:return"LITERAL";case 5:return"LITERAL";case 6:return"EOF"}},rules:[/^(?:\()/,/^(?:\))/,/^(?:\*+\w+)/,/^(?::+\w+)/,/^(?:[\w%\-~\n]+)/,/^(?:.)/,/^(?:$)/],conditions:{INITIAL:{rules:[0,1,2,3,4,5,6],inclusive:!0}}};return _}();a.lexer=c;function l(){this.yy={}}return l.prototype=a,a.Parser=l,new l}();typeof me<"u"&&typeof pe<"u"&&(pe.parser=Ne,pe.Parser=Ne.Parser,pe.parse=function(){return Ne.parse.apply(Ne,arguments)})});var tt=N((wo,or)=>{"use strict";function ne(t){return function(e,r){return{displayName:t,props:e,children:r||[]}}}or.exports={Root:ne("Root"),Concat:ne("Concat"),Literal:ne("Literal"),Splat:ne("Splat"),Param:ne("Param"),Optional:ne("Optional")}});var ur=N((xo,ar)=>{"use strict";var sr=ir().parser;sr.yy=tt();ar.exports=sr});var rt=N((Eo,lr)=>{"use strict";var Tn=Object.keys(tt());function On(t){return Tn.forEach(function(e){if(typeof t[e]>"u")throw new Error("No handler defined for "+e.displayName)}),{visit:function(e,r){return this.handlers[e.displayName].call(this,e,r)},handlers:t}}lr.exports=On});var _r=N((bo,fr)=>{"use strict";var Pn=rt(),Rn=/[\-{}\[\]+?.,\\\^$|#\s]/g;function cr(t){this.captures=t.captures,this.re=t.re}cr.prototype.match=function(t){var e=this.re.exec(t),r={};return e?(this.captures.forEach(function(n,i){typeof e[i+1]>"u"?r[n]=void 0:r[n]=decodeURIComponent(e[i+1])}),r):!1};var Cn=Pn({Concat:function(t){return t.children.reduce(function(e,r){var n=this.visit(r);return{re:e.re+n.re,captures:e.captures.concat(n.captures)}}.bind(this),{re:"",captures:[]})},Literal:function(t){return{re:t.props.value.replace(Rn,"\\$&"),captures:[]}},Splat:function(t){return{re:"([^?#]*?)",captures:[t.props.name]}},Param:function(t){return{re:"([^\\/\\?#]+)",captures:[t.props.name]}},Optional:function(t){var e=this.visit(t.children[0]);return{re:"(?:"+e.re+")?",captures:e.captures}},Root:function(t){var e=this.visit(t.children[0]);return new cr({re:new RegExp("^"+e.re+"(?=\\?|#|$)"),captures:e.captures})}});fr.exports=Cn});var pr=N((ko,hr)=>{"use strict";var Nn=rt(),In=Nn({Concat:function(t,e){var r=t.children.map(function(n){return this.visit(n,e)}.bind(this));return r.some(function(n){return n===!1})?!1:r.join("")},Literal:function(t){return decodeURI(t.props.value)},Splat:function(t,e){return typeof e[t.props.name]>"u"?!1:e[t.props.name]},Param:function(t,e){return typeof e[t.props.name]>"u"?!1:e[t.props.name]},Optional:function(t,e){var r=this.visit(t.children[0],e);return r||""},Root:function(t,e){e=e||{};var r=this.visit(t.children[0],e);return r===!1||typeof r>"u"?!1:encodeURI(r)}});hr.exports=In});var yr=N((So,dr)=>{"use strict";var $n=ur(),jn=_r(),Mn=pr();function de(t){var e;if(this?e=this:e=Object.create(de.prototype),typeof t>"u")throw new Error("A route spec is required");return e.spec=t,e.ast=$n.parse(t),e}de.prototype=Object.create(null);de.prototype.match=function(t){var e=jn.visit(this.ast),r=e.match(t);return r!==null?r:!1};de.prototype.reverse=function(t){return Mn.visit(this.ast,t)};dr.exports=de});var mr=N((Ao,vr)=>{"use strict";var Dn=yr();vr.exports=Dn});var Ee,v,ht,Ve,K,ut,pt,Ue,Or,oe={},dt=[],Pr=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,Be=Array.isArray;function L(t,e){for(var r in e)t[r]=e[r];return t}function yt(t){var e=t.parentNode;e&&e.removeChild(t)}function I(t,e,r){var n,i,o,a={};for(o in e)o=="key"?n=e[o]:o=="ref"?i=e[o]:a[o]=e[o];if(arguments.length>2&&(a.children=arguments.length>3?Ee.call(arguments,2):r),typeof t=="function"&&t.defaultProps!=null)for(o in t.defaultProps)a[o]===void 0&&(a[o]=t.defaultProps[o]);return we(t,a,n,i,null)}function we(t,e,r,n,i){var o={type:t,props:e,key:r,ref:n,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,constructor:void 0,__v:i??++ht,__i:-1,__u:0};return i==null&&v.vnode!=null&&v.vnode(o),o}function vt(){return{current:null}}function se(t){return t.children}function V(t,e){this.props=t,this.context=e}function Y(t,e){if(e==null)return t.__?Y(t.__,t.__i+1):null;for(var r;ee&&K.sort(Ue));xe.__r=0}function gt(t,e,r,n,i,o,a,c,l,_,u){var s,h,f,p,d,g=n&&n.__k||dt,y=e.length;for(r.__d=l,Rr(r,e,g),l=r.__d,s=0;s0?we(i.type,i.props,i.key,i.ref?i.ref:null,i.__v):i)!=null?(i.__=t,i.__b=t.__b+1,c=Cr(i,r,a,u),i.__i=c,o=null,c!==-1&&(u--,(o=r[c])&&(o.__u|=131072)),o==null||o.__v===null?(c==-1&&s--,typeof i.type!="function"&&(i.__u|=65536)):c!==a&&(c===a+1?s++:c>a?u>l-a?s+=c-a:s--:c(l!=null&&!(131072&l.__u)?1:0))for(;a>=0||c=0){if((l=e[a])&&!(131072&l.__u)&&i==l.key&&o===l.type)return a;a--}if(c=r.__.length&&r.__.push({__V:be}),r.__[t]}function z(t,e){var r=Rt(Se++,3);!b.__s&&Ct(r.__H,e)&&(r.__=t,r.i=e,T.__H.__h.push(r))}function ue(t){return Ge=5,$(function(){return{current:t}},[])}function $(t,e){var r=Rt(Se++,7);return Ct(r.__H,e)?(r.__V=t(),r.i=e,r.__h=t,r.__V):r.__}function $r(){for(var t;t=Pt.shift();)if(t.__P&&t.__H)try{t.__H.__h.forEach(ke),t.__H.__h.forEach(Ke),t.__H.__h=[]}catch(e){t.__H.__h=[],b.__e(e,t.__v)}}b.__b=function(t){T=null,bt&&bt(t)},b.__=function(t,e){t&&e.__k&&e.__k.__m&&(t.__m=e.__k.__m),Tt&&Tt(t,e)},b.__r=function(t){kt&&kt(t),Se=0;var e=(T=t.__c).__H;e&&(We===T?(e.__h=[],T.__h=[],e.__.forEach(function(r){r.__N&&(r.__=r.__N),r.__V=be,r.__N=r.i=void 0})):(e.__h.forEach(ke),e.__h.forEach(Ke),e.__h=[],Se=0)),We=T},b.diffed=function(t){St&&St(t);var e=t.__c;e&&e.__H&&(e.__H.__h.length&&(Pt.push(e)!==1&&Et===b.requestAnimationFrame||((Et=b.requestAnimationFrame)||jr)($r)),e.__H.__.forEach(function(r){r.i&&(r.__H=r.i),r.__V!==be&&(r.__=r.__V),r.i=void 0,r.__V=be})),We=T=null},b.__c=function(t,e){e.some(function(r){try{r.__h.forEach(ke),r.__h=r.__h.filter(function(n){return!n.__||Ke(n)})}catch(n){e.some(function(i){i.__h&&(i.__h=[])}),e=[],b.__e(n,r.__v)}}),At&&At(t,e)},b.unmount=function(t){qt&&qt(t);var e,r=t.__c;r&&r.__H&&(r.__H.__.forEach(function(n){try{ke(n)}catch(i){e=i}}),r.__H=void 0,e&&b.__e(e,r.__v))};var Ot=typeof requestAnimationFrame=="function";function jr(t){var e,r=function(){clearTimeout(n),Ot&&cancelAnimationFrame(e),setTimeout(t)},n=setTimeout(r,100);Ot&&(e=requestAnimationFrame(r))}function ke(t){var e=T,r=t.__c;typeof r=="function"&&(t.__c=void 0,r()),T=e}function Ke(t){var e=T;t.__c=t.__(),T=e}function Ct(t,e){return!t||t.length!==e.length||e.some(function(r,n){return r!==t[n]})}var Mr=Symbol.for("preact-signals");function qe(){if(B>1)B--;else{for(var t,e=!1;le!==void 0;){var r=le;for(le=void 0,Ye++;r!==void 0;){var n=r.o;if(r.o=void 0,r.f&=-3,!(8&r.f)&&$t(r))try{r.c()}catch(i){e||(t=i,e=!0)}r=n}}if(Ye=0,B--,e)throw t}}function Nt(t){if(B>0)return t();B++;try{return t()}finally{qe()}}var m=void 0;function Te(t){var e=m;m=void 0;try{return t()}finally{m=e}}var le=void 0,B=0,Ye=0,Ae=0;function It(t){if(m!==void 0){var e=t.n;if(e===void 0||e.t!==m)return e={i:0,S:t,p:m.s,n:void 0,t:m,e:void 0,x:void 0,r:e},m.s!==void 0&&(m.s.n=e),m.s=e,t.n=e,32&m.f&&t.S(e),e;if(e.i===-1)return e.i=0,e.n!==void 0&&(e.n.p=e.p,e.p!==void 0&&(e.p.n=e.n),e.p=m.s,e.n=void 0,m.s.n=e,m.s=e),e}}function k(t){this.v=t,this.i=0,this.n=void 0,this.t=void 0}k.prototype.brand=Mr;k.prototype.h=function(){return!0};k.prototype.S=function(t){this.t!==t&&t.e===void 0&&(t.x=this.t,this.t!==void 0&&(this.t.e=t),this.t=t)};k.prototype.U=function(t){if(this.t!==void 0){var e=t.e,r=t.x;e!==void 0&&(e.x=r,t.e=void 0),r!==void 0&&(r.e=e,t.x=void 0),t===this.t&&(this.t=r)}};k.prototype.subscribe=function(t){var e=this;return ee(function(){var r=e.value,n=m;m=void 0;try{t(r)}finally{m=n}})};k.prototype.valueOf=function(){return this.value};k.prototype.toString=function(){return this.value+""};k.prototype.toJSON=function(){return this.value};k.prototype.peek=function(){var t=m;m=void 0;try{return this.value}finally{m=t}};Object.defineProperty(k.prototype,"value",{get:function(){var t=It(this);return t!==void 0&&(t.i=this.i),this.v},set:function(t){if(t!==this.v){if(Ye>100)throw new Error("Cycle detected");this.v=t,this.i++,Ae++,B++;try{for(var e=this.t;e!==void 0;e=e.x)e.t.N()}finally{qe()}}}});function j(t){return new k(t)}function $t(t){for(var e=t.s;e!==void 0;e=e.n)if(e.S.i!==e.i||!e.S.h()||e.S.i!==e.i)return!0;return!1}function jt(t){for(var e=t.s;e!==void 0;e=e.n){var r=e.S.n;if(r!==void 0&&(e.r=r),e.S.n=e,e.i=-1,e.n===void 0){t.s=e;break}}}function Mt(t){for(var e=t.s,r=void 0;e!==void 0;){var n=e.p;e.i===-1?(e.S.U(e),n!==void 0&&(n.n=e.n),e.n!==void 0&&(e.n.p=n)):r=e,e.S.n=e.r,e.r!==void 0&&(e.r=void 0),e=n}t.s=r}function Q(t){k.call(this,void 0),this.x=t,this.s=void 0,this.g=Ae-1,this.f=4}(Q.prototype=new k).h=function(){if(this.f&=-3,1&this.f)return!1;if((36&this.f)==32||(this.f&=-5,this.g===Ae))return!0;if(this.g=Ae,this.f|=1,this.i>0&&!$t(this))return this.f&=-2,!0;var t=m;try{jt(this),m=this;var e=this.x();(16&this.f||this.v!==e||this.i===0)&&(this.v=e,this.f&=-17,this.i++)}catch(r){this.v=r,this.f|=16,this.i++}return m=t,Mt(this),this.f&=-2,!0};Q.prototype.S=function(t){if(this.t===void 0){this.f|=36;for(var e=this.s;e!==void 0;e=e.n)e.S.S(e)}k.prototype.S.call(this,t)};Q.prototype.U=function(t){if(this.t!==void 0&&(k.prototype.U.call(this,t),this.t===void 0)){this.f&=-33;for(var e=this.s;e!==void 0;e=e.n)e.S.U(e)}};Q.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(var t=this.t;t!==void 0;t=t.x)t.t.N()}};Object.defineProperty(Q.prototype,"value",{get:function(){if(1&this.f)throw new Error("Cycle detected");var t=It(this);if(this.h(),t!==void 0&&(t.i=this.i),16&this.f)throw this.v;return this.v}});function ce(t){return new Q(t)}function Dt(t){var e=t.u;if(t.u=void 0,typeof e=="function"){B++;var r=m;m=void 0;try{e()}catch(n){throw t.f&=-2,t.f|=8,ze(t),n}finally{m=r,qe()}}}function ze(t){for(var e=t.s;e!==void 0;e=e.n)e.S.U(e);t.x=void 0,t.s=void 0,Dt(t)}function Dr(t){if(m!==this)throw new Error("Out-of-order effect");Mt(this),m=t,this.f&=-2,8&this.f&&ze(this),qe()}function fe(t){this.x=t,this.u=void 0,this.s=void 0,this.o=void 0,this.f=32}fe.prototype.c=function(){var t=this.S();try{if(8&this.f||this.x===void 0)return;var e=this.x();typeof e=="function"&&(this.u=e)}finally{t()}};fe.prototype.S=function(){if(1&this.f)throw new Error("Cycle detected");this.f|=1,this.f&=-9,Dt(this),jt(this),B++;var t=m;return m=this,Dr.bind(this,t)};fe.prototype.N=function(){2&this.f||(this.f|=2,this.o=le,le=this)};fe.prototype.d=function(){this.f|=8,1&this.f||ze(this)};function ee(t){var e=new fe(t);try{e.c()}catch(r){throw e.d(),r}return e.d.bind(e)}var Pe,Je;function te(t,e){v[t]=e.bind(null,v[t]||function(){})}function Oe(t){Je&&Je(),Je=t&&t.S()}function Ut(t){var e=this,r=t.data,n=Lr(r);n.value=r;var i=$(function(){for(var o=e.__v;o=o.__;)if(o.__c){o.__c.__$f|=4;break}return e.__$u.c=function(){var a;!Ve(i.peek())&&((a=e.base)==null?void 0:a.nodeType)===3?e.base.data=i.peek():(e.__$f|=1,e.setState({}))},ce(function(){var a=n.value.value;return a===0?0:a===!0?"":a||""})},[]);return i.value}Ut.displayName="_st";Object.defineProperties(k.prototype,{constructor:{configurable:!0,value:void 0},type:{configurable:!0,value:Ut},props:{configurable:!0,get:function(){return{data:this}}},__b:{configurable:!0,value:1}});te("__b",function(t,e){if(typeof e.type=="string"){var r,n=e.props;for(var i in n)if(i!=="children"){var o=n[i];o instanceof k&&(r||(e.__np=r={}),r[i]=o,n[i]=o.peek())}}t(e)});te("__r",function(t,e){Oe();var r,n=e.__c;n&&(n.__$f&=-2,(r=n.__$u)===void 0&&(n.__$u=r=function(i){var o;return ee(function(){o=this}),o.c=function(){n.__$f|=1,n.setState({})},o}())),Pe=n,Oe(r),t(e)});te("__e",function(t,e,r,n){Oe(),Pe=void 0,t(e,r,n)});te("diffed",function(t,e){Oe(),Pe=void 0;var r;if(typeof e.type=="string"&&(r=e.__e)){var n=e.__np,i=e.props;if(n){var o=r.U;if(o)for(var a in o){var c=o[a];c!==void 0&&!(a in n)&&(c.d(),o[a]=void 0)}else r.U=o={};for(var l in n){var _=o[l],u=n[l];_===void 0?(_=Ur(r,l,u,i),o[l]=_):_.o(u,i)}}}t(e)});function Ur(t,e,r,n){var i=e in t&&t.ownerSVGElement===void 0,o=j(r);return{o:function(a,c){o.value=a,n=c},d:ee(function(){var a=o.value.value;n[e]!==a&&(n[e]=a,i?t[e]=a:a?t.setAttribute(e,a):t.removeAttribute(e))})}}te("unmount",function(t,e){if(typeof e.type=="string"){var r=e.__e;if(r){var n=r.U;if(n){r.U=void 0;for(var i in n){var o=n[i];o&&o.d()}}}}else{var a=e.__c;if(a){var c=a.__$u;c&&(a.__$u=void 0,c.d())}}t(e)});te("__h",function(t,e,r,n){(n<3||n===9)&&(e.__$f|=2),t(e,r,n)});V.prototype.shouldComponentUpdate=function(t,e){var r=this.__$u;if(!(r&&r.s!==void 0||4&this.__$f)||3&this.__$f)return!0;for(var n in e)return!0;for(var i in t)if(i!=="__source"&&t[i]!==this.props[i])return!0;for(var o in this.props)if(!(o in t))return!0;return!1};function Lr(t){return $(function(){return j(t)},[])}function Vr(t){var e=ue(t);return e.current=t,Pe.__$f|=4,$(function(){return ce(function(){return e.current()})},[])}var S=Symbol("Equals");typeof Node>"u"&&(self.Node=class{});Boolean.prototype[S]=Symbol.prototype[S]=Number.prototype[S]=String.prototype[S]=function(t){return this.valueOf()===t};Date.prototype[S]=function(t){return+this==+t};Function.prototype[S]=Node.prototype[S]=function(t){return this===t};URLSearchParams.prototype[S]=function(t){return t==null?!1:this.toString()===t.toString()};Set.prototype[S]=function(t){return t==null?!1:q(Array.from(this).sort(),Array.from(t).sort())};Array.prototype[S]=function(t){if(t==null||this.length!==t.length)return!1;if(this.length==0)return!0;for(let e in this)if(!q(this[e],t[e]))return!1;return!0};FormData.prototype[S]=function(t){if(t==null)return!1;let e=Array.from(t.keys()).sort(),r=Array.from(this.keys()).sort();if(q(r,e)){if(r.length==0)return!0;for(let n of r){let i=Array.from(t.getAll(n).sort()),o=Array.from(this.getAll(n).sort());if(!q(o,i))return!1}return!0}else return!1};Map.prototype[S]=function(t){if(t==null)return!1;let e=Array.from(this.keys()).sort(),r=Array.from(t.keys()).sort();if(q(e,r)){if(e.length==0)return!0;for(let n of e)if(!q(this.get(n),t.get(n)))return!1;return!0}else return!1};var Lt=t=>t!=null&&typeof t=="object"&&"constructor"in t&&"props"in t&&"type"in t&&"ref"in t&&"key"in t&&"__"in t,q=(t,e)=>t===void 0&&e===void 0||t===null&&e===null?!0:t!=null&&t!=null&&t[S]?t[S](e):e!=null&&e!=null&&e[S]?e[S](t):Lt(t)||Lt(e)?t===e:Xe(t,e),Xe=(t,e)=>{if(t instanceof Object&&e instanceof Object){let r=Object.keys(t),n=Object.keys(e);if(r.length!==n.length)return!1;let i=new Set(r.concat(n));for(let o of i)if(!q(t[o],e[o]))return!1;return!0}else return t===e};var _e=class{constructor(e){this.patterns=e}},Re=class{constructor(e,r){this.pattern=r,this.variant=e}},oi=(t,e)=>new Re(t,e),si=t=>new _e(t),Br=Symbol("Variable"),Ze=Symbol("Spread"),J=(t,e,r=[])=>{if(e!==null){if(e===Br)r.push(t);else if(Array.isArray(e))if(e.some(i=>i===Ze)&&t.length>=e.length-1){let i=0,o=[],a=1;for(;e[i]!==Ze&&i{for(let r of e){if(r[0]===null)return r[1]();{let n=J(t,r[0]);if(n)return r[1].apply(null,n)}}};"DataTransfer"in window||(window.DataTransfer=class{constructor(){this.effectAllowed="none",this.dropEffect="none",this.files=[],this.types=[],this.cache={}}getData(t){return this.cache[t]||""}setData(t,e){return this.cache[t]=e,null}clearData(){return this.cache={},null}});var Fr=t=>new Proxy(t,{get:function(e,r){if(r==="event")return t;if(r in e){let n=e[r];return n instanceof Function?()=>e[r]():n}else switch(r){case"clipboardData":return e.clipboardData=new DataTransfer;case"dataTransfer":return e.dataTransfer=new DataTransfer;case"data":return"";case"altKey":return!1;case"charCode":return-1;case"ctrlKey":return!1;case"key":return"";case"keyCode":return-1;case"locale":return"";case"location":return-1;case"metaKey":return!1;case"repeat":return!1;case"shiftKey":return!1;case"which":return-1;case"button":return-1;case"buttons":return-1;case"clientX":return-1;case"clientY":return-1;case"pageX":return-1;case"pageY":return-1;case"screenX":return-1;case"screenY":return-1;case"detail":return-1;case"deltaMode":return-1;case"deltaX":return-1;case"deltaY":return-1;case"deltaZ":return-1;case"animationName":return"";case"pseudoElement":return"";case"elapsedTime":return-1;case"propertyName":return"";default:return}}});v.event=Fr;var yi=(t,e,r,n)=>{for(let i of t)if(q(i[0],e))return new r(i[1]);return new n},vi=(t,e,r,n)=>t.length>=e+1&&e>=0?new r(t[e]):new n,mi=(t,e)=>r=>{t.current._0!==r&&(t.current=new e(r))},gi=t=>{let e=$(()=>j(t),[]);return e.value,e},wi=t=>{let e=vt();return e.current=t,e},xi=t=>{let e=ue(!1);z(()=>{e.current?t():e.current=!0})},Ei=(t,e,r,n)=>r instanceof t||r instanceof e?n:r._0,bi=(...t)=>{let e=Array.from(t);return Array.isArray(e[0])&&e.length===1?e[0]:e},ki=t=>e=>e[t],Bt=t=>t,Vt=class extends V{async componentDidMount(){let e=await this.props.x();this.setState({x:e})}render(){return this.state.x?I(this.state.x,this.props.p,this.props.c):null}},Si=t=>async()=>Hr(t),Hr=async t=>(await import(t)).default;var Wr=j({}),Ft=j({}),Ti=t=>Ft.value=t,Oi=t=>(Wr.value[Ft.value]||{})[t]||"";var Gt=at(Wt()),Di=(t,e)=>(r,n)=>{let i=()=>{t.has(r)&&(t.delete(r),Te(e))};z(()=>i,[]),z(()=>{let o=n();if(o===null)i();else{let a=t.get(r);q(a,o)||(t.set(r,o),Te(e))}})},Ui=t=>Array.from(t.values()),Li=()=>$(Gt.default,[]);function et(t,e=1,r={}){let{indent:n=" ",includeEmptyLines:i=!1}=r;if(typeof t!="string")throw new TypeError(`Expected \`input\` to be a \`string\`, got \`${typeof t}\``);if(typeof e!="number")throw new TypeError(`Expected \`count\` to be a \`number\`, got \`${typeof e}\``);if(e<0)throw new RangeError(`Expected \`count\` to be at least 0, got \`${e}\``);if(typeof n!="string")throw new TypeError(`Expected \`options.indent\` to be a \`string\`, got \`${typeof n}\``);if(e===0)return t;let o=i?/^/gm:/^(?!\s*$)/gm;return t.replace(o,n.repeat(e))}var M=t=>{let e=JSON.stringify(t,"",2);return typeof e>"u"&&(e="undefined"),et(e)},R=class{constructor(e,r=[]){this.message=e,this.object=null,this.path=r}push(e){this.path.unshift(e)}toString(){let e=this.message.trim(),r=this.path.reduce((n,i)=>{if(n.length)switch(i.type){case"FIELD":return`${n}.${i.value}`;case"ARRAY":return`${n}[${i.value}]`}else switch(i.type){case"FIELD":return i.value;case"ARRAY":return"[$(item.value)]"}},"");return r.length&&this.object?e+` + +`+Gr.trim().replace("{value}",M(this.object)).replace("{path}",r):e}},Gr=` +The input is in this object: + +{value} + +at: {path} +`,Kr=` +I was trying to decode the value: + +{value} + +as a String, but could not. +`,Yr=` +I was trying to decode the value: + +{value} + +as a Time, but could not. +`,zr=` +I was trying to decode the value: + +{value} + +as a Number, but could not. +`,Jr=` +I was trying to decode the value: + +{value} + +as a Bool, but could not. +`,Xr=` +I was trying to decode the field "{field}" from the object: + +{value} + +but I could not because it's not an object. +`,Zr=` +I was trying to decode the value: + +{value} + +as an Array, but could not. +`,Qr=` +I was trying to decode the value: + +{value} + +as an Tuple, but could not. +`,en=` +I was trying to decode one of the values of a tuple: + +{value} + +but could not. +`,tn=` +I was trying to decode the value: + +{value} + +as a Map, but could not. +`,Hi=(t,e)=>r=>typeof r!="string"?new e(new R(Kr.replace("{value}",M(r)))):new t(r),Wi=(t,e)=>r=>{let n=NaN;return typeof r=="number"?n=new Date(r):n=Date.parse(r),Number.isNaN(n)?new e(new R(Yr.replace("{value}",M(r)))):new t(new Date(n))},Gi=(t,e)=>r=>{let n=parseFloat(r);return isNaN(n)?new e(new R(zr.replace("{value}",M(r)))):new t(n)},Ki=(t,e)=>r=>typeof r!="boolean"?new e(new R(Jr.replace("{value}",M(r)))):new t(r),rn=(t,e,r)=>n=>{if(typeof n!="object"||Array.isArray(n)||n==null||n==null){let i=Xr.replace("{field}",t).replace("{value}",M(n));return new r(new R(i))}else{let i=e(n[t]);return i instanceof r&&(i._0.push({type:"FIELD",value:t}),i._0.object=n),i}},Yi=(t,e,r)=>n=>{if(!Array.isArray(n))return new r(new R(Zr.replace("{value}",M(n))));let i=[],o=0;for(let a of n){let c=t(a);if(c instanceof r)return c._0.push({type:"ARRAY",value:o}),c._0.object=n,c;i.push(c._0),o++}return new e(i)},zi=(t,e,r,n,i)=>o=>{if(o==null)return new e(new i);{let a=t(o);return a instanceof r?a:new e(new n(a._0))}},Ji=(t,e,r)=>n=>{if(!Array.isArray(n))return new r(new R(Qr.replace("{value}",M(n))));let i=[],o=0;for(let a of t){if(n[o]===void 0||n[o]===null)return new r(new R(en.replace("{value}",M(n[o]))));{let c=a(n[o]);if(c instanceof r)return c._0.push({type:"ARRAY",value:o}),c._0.object=n,c;i.push(c._0)}o++}return new e(i)},Xi=(t,e,r)=>n=>{if(typeof n!="object"||Array.isArray(n)||n==null||n==null){let i=tn.replace("{value}",M(n));return new r(new R(i))}else{let i=[];for(let o in n){let a=t(n[o]);if(a instanceof r)return a;i.push([o,a._0])}return new e(i)}},Zi=(t,e,r)=>n=>{let i={};for(let o in t){let a=t[o],c=o;Array.isArray(a)&&(a=t[o][0],c=t[o][1]);let l=rn(c,a,r)(n);if(l instanceof r)return l;i[o]=l._0}return new e(i)},Qi=t=>e=>new t(e);var ro=t=>t.toISOString(),no=t=>e=>e.map(r=>t?t(r):r),io=t=>e=>{let r={};for(let n of e)r[n[0]]=t?t(n[1]):n[1];return r},oo=(t,e)=>r=>r instanceof e?t(r._0):null,so=t=>e=>e.map((r,n)=>{let i=t[n];return i?i(r):r}),ao=t=>e=>{let r={};for(let n in t){let i=t[n],o=n;Array.isArray(i)&&(i=t[n][0],o=t[n][1]),r[o]=(i||Bt)(e[n])}return r};var nn=Object.getOwnPropertyNames,on=Object.getOwnPropertySymbols,sn=Object.prototype.hasOwnProperty;function Kt(t,e){return function(n,i,o){return t(n,i,o)&&e(n,i,o)}}function Ce(t){return function(r,n,i){if(!r||!n||typeof r!="object"||typeof n!="object")return t(r,n,i);var o=i.cache,a=o.get(r),c=o.get(n);if(a&&c)return a===n&&c===r;o.set(r,n),o.set(n,r);var l=t(r,n,i);return o.delete(r),o.delete(n),l}}function Yt(t){return nn(t).concat(on(t))}var tr=Object.hasOwn||function(t,e){return sn.call(t,e)};function re(t,e){return t||e?t===e:t===e||t!==t&&e!==e}var rr="_owner",zt=Object.getOwnPropertyDescriptor,Jt=Object.keys;function an(t,e,r){var n=t.length;if(e.length!==n)return!1;for(;n-- >0;)if(!r.equals(t[n],e[n],n,n,t,e,r))return!1;return!0}function un(t,e){return re(t.getTime(),e.getTime())}function Xt(t,e,r){if(t.size!==e.size)return!1;for(var n={},i=t.entries(),o=0,a,c;(a=i.next())&&!a.done;){for(var l=e.entries(),_=!1,u=0;(c=l.next())&&!c.done;){var s=a.value,h=s[0],f=s[1],p=c.value,d=p[0],g=p[1];!_&&!n[u]&&(_=r.equals(h,d,o,u,t,e,r)&&r.equals(f,g,h,d,t,e,r))&&(n[u]=!0),u++}if(!_)return!1;o++}return!0}function ln(t,e,r){var n=Jt(t),i=n.length;if(Jt(e).length!==i)return!1;for(var o;i-- >0;)if(o=n[i],o===rr&&(t.$$typeof||e.$$typeof)&&t.$$typeof!==e.$$typeof||!tr(e,o)||!r.equals(t[o],e[o],o,o,t,e,r))return!1;return!0}function he(t,e,r){var n=Yt(t),i=n.length;if(Yt(e).length!==i)return!1;for(var o,a,c;i-- >0;)if(o=n[i],o===rr&&(t.$$typeof||e.$$typeof)&&t.$$typeof!==e.$$typeof||!tr(e,o)||!r.equals(t[o],e[o],o,o,t,e,r)||(a=zt(t,o),c=zt(e,o),(a||c)&&(!a||!c||a.configurable!==c.configurable||a.enumerable!==c.enumerable||a.writable!==c.writable)))return!1;return!0}function cn(t,e){return re(t.valueOf(),e.valueOf())}function fn(t,e){return t.source===e.source&&t.flags===e.flags}function Zt(t,e,r){if(t.size!==e.size)return!1;for(var n={},i=t.values(),o,a;(o=i.next())&&!o.done;){for(var c=e.values(),l=!1,_=0;(a=c.next())&&!a.done;)!l&&!n[_]&&(l=r.equals(o.value,a.value,o.value,a.value,t,e,r))&&(n[_]=!0),_++;if(!l)return!1}return!0}function _n(t,e){var r=t.length;if(e.length!==r)return!1;for(;r-- >0;)if(t[r]!==e[r])return!1;return!0}var hn="[object Arguments]",pn="[object Boolean]",dn="[object Date]",yn="[object Map]",vn="[object Number]",mn="[object Object]",gn="[object RegExp]",wn="[object Set]",xn="[object String]",En=Array.isArray,Qt=typeof ArrayBuffer=="function"&&ArrayBuffer.isView?ArrayBuffer.isView:null,er=Object.assign,bn=Object.prototype.toString.call.bind(Object.prototype.toString);function kn(t){var e=t.areArraysEqual,r=t.areDatesEqual,n=t.areMapsEqual,i=t.areObjectsEqual,o=t.arePrimitiveWrappersEqual,a=t.areRegExpsEqual,c=t.areSetsEqual,l=t.areTypedArraysEqual;return function(u,s,h){if(u===s)return!0;if(u==null||s==null||typeof u!="object"||typeof s!="object")return u!==u&&s!==s;var f=u.constructor;if(f!==s.constructor)return!1;if(f===Object)return i(u,s,h);if(En(u))return e(u,s,h);if(Qt!=null&&Qt(u))return l(u,s,h);if(f===Date)return r(u,s,h);if(f===RegExp)return a(u,s,h);if(f===Map)return n(u,s,h);if(f===Set)return c(u,s,h);var p=bn(u);return p===dn?r(u,s,h):p===gn?a(u,s,h):p===yn?n(u,s,h):p===wn?c(u,s,h):p===mn?typeof u.then!="function"&&typeof s.then!="function"&&i(u,s,h):p===hn?i(u,s,h):p===pn||p===vn||p===xn?o(u,s,h):!1}}function Sn(t){var e=t.circular,r=t.createCustomConfig,n=t.strict,i={areArraysEqual:n?he:an,areDatesEqual:un,areMapsEqual:n?Kt(Xt,he):Xt,areObjectsEqual:n?he:ln,arePrimitiveWrappersEqual:cn,areRegExpsEqual:fn,areSetsEqual:n?Kt(Zt,he):Zt,areTypedArraysEqual:n?he:_n};if(r&&(i=er({},i,r(i))),e){var o=Ce(i.areArraysEqual),a=Ce(i.areMapsEqual),c=Ce(i.areObjectsEqual),l=Ce(i.areSetsEqual);i=er({},i,{areArraysEqual:o,areMapsEqual:a,areObjectsEqual:c,areSetsEqual:l})}return i}function An(t){return function(e,r,n,i,o,a,c){return t(e,r,c)}}function qn(t){var e=t.circular,r=t.comparator,n=t.createState,i=t.equals,o=t.strict;if(n)return function(l,_){var u=n(),s=u.cache,h=s===void 0?e?new WeakMap:void 0:s,f=u.meta;return r(l,_,{cache:h,equals:i,meta:f,strict:o})};if(e)return function(l,_){return r(l,_,{cache:new WeakMap,equals:i,meta:void 0,strict:o})};var a={cache:void 0,equals:i,meta:void 0,strict:o};return function(l,_){return r(l,_,a)}}var nr=F(),lo=F({strict:!0}),co=F({circular:!0}),fo=F({circular:!0,strict:!0}),_o=F({createInternalComparator:function(){return re}}),ho=F({strict:!0,createInternalComparator:function(){return re}}),po=F({circular:!0,createInternalComparator:function(){return re}}),yo=F({circular:!0,createInternalComparator:function(){return re},strict:!0});function F(t){t===void 0&&(t={});var e=t.circular,r=e===void 0?!1:e,n=t.createInternalComparator,i=t.createState,o=t.strict,a=o===void 0?!1:o,c=Sn(t),l=kn(c),_=n?n(l):An(l);return qn({circular:r,comparator:l,createState:i,equals:_,strict:a})}var wr=at(mr());var Ie=class extends Error{},Un=(t,e)=>t instanceof Object?e instanceof Object&&nr(t,e):!(e instanceof Object)&&t===e,Ln=t=>{typeof window.queueMicrotask!="function"?Promise.resolve().then(t).catch(e=>setTimeout(()=>{throw e})):window.queueMicrotask(t)},gr=(t,e)=>{for(let r of e){if(r.path==="*")return{route:r,vars:!1,url:t};{let n=new wr.default(r.path).match(t);if(n)return{route:r,vars:n,url:t}}}return null},nt=class{constructor(e,r){this.root=document.createElement("div"),this.routeInfo=null,this.routes=r,this.ok=e,document.body.appendChild(this.root),window.addEventListener("popstate",this.handlePopState.bind(this)),window.addEventListener("click",this.handleClick.bind(this),!0)}handleClick(e){if(!e.defaultPrevented&&!e.ctrlKey){for(let r of e.composedPath())if(r.tagName==="A"){if(r.target.trim()!=="")return;if(r.origin===window.location.origin){let n=r.pathname+r.search+r.hash,i=gr(n,this.routes);if(i){e.preventDefault(),Vn(n,!0,!0,i);return}}}}}resolvePagePosition(e){Ln(()=>{requestAnimationFrame(()=>{let r=window.location.hash;if(r){let n=null;try{n=this.root.querySelector(r)||this.root.querySelector(`a[name="${r.slice(1)}"]`)}catch{}n?e&&n.scrollIntoView():console.warn(`MINT: ${r} matches no element with an id and no link with a name`)}else e&&window.scrollTo(0,0)})})}async handlePopState(e){let r=window.location.pathname+window.location.search+window.location.hash,n=e?.routeInfo||gr(r,this.routes);if(n){if(this.routeInfo===null||n.url!==this.routeInfo.url||!Un(n.vars,this.routeInfo.vars)){let i=this.runRouteHandler(n);n.route.await&&await i}this.resolvePagePosition(!!e?.triggerJump)}this.routeInfo=n}async runRouteHandler(e){let{route:r}=e;if(r.path==="*")return r.handler();{let{vars:n}=e;try{let i=r.mapping.map((o,a)=>{let c=n[o],l=r.decoders[a](c);if(l instanceof this.ok)return l._0;throw new Ie});return r.handler.apply(null,i)}catch(i){if(i.constructor!==Ie)throw i}}}render(e,r){let n=[];for(let o in r)n.push(I(r[o],{key:o}));let i;typeof e<"u"&&(i=I(e,{key:"MINT_MAIN"})),ae([...n,i],this.root),this.handlePopState()}},Vn=(t,e=!0,r=!0,n=null)=>{let i=window.location.pathname,o=window.location.search,a=window.location.hash;if(i+o+a!==t&&(e?window.history.pushState({},"",t):window.history.replaceState({},"",t)),e){let l=new PopStateEvent("popstate");l.triggerJump=r,l.routeInfo=n,dispatchEvent(l)}},Oo=(t,e,r,n=[])=>{new nt(r,n).render(t,e)};function Bn(t){return this.getChildContext=()=>t.context,t.children}function Fn(t){let e=this,r=t._container;e.componentWillUnmount=function(){ae(null,e._temp),e._temp=null,e._container=null},e._container&&e._container!==r&&e.componentWillUnmount(),e._temp||(e._container=r,e._temp={nodeType:1,parentNode:r,childNodes:[],appendChild(n){this.childNodes.push(n),e._container.appendChild(n)},insertBefore(n,i){this.childNodes.push(n),e._container.appendChild(n)},removeChild(n){this.childNodes.splice(this.childNodes.indexOf(n)>>>1,1),e._container.removeChild(n)}}),ae(I(Bn,{context:e.context},t._vnode),e._temp)}function Co(t,e){let r=I(Fn,{_vnode:t,_container:e});return r.containerInfo=e,r}var it=class{[S](e){if(!(e instanceof this.constructor)||e.length!==this.length)return!1;if(this.record)return Xe(this,e);for(let r=0;rclass extends it{constructor(...e){if(super(),Array.isArray(t)){this.length=t.length,this.record=!0;for(let r=0;r(...e)=>new t(...e);var Uo=t=>{let e=document.createElement("style");document.head.appendChild(e),e.innerHTML=t},Lo=t=>{let e={},r=(n,i)=>{e[n.toString().trim()]=i.toString().trim()};for(let n of t)if(typeof n=="string")n.split(";").forEach(i=>{let[o,a]=i.split(":");o&&a&&r(o,a)});else if(n instanceof Map||n instanceof Array)for(let[i,o]of n)r(i,o);else for(let i in n)r(i,n[i]);return e};var export_uuid=Gt.default;export{S as Equals,R as Error,ki as access,Nt as batch,vi as bracketAccess,q as compare,Xe as compareObjects,ce as computed,I as createElement,Co as createPortal,Di as createProvider,wi as createRef,Yi as decodeArray,Ki as decodeBoolean,rn as decodeField,Xi as decodeMap,zi as decodeMaybe,Gi as decodeNumber,Qi as decodeObject,Hi as decodeString,Wi as decodeTime,Ji as decodeTuple,Zi as decoder,J as destructure,ee as effect,no as encodeArray,io as encodeMap,oo as encodeMaybe,ro as encodeTime,so as encodeTuple,ao as encoder,se as fragment,Bt as identity,Uo as insertStyles,Si as lazy,Vt as lazyComponent,Hr as load,Ft as locale,yi as mapAccess,ai as match,Vn as navigate,jo as newVariant,Fr as normalizeEvent,Ei as or,oi as pattern,si as patternRecord,Ze as patternSpread,Br as patternVariable,Oo as program,Ti as setLocale,mi as setRef,j as signal,Lo as style,Ui as subscriptions,bi as toArray,Oi as translate,Wr as translations,Vr as useComputed,xi as useDidUpdate,z as useEffect,Li as useId,$ as useMemo,ue as useRef,gi as useSignal,export_uuid as uuid,$o as variant}; diff --git a/src/assets/runtime_test.js b/src/assets/runtime_test.js new file mode 100644 index 000000000..99ef7e34a --- /dev/null +++ b/src/assets/runtime_test.js @@ -0,0 +1,68 @@ +var Sr=Object.create;var ut=Object.defineProperty;var Ar=Object.getOwnPropertyDescriptor;var qr=Object.getOwnPropertyNames;var Tr=Object.getPrototypeOf,Or=Object.prototype.hasOwnProperty;var ge=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,r)=>(typeof require<"u"?require:e)[r]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var N=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var Pr=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of qr(e))!Or.call(t,i)&&i!==r&&ut(t,i,{get:()=>e[i],enumerable:!(n=Ar(e,i))||n.enumerable});return t};var lt=(t,e,r)=>(r=t!=null?Sr(Tr(t)):{},Pr(e||!t||!t.__esModule?ut(r,"default",{value:t,enumerable:!0}):r,t));var Gt=N(()=>{});var Kt=N((Li,tt)=>{"use strict";(function(){var t,e=0,r=[],n;for(n=0;n<256;n++)r[n]=(n+256).toString(16).substr(1);c.BUFFER_SIZE=4096,c.bin=a,c.clearBuffer=function(){t=null,e=0},c.test=function(l){return typeof l=="string"?/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(l):!1};var i;typeof crypto<"u"?i=crypto:typeof window<"u"&&typeof window.msCrypto<"u"&&(i=window.msCrypto),typeof tt<"u"&&typeof ge=="function"?(i=i||Gt(),tt.exports=c):typeof window<"u"&&(window.uuid=c),c.randomBytes=function(){if(i){if(i.randomBytes)return i.randomBytes;if(i.getRandomValues)return typeof Uint8Array.prototype.slice!="function"?function(l){var h=new Uint8Array(l);return i.getRandomValues(h),Array.from(h)}:function(l){var h=new Uint8Array(l);return i.getRandomValues(h),h}}return function(l){var h,u=[];for(h=0;hc.BUFFER_SIZE)&&(e=0,t=c.randomBytes(c.BUFFER_SIZE)),t.slice(e,e+=l)}function a(){var l=o(16);return l[6]=l[6]&15|64,l[8]=l[8]&63|128,l}function c(){var l=a();return r[l[0]]+r[l[1]]+r[l[2]]+r[l[3]]+"-"+r[l[4]]+r[l[5]]+"-"+r[l[6]]+r[l[7]]+"-"+r[l[8]]+r[l[9]]+"-"+r[l[10]]+r[l[11]]+r[l[12]]+r[l[13]]+r[l[14]]+r[l[15]]}})()});var sr=N(de=>{var Ie=function(){var t=function(h,u,s,_){for(s=s||{},_=h.length;_--;s[h[_]]=u);return s},e=[1,9],r=[1,10],n=[1,11],i=[1,12],o=[5,11,12,13,14,15],a={trace:function(){},yy:{},symbols_:{error:2,root:3,expressions:4,EOF:5,expression:6,optional:7,literal:8,splat:9,param:10,"(":11,")":12,LITERAL:13,SPLAT:14,PARAM:15,$accept:0,$end:1},terminals_:{2:"error",5:"EOF",11:"(",12:")",13:"LITERAL",14:"SPLAT",15:"PARAM"},productions_:[0,[3,2],[3,1],[4,2],[4,1],[6,1],[6,1],[6,1],[6,1],[7,3],[8,1],[9,1],[10,1]],performAction:function(u,s,_,f,p,d,g){var y=d.length-1;switch(p){case 1:return new f.Root({},[d[y-1]]);case 2:return new f.Root({},[new f.Literal({value:""})]);case 3:this.$=new f.Concat({},[d[y-1],d[y]]);break;case 4:case 5:this.$=d[y];break;case 6:this.$=new f.Literal({value:d[y]});break;case 7:this.$=new f.Splat({name:d[y]});break;case 8:this.$=new f.Param({name:d[y]});break;case 9:this.$=new f.Optional({},[d[y-1]]);break;case 10:this.$=u;break;case 11:case 12:this.$=u.slice(1);break}},table:[{3:1,4:2,5:[1,3],6:4,7:5,8:6,9:7,10:8,11:e,13:r,14:n,15:i},{1:[3]},{5:[1,13],6:14,7:5,8:6,9:7,10:8,11:e,13:r,14:n,15:i},{1:[2,2]},t(o,[2,4]),t(o,[2,5]),t(o,[2,6]),t(o,[2,7]),t(o,[2,8]),{4:15,6:4,7:5,8:6,9:7,10:8,11:e,13:r,14:n,15:i},t(o,[2,10]),t(o,[2,11]),t(o,[2,12]),{1:[2,1]},t(o,[2,3]),{6:14,7:5,8:6,9:7,10:8,11:e,12:[1,16],13:r,14:n,15:i},t(o,[2,9])],defaultActions:{3:[2,2],13:[2,1]},parseError:function(u,s){if(s.recoverable)this.trace(u);else{let f=function(p,d){this.message=p,this.hash=d};var _=f;throw f.prototype=Error,new f(u,s)}},parse:function(u){var s=this,_=[0],f=[],p=[null],d=[],g=this.table,y="",w=0,P=0,H=0,W=2,oe=1,X=d.slice.call(arguments,1),x=Object.create(this.lexer),E={yy:{}};for(var U in this.yy)Object.prototype.hasOwnProperty.call(this.yy,U)&&(E.yy[U]=this.yy[U]);x.setInput(u,E.yy),E.yy.lexer=x,E.yy.parser=this,typeof x.yylloc>"u"&&(x.yylloc={});var De=x.yylloc;d.push(De);var br=x.options&&x.options.ranges;typeof E.yy.parseError=="function"?this.parseError=E.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function Gn(C){_.length=_.length-2*C,p.length=p.length-C,d.length=d.length-C}for(var kr=function(){var C;return C=x.lex()||oe,typeof C!="number"&&(C=s.symbols_[C]||C),C},q,je,G,O,Kn,Me,Z={},ve,M,at,me;;){if(G=_[_.length-1],this.defaultActions[G]?O=this.defaultActions[G]:((q===null||typeof q>"u")&&(q=kr()),O=g[G]&&g[G][q]),typeof O>"u"||!O.length||!O[0]){var Ue="";me=[];for(ve in g[G])this.terminals_[ve]&&ve>W&&me.push("'"+this.terminals_[ve]+"'");x.showPosition?Ue="Parse error on line "+(w+1)+`: +`+x.showPosition()+` +Expecting `+me.join(", ")+", got '"+(this.terminals_[q]||q)+"'":Ue="Parse error on line "+(w+1)+": Unexpected "+(q==oe?"end of input":"'"+(this.terminals_[q]||q)+"'"),this.parseError(Ue,{text:x.match,token:this.terminals_[q]||q,line:x.yylineno,loc:De,expected:me})}if(O[0]instanceof Array&&O.length>1)throw new Error("Parse Error: multiple actions possible at state: "+G+", token: "+q);switch(O[0]){case 1:_.push(q),p.push(x.yytext),d.push(x.yylloc),_.push(O[1]),q=null,je?(q=je,je=null):(P=x.yyleng,y=x.yytext,w=x.yylineno,De=x.yylloc,H>0&&H--);break;case 2:if(M=this.productions_[O[1]][1],Z.$=p[p.length-M],Z._$={first_line:d[d.length-(M||1)].first_line,last_line:d[d.length-1].last_line,first_column:d[d.length-(M||1)].first_column,last_column:d[d.length-1].last_column},br&&(Z._$.range=[d[d.length-(M||1)].range[0],d[d.length-1].range[1]]),Me=this.performAction.apply(Z,[y,P,w,E.yy,O[1],p,d].concat(X)),typeof Me<"u")return Me;M&&(_=_.slice(0,-1*M*2),p=p.slice(0,-1*M),d=d.slice(0,-1*M)),_.push(this.productions_[O[1]][0]),p.push(Z.$),d.push(Z._$),at=g[_[_.length-2]][_[_.length-1]],_.push(at);break;case 3:return!0}}return!0}},c=function(){var h={EOF:1,parseError:function(s,_){if(this.yy.parser)this.yy.parser.parseError(s,_);else throw new Error(s)},setInput:function(u,s){return this.yy=s||this.yy||{},this._input=u,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var u=this._input[0];this.yytext+=u,this.yyleng++,this.offset++,this.match+=u,this.matched+=u;var s=u.match(/(?:\r\n?|\n).*/g);return s?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),u},unput:function(u){var s=u.length,_=u.split(/(?:\r\n?|\n)/g);this._input=u+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-s),this.offset-=s;var f=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),_.length-1&&(this.yylineno-=_.length-1);var p=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:_?(_.length===f.length?this.yylloc.first_column:0)+f[f.length-_.length].length-_[0].length:this.yylloc.first_column-s},this.options.ranges&&(this.yylloc.range=[p[0],p[0]+this.yyleng-s]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true). +`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},less:function(u){this.unput(this.match.slice(u))},pastInput:function(){var u=this.matched.substr(0,this.matched.length-this.match.length);return(u.length>20?"...":"")+u.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var u=this.match;return u.length<20&&(u+=this._input.substr(0,20-u.length)),(u.substr(0,20)+(u.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var u=this.pastInput(),s=new Array(u.length+1).join("-");return u+this.upcomingInput()+` +`+s+"^"},test_match:function(u,s){var _,f,p;if(this.options.backtrack_lexer&&(p={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(p.yylloc.range=this.yylloc.range.slice(0))),f=u[0].match(/(?:\r\n?|\n).*/g),f&&(this.yylineno+=f.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:f?f[f.length-1].length-f[f.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+u[0].length},this.yytext+=u[0],this.match+=u[0],this.matches=u,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(u[0].length),this.matched+=u[0],_=this.performAction.call(this,this.yy,this,s,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),_)return _;if(this._backtrack){for(var d in p)this[d]=p[d];return!1}return!1},next:function(){if(this.done)return this.EOF;this._input||(this.done=!0);var u,s,_,f;this._more||(this.yytext="",this.match="");for(var p=this._currentRules(),d=0;ds[0].length)){if(s=_,f=d,this.options.backtrack_lexer){if(u=this.test_match(_,p[d]),u!==!1)return u;if(this._backtrack){s=!1;continue}else return!1}else if(!this.options.flex)break}return s?(u=this.test_match(s,p[f]),u!==!1?u:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text. +`+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var s=this.next();return s||this.lex()},begin:function(s){this.conditionStack.push(s)},popState:function(){var s=this.conditionStack.length-1;return s>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(s){return s=this.conditionStack.length-1-Math.abs(s||0),s>=0?this.conditionStack[s]:"INITIAL"},pushState:function(s){this.begin(s)},stateStackSize:function(){return this.conditionStack.length},options:{},performAction:function(s,_,f,p){var d=p;switch(f){case 0:return"(";case 1:return")";case 2:return"SPLAT";case 3:return"PARAM";case 4:return"LITERAL";case 5:return"LITERAL";case 6:return"EOF"}},rules:[/^(?:\()/,/^(?:\))/,/^(?:\*+\w+)/,/^(?::+\w+)/,/^(?:[\w%\-~\n]+)/,/^(?:.)/,/^(?:$)/],conditions:{INITIAL:{rules:[0,1,2,3,4,5,6],inclusive:!0}}};return h}();a.lexer=c;function l(){this.yy={}}return l.prototype=a,a.Parser=l,new l}();typeof ge<"u"&&typeof de<"u"&&(de.parser=Ie,de.Parser=Ie.Parser,de.parse=function(){return Ie.parse.apply(Ie,arguments)})});var nt=N((qo,ar)=>{"use strict";function ie(t){return function(e,r){return{displayName:t,props:e,children:r||[]}}}ar.exports={Root:ie("Root"),Concat:ie("Concat"),Literal:ie("Literal"),Splat:ie("Splat"),Param:ie("Param"),Optional:ie("Optional")}});var cr=N((To,lr)=>{"use strict";var ur=sr().parser;ur.yy=nt();lr.exports=ur});var it=N((Oo,fr)=>{"use strict";var Pn=Object.keys(nt());function Rn(t){return Pn.forEach(function(e){if(typeof t[e]>"u")throw new Error("No handler defined for "+e.displayName)}),{visit:function(e,r){return this.handlers[e.displayName].call(this,e,r)},handlers:t}}fr.exports=Rn});var pr=N((Po,_r)=>{"use strict";var Cn=it(),Nn=/[\-{}\[\]+?.,\\\^$|#\s]/g;function hr(t){this.captures=t.captures,this.re=t.re}hr.prototype.match=function(t){var e=this.re.exec(t),r={};return e?(this.captures.forEach(function(n,i){typeof e[i+1]>"u"?r[n]=void 0:r[n]=decodeURIComponent(e[i+1])}),r):!1};var In=Cn({Concat:function(t){return t.children.reduce(function(e,r){var n=this.visit(r);return{re:e.re+n.re,captures:e.captures.concat(n.captures)}}.bind(this),{re:"",captures:[]})},Literal:function(t){return{re:t.props.value.replace(Nn,"\\$&"),captures:[]}},Splat:function(t){return{re:"([^?#]*?)",captures:[t.props.name]}},Param:function(t){return{re:"([^\\/\\?#]+)",captures:[t.props.name]}},Optional:function(t){var e=this.visit(t.children[0]);return{re:"(?:"+e.re+")?",captures:e.captures}},Root:function(t){var e=this.visit(t.children[0]);return new hr({re:new RegExp("^"+e.re+"(?=\\?|#|$)"),captures:e.captures})}});_r.exports=In});var yr=N((Ro,dr)=>{"use strict";var $n=it(),Dn=$n({Concat:function(t,e){var r=t.children.map(function(n){return this.visit(n,e)}.bind(this));return r.some(function(n){return n===!1})?!1:r.join("")},Literal:function(t){return decodeURI(t.props.value)},Splat:function(t,e){return typeof e[t.props.name]>"u"?!1:e[t.props.name]},Param:function(t,e){return typeof e[t.props.name]>"u"?!1:e[t.props.name]},Optional:function(t,e){var r=this.visit(t.children[0],e);return r||""},Root:function(t,e){e=e||{};var r=this.visit(t.children[0],e);return r===!1||typeof r>"u"?!1:encodeURI(r)}});dr.exports=Dn});var mr=N((Co,vr)=>{"use strict";var jn=cr(),Mn=pr(),Un=yr();function ye(t){var e;if(this?e=this:e=Object.create(ye.prototype),typeof t>"u")throw new Error("A route spec is required");return e.spec=t,e.ast=jn.parse(t),e}ye.prototype=Object.create(null);ye.prototype.match=function(t){var e=Mn.visit(this.ast),r=e.match(t);return r!==null?r:!1};ye.prototype.reverse=function(t){return Un.visit(this.ast,t)};vr.exports=ye});var wr=N((No,gr)=>{"use strict";var Ln=mr();gr.exports=Ln});var be,v,dt,Fe,K,ct,yt,Le,Rr,se={},vt=[],Cr=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,Be=Array.isArray;function L(t,e){for(var r in e)t[r]=e[r];return t}function mt(t){var e=t.parentNode;e&&e.removeChild(t)}function I(t,e,r){var n,i,o,a={};for(o in e)o=="key"?n=e[o]:o=="ref"?i=e[o]:a[o]=e[o];if(arguments.length>2&&(a.children=arguments.length>3?be.call(arguments,2):r),typeof t=="function"&&t.defaultProps!=null)for(o in t.defaultProps)a[o]===void 0&&(a[o]=t.defaultProps[o]);return xe(t,a,n,i,null)}function xe(t,e,r,n,i){var o={type:t,props:e,key:r,ref:n,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,constructor:void 0,__v:i??++dt,__i:-1,__u:0};return i==null&&v.vnode!=null&&v.vnode(o),o}function gt(){return{current:null}}function ae(t){return t.children}function V(t,e){this.props=t,this.context=e}function Y(t,e){if(e==null)return t.__?Y(t.__,t.__i+1):null;for(var r;ee&&K.sort(Le));Ee.__r=0}function xt(t,e,r,n,i,o,a,c,l,h,u){var s,_,f,p,d,g=n&&n.__k||vt,y=e.length;for(r.__d=l,Nr(r,e,g),l=r.__d,s=0;s0?xe(i.type,i.props,i.key,i.ref?i.ref:null,i.__v):i)!=null?(i.__=t,i.__b=t.__b+1,c=Ir(i,r,a,u),i.__i=c,o=null,c!==-1&&(u--,(o=r[c])&&(o.__u|=131072)),o==null||o.__v===null?(c==-1&&s--,typeof i.type!="function"&&(i.__u|=65536)):c!==a&&(c===a+1?s++:c>a?u>l-a?s+=c-a:s--:c(l!=null&&!(131072&l.__u)?1:0))for(;a>=0||c=0){if((l=e[a])&&!(131072&l.__u)&&i==l.key&&o===l.type)return a;a--}if(c"u"&&(self.Node=class{});Boolean.prototype[S]=Symbol.prototype[S]=Number.prototype[S]=String.prototype[S]=function(t){return this.valueOf()===t};Date.prototype[S]=function(t){return+this==+t};Function.prototype[S]=Node.prototype[S]=function(t){return this===t};URLSearchParams.prototype[S]=function(t){return t==null?!1:this.toString()===t.toString()};Set.prototype[S]=function(t){return t==null?!1:A(Array.from(this).sort(),Array.from(t).sort())};Array.prototype[S]=function(t){if(t==null||this.length!==t.length)return!1;if(this.length==0)return!0;for(let e in this)if(!A(this[e],t[e]))return!1;return!0};FormData.prototype[S]=function(t){if(t==null)return!1;let e=Array.from(t.keys()).sort(),r=Array.from(this.keys()).sort();if(A(r,e)){if(r.length==0)return!0;for(let n of r){let i=Array.from(t.getAll(n).sort()),o=Array.from(this.getAll(n).sort());if(!A(o,i))return!1}return!0}else return!1};Map.prototype[S]=function(t){if(t==null)return!1;let e=Array.from(this.keys()).sort(),r=Array.from(t.keys()).sort();if(A(e,r)){if(e.length==0)return!0;for(let n of e)if(!A(this.get(n),t.get(n)))return!1;return!0}else return!1};var kt=t=>t!=null&&typeof t=="object"&&"constructor"in t&&"props"in t&&"type"in t&&"ref"in t&&"key"in t&&"__"in t,A=(t,e)=>t===void 0&&e===void 0||t===null&&e===null?!0:t!=null&&t!=null&&t[S]?t[S](e):e!=null&&e!=null&&e[S]?e[S](t):kt(t)||kt(e)?t===e:Ge(t,e),Ge=(t,e)=>{if(t instanceof Object&&e instanceof Object){let r=Object.keys(t),n=Object.keys(e);if(r.length!==n.length)return!1;let i=new Set(r.concat(n));for(let o of i)if(!A(t[o],e[o]))return!1;return!0}else return t===e};var ue=class{constructor(e,r){this.teardown=r,this.subject=e,this.steps=[]}async run(){let e;try{e=await new Promise(this.next.bind(this))}finally{this.teardown&&this.teardown()}return e}async next(e,r){requestAnimationFrame(async()=>{let n=this.steps.shift();if(n)try{this.subject=await n(this.subject)}catch(i){return r(i)}this.steps.length?this.next(e,r):e(this.subject)})}step(e){return this.steps.push(e),this}},Ke=class{constructor(e,r,n){this.socket=new WebSocket(r),this.suites=e,this.url=r,this.id=n,window.DEBUG={log:o=>{let a="";o===void 0?a="undefined":o===null?a="null":a=o.toString(),this.log(a)}};let i=null;window.onerror=o=>{this.socket.readyState===1?this.crash(o):i=i||o},this.socket.onopen=()=>{i!=null&&this.crash(i)},this.start()}start(){this.socket.readyState===1?this.run():this.socket.addEventListener("open",()=>this.run())}run(){return new Promise((e,r)=>{this.next(e,r)}).catch(e=>this.log(e.reason)).finally(()=>this.socket.send("DONE"))}report(e,r,n,i,o){i&&i.toString&&(i=i.toString()),this.socket.send(JSON.stringify({location:o,result:i,suite:r,id:this.id,type:e,name:n}))}reportTested(e,r,n){this.report(r,this.suite.name,e.name,n,e.location)}crash(e){this.report("CRASHED",null,null,e)}log(e){this.report("LOG",null,null,e)}next(e,r){requestAnimationFrame(async()=>{if(!this.suite||this.suite.tests.length===0)if(this.suite=this.suites.shift(),this.suite)this.report("SUITE",this.suite.name);else return e();let n=this.suite.tests.shift();try{let i=await n.proc.call(this.suite.context);if(window.location.pathname!=="/"&&window.history.replaceState({},"","/"),sessionStorage.clear(),localStorage.clear(),i instanceof ue)try{await i.run(),this.reportTested(n,"SUCCEEDED",i.subject)}catch(o){this.reportTested(n,"FAILED",o)}else i?this.reportTested(n,"SUCCEEDED"):this.reportTested(n,"FAILED")}catch(i){this.reportTested(n,"ERRORED",i)}this.next(e,r)})}},Qn=(t,e,r)=>new ue(t).step(n=>{let i=A(n,e);if(r==="=="&&(i=!i),i)throw`Assertion failed: ${e} ${r} ${n}`;return!0}),ei=ue,ti=Ke;var Ae,T,Ye,St,ze=0,Nt=[],ke=[],b=v,At=b.__b,qt=b.__r,Tt=b.diffed,Ot=b.__c,Pt=b.unmount,Rt=b.__;function It(t,e){b.__h&&b.__h(T,t,ze||e),ze=0;var r=T.__H||(T.__H={__:[],__h:[]});return t>=r.__.length&&r.__.push({__V:ke}),r.__[t]}function z(t,e){var r=It(Ae++,3);!b.__s&&$t(r.__H,e)&&(r.__=t,r.i=e,T.__H.__h.push(r))}function le(t){return ze=5,$(function(){return{current:t}},[])}function $(t,e){var r=It(Ae++,7);return $t(r.__H,e)?(r.__V=t(),r.i=e,r.__h=t,r.__V):r.__}function jr(){for(var t;t=Nt.shift();)if(t.__P&&t.__H)try{t.__H.__h.forEach(Se),t.__H.__h.forEach(Je),t.__H.__h=[]}catch(e){t.__H.__h=[],b.__e(e,t.__v)}}b.__b=function(t){T=null,At&&At(t)},b.__=function(t,e){t&&e.__k&&e.__k.__m&&(t.__m=e.__k.__m),Rt&&Rt(t,e)},b.__r=function(t){qt&&qt(t),Ae=0;var e=(T=t.__c).__H;e&&(Ye===T?(e.__h=[],T.__h=[],e.__.forEach(function(r){r.__N&&(r.__=r.__N),r.__V=ke,r.__N=r.i=void 0})):(e.__h.forEach(Se),e.__h.forEach(Je),e.__h=[],Ae=0)),Ye=T},b.diffed=function(t){Tt&&Tt(t);var e=t.__c;e&&e.__H&&(e.__H.__h.length&&(Nt.push(e)!==1&&St===b.requestAnimationFrame||((St=b.requestAnimationFrame)||Mr)(jr)),e.__H.__.forEach(function(r){r.i&&(r.__H=r.i),r.__V!==ke&&(r.__=r.__V),r.i=void 0,r.__V=ke})),Ye=T=null},b.__c=function(t,e){e.some(function(r){try{r.__h.forEach(Se),r.__h=r.__h.filter(function(n){return!n.__||Je(n)})}catch(n){e.some(function(i){i.__h&&(i.__h=[])}),e=[],b.__e(n,r.__v)}}),Ot&&Ot(t,e)},b.unmount=function(t){Pt&&Pt(t);var e,r=t.__c;r&&r.__H&&(r.__H.__.forEach(function(n){try{Se(n)}catch(i){e=i}}),r.__H=void 0,e&&b.__e(e,r.__v))};var Ct=typeof requestAnimationFrame=="function";function Mr(t){var e,r=function(){clearTimeout(n),Ct&&cancelAnimationFrame(e),setTimeout(t)},n=setTimeout(r,100);Ct&&(e=requestAnimationFrame(r))}function Se(t){var e=T,r=t.__c;typeof r=="function"&&(t.__c=void 0,r()),T=e}function Je(t){var e=T;t.__c=t.__(),T=e}function $t(t,e){return!t||t.length!==e.length||e.some(function(r,n){return r!==t[n]})}var Ur=Symbol.for("preact-signals");function Te(){if(F>1)F--;else{for(var t,e=!1;ce!==void 0;){var r=ce;for(ce=void 0,Xe++;r!==void 0;){var n=r.o;if(r.o=void 0,r.f&=-3,!(8&r.f)&&Mt(r))try{r.c()}catch(i){e||(t=i,e=!0)}r=n}}if(Xe=0,F--,e)throw t}}function Dt(t){if(F>0)return t();F++;try{return t()}finally{Te()}}var m=void 0;function Oe(t){var e=m;m=void 0;try{return t()}finally{m=e}}var ce=void 0,F=0,Xe=0,qe=0;function jt(t){if(m!==void 0){var e=t.n;if(e===void 0||e.t!==m)return e={i:0,S:t,p:m.s,n:void 0,t:m,e:void 0,x:void 0,r:e},m.s!==void 0&&(m.s.n=e),m.s=e,t.n=e,32&m.f&&t.S(e),e;if(e.i===-1)return e.i=0,e.n!==void 0&&(e.n.p=e.p,e.p!==void 0&&(e.p.n=e.n),e.p=m.s,e.n=void 0,m.s.n=e,m.s=e),e}}function k(t){this.v=t,this.i=0,this.n=void 0,this.t=void 0}k.prototype.brand=Ur;k.prototype.h=function(){return!0};k.prototype.S=function(t){this.t!==t&&t.e===void 0&&(t.x=this.t,this.t!==void 0&&(this.t.e=t),this.t=t)};k.prototype.U=function(t){if(this.t!==void 0){var e=t.e,r=t.x;e!==void 0&&(e.x=r,t.e=void 0),r!==void 0&&(r.e=e,t.x=void 0),t===this.t&&(this.t=r)}};k.prototype.subscribe=function(t){var e=this;return te(function(){var r=e.value,n=m;m=void 0;try{t(r)}finally{m=n}})};k.prototype.valueOf=function(){return this.value};k.prototype.toString=function(){return this.value+""};k.prototype.toJSON=function(){return this.value};k.prototype.peek=function(){var t=m;m=void 0;try{return this.value}finally{m=t}};Object.defineProperty(k.prototype,"value",{get:function(){var t=jt(this);return t!==void 0&&(t.i=this.i),this.v},set:function(t){if(t!==this.v){if(Xe>100)throw new Error("Cycle detected");this.v=t,this.i++,qe++,F++;try{for(var e=this.t;e!==void 0;e=e.x)e.t.N()}finally{Te()}}}});function D(t){return new k(t)}function Mt(t){for(var e=t.s;e!==void 0;e=e.n)if(e.S.i!==e.i||!e.S.h()||e.S.i!==e.i)return!0;return!1}function Ut(t){for(var e=t.s;e!==void 0;e=e.n){var r=e.S.n;if(r!==void 0&&(e.r=r),e.S.n=e,e.i=-1,e.n===void 0){t.s=e;break}}}function Lt(t){for(var e=t.s,r=void 0;e!==void 0;){var n=e.p;e.i===-1?(e.S.U(e),n!==void 0&&(n.n=e.n),e.n!==void 0&&(e.n.p=n)):r=e,e.S.n=e.r,e.r!==void 0&&(e.r=void 0),e=n}t.s=r}function ee(t){k.call(this,void 0),this.x=t,this.s=void 0,this.g=qe-1,this.f=4}(ee.prototype=new k).h=function(){if(this.f&=-3,1&this.f)return!1;if((36&this.f)==32||(this.f&=-5,this.g===qe))return!0;if(this.g=qe,this.f|=1,this.i>0&&!Mt(this))return this.f&=-2,!0;var t=m;try{Ut(this),m=this;var e=this.x();(16&this.f||this.v!==e||this.i===0)&&(this.v=e,this.f&=-17,this.i++)}catch(r){this.v=r,this.f|=16,this.i++}return m=t,Lt(this),this.f&=-2,!0};ee.prototype.S=function(t){if(this.t===void 0){this.f|=36;for(var e=this.s;e!==void 0;e=e.n)e.S.S(e)}k.prototype.S.call(this,t)};ee.prototype.U=function(t){if(this.t!==void 0&&(k.prototype.U.call(this,t),this.t===void 0)){this.f&=-33;for(var e=this.s;e!==void 0;e=e.n)e.S.U(e)}};ee.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(var t=this.t;t!==void 0;t=t.x)t.t.N()}};Object.defineProperty(ee.prototype,"value",{get:function(){if(1&this.f)throw new Error("Cycle detected");var t=jt(this);if(this.h(),t!==void 0&&(t.i=this.i),16&this.f)throw this.v;return this.v}});function fe(t){return new ee(t)}function Vt(t){var e=t.u;if(t.u=void 0,typeof e=="function"){F++;var r=m;m=void 0;try{e()}catch(n){throw t.f&=-2,t.f|=8,Ze(t),n}finally{m=r,Te()}}}function Ze(t){for(var e=t.s;e!==void 0;e=e.n)e.S.U(e);t.x=void 0,t.s=void 0,Vt(t)}function Lr(t){if(m!==this)throw new Error("Out-of-order effect");Lt(this),m=t,this.f&=-2,8&this.f&&Ze(this),Te()}function he(t){this.x=t,this.u=void 0,this.s=void 0,this.o=void 0,this.f=32}he.prototype.c=function(){var t=this.S();try{if(8&this.f||this.x===void 0)return;var e=this.x();typeof e=="function"&&(this.u=e)}finally{t()}};he.prototype.S=function(){if(1&this.f)throw new Error("Cycle detected");this.f|=1,this.f&=-9,Vt(this),Ut(this),F++;var t=m;return m=this,Lr.bind(this,t)};he.prototype.N=function(){2&this.f||(this.f|=2,this.o=ce,ce=this)};he.prototype.d=function(){this.f|=8,1&this.f||Ze(this)};function te(t){var e=new he(t);try{e.c()}catch(r){throw e.d(),r}return e.d.bind(e)}var Re,Qe;function re(t,e){v[t]=e.bind(null,v[t]||function(){})}function Pe(t){Qe&&Qe(),Qe=t&&t.S()}function Ft(t){var e=this,r=t.data,n=Fr(r);n.value=r;var i=$(function(){for(var o=e.__v;o=o.__;)if(o.__c){o.__c.__$f|=4;break}return e.__$u.c=function(){var a;!Fe(i.peek())&&((a=e.base)==null?void 0:a.nodeType)===3?e.base.data=i.peek():(e.__$f|=1,e.setState({}))},fe(function(){var a=n.value.value;return a===0?0:a===!0?"":a||""})},[]);return i.value}Ft.displayName="_st";Object.defineProperties(k.prototype,{constructor:{configurable:!0,value:void 0},type:{configurable:!0,value:Ft},props:{configurable:!0,get:function(){return{data:this}}},__b:{configurable:!0,value:1}});re("__b",function(t,e){if(typeof e.type=="string"){var r,n=e.props;for(var i in n)if(i!=="children"){var o=n[i];o instanceof k&&(r||(e.__np=r={}),r[i]=o,n[i]=o.peek())}}t(e)});re("__r",function(t,e){Pe();var r,n=e.__c;n&&(n.__$f&=-2,(r=n.__$u)===void 0&&(n.__$u=r=function(i){var o;return te(function(){o=this}),o.c=function(){n.__$f|=1,n.setState({})},o}())),Re=n,Pe(r),t(e)});re("__e",function(t,e,r,n){Pe(),Re=void 0,t(e,r,n)});re("diffed",function(t,e){Pe(),Re=void 0;var r;if(typeof e.type=="string"&&(r=e.__e)){var n=e.__np,i=e.props;if(n){var o=r.U;if(o)for(var a in o){var c=o[a];c!==void 0&&!(a in n)&&(c.d(),o[a]=void 0)}else r.U=o={};for(var l in n){var h=o[l],u=n[l];h===void 0?(h=Vr(r,l,u,i),o[l]=h):h.o(u,i)}}}t(e)});function Vr(t,e,r,n){var i=e in t&&t.ownerSVGElement===void 0,o=D(r);return{o:function(a,c){o.value=a,n=c},d:te(function(){var a=o.value.value;n[e]!==a&&(n[e]=a,i?t[e]=a:a?t.setAttribute(e,a):t.removeAttribute(e))})}}re("unmount",function(t,e){if(typeof e.type=="string"){var r=e.__e;if(r){var n=r.U;if(n){r.U=void 0;for(var i in n){var o=n[i];o&&o.d()}}}}else{var a=e.__c;if(a){var c=a.__$u;c&&(a.__$u=void 0,c.d())}}t(e)});re("__h",function(t,e,r,n){(n<3||n===9)&&(e.__$f|=2),t(e,r,n)});V.prototype.shouldComponentUpdate=function(t,e){var r=this.__$u;if(!(r&&r.s!==void 0||4&this.__$f)||3&this.__$f)return!0;for(var n in e)return!0;for(var i in t)if(i!=="__source"&&t[i]!==this.props[i])return!0;for(var o in this.props)if(!(o in t))return!0;return!1};function Fr(t){return $(function(){return D(t)},[])}function Br(t){var e=le(t);return e.current=t,Re.__$f|=4,$(function(){return fe(function(){return e.current()})},[])}var _e=class{constructor(e){this.patterns=e}},Ce=class{constructor(e,r){this.pattern=r,this.variant=e}},hi=(t,e)=>new Ce(t,e),_i=t=>new _e(t),Hr=Symbol("Variable"),et=Symbol("Spread"),J=(t,e,r=[])=>{if(e!==null){if(e===Hr)r.push(t);else if(Array.isArray(e))if(e.some(i=>i===et)&&t.length>=e.length-1){let i=0,o=[],a=1;for(;e[i]!==et&&i{for(let r of e){if(r[0]===null)return r[1]();{let n=J(t,r[0]);if(n)return r[1].apply(null,n)}}};"DataTransfer"in window||(window.DataTransfer=class{constructor(){this.effectAllowed="none",this.dropEffect="none",this.files=[],this.types=[],this.cache={}}getData(t){return this.cache[t]||""}setData(t,e){return this.cache[t]=e,null}clearData(){return this.cache={},null}});var Wr=t=>new Proxy(t,{get:function(e,r){if(r==="event")return t;if(r in e){let n=e[r];return n instanceof Function?()=>e[r]():n}else switch(r){case"clipboardData":return e.clipboardData=new DataTransfer;case"dataTransfer":return e.dataTransfer=new DataTransfer;case"data":return"";case"altKey":return!1;case"charCode":return-1;case"ctrlKey":return!1;case"key":return"";case"keyCode":return-1;case"locale":return"";case"location":return-1;case"metaKey":return!1;case"repeat":return!1;case"shiftKey":return!1;case"which":return-1;case"button":return-1;case"buttons":return-1;case"clientX":return-1;case"clientY":return-1;case"pageX":return-1;case"pageY":return-1;case"screenX":return-1;case"screenY":return-1;case"detail":return-1;case"deltaMode":return-1;case"deltaX":return-1;case"deltaY":return-1;case"deltaZ":return-1;case"animationName":return"";case"pseudoElement":return"";case"elapsedTime":return-1;case"propertyName":return"";default:return}}});v.event=Wr;var bi=(t,e,r,n)=>{for(let i of t)if(A(i[0],e))return new r(i[1]);return new n},ki=(t,e,r,n)=>t.length>=e+1&&e>=0?new r(t[e]):new n,Si=(t,e)=>r=>{t.current._0!==r&&(t.current=new e(r))},Ai=t=>{let e=$(()=>D(t),[]);return e.value,e},qi=t=>{let e=gt();return e.current=t,e},Ti=t=>{let e=le(!1);z(()=>{e.current?t():e.current=!0})},Oi=(t,e,r,n)=>r instanceof t||r instanceof e?n:r._0,Pi=(...t)=>{let e=Array.from(t);return Array.isArray(e[0])&&e.length===1?e[0]:e},Ri=t=>e=>e[t],Ht=t=>t,Bt=class extends V{async componentDidMount(){let e=await this.props.x();this.setState({x:e})}render(){return this.state.x?I(this.state.x,this.props.p,this.props.c):null}},Ci=t=>async()=>Gr(t),Gr=async t=>(await import(t)).default;var Kr=D({}),Wt=D({}),$i=t=>Wt.value=t,Di=t=>(Kr.value[Wt.value]||{})[t]||"";var Yt=lt(Kt()),Wi=(t,e)=>(r,n)=>{let i=()=>{t.has(r)&&(t.delete(r),Oe(e))};z(()=>i,[]),z(()=>{let o=n();if(o===null)i();else{let a=t.get(r);A(a,o)||(t.set(r,o),Oe(e))}})},Gi=t=>Array.from(t.values()),Ki=()=>$(Yt.default,[]);function rt(t,e=1,r={}){let{indent:n=" ",includeEmptyLines:i=!1}=r;if(typeof t!="string")throw new TypeError(`Expected \`input\` to be a \`string\`, got \`${typeof t}\``);if(typeof e!="number")throw new TypeError(`Expected \`count\` to be a \`number\`, got \`${typeof e}\``);if(e<0)throw new RangeError(`Expected \`count\` to be at least 0, got \`${e}\``);if(typeof n!="string")throw new TypeError(`Expected \`options.indent\` to be a \`string\`, got \`${typeof n}\``);if(e===0)return t;let o=i?/^/gm:/^(?!\s*$)/gm;return t.replace(o,n.repeat(e))}var j=t=>{let e=JSON.stringify(t,"",2);return typeof e>"u"&&(e="undefined"),rt(e)},R=class{constructor(e,r=[]){this.message=e,this.object=null,this.path=r}push(e){this.path.unshift(e)}toString(){let e=this.message.trim(),r=this.path.reduce((n,i)=>{if(n.length)switch(i.type){case"FIELD":return`${n}.${i.value}`;case"ARRAY":return`${n}[${i.value}]`}else switch(i.type){case"FIELD":return i.value;case"ARRAY":return"[$(item.value)]"}},"");return r.length&&this.object?e+` + +`+Yr.trim().replace("{value}",j(this.object)).replace("{path}",r):e}},Yr=` +The input is in this object: + +{value} + +at: {path} +`,zr=` +I was trying to decode the value: + +{value} + +as a String, but could not. +`,Jr=` +I was trying to decode the value: + +{value} + +as a Time, but could not. +`,Xr=` +I was trying to decode the value: + +{value} + +as a Number, but could not. +`,Zr=` +I was trying to decode the value: + +{value} + +as a Bool, but could not. +`,Qr=` +I was trying to decode the field "{field}" from the object: + +{value} + +but I could not because it's not an object. +`,en=` +I was trying to decode the value: + +{value} + +as an Array, but could not. +`,tn=` +I was trying to decode the value: + +{value} + +as an Tuple, but could not. +`,rn=` +I was trying to decode one of the values of a tuple: + +{value} + +but could not. +`,nn=` +I was trying to decode the value: + +{value} + +as a Map, but could not. +`,Xi=(t,e)=>r=>typeof r!="string"?new e(new R(zr.replace("{value}",j(r)))):new t(r),Zi=(t,e)=>r=>{let n=NaN;return typeof r=="number"?n=new Date(r):n=Date.parse(r),Number.isNaN(n)?new e(new R(Jr.replace("{value}",j(r)))):new t(new Date(n))},Qi=(t,e)=>r=>{let n=parseFloat(r);return isNaN(n)?new e(new R(Xr.replace("{value}",j(r)))):new t(n)},eo=(t,e)=>r=>typeof r!="boolean"?new e(new R(Zr.replace("{value}",j(r)))):new t(r),on=(t,e,r)=>n=>{if(typeof n!="object"||Array.isArray(n)||n==null||n==null){let i=Qr.replace("{field}",t).replace("{value}",j(n));return new r(new R(i))}else{let i=e(n[t]);return i instanceof r&&(i._0.push({type:"FIELD",value:t}),i._0.object=n),i}},to=(t,e,r)=>n=>{if(!Array.isArray(n))return new r(new R(en.replace("{value}",j(n))));let i=[],o=0;for(let a of n){let c=t(a);if(c instanceof r)return c._0.push({type:"ARRAY",value:o}),c._0.object=n,c;i.push(c._0),o++}return new e(i)},ro=(t,e,r,n,i)=>o=>{if(o==null)return new e(new i);{let a=t(o);return a instanceof r?a:new e(new n(a._0))}},no=(t,e,r)=>n=>{if(!Array.isArray(n))return new r(new R(tn.replace("{value}",j(n))));let i=[],o=0;for(let a of t){if(n[o]===void 0||n[o]===null)return new r(new R(rn.replace("{value}",j(n[o]))));{let c=a(n[o]);if(c instanceof r)return c._0.push({type:"ARRAY",value:o}),c._0.object=n,c;i.push(c._0)}o++}return new e(i)},io=(t,e,r)=>n=>{if(typeof n!="object"||Array.isArray(n)||n==null||n==null){let i=nn.replace("{value}",j(n));return new r(new R(i))}else{let i=[];for(let o in n){let a=t(n[o]);if(a instanceof r)return a;i.push([o,a._0])}return new e(i)}},oo=(t,e,r)=>n=>{let i={};for(let o in t){let a=t[o],c=o;Array.isArray(a)&&(a=t[o][0],c=t[o][1]);let l=on(c,a,r)(n);if(l instanceof r)return l;i[o]=l._0}return new e(i)},so=t=>e=>new t(e);var lo=t=>t.toISOString(),co=t=>e=>e.map(r=>t?t(r):r),fo=t=>e=>{let r={};for(let n of e)r[n[0]]=t?t(n[1]):n[1];return r},ho=(t,e)=>r=>r instanceof e?t(r._0):null,_o=t=>e=>e.map((r,n)=>{let i=t[n];return i?i(r):r}),po=t=>e=>{let r={};for(let n in t){let i=t[n],o=n;Array.isArray(i)&&(i=t[n][0],o=t[n][1]),r[o]=(i||Ht)(e[n])}return r};var sn=Object.getOwnPropertyNames,an=Object.getOwnPropertySymbols,un=Object.prototype.hasOwnProperty;function zt(t,e){return function(n,i,o){return t(n,i,o)&&e(n,i,o)}}function Ne(t){return function(r,n,i){if(!r||!n||typeof r!="object"||typeof n!="object")return t(r,n,i);var o=i.cache,a=o.get(r),c=o.get(n);if(a&&c)return a===n&&c===r;o.set(r,n),o.set(n,r);var l=t(r,n,i);return o.delete(r),o.delete(n),l}}function Jt(t){return sn(t).concat(an(t))}var nr=Object.hasOwn||function(t,e){return un.call(t,e)};function ne(t,e){return t||e?t===e:t===e||t!==t&&e!==e}var ir="_owner",Xt=Object.getOwnPropertyDescriptor,Zt=Object.keys;function ln(t,e,r){var n=t.length;if(e.length!==n)return!1;for(;n-- >0;)if(!r.equals(t[n],e[n],n,n,t,e,r))return!1;return!0}function cn(t,e){return ne(t.getTime(),e.getTime())}function Qt(t,e,r){if(t.size!==e.size)return!1;for(var n={},i=t.entries(),o=0,a,c;(a=i.next())&&!a.done;){for(var l=e.entries(),h=!1,u=0;(c=l.next())&&!c.done;){var s=a.value,_=s[0],f=s[1],p=c.value,d=p[0],g=p[1];!h&&!n[u]&&(h=r.equals(_,d,o,u,t,e,r)&&r.equals(f,g,_,d,t,e,r))&&(n[u]=!0),u++}if(!h)return!1;o++}return!0}function fn(t,e,r){var n=Zt(t),i=n.length;if(Zt(e).length!==i)return!1;for(var o;i-- >0;)if(o=n[i],o===ir&&(t.$$typeof||e.$$typeof)&&t.$$typeof!==e.$$typeof||!nr(e,o)||!r.equals(t[o],e[o],o,o,t,e,r))return!1;return!0}function pe(t,e,r){var n=Jt(t),i=n.length;if(Jt(e).length!==i)return!1;for(var o,a,c;i-- >0;)if(o=n[i],o===ir&&(t.$$typeof||e.$$typeof)&&t.$$typeof!==e.$$typeof||!nr(e,o)||!r.equals(t[o],e[o],o,o,t,e,r)||(a=Xt(t,o),c=Xt(e,o),(a||c)&&(!a||!c||a.configurable!==c.configurable||a.enumerable!==c.enumerable||a.writable!==c.writable)))return!1;return!0}function hn(t,e){return ne(t.valueOf(),e.valueOf())}function _n(t,e){return t.source===e.source&&t.flags===e.flags}function er(t,e,r){if(t.size!==e.size)return!1;for(var n={},i=t.values(),o,a;(o=i.next())&&!o.done;){for(var c=e.values(),l=!1,h=0;(a=c.next())&&!a.done;)!l&&!n[h]&&(l=r.equals(o.value,a.value,o.value,a.value,t,e,r))&&(n[h]=!0),h++;if(!l)return!1}return!0}function pn(t,e){var r=t.length;if(e.length!==r)return!1;for(;r-- >0;)if(t[r]!==e[r])return!1;return!0}var dn="[object Arguments]",yn="[object Boolean]",vn="[object Date]",mn="[object Map]",gn="[object Number]",wn="[object Object]",xn="[object RegExp]",En="[object Set]",bn="[object String]",kn=Array.isArray,tr=typeof ArrayBuffer=="function"&&ArrayBuffer.isView?ArrayBuffer.isView:null,rr=Object.assign,Sn=Object.prototype.toString.call.bind(Object.prototype.toString);function An(t){var e=t.areArraysEqual,r=t.areDatesEqual,n=t.areMapsEqual,i=t.areObjectsEqual,o=t.arePrimitiveWrappersEqual,a=t.areRegExpsEqual,c=t.areSetsEqual,l=t.areTypedArraysEqual;return function(u,s,_){if(u===s)return!0;if(u==null||s==null||typeof u!="object"||typeof s!="object")return u!==u&&s!==s;var f=u.constructor;if(f!==s.constructor)return!1;if(f===Object)return i(u,s,_);if(kn(u))return e(u,s,_);if(tr!=null&&tr(u))return l(u,s,_);if(f===Date)return r(u,s,_);if(f===RegExp)return a(u,s,_);if(f===Map)return n(u,s,_);if(f===Set)return c(u,s,_);var p=Sn(u);return p===vn?r(u,s,_):p===xn?a(u,s,_):p===mn?n(u,s,_):p===En?c(u,s,_):p===wn?typeof u.then!="function"&&typeof s.then!="function"&&i(u,s,_):p===dn?i(u,s,_):p===yn||p===gn||p===bn?o(u,s,_):!1}}function qn(t){var e=t.circular,r=t.createCustomConfig,n=t.strict,i={areArraysEqual:n?pe:ln,areDatesEqual:cn,areMapsEqual:n?zt(Qt,pe):Qt,areObjectsEqual:n?pe:fn,arePrimitiveWrappersEqual:hn,areRegExpsEqual:_n,areSetsEqual:n?zt(er,pe):er,areTypedArraysEqual:n?pe:pn};if(r&&(i=rr({},i,r(i))),e){var o=Ne(i.areArraysEqual),a=Ne(i.areMapsEqual),c=Ne(i.areObjectsEqual),l=Ne(i.areSetsEqual);i=rr({},i,{areArraysEqual:o,areMapsEqual:a,areObjectsEqual:c,areSetsEqual:l})}return i}function Tn(t){return function(e,r,n,i,o,a,c){return t(e,r,c)}}function On(t){var e=t.circular,r=t.comparator,n=t.createState,i=t.equals,o=t.strict;if(n)return function(l,h){var u=n(),s=u.cache,_=s===void 0?e?new WeakMap:void 0:s,f=u.meta;return r(l,h,{cache:_,equals:i,meta:f,strict:o})};if(e)return function(l,h){return r(l,h,{cache:new WeakMap,equals:i,meta:void 0,strict:o})};var a={cache:void 0,equals:i,meta:void 0,strict:o};return function(l,h){return r(l,h,a)}}var or=B(),vo=B({strict:!0}),mo=B({circular:!0}),go=B({circular:!0,strict:!0}),wo=B({createInternalComparator:function(){return ne}}),xo=B({strict:!0,createInternalComparator:function(){return ne}}),Eo=B({circular:!0,createInternalComparator:function(){return ne}}),bo=B({circular:!0,createInternalComparator:function(){return ne},strict:!0});function B(t){t===void 0&&(t={});var e=t.circular,r=e===void 0?!1:e,n=t.createInternalComparator,i=t.createState,o=t.strict,a=o===void 0?!1:o,c=qn(t),l=An(c),h=n?n(l):Tn(l);return On({circular:r,comparator:l,createState:i,equals:h,strict:a})}var Er=lt(wr());var $e=class extends Error{},Vn=(t,e)=>t instanceof Object?e instanceof Object&&or(t,e):!(e instanceof Object)&&t===e,Fn=t=>{typeof window.queueMicrotask!="function"?Promise.resolve().then(t).catch(e=>setTimeout(()=>{throw e})):window.queueMicrotask(t)},xr=(t,e)=>{for(let r of e){if(r.path==="*")return{route:r,vars:!1,url:t};{let n=new Er.default(r.path).match(t);if(n)return{route:r,vars:n,url:t}}}return null},ot=class{constructor(e,r){this.root=document.createElement("div"),this.routeInfo=null,this.routes=r,this.ok=e,document.body.appendChild(this.root),window.addEventListener("popstate",this.handlePopState.bind(this)),window.addEventListener("click",this.handleClick.bind(this),!0)}handleClick(e){if(!e.defaultPrevented&&!e.ctrlKey){for(let r of e.composedPath())if(r.tagName==="A"){if(r.target.trim()!=="")return;if(r.origin===window.location.origin){let n=r.pathname+r.search+r.hash,i=xr(n,this.routes);if(i){e.preventDefault(),Bn(n,!0,!0,i);return}}}}}resolvePagePosition(e){Fn(()=>{requestAnimationFrame(()=>{let r=window.location.hash;if(r){let n=null;try{n=this.root.querySelector(r)||this.root.querySelector(`a[name="${r.slice(1)}"]`)}catch{}n?e&&n.scrollIntoView():console.warn(`MINT: ${r} matches no element with an id and no link with a name`)}else e&&window.scrollTo(0,0)})})}async handlePopState(e){let r=window.location.pathname+window.location.search+window.location.hash,n=e?.routeInfo||xr(r,this.routes);if(n){if(this.routeInfo===null||n.url!==this.routeInfo.url||!Vn(n.vars,this.routeInfo.vars)){let i=this.runRouteHandler(n);n.route.await&&await i}this.resolvePagePosition(!!e?.triggerJump)}this.routeInfo=n}async runRouteHandler(e){let{route:r}=e;if(r.path==="*")return r.handler();{let{vars:n}=e;try{let i=r.mapping.map((o,a)=>{let c=n[o],l=r.decoders[a](c);if(l instanceof this.ok)return l._0;throw new $e});return r.handler.apply(null,i)}catch(i){if(i.constructor!==$e)throw i}}}render(e,r){let n=[];for(let o in r)n.push(I(r[o],{key:o}));let i;typeof e<"u"&&(i=I(e,{key:"MINT_MAIN"})),Q([...n,i],this.root),this.handlePopState()}},Bn=(t,e=!0,r=!0,n=null)=>{let i=window.location.pathname,o=window.location.search,a=window.location.hash;if(i+o+a!==t&&(e?window.history.pushState({},"",t):window.history.replaceState({},"",t)),e){let l=new PopStateEvent("popstate");l.triggerJump=r,l.routeInfo=n,dispatchEvent(l)}},Do=(t,e,r,n=[])=>{new ot(r,n).render(t,e)};function Hn(t){return this.getChildContext=()=>t.context,t.children}function Wn(t){let e=this,r=t._container;e.componentWillUnmount=function(){Q(null,e._temp),e._temp=null,e._container=null},e._container&&e._container!==r&&e.componentWillUnmount(),e._temp||(e._container=r,e._temp={nodeType:1,parentNode:r,childNodes:[],appendChild(n){this.childNodes.push(n),e._container.appendChild(n)},insertBefore(n,i){this.childNodes.push(n),e._container.appendChild(n)},removeChild(n){this.childNodes.splice(this.childNodes.indexOf(n)>>>1,1),e._container.removeChild(n)}}),Q(I(Hn,{context:e.context},t._vnode),e._temp)}function Uo(t,e){let r=I(Wn,{_vnode:t,_container:e});return r.containerInfo=e,r}var st=class{[S](e){if(!(e instanceof this.constructor)||e.length!==this.length)return!1;if(this.record)return Ge(this,e);for(let r=0;rclass extends st{constructor(...e){if(super(),Array.isArray(t)){this.length=t.length,this.record=!0;for(let r=0;r(...e)=>new t(...e);var Go=t=>{let e=document.createElement("style");document.head.appendChild(e),e.innerHTML=t},Ko=t=>{let e={},r=(n,i)=>{e[n.toString().trim()]=i.toString().trim()};for(let n of t)if(typeof n=="string")n.split(";").forEach(i=>{let[o,a]=i.split(":");o&&a&&r(o,a)});else if(n instanceof Map||n instanceof Array)for(let[i,o]of n)r(i,o);else for(let i in n)r(i,n[i]);return e};var export_uuid=Yt.default;export{S as Equals,R as Error,Ri as access,Dt as batch,ki as bracketAccess,A as compare,Ge as compareObjects,fe as computed,I as createElement,Uo as createPortal,Wi as createProvider,qi as createRef,to as decodeArray,eo as decodeBoolean,on as decodeField,io as decodeMap,ro as decodeMaybe,Qi as decodeNumber,so as decodeObject,Xi as decodeString,Zi as decodeTime,no as decodeTuple,oo as decoder,J as destructure,te as effect,co as encodeArray,fo as encodeMap,ho as encodeMaybe,lo as encodeTime,_o as encodeTuple,po as encoder,ae as fragment,Ht as identity,Go as insertStyles,Ci as lazy,Bt as lazyComponent,Gr as load,Wt as locale,bi as mapAccess,pi as match,Bn as navigate,Bo as newVariant,Wr as normalizeEvent,Oi as or,hi as pattern,_i as patternRecord,et as patternSpread,Hr as patternVariable,Do as program,$i as setLocale,Si as setRef,D as signal,Ko as style,Gi as subscriptions,ei as testContext,Qn as testOperation,Q as testRender,ti as testRunner,Pi as toArray,Di as translate,Kr as translations,Br as useComputed,Ti as useDidUpdate,z as useEffect,Ki as useId,$ as useMemo,le as useRef,Ai as useSignal,export_uuid as uuid,Fo as variant}; diff --git a/src/app_init/app/.gitignore b/src/assets/scaffold/.gitignore similarity index 100% rename from src/app_init/app/.gitignore rename to src/assets/scaffold/.gitignore diff --git a/src/assets/scaffold/assets/bottom-center.png b/src/assets/scaffold/assets/bottom-center.png new file mode 100644 index 000000000..f7b5d9121 Binary files /dev/null and b/src/assets/scaffold/assets/bottom-center.png differ diff --git a/src/assets/scaffold/assets/bottom-left.png b/src/assets/scaffold/assets/bottom-left.png new file mode 100644 index 000000000..44f766595 Binary files /dev/null and b/src/assets/scaffold/assets/bottom-left.png differ diff --git a/src/assets/scaffold/assets/bottom-right.png b/src/assets/scaffold/assets/bottom-right.png new file mode 100644 index 000000000..c9b3836dc Binary files /dev/null and b/src/assets/scaffold/assets/bottom-right.png differ diff --git a/src/assets/scaffold/assets/favicon.png b/src/assets/scaffold/assets/favicon.png new file mode 100644 index 000000000..0ea303fa3 Binary files /dev/null and b/src/assets/scaffold/assets/favicon.png differ diff --git a/src/assets/scaffold/assets/head.html b/src/assets/scaffold/assets/head.html new file mode 100644 index 000000000..263f36679 --- /dev/null +++ b/src/assets/scaffold/assets/head.html @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/src/assets/scaffold/assets/logo.svg b/src/assets/scaffold/assets/logo.svg new file mode 100644 index 000000000..7efe69bd6 --- /dev/null +++ b/src/assets/scaffold/assets/logo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/scaffold/assets/top-center.png b/src/assets/scaffold/assets/top-center.png new file mode 100644 index 000000000..d2ee1d6d8 Binary files /dev/null and b/src/assets/scaffold/assets/top-center.png differ diff --git a/src/assets/scaffold/assets/top-left.png b/src/assets/scaffold/assets/top-left.png new file mode 100644 index 000000000..56f44ff96 Binary files /dev/null and b/src/assets/scaffold/assets/top-left.png differ diff --git a/src/assets/scaffold/assets/top-right.png b/src/assets/scaffold/assets/top-right.png new file mode 100644 index 000000000..994d3f23f Binary files /dev/null and b/src/assets/scaffold/assets/top-right.png differ diff --git a/src/assets/scaffold/source/Content.mint b/src/assets/scaffold/source/Content.mint new file mode 100644 index 000000000..690c1e62c --- /dev/null +++ b/src/assets/scaffold/source/Content.mint @@ -0,0 +1,85 @@ +component Content { + // Styles for the root element. + style root { + max-width: 72ch; + font-size: 20px; + color: #333; + + code { + padding: 0.15em 0.3em 0.1em; + border: 1px solid #EEE; + border-radius: 0.15em; + background: #F6F6F6; + font-size: 0.9em; + } + + a { + color: #56A972; + } + + h3 { + margin-top: 0; + } + + li + li { + margin-top: 0.5em; + } + + blockquote { + border-left: 3px solid #EEE; + font-style: italic; + padding-left: 15px; + font-size: 0.8em; + + margin-bottom: 0; + margin-top: 30px; + margin-left: 0; + + p { + margin: 0; + } + } + + @media (max-width: 600px) { + font-size: 16px; + + ul { + padding-left: 20px; + } + } + } + + // Renders the component. + fun render : Html { + + <<#MARKDOWN + ### Hello there 👋 + + Congratulations 🎉 You just made your first step of creating a **single + page application** with Mint by generating this example skeleton. + + You can edit any `.mint` file to make changes which will be reflected + here (this page reloads when something changes). + + Here are some links which you might find helpful going forward: + + * The [interactive tutorial] to learn Mint 🧑‍🎓 + * The [guide] with information on best practices 📚 + * The documentation of the [standard library] 📜 + * The [RealWorld] example application 💡 + + If you get stuck 🤯 you are welcome to ask questions on our [discord + server] 💬 + + > P.S. If you want to initialize an empty project (without this stuff) + use the `--bare` flag. + + [RealWorld]: https://github.com/mint-lang/mint-realworld + [interactive tutorial]: https://mint-lang.com/tutorial + [discord server]: https://discord.gg/EtApG7BGfy + [standard library]: https://mint-lang.com/api + [guide]: https://mint-lang.com/guide + MARKDOWN +
+ } +} diff --git a/src/assets/scaffold/source/Main.mint b/src/assets/scaffold/source/Main.mint new file mode 100644 index 000000000..07fa3c182 --- /dev/null +++ b/src/assets/scaffold/source/Main.mint @@ -0,0 +1,81 @@ +// This is the component which gets rendered on the screen +component Main { + // Styles for the root element. + style root { + background-image: url(#{@asset(../assets/bottom-left.png)}), + url(#{@asset(../assets/bottom-center.png)}), + url(#{@asset(../assets/bottom-right.png)}), + url(#{@asset(../assets/top-left.png)}), + url(#{@asset(../assets/top-center.png)}), + url(#{@asset(../assets/top-right.png)}); + + background-position: calc(100% + 15px) 100%, 50% 100%, -20px 100%, + -20px 0, 50% 0, calc(100% + 15px) 0; + + background-repeat: no-repeat; + background-color: white; + + box-sizing: border-box; + min-height: 100vh; + padding: 100px; + display: grid; + width: 100vw; + + font-family: Noto Sans, sans; + background-color: #FFF; + color: #333; + + @media (max-width: 600px) { + padding: 10px; + } + } + + // Styles for the content. + style content { + justify-content: center; + flex-direction: column; + align-items: center; + display: flex; + + @media (max-width: 600px) { + background: rgba(255, 255, 255, 0.5); + backdrop-filter: blur(3px); + + justify-content: space-between; + padding: 20px; + } + } + + // Styles for the footer. + style footer { + border-top: 3px double rgba(0,0,0,0.1); + padding-top: 30px; + margin-top: 30px; + max-width: 72ch; + width: 100%; + + text-align: center; + font-size: 20px; + + small { + margin-top: 5px; + font-size: 14px; + display: block; + opacity: 0.75; + } + } + + // Renders the component. + fun render : Html { + + + + + + @svg(../assets/logo.svg) + "2018 - #{Time.year(Time.now())}" +
+
+
+ } +} diff --git a/src/assets/scaffold/tests/Main.mint b/src/assets/scaffold/tests/Main.mint new file mode 100644 index 000000000..1be1f9344 --- /dev/null +++ b/src/assets/scaffold/tests/Main.mint @@ -0,0 +1,7 @@ +suite "Main" { + test "h3 has the correct content" { +
+ |> Test.Html.start() + |> Test.Html.assertTextOf("h3", "Hello there 👋") + } +} diff --git a/src/assets/sw-utils.js b/src/assets/sw-utils.js deleted file mode 100644 index ddfb55ac0..000000000 --- a/src/assets/sw-utils.js +++ /dev/null @@ -1,946 +0,0 @@ -var Mint = (function (exports) { - 'use strict'; - - function createCommonjsModule(fn, basedir, module) { - return module = { - path: basedir, - exports: {}, - require: function (path, base) { - return commonjsRequire(path, (base === undefined || base === null) ? module.path : base); - } - }, fn(module, module.exports), module.exports; - } - - function commonjsRequire () { - throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs'); - } - - var compiledGrammar = createCommonjsModule(function (module, exports) { - /* parser generated by jison 0.4.17 */ - /* - Returns a Parser object of the following structure: - - Parser: { - yy: {} - } - - Parser.prototype: { - yy: {}, - trace: function(), - symbols_: {associative list: name ==> number}, - terminals_: {associative list: number ==> name}, - productions_: [...], - performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$), - table: [...], - defaultActions: {...}, - parseError: function(str, hash), - parse: function(input), - - lexer: { - EOF: 1, - parseError: function(str, hash), - setInput: function(input), - input: function(), - unput: function(str), - more: function(), - less: function(n), - pastInput: function(), - upcomingInput: function(), - showPosition: function(), - test_match: function(regex_match_array, rule_index), - next: function(), - lex: function(), - begin: function(condition), - popState: function(), - _currentRules: function(), - topState: function(), - pushState: function(condition), - - options: { - ranges: boolean (optional: true ==> token location info will include a .range[] member) - flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match) - backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code) - }, - - performAction: function(yy, yy_, $avoiding_name_collisions, YY_START), - rules: [...], - conditions: {associative list: name ==> set}, - } - } - - - token location info (@$, _$, etc.): { - first_line: n, - last_line: n, - first_column: n, - last_column: n, - range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based) - } - - - the parseError function receives a 'hash' object with these members for lexer and parser errors: { - text: (matched text) - token: (the produced terminal token, if any) - line: (yylineno) - } - while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: { - loc: (yylloc) - expected: (string describing the set of expected tokens) - recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error) - } - */ - var parser = (function(){ - var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,9],$V1=[1,10],$V2=[1,11],$V3=[1,12],$V4=[5,11,12,13,14,15]; - var parser = {trace: function trace() { }, - yy: {}, - symbols_: {"error":2,"root":3,"expressions":4,"EOF":5,"expression":6,"optional":7,"literal":8,"splat":9,"param":10,"(":11,")":12,"LITERAL":13,"SPLAT":14,"PARAM":15,"$accept":0,"$end":1}, - terminals_: {2:"error",5:"EOF",11:"(",12:")",13:"LITERAL",14:"SPLAT",15:"PARAM"}, - productions_: [0,[3,2],[3,1],[4,2],[4,1],[6,1],[6,1],[6,1],[6,1],[7,3],[8,1],[9,1],[10,1]], - performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) { - /* this == yyval */ - - var $0 = $$.length - 1; - switch (yystate) { - case 1: - return new yy.Root({},[$$[$0-1]]) - case 2: - return new yy.Root({},[new yy.Literal({value: ''})]) - case 3: - this.$ = new yy.Concat({},[$$[$0-1],$$[$0]]); - break; - case 4: case 5: - this.$ = $$[$0]; - break; - case 6: - this.$ = new yy.Literal({value: $$[$0]}); - break; - case 7: - this.$ = new yy.Splat({name: $$[$0]}); - break; - case 8: - this.$ = new yy.Param({name: $$[$0]}); - break; - case 9: - this.$ = new yy.Optional({},[$$[$0-1]]); - break; - case 10: - this.$ = yytext; - break; - case 11: case 12: - this.$ = yytext.slice(1); - break; - } - }, - table: [{3:1,4:2,5:[1,3],6:4,7:5,8:6,9:7,10:8,11:$V0,13:$V1,14:$V2,15:$V3},{1:[3]},{5:[1,13],6:14,7:5,8:6,9:7,10:8,11:$V0,13:$V1,14:$V2,15:$V3},{1:[2,2]},o($V4,[2,4]),o($V4,[2,5]),o($V4,[2,6]),o($V4,[2,7]),o($V4,[2,8]),{4:15,6:4,7:5,8:6,9:7,10:8,11:$V0,13:$V1,14:$V2,15:$V3},o($V4,[2,10]),o($V4,[2,11]),o($V4,[2,12]),{1:[2,1]},o($V4,[2,3]),{6:14,7:5,8:6,9:7,10:8,11:$V0,12:[1,16],13:$V1,14:$V2,15:$V3},o($V4,[2,9])], - defaultActions: {3:[2,2],13:[2,1]}, - parseError: function parseError(str, hash) { - if (hash.recoverable) { - this.trace(str); - } else { - function _parseError (msg, hash) { - this.message = msg; - this.hash = hash; - } - _parseError.prototype = Error; - - throw new _parseError(str, hash); - } - }, - parse: function parse(input) { - var self = this, stack = [0], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, TERROR = 2, EOF = 1; - var args = lstack.slice.call(arguments, 1); - var lexer = Object.create(this.lexer); - var sharedState = { yy: {} }; - for (var k in this.yy) { - if (Object.prototype.hasOwnProperty.call(this.yy, k)) { - sharedState.yy[k] = this.yy[k]; - } - } - lexer.setInput(input, sharedState.yy); - sharedState.yy.lexer = lexer; - sharedState.yy.parser = this; - if (typeof lexer.yylloc == 'undefined') { - lexer.yylloc = {}; - } - var yyloc = lexer.yylloc; - lstack.push(yyloc); - var ranges = lexer.options && lexer.options.ranges; - if (typeof sharedState.yy.parseError === 'function') { - this.parseError = sharedState.yy.parseError; - } else { - this.parseError = Object.getPrototypeOf(this).parseError; - } - var lex = function () { - var token; - token = lexer.lex() || EOF; - if (typeof token !== 'number') { - token = self.symbols_[token] || token; - } - return token; - }; - var symbol, state, action, r, yyval = {}, p, len, newState, expected; - while (true) { - state = stack[stack.length - 1]; - if (this.defaultActions[state]) { - action = this.defaultActions[state]; - } else { - if (symbol === null || typeof symbol == 'undefined') { - symbol = lex(); - } - action = table[state] && table[state][symbol]; - } - if (typeof action === 'undefined' || !action.length || !action[0]) { - var errStr = ''; - expected = []; - for (p in table[state]) { - if (this.terminals_[p] && p > TERROR) { - expected.push('\'' + this.terminals_[p] + '\''); - } - } - if (lexer.showPosition) { - errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\''; - } else { - errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\''); - } - this.parseError(errStr, { - text: lexer.match, - token: this.terminals_[symbol] || symbol, - line: lexer.yylineno, - loc: yyloc, - expected: expected - }); - } - if (action[0] instanceof Array && action.length > 1) { - throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol); - } - switch (action[0]) { - case 1: - stack.push(symbol); - vstack.push(lexer.yytext); - lstack.push(lexer.yylloc); - stack.push(action[1]); - symbol = null; - { - yyleng = lexer.yyleng; - yytext = lexer.yytext; - yylineno = lexer.yylineno; - yyloc = lexer.yylloc; - } - break; - case 2: - len = this.productions_[action[1]][1]; - yyval.$ = vstack[vstack.length - len]; - yyval._$ = { - first_line: lstack[lstack.length - (len || 1)].first_line, - last_line: lstack[lstack.length - 1].last_line, - first_column: lstack[lstack.length - (len || 1)].first_column, - last_column: lstack[lstack.length - 1].last_column - }; - if (ranges) { - yyval._$.range = [ - lstack[lstack.length - (len || 1)].range[0], - lstack[lstack.length - 1].range[1] - ]; - } - r = this.performAction.apply(yyval, [ - yytext, - yyleng, - yylineno, - sharedState.yy, - action[1], - vstack, - lstack - ].concat(args)); - if (typeof r !== 'undefined') { - return r; - } - if (len) { - stack = stack.slice(0, -1 * len * 2); - vstack = vstack.slice(0, -1 * len); - lstack = lstack.slice(0, -1 * len); - } - stack.push(this.productions_[action[1]][0]); - vstack.push(yyval.$); - lstack.push(yyval._$); - newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; - stack.push(newState); - break; - case 3: - return true; - } - } - return true; - }}; - /* generated by jison-lex 0.3.4 */ - var lexer = (function(){ - var lexer = ({ - - EOF:1, - - parseError:function parseError(str, hash) { - if (this.yy.parser) { - this.yy.parser.parseError(str, hash); - } else { - throw new Error(str); - } - }, - - // resets the lexer, sets new input - setInput:function (input, yy) { - this.yy = yy || this.yy || {}; - this._input = input; - this._more = this._backtrack = this.done = false; - this.yylineno = this.yyleng = 0; - this.yytext = this.matched = this.match = ''; - this.conditionStack = ['INITIAL']; - this.yylloc = { - first_line: 1, - first_column: 0, - last_line: 1, - last_column: 0 - }; - if (this.options.ranges) { - this.yylloc.range = [0,0]; - } - this.offset = 0; - return this; - }, - - // consumes and returns one char from the input - input:function () { - var ch = this._input[0]; - this.yytext += ch; - this.yyleng++; - this.offset++; - this.match += ch; - this.matched += ch; - var lines = ch.match(/(?:\r\n?|\n).*/g); - if (lines) { - this.yylineno++; - this.yylloc.last_line++; - } else { - this.yylloc.last_column++; - } - if (this.options.ranges) { - this.yylloc.range[1]++; - } - - this._input = this._input.slice(1); - return ch; - }, - - // unshifts one char (or a string) into the input - unput:function (ch) { - var len = ch.length; - var lines = ch.split(/(?:\r\n?|\n)/g); - - this._input = ch + this._input; - this.yytext = this.yytext.substr(0, this.yytext.length - len); - //this.yyleng -= len; - this.offset -= len; - var oldLines = this.match.split(/(?:\r\n?|\n)/g); - this.match = this.match.substr(0, this.match.length - 1); - this.matched = this.matched.substr(0, this.matched.length - 1); - - if (lines.length - 1) { - this.yylineno -= lines.length - 1; - } - var r = this.yylloc.range; - - this.yylloc = { - first_line: this.yylloc.first_line, - last_line: this.yylineno + 1, - first_column: this.yylloc.first_column, - last_column: lines ? - (lines.length === oldLines.length ? this.yylloc.first_column : 0) - + oldLines[oldLines.length - lines.length].length - lines[0].length : - this.yylloc.first_column - len - }; - - if (this.options.ranges) { - this.yylloc.range = [r[0], r[0] + this.yyleng - len]; - } - this.yyleng = this.yytext.length; - return this; - }, - - // When called from action, caches matched text and appends it on next action - more:function () { - this._more = true; - return this; - }, - - // When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead. - reject:function () { - if (this.options.backtrack_lexer) { - this._backtrack = true; - } else { - return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), { - text: "", - token: null, - line: this.yylineno - }); - - } - return this; - }, - - // retain first n characters of the match - less:function (n) { - this.unput(this.match.slice(n)); - }, - - // displays already matched input, i.e. for error messages - pastInput:function () { - var past = this.matched.substr(0, this.matched.length - this.match.length); - return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); - }, - - // displays upcoming input, i.e. for error messages - upcomingInput:function () { - var next = this.match; - if (next.length < 20) { - next += this._input.substr(0, 20-next.length); - } - return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, ""); - }, - - // displays the character position where the lexing error occurred, i.e. for error messages - showPosition:function () { - var pre = this.pastInput(); - var c = new Array(pre.length + 1).join("-"); - return pre + this.upcomingInput() + "\n" + c + "^"; - }, - - // test the lexed token: return FALSE when not a match, otherwise return token - test_match:function (match, indexed_rule) { - var token, - lines, - backup; - - if (this.options.backtrack_lexer) { - // save context - backup = { - yylineno: this.yylineno, - yylloc: { - first_line: this.yylloc.first_line, - last_line: this.last_line, - first_column: this.yylloc.first_column, - last_column: this.yylloc.last_column - }, - yytext: this.yytext, - match: this.match, - matches: this.matches, - matched: this.matched, - yyleng: this.yyleng, - offset: this.offset, - _more: this._more, - _input: this._input, - yy: this.yy, - conditionStack: this.conditionStack.slice(0), - done: this.done - }; - if (this.options.ranges) { - backup.yylloc.range = this.yylloc.range.slice(0); - } - } - - lines = match[0].match(/(?:\r\n?|\n).*/g); - if (lines) { - this.yylineno += lines.length; - } - this.yylloc = { - first_line: this.yylloc.last_line, - last_line: this.yylineno + 1, - first_column: this.yylloc.last_column, - last_column: lines ? - lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : - this.yylloc.last_column + match[0].length - }; - this.yytext += match[0]; - this.match += match[0]; - this.matches = match; - this.yyleng = this.yytext.length; - if (this.options.ranges) { - this.yylloc.range = [this.offset, this.offset += this.yyleng]; - } - this._more = false; - this._backtrack = false; - this._input = this._input.slice(match[0].length); - this.matched += match[0]; - token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]); - if (this.done && this._input) { - this.done = false; - } - if (token) { - return token; - } else if (this._backtrack) { - // recover context - for (var k in backup) { - this[k] = backup[k]; - } - return false; // rule action called reject() implying the next rule should be tested instead. - } - return false; - }, - - // return next match in input - next:function () { - if (this.done) { - return this.EOF; - } - if (!this._input) { - this.done = true; - } - - var token, - match, - tempMatch, - index; - if (!this._more) { - this.yytext = ''; - this.match = ''; - } - var rules = this._currentRules(); - for (var i = 0; i < rules.length; i++) { - tempMatch = this._input.match(this.rules[rules[i]]); - if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { - match = tempMatch; - index = i; - if (this.options.backtrack_lexer) { - token = this.test_match(tempMatch, rules[i]); - if (token !== false) { - return token; - } else if (this._backtrack) { - match = false; - continue; // rule action called reject() implying a rule MISmatch. - } else { - // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) - return false; - } - } else if (!this.options.flex) { - break; - } - } - } - if (match) { - token = this.test_match(match, rules[index]); - if (token !== false) { - return token; - } - // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) - return false; - } - if (this._input === "") { - return this.EOF; - } else { - return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), { - text: "", - token: null, - line: this.yylineno - }); - } - }, - - // return next match that has a token - lex:function lex() { - var r = this.next(); - if (r) { - return r; - } else { - return this.lex(); - } - }, - - // activates a new lexer condition state (pushes the new lexer condition state onto the condition stack) - begin:function begin(condition) { - this.conditionStack.push(condition); - }, - - // pop the previously active lexer condition state off the condition stack - popState:function popState() { - var n = this.conditionStack.length - 1; - if (n > 0) { - return this.conditionStack.pop(); - } else { - return this.conditionStack[0]; - } - }, - - // produce the lexer rule set which is active for the currently active lexer condition state - _currentRules:function _currentRules() { - if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) { - return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules; - } else { - return this.conditions["INITIAL"].rules; - } - }, - - // return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available - topState:function topState(n) { - n = this.conditionStack.length - 1 - Math.abs(n || 0); - if (n >= 0) { - return this.conditionStack[n]; - } else { - return "INITIAL"; - } - }, - - // alias for begin(condition) - pushState:function pushState(condition) { - this.begin(condition); - }, - - // return the number of states currently on the stack - stateStackSize:function stateStackSize() { - return this.conditionStack.length; - }, - options: {}, - performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { - switch($avoiding_name_collisions) { - case 0:return "("; - case 1:return ")"; - case 2:return "SPLAT"; - case 3:return "PARAM"; - case 4:return "LITERAL"; - case 5:return "LITERAL"; - case 6:return "EOF"; - } - }, - rules: [/^(?:\()/,/^(?:\))/,/^(?:\*+\w+)/,/^(?::+\w+)/,/^(?:[\w%\-~\n]+)/,/^(?:.)/,/^(?:$)/], - conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6],"inclusive":true}} - }); - return lexer; - })(); - parser.lexer = lexer; - function Parser () { - this.yy = {}; - } - Parser.prototype = parser;parser.Parser = Parser; - return new Parser; - })(); - - - if (typeof commonjsRequire !== 'undefined' && 'object' !== 'undefined') { - exports.parser = parser; - exports.Parser = parser.Parser; - exports.parse = function () { return parser.parse.apply(parser, arguments); }; - } - }); - - /** @module route/nodes */ - - - /** - * Create a node for use with the parser, giving it a constructor that takes - * props, children, and returns an object with props, children, and a - * displayName. - * @param {String} displayName The display name for the node - * @return {{displayName: string, props: Object, children: Array}} - */ - function createNode(displayName) { - return function(props, children) { - return { - displayName: displayName, - props: props, - children: children || [] - }; - }; - } - - var nodes = { - Root: createNode('Root'), - Concat: createNode('Concat'), - Literal: createNode('Literal'), - Splat: createNode('Splat'), - Param: createNode('Param'), - Optional: createNode('Optional') - }; - - /** Wrap the compiled parser with the context to create node objects */ - var parser = compiledGrammar.parser; - parser.yy = nodes; - var parser_1 = parser; - - /** - * @module route/visitors/create_visitor - */ - - var nodeTypes = Object.keys(nodes); - - /** - * Helper for creating visitors. Take an object of node name to handler - * mappings, returns an object with a "visit" method that can be called - * @param {Object.} handlers A mapping of node - * type to visitor functions - * @return {{visit: function(node,context)}} A visitor object with a "visit" - * method that can be called on a node with a context - */ - function createVisitor(handlers) { - nodeTypes.forEach(function(nodeType) { - if( typeof handlers[nodeType] === 'undefined') { - throw new Error('No handler defined for ' + nodeType.displayName); - } - - }); - - return { - /** - * Call the given handler for this node type - * @param {Object} node the AST node - * @param {Object} context context to pass through to handlers - * @return {Object} - */ - visit: function(node, context) { - return this.handlers[node.displayName].call(this,node, context); - }, - handlers: handlers - }; - } - - var create_visitor = createVisitor; - - var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g; - - /** - * @class - * @private - */ - function Matcher(options) { - this.captures = options.captures; - this.re = options.re; - } - - /** - * Try matching a path against the generated regular expression - * @param {String} path The path to try to match - * @return {Object|false} matched parameters or false - */ - Matcher.prototype.match = function (path) { - var match = this.re.exec(path), - matchParams = {}; - - if( !match ) { - return; - } - - this.captures.forEach( function(capture, i) { - if( typeof match[i+1] === 'undefined' ) { - matchParams[capture] = undefined; - } - else { - matchParams[capture] = decodeURIComponent(match[i+1]); - } - }); - - return matchParams; - }; - - /** - * Visitor for the AST to create a regular expression matcher - * @class RegexpVisitor - * @borrows Visitor-visit - */ - var RegexpVisitor = create_visitor({ - 'Concat': function(node) { - return node.children - .reduce( - function(memo, child) { - var childResult = this.visit(child); - return { - re: memo.re + childResult.re, - captures: memo.captures.concat(childResult.captures) - }; - }.bind(this), - {re: '', captures: []} - ); - }, - 'Literal': function(node) { - return { - re: node.props.value.replace(escapeRegExp, '\\$&'), - captures: [] - }; - }, - - 'Splat': function(node) { - return { - re: '([^?]*?)', - captures: [node.props.name] - }; - }, - - 'Param': function(node) { - return { - re: '([^\\/\\?]+)', - captures: [node.props.name] - }; - }, - - 'Optional': function(node) { - var child = this.visit(node.children[0]); - return { - re: '(?:' + child.re + ')?', - captures: child.captures - }; - }, - - 'Root': function(node) { - var childResult = this.visit(node.children[0]); - return new Matcher({ - re: new RegExp('^' + childResult.re + '(?=\\?|$)' ), - captures: childResult.captures - }); - } - }); - - var regexp = RegexpVisitor; - - /** - * Visitor for the AST to construct a path with filled in parameters - * @class ReverseVisitor - * @borrows Visitor-visit - */ - var ReverseVisitor = create_visitor({ - 'Concat': function(node, context) { - var childResults = node.children - .map( function(child) { - return this.visit(child,context); - }.bind(this)); - - if( childResults.some(function(c) { return c === false; }) ) { - return false; - } - else { - return childResults.join(''); - } - }, - - 'Literal': function(node) { - return decodeURI(node.props.value); - }, - - 'Splat': function(node, context) { - if( context[node.props.name] ) { - return context[node.props.name]; - } - else { - return false; - } - }, - - 'Param': function(node, context) { - if( context[node.props.name] ) { - return context[node.props.name]; - } - else { - return false; - } - }, - - 'Optional': function(node, context) { - var childResult = this.visit(node.children[0], context); - if( childResult ) { - return childResult; - } - else { - return ''; - } - }, - - 'Root': function(node, context) { - context = context || {}; - var childResult = this.visit(node.children[0], context); - if( !childResult ) { - return false; - } - return encodeURI(childResult); - } - }); - - var reverse = ReverseVisitor; - - Route.prototype = Object.create(null); - - /** - * Match a path against this route, returning the matched parameters if - * it matches, false if not. - * @example - * var route = new Route('/this/is/my/route') - * route.match('/this/is/my/route') // -> {} - * @example - * var route = new Route('/:one/:two') - * route.match('/foo/bar/') // -> {one: 'foo', two: 'bar'} - * @param {string} path the path to match this route against - * @return {(Object.|false)} A map of the matched route - * parameters, or false if matching failed - */ - Route.prototype.match = function(path) { - var re = regexp.visit(this.ast), - matched = re.match(path); - - return matched ? matched : false; - - }; - - /** - * Reverse a route specification to a path, returning false if it can't be - * fulfilled - * @example - * var route = new Route('/:one/:two') - * route.reverse({one: 'foo', two: 'bar'}) -> '/foo/bar' - * @param {Object} params The parameters to fill in - * @return {(String|false)} The filled in path - */ - Route.prototype.reverse = function(params) { - return reverse.visit(this.ast, params); - }; - - /** - * Represents a route - * @example - * var route = Route('/:foo/:bar'); - * @example - * var route = Route('/:foo/:bar'); - * @param {string} spec - the string specification of the route. - * use :param for single portion captures, *param for splat style captures, - * and () for optional route branches - * @constructor - */ - function Route(spec) { - var route; - if (this) { - // constructor called with new - route = this; - } else { - // constructor called as a function - route = Object.create(Route.prototype); - } - if( typeof spec === 'undefined' ) { - throw new Error('A route spec is required'); - } - route.spec = spec; - route.ast = parser_1.parse(spec); - return route; - } - - var route = Route; - - var routeParser = route; - - function isMatchingRoute(request, routes) { - const { pathname } = new URL(request.url); - const matcher = (route) => - route == "*" || new routeParser(route).match(pathname); - return routes.some(matcher); - } - - var ServiceWorker = { isMatchingRoute }; - - exports["default"] = ServiceWorker; - exports.isMatchingRoute = isMatchingRoute; - - Object.defineProperty(exports, '__esModule', { value: true }); - - return exports; - -})({}); diff --git a/src/ast.cr b/src/ast.cr index 9ccaf28ea..b15b3c6bb 100644 --- a/src/ast.cr +++ b/src/ast.cr @@ -26,7 +26,7 @@ module Mint end def self.space_separated?(node1, node2) - node1.file.contents[node1.from, node2.from - node1.from].includes?("\n\n") + node1.file.contents[node1.to, node2.from - node1.to].count('\n') > 1 end def self.new_line?(node1, node2) diff --git a/src/ast/access.cr b/src/ast/access.cr index 89b1257e9..81b6f00c1 100644 --- a/src/ast/access.cr +++ b/src/ast/access.cr @@ -3,7 +3,7 @@ module Mint class Access < Node getter field, expression, type - # TODO: Remove in 0.21.0 when deprecation ends. + # TODO: Remove in 0.21.0. enum Type DoubleColon Colon diff --git a/src/ast/array_access.cr b/src/ast/bracket_access.cr similarity index 89% rename from src/ast/array_access.cr rename to src/ast/bracket_access.cr index ff171c66f..46a0ebac0 100644 --- a/src/ast/array_access.cr +++ b/src/ast/bracket_access.cr @@ -1,6 +1,6 @@ module Mint class Ast - class ArrayAccess < Node + class BracketAccess < Node getter index, expression def initialize(@file : Parser::File, diff --git a/src/ast/builtin.cr b/src/ast/builtin.cr new file mode 100644 index 000000000..ed20be41b --- /dev/null +++ b/src/ast/builtin.cr @@ -0,0 +1,13 @@ +module Mint + class Ast + class Builtin < Node + getter value + + def initialize(@file : Parser::File, + @value : String, + @from : Int64, + @to : Int64) + end + end + end +end diff --git a/src/ast/comment.cr b/src/ast/comment.cr index 1ac4f3cdd..8f09c8dea 100644 --- a/src/ast/comment.cr +++ b/src/ast/comment.cr @@ -1,21 +1,25 @@ module Mint class Ast - # TODO: Allow multiple comments in this node instead of a single one. class Comment < Node enum Type Inline Block end - getter content, type + getter content, type, next_comment - def initialize(@file : Parser::File, + def initialize(@next_comment : Comment?, + @file : Parser::File, @content : String, @from : Int64, @type : Type, @to : Int64) end + def block? + type == Type::Block + end + def to_html Markd.to_html(content) end diff --git a/src/ast/component.cr b/src/ast/component.cr index d89d172b3..bb80c210f 100644 --- a/src/ast/component.cr +++ b/src/ast/component.cr @@ -4,7 +4,7 @@ module Mint getter functions, gets, uses, name, comment, refs, constants getter properties, connects, styles, states, comments - getter? global, locales + getter? global, locales, async def initialize(@refs : Array(Tuple(Variable, Node)), @properties : Array(Property), @@ -20,6 +20,7 @@ module Mint @uses : Array(Use), @locales : Bool, @global : Bool, + @async : Bool, @from : Int64, @to : Int64, @name : Id) diff --git a/src/ast/defer.cr b/src/ast/defer.cr new file mode 100644 index 000000000..b2a9f299b --- /dev/null +++ b/src/ast/defer.cr @@ -0,0 +1,13 @@ +module Mint + class Ast + class Defer < Node + getter body + + def initialize(@file : Parser::File, + @from : Int64, + @body : Node, + @to : Int64) + end + end + end +end diff --git a/src/ast/directives/file_based.cr b/src/ast/directives/file_based.cr index e2d49af9b..efa880827 100644 --- a/src/ast/directives/file_based.cr +++ b/src/ast/directives/file_based.cr @@ -2,21 +2,26 @@ module Mint class Ast module Directives class FileBased < Node + # The real path of the asset on the disk. getter real_path : Path + + # The given path of the asset. getter path : String - def initialize(@file : Parser::File, - @path : String, - @from : Int64, - @to : Int64) + def initialize( + @file : Parser::File, + @path : String, + @from : Int64, + @to : Int64 + ) @real_path = Path[file.path].sibling(path).expand end # Returns the hashed filename of the target. For the build version it - # uses the the file contents of the file as the hash value to make sure - # that the file will not be cached. + # uses the the file contents as the hash value to make sure that the + # file will not be cached. def filename(*, build : Bool) : String? - return unless exists? + raise "Should not happen!" unless exists? hash_base = build ? file_contents : real_path.to_s @@ -41,16 +46,16 @@ module Mint end end - class Asset < FileBased + class HighlightFile < FileBased end class Inline < FileBased end - class Svg < FileBased + class Asset < FileBased end - class HighlightFile < FileBased + class Svg < FileBased end end end diff --git a/src/ast/member_access.cr b/src/ast/field_access.cr similarity index 69% rename from src/ast/member_access.cr rename to src/ast/field_access.cr index da863cf54..ccdb022b4 100644 --- a/src/ast/member_access.cr +++ b/src/ast/field_access.cr @@ -1,11 +1,12 @@ module Mint class Ast - class MemberAccess < Node - getter name + class FieldAccess < Node + getter name, type def initialize(@file : Parser::File, @name : Variable, @from : Int64, + @type : Type, @to : Int64) end end diff --git a/src/ast/function.cr b/src/ast/function.cr index b8a80a330..1c5fe509e 100644 --- a/src/ast/function.cr +++ b/src/ast/function.cr @@ -1,9 +1,9 @@ module Mint class Ast class Function < Node - getter name, arguments, body, type - getter comment + getter arguments, comment, name, type, body + # TOOD: Remove when the old compiler is removed. property? keep_name = false def initialize(@arguments : Array(Argument), diff --git a/src/ast/get.cr b/src/ast/get.cr index f2a6ec7a4..cd4aa3b9e 100644 --- a/src/ast/get.cr +++ b/src/ast/get.cr @@ -1,7 +1,7 @@ module Mint class Ast class Get < Node - getter name, body, type, comment + getter comment, name, body, type def initialize(@file : Parser::File, @comment : Comment?, diff --git a/src/ast/here_document.cr b/src/ast/here_document.cr index b7a7772cf..56b9d4ae3 100644 --- a/src/ast/here_document.cr +++ b/src/ast/here_document.cr @@ -1,10 +1,11 @@ module Mint class Ast class HereDocument < Node - getter value, token, modifier + getter highlight, modifier, token, value def initialize(@value : Array(String | Interpolation), @file : Parser::File, + @highlight : Bool?, @modifier : Char, @token : String, @from : Int64, diff --git a/src/ast/html_attribute.cr b/src/ast/html_attribute.cr index e7e42a3c9..1eaa04f7c 100644 --- a/src/ast/html_attribute.cr +++ b/src/ast/html_attribute.cr @@ -1,7 +1,7 @@ module Mint class Ast class HtmlAttribute < Node - getter name, value + getter value, name def initialize(@file : Parser::File, @name : Variable, diff --git a/src/ast/html_component.cr b/src/ast/html_component.cr index 6307e867e..8a157a2a5 100644 --- a/src/ast/html_component.cr +++ b/src/ast/html_component.cr @@ -1,7 +1,7 @@ module Mint class Ast class HtmlComponent < Node - getter attributes, children, component, comments, ref + getter attributes, component, children, comments, ref getter closing_tag_position property component_node : Ast::Component? = nil diff --git a/src/ast/html_element.cr b/src/ast/html_element.cr index 35a54e1e2..256a5f8b7 100644 --- a/src/ast/html_element.cr +++ b/src/ast/html_element.cr @@ -1,7 +1,7 @@ module Mint class Ast class HtmlElement < Node - getter attributes, children, styles, tag, comments, ref + getter attributes, children, comments, styles, tag, ref getter closing_tag_position property? in_component : Bool = false diff --git a/src/ast/html_fragment.cr b/src/ast/html_fragment.cr index cb2ca352f..5b1f4fd35 100644 --- a/src/ast/html_fragment.cr +++ b/src/ast/html_fragment.cr @@ -1,7 +1,7 @@ module Mint class Ast class HtmlFragment < Node - getter children, tag, comments + getter comments, children, tag def initialize(@comments : Array(Comment), @children : Array(Node), diff --git a/src/ast/html_style.cr b/src/ast/html_style.cr index 6bc9a5489..53cbc4c5a 100644 --- a/src/ast/html_style.cr +++ b/src/ast/html_style.cr @@ -1,11 +1,11 @@ module Mint class Ast class HtmlStyle < Node - getter name, arguments + getter arguments, name property style_node : Ast::Style? = nil - def initialize(@arguments : Array(Node), + def initialize(@arguments : Array(Field), @file : Parser::File, @name : Variable, @from : Int64, diff --git a/src/ast/inline_function.cr b/src/ast/inline_function.cr index b681e5132..d264f6f81 100644 --- a/src/ast/inline_function.cr +++ b/src/ast/inline_function.cr @@ -1,7 +1,7 @@ module Mint class Ast class InlineFunction < Node - getter body, arguments, type + getter arguments, body, type def initialize(@arguments : Array(Argument), @file : Parser::File, diff --git a/src/ast/locale.cr b/src/ast/locale.cr index d33f9603d..d3036f5d9 100644 --- a/src/ast/locale.cr +++ b/src/ast/locale.cr @@ -1,7 +1,7 @@ module Mint class Ast class Locale < Node - getter fields, comment, language + getter language, fields, comment def initialize(@fields : Array(Field), @file : Parser::File, diff --git a/src/ast/html_expression.cr b/src/ast/map.cr similarity index 51% rename from src/ast/html_expression.cr rename to src/ast/map.cr index 3937bb9be..bbd7514aa 100644 --- a/src/ast/html_expression.cr +++ b/src/ast/map.cr @@ -1,9 +1,10 @@ module Mint class Ast - class HtmlExpression < Node - getter expressions + class Map < Node + getter fields, types - def initialize(@expressions : Array(Node), + def initialize(@types : Tuple(Ast::Node, Ast::Node)?, + @fields : Array(MapField), @file : Parser::File, @from : Int64, @to : Int64) diff --git a/src/ast/map_field.cr b/src/ast/map_field.cr new file mode 100644 index 000000000..2735649d4 --- /dev/null +++ b/src/ast/map_field.cr @@ -0,0 +1,15 @@ +module Mint + class Ast + class MapField < Node + getter key, value, comment + + def initialize(@file : Parser::File, + @comment : Comment?, + @from : Int64, + @value : Node, + @key : Node, + @to : Int64) + end + end + end +end diff --git a/src/ast/module.cr b/src/ast/module.cr index 2e08fadeb..a40be5bc3 100644 --- a/src/ast/module.cr +++ b/src/ast/module.cr @@ -1,7 +1,7 @@ module Mint class Ast class Module < Node - getter name, functions, comment, comments, constants + getter functions, constants, comments, comment, name def initialize(@functions : Array(Function), @constants : Array(Constant), diff --git a/src/ast/node.cr b/src/ast/node.cr index 58c8945ce..b3de1313e 100644 --- a/src/ast/node.cr +++ b/src/ast/node.cr @@ -41,7 +41,7 @@ module Mint end getter file : Parser::File - + property parent : Node? property from : Int64 getter to : Int64 @@ -99,8 +99,8 @@ module Mint def self.compute_location(file : Parser::File, from, to) # TODO: avoid creating this array for every (initial) call to `Node#location` lines = [0] - file.contents.each_char_with_index do |ch, i| - lines << i + 1 if ch == '\n' + file.contents.each_char_with_index do |char, i| + lines << i + 1 if char == '\n' end Location.new( diff --git a/src/ast/operation.cr b/src/ast/operation.cr index 99190c197..da5ba2d80 100644 --- a/src/ast/operation.cr +++ b/src/ast/operation.cr @@ -1,7 +1,7 @@ module Mint class Ast class Operation < Node - getter left, right, operator + getter operator, right, left def initialize(@file : Parser::File, @operator : String, diff --git a/src/ast/pipe.cr b/src/ast/pipe.cr index 9e8a5ed12..ebd8b08d5 100644 --- a/src/ast/pipe.cr +++ b/src/ast/pipe.cr @@ -11,16 +11,16 @@ module Mint end def call - arg = - Ast::Field.new( - file: argument.file, - from: argument.from, - to: argument.to, - value: argument, - comment: nil, - key: nil) + @call ||= begin + arg = + Ast::Field.new( + file: argument.file, + from: argument.from, + to: argument.to, + value: argument, + comment: nil, + key: nil) - @call ||= case item = expression when Ast::Call Ast::Call.new( @@ -37,6 +37,7 @@ module Mint from: from, to: to) end + end end end end diff --git a/src/ast/property.cr b/src/ast/property.cr index 76b23923f..d1e5b317d 100644 --- a/src/ast/property.cr +++ b/src/ast/property.cr @@ -1,7 +1,7 @@ module Mint class Ast class Property < Node - getter name, default, type, comment + getter default, comment, type, name def initialize(@file : Parser::File, @comment : Comment?, diff --git a/src/ast/provider.cr b/src/ast/provider.cr index e1eb900dc..0357f2a41 100644 --- a/src/ast/provider.cr +++ b/src/ast/provider.cr @@ -1,8 +1,8 @@ module Mint class Ast class Provider < Node - getter subscription, functions, name, comment, comments - getter gets, states, constants + getter subscription, functions, constants, comments + getter comment, states, gets, name def initialize(@functions : Array(Function), @constants : Array(Constant), diff --git a/src/ast/record.cr b/src/ast/record.cr index 1d29b5805..95c7207c4 100644 --- a/src/ast/record.cr +++ b/src/ast/record.cr @@ -3,21 +3,11 @@ module Mint class Record < Node getter fields - UNIT = new( - file: Parser::File.new("", ""), - fields: [] of Field, - from: 0, - to: 2) - def initialize(@fields : Array(Field), @file : Parser::File, @from : Int64, @to : Int64) end - - def self.empty - UNIT - end end end end diff --git a/src/ast/record_update.cr b/src/ast/record_update.cr index bbfcbca01..dc46d3b4c 100644 --- a/src/ast/record_update.cr +++ b/src/ast/record_update.cr @@ -1,7 +1,7 @@ module Mint class Ast class RecordUpdate < Node - getter fields, expression + getter expression, fields def initialize(@expression : Ast::Node, @fields : Array(Field), diff --git a/src/ast/route.cr b/src/ast/route.cr index 169151da4..a8a6e3986 100644 --- a/src/ast/route.cr +++ b/src/ast/route.cr @@ -1,12 +1,13 @@ module Mint class Ast class Route < Node - getter url, expression, arguments + getter expression, arguments, url, await def initialize(@arguments : Array(Argument), @file : Parser::File, @expression : Block, @from : Int64, + @await : Bool, @url : String, @to : Int64) end diff --git a/src/ast/routes.cr b/src/ast/routes.cr index 6b04226ce..693c2bec4 100644 --- a/src/ast/routes.cr +++ b/src/ast/routes.cr @@ -1,7 +1,7 @@ module Mint class Ast class Routes < Node - getter routes, comments + getter comments, routes def initialize(@comments : Array(Comment), @routes : Array(Route), diff --git a/src/ast/state.cr b/src/ast/state.cr index f95ab4c60..550024181 100644 --- a/src/ast/state.cr +++ b/src/ast/state.cr @@ -1,7 +1,7 @@ module Mint class Ast class State < Node - getter default, type, name, comment + getter default, comment, type, name def initialize(@file : Parser::File, @comment : Comment?, diff --git a/src/ast/state_setter.cr b/src/ast/state_setter.cr new file mode 100644 index 000000000..351d53cf8 --- /dev/null +++ b/src/ast/state_setter.cr @@ -0,0 +1,14 @@ +module Mint + class Ast + class StateSetter < Node + getter entity, state + + def initialize(@file : Parser::File, + @state : Variable, + @from : Int64, + @entity : Id?, + @to : Int64) + end + end + end +end diff --git a/src/ast/statement.cr b/src/ast/statement.cr index 7bb8384fc..ead554d64 100644 --- a/src/ast/statement.cr +++ b/src/ast/statement.cr @@ -3,7 +3,7 @@ module Mint class Statement < Node property if_node : Ast::If? = nil - getter target, expression, await + getter expression, target, await def initialize(@file : Parser::File, @expression : Node, diff --git a/src/ast/store.cr b/src/ast/store.cr index 2f87c6fca..01dc782bf 100644 --- a/src/ast/store.cr +++ b/src/ast/store.cr @@ -1,7 +1,7 @@ module Mint class Ast class Store < Node - getter states, functions, name, gets, comment, comments, constants + getter functions, constants, comments, comment, states, gets, name def initialize(@functions : Array(Function), @constants : Array(Constant), diff --git a/src/ast/style.cr b/src/ast/style.cr index 83f3fb0b8..f2f5896b4 100644 --- a/src/ast/style.cr +++ b/src/ast/style.cr @@ -1,7 +1,7 @@ module Mint class Ast class Style < Node - getter name, body, arguments + getter arguments, body, name def initialize(@arguments : Array(Argument), @file : Parser::File, diff --git a/src/ast/suite.cr b/src/ast/suite.cr index 07c5fa7a8..66a5a5125 100644 --- a/src/ast/suite.cr +++ b/src/ast/suite.cr @@ -1,7 +1,7 @@ module Mint class Ast class Suite < Node - getter tests, name, comments, constants, functions + getter constants, functions, comments, tests, name def initialize(@constants : Array(Constant), @functions : Array(Function), diff --git a/src/ast/test.cr b/src/ast/test.cr index ab7f40100..131dafd8e 100644 --- a/src/ast/test.cr +++ b/src/ast/test.cr @@ -1,7 +1,7 @@ module Mint class Ast class Test < Node - getter name, expression + getter expression, name def initialize(@name : StringLiteral, @file : Parser::File, diff --git a/src/ast/type.cr b/src/ast/type.cr index 741b483d5..dbb9c237a 100644 --- a/src/ast/type.cr +++ b/src/ast/type.cr @@ -1,7 +1,7 @@ module Mint class Ast class Type < Node - getter name, parameters + getter parameters, name def initialize(@parameters : Array(Node), @file : Parser::File, diff --git a/src/ast/type_definition.cr b/src/ast/type_definition.cr index 98aace20d..e3a5ab697 100644 --- a/src/ast/type_definition.cr +++ b/src/ast/type_definition.cr @@ -1,7 +1,7 @@ module Mint class Ast class TypeDefinition < Node - getter name, fields, parameters, comment + getter parameters, comment, fields, name def initialize(@fields : Array(TypeDefinitionField) | Array(Ast::TypeVariant), @parameters : Array(TypeVariable), diff --git a/src/ast/type_definition_field.cr b/src/ast/type_definition_field.cr index a85753282..6be1e1eb5 100644 --- a/src/ast/type_definition_field.cr +++ b/src/ast/type_definition_field.cr @@ -1,7 +1,7 @@ module Mint class Ast class TypeDefinitionField < Node - getter key, type, mapping, comment + getter mapping, comment, type, key def initialize(@mapping : StringLiteral?, @file : Parser::File, diff --git a/src/ast/type_destructuring.cr b/src/ast/type_destructuring.cr index 093b4b7f2..138208da9 100644 --- a/src/ast/type_destructuring.cr +++ b/src/ast/type_destructuring.cr @@ -1,7 +1,7 @@ module Mint class Ast class TypeDestructuring < Node - getter name, variant, items + getter variant, items, name def initialize(@items : Array(Node), @file : Parser::File, diff --git a/src/ast/type_variant.cr b/src/ast/type_variant.cr index 1de912313..91fb7040c 100644 --- a/src/ast/type_variant.cr +++ b/src/ast/type_variant.cr @@ -1,7 +1,7 @@ module Mint class Ast class TypeVariant < Node - getter value, comment, parameters + getter parameters, comment, value def initialize(@parameters : Array(Node) | Array(TypeDefinitionField), @file : Parser::File, diff --git a/src/ast/use.cr b/src/ast/use.cr index 5860244d6..34ea98b36 100644 --- a/src/ast/use.cr +++ b/src/ast/use.cr @@ -1,7 +1,7 @@ module Mint class Ast class Use < Node - getter data, provider, condition + getter provider, condition, data def initialize(@file : Parser::File, @condition : Node?, diff --git a/src/builder.cr b/src/builder.cr deleted file mode 100644 index cbb190e20..000000000 --- a/src/builder.cr +++ /dev/null @@ -1,220 +0,0 @@ -module Mint - class Builder - def initialize(relative, skip_manifest, skip_service_worker, skip_icons, optimize, inline, runtime_path, watch) - build(relative, skip_manifest, skip_service_worker, skip_icons, optimize, inline, runtime_path) - - if watch - watch_workspace(relative, skip_manifest, skip_service_worker, skip_icons, optimize, inline, runtime_path) - end - end - - def build(relative, skip_manifest, skip_service_worker, skip_icons, optimize, inline, runtime_path) - json = MintJson.parse_current - - if !skip_icons && !Process.find_executable("convert") - terminal.puts("#{WARNING} ImageMagick is not installed, skipping icon generation...") - skip_icons = true - end - - json.check_dependencies! - - terminal.measure "#{COG} Clearing the \"#{DIST_DIR}\" directory..." do - FileUtils.rm_rf DIST_DIR - end - - if Dir.exists?(PUBLIC_DIR) - terminal.measure "#{COG} Copying \"#{PUBLIC_DIR}\" folder contents..." do - FileUtils.cp_r PUBLIC_DIR, DIST_DIR - end - else - FileUtils.mkdir DIST_DIR - end - - terminal.puts "#{COG} Compiling your application:" - - index_js, artifacts = - index(json.application.css_prefix, relative, optimize, runtime_path, json.web_components) - - unless inline - File.write Path[DIST_DIR, "index.js"], index_js - - if SourceFiles.external_javascripts? - terminal.measure "#{COG} Writing external javascripts..." do - File.write Path[DIST_DIR, "external-javascripts.js"], - SourceFiles.external_javascripts - end - end - - if SourceFiles.external_stylesheets? - terminal.measure "#{COG} Writing external stylesheets..." do - File.write Path[DIST_DIR, "external-stylesheets.css"], - SourceFiles.external_stylesheets - end - end - end - - unless artifacts.assets.empty? - asset_path = - Path[DIST_DIR, ASSET_DIR].to_s - - FileUtils.mkdir(asset_path) unless Dir.exists?(asset_path) - - terminal.puts "#{COG} Writing assets..." - - assets = - artifacts.assets.uniq(&.real_path).select!(&.exists?) - - assets.each do |asset| - filename = - asset.filename(build: true).not_nil! - - dest_path = - Path[DIST_DIR, ASSET_DIR, filename] - - terminal.puts " #{ARROW} #{filename}" - - File.write dest_path, asset.file_contents - end - end - - terminal.measure "#{COG} Writing index.html..." do - File.write Path[DIST_DIR, "index.html"], - IndexHtml.render(:build, relative, skip_manifest, skip_service_worker, skip_icons, inline, index_js) - end - - unless skip_manifest - terminal.measure "#{COG} Writing manifest.webmanifest..." do - File.write Path[DIST_DIR, "manifest.webmanifest"], - manifest(json, skip_icons) - end - end - - unless skip_icons - terminal.measure "#{COG} Generating icons..." do - icons(json) - end - end - - unless skip_service_worker - terminal.measure "#{COG} Creating service worker..." do - File.write Path[DIST_DIR, "service-worker.js"], - service_worker(artifacts, relative, optimize) - end - end - end - - def manifest(json, skip_icons) - application = json.application - { - "name" => application.name, - "short_name" => application.name, - "background_color" => application.theme, - "theme_color" => application.theme, - "display" => application.display, - "orientation" => application.orientation, - "start_url" => "/", - "icons" => manifest_icons(skip_icons), - }.to_pretty_json - end - - private def manifest_icons(skip_icons) - return %w[] if skip_icons - - ICON_SIZES.map do |size| - { - "src" => "icon-#{size}x#{size}.png", - "sizes" => "#{size}x#{size}", - "type" => "image/png", - } - end - end - - def icons(json) - ICON_SIZES.each do |size| - destination = - Path[DIST_DIR, "icon-#{size}x#{size}.png"] - - icon = - IconGenerator.convert(json.application.icon, size) - - File.write(destination, icon) - end - end - - def index(css_prefix, relative, optimize, runtime_path, web_components) - runtime = - if runtime_path - Cli.runtime_file_not_found(runtime_path) unless File.exists?(runtime_path) - File.read(runtime_path) - else - Assets.read("runtime.js") - end - - sources = - Dir.glob(SourceFiles.all) - - ast = - Ast.new - .merge(Core.ast) - - terminal.measure " #{ARROW} Parsing #{sources.size} source files..." do - sources.reduce(ast) do |memo, file| - memo.merge Parser.parse(file) - end - end - - type_checker = - TypeChecker.new(ast, web_components: web_components.keys) - - terminal.measure " #{ARROW} Type checking..." do - type_checker.check - end - - compiled = nil - - terminal.measure " #{ARROW} Compiling..." do - compiled = Compiler.compile type_checker.artifacts, { - web_components: web_components, - css_prefix: css_prefix, - relative: relative, - optimize: optimize, - build: true, - } - end - - {runtime + compiled.to_s, type_checker.artifacts} - end - - def watch_workspace(relative, skip_manifest, skip_service_worker, skip_icons, optimize, inline, runtime_path) - workspace = Workspace.current - - workspace.on "change" do |result| - case result - when Ast - terminal.reset - terminal.puts "Rebuilding for production" - terminal.divider - build(relative, skip_manifest, skip_service_worker, skip_icons, optimize, inline, runtime_path) - terminal.divider - when Error - end - end - - workspace.update_cache - workspace.watch - end - - def get_service_worker_utils - Assets.read("sw-utils.js") - end - - def terminal - Render::Terminal::STDOUT - end - - def service_worker(artifacts, relative, optimize) - worker = ServiceWorker.new(artifacts, relative, optimize) - "#{get_service_worker_utils}#{worker}" - end - end -end diff --git a/src/bundler.cr b/src/bundler.cr new file mode 100644 index 000000000..ce8bbd017 --- /dev/null +++ b/src/bundler.cr @@ -0,0 +1,452 @@ +require "csv" + +module Mint + # This class is responsible for compiling and building the application. + class Bundler + alias Bundle = Compiler2::Bundle + + record Config, + test : NamedTuple(url: String, id: String)?, + generate_manifest : Bool, + include_program : Bool, + runtime_path : String?, + live_reload : Bool, + hash_assets : Bool, + skip_icons : Bool, + relative : Bool, + optimize : Bool + + # The end result of the bundling. It contains the all the files for the + # application. + getter files = {} of String => Proc(String) + + # The artifacts to bundle. + getter artifacts : TypeChecker::Artifacts + + # The bundle configuration. + getter config : Config + + # The application configuration. + getter json : MintJson + + # Contains the names of the bundles. + getter bundle_names = {} of Ast::Node | Bundle => String + + delegate application, to: json + + def initialize(*, @config, @artifacts, @json) + @bundle_counter = 0 + end + + def bundle + Logger.log "Building application" { generate_application } + Logger.log "Building index.html" { generate_index_html } + Logger.log "Building manifest" { generate_manifest } if config.generate_manifest + Logger.log "Building icons" { generate_icons } unless config.skip_icons + Logger.log "Building assets" { generate_assets } + + files + end + + def generate_application + compiler = + Compiler2.new(artifacts, application.css_prefix, config) + + Logger.log "Compiling intermediate representation..." do + # Gather all top level entities and resolve them, this will populate the + # `compiled` instance variable of the compiler. + (artifacts.ast.type_definitions + + artifacts.ast.unified_modules + + artifacts.ast.components + + artifacts.ast.providers + + artifacts.ast.stores).tap { |items| compiler.resolve(items) } + end + + # Compile the CSS. + files[path_for_asset("index.css")] = + ->do + Logger.log "Building index.css" do + compiler.style_builder.compile + end + end + + tests = + if test_information = config.test + # Compile tests if there is configration for it. + Logger.log "Compiling tests" do + [ + compiler.test(test_information[:url], test_information[:id]), + ] + end + end + + # This holds the to be compiled constants per bundle. `Bundle::Index` holds + # the ones meant for the main bundle. + bundles = + { + Bundle::Index => ([] of Tuple(Ast::Node, Compiler2::Id, Compiler2::Compiled)), + } of Ast::Node | Bundle => Array(Tuple(Ast::Node, Compiler2::Id, Compiler2::Compiled)) + + # This holds which node belongs to which bundle. + scopes = + {} of Ast::Node => Ast::Node + + # Gather all of the IDs so we can use it to filter out imports later on. + ids = + compiler.compiled.map { |(_, id, _)| id } + + Logger.log "Calculating dependencies for bundles..." do + # Calculate the bundles. + artifacts.references.calculate(artifacts.ast.nodes.to_set) + end + + Logger.log "Bundling and rendering JavaScript..." do + # Here we separate the compiled items to each bundle. + artifacts.references.bundles.each do |node, dependencies| + bundles[node] = + dependencies.flat_map do |dependency| + compiler.compiled.select { |item| item[0] == dependency } + end + + bundles[node].try(&.each do |item| + case node + when Ast::Node + scopes[item[0]] = node + end + end) + end + + # Here we add async components to a bundle so they can be loaded + # and referenced in the virtual DOM. + artifacts + .ast + .nodes + .select(Ast::HtmlComponent) + .select(&.component_node.try(&.async?)) + .map { |item| {item.component_node.not_nil!, artifacts.references.bundle_of(item)} } + .uniq! + .map do |(component, bundle)| + bundles[bundle]?.try(&.unshift({ + component, + component, + compiler.js.call( + Compiler2::Builtin::Lazy, + [[Compiler2::Deferred.new(component)] of Compiler2::Item]), + })) + end + + class_pool = + NamePool(Ast::Node | Compiler2::Builtin, Ast::Node | Bundle).new('A'.pred.to_s) + + pool = + NamePool(Compiler2::Variable | + Compiler2::Encoder | + Compiler2::Decoder | + Ast::Node | + String, Ast::Node | Bundle).new + + rendered_bundles = + {} of Ast::Node | Bundle => Tuple(Compiler2::Renderer, Array(String)) + + # We render the bundles so we can know after what we need to import. + bundles.each do |node, contents| + renderer = + Compiler2::Renderer.new( + bundle_path: ->path_for_bundle(Ast::Node | Bundle), + deferred_path: ->bundle_name(Ast::Node | Bundle), + references: artifacts.references, + class_pool: class_pool, + base: node, + pool: pool) + + # Built the singe `const` with multiple assignments so we can add + # things later to the array. + items = + if contents.empty? + [] of Compiler2::Compiled + else + # Here we sort the compiled node by the order they are resovled, which + # will prevent issues of one entity depending on others (like a const + # depending on a function from a module). + contents.sort_by! do |(node, id, _)| + case id + when Ast::TypeVariant + -2 if id.value.value.in?("Just", "Nothing", "Err", "Ok") + end || artifacts.resolve_order.index(node) || -1 + end + + [["export "] + compiler.js.consts(contents)] + end + + # If we are building the main bundle we add the translations, tests + # and the program. + case node + when Bundle::Index + # Add translations and tests + items.concat compiler.translations + items.concat tests if tests + + # Add the program if needed. + items << compiler.program if config.include_program + end + + # Render the final JavaScript. + items = + items.reject(&.empty?).map { |item| renderer.render(item) } + + rendered_bundles[node] = {renderer, items} + end + + rendered_bundles.each do |node, (renderer, items)| + case node + when Bundle::Index + # Index doesn't import from other nodes. + else + # This holds the imports for each other bundle. + imports = + {} of Ast::Node | Bundle => Hash(String, String) + + renderer.used.map do |item| + # We only need to import things that are actually exported (all + # other entities show up here like function arguments statement + # variables, etc...) + next unless ids.includes?(item) + + case item + when Ast::Component + next if item.async? + end + + # Get where the entity should be. + target = + scopes[item]? || Bundle::Index + + # If the target is not this bundle and it's not the same bundle + # then we need to import. + if target != node && item != node + exported_name = + rendered_bundles[target][0].render(item).to_s + + imported_name = + renderer.render(item).to_s + + imports[target] ||= {} of String => String + imports[target][exported_name] = imported_name + end + end + + # For each import we insert an import statement. + imports.each do |target, data| + items.unshift( + renderer.import( + data, + config.optimize, + path_for_import(target))) + end + + case node + when Ast::Node + items << "export default #{renderer.render(node)}" if node + end + end + + # Gather what builtins need to be imported and add it's statement + # as well. + builtins = + renderer + .builtins + .each_with_object({} of String => String) do |item, memo| + memo[item.to_s.camelcase(lower: true)] = renderer.class_pool.of(item, node) + end + + items + .unshift(renderer.import(builtins, config.optimize, "./runtime.js")) + .reject!(&.blank?) + + js = + if items.empty? + "" + elsif config.optimize + items.join(";") + else + items.join(";\n\n") + ";" + end + + files[path_for_bundle(node)] = ->{ js } + end + end + end + + def generate_index_html + files["index.html"] = ->do + HtmlBuilder.build(optimize: config.optimize) do + html do + head do + meta charset: application.meta["charset"]? || "utf-8" + + if config.generate_manifest + link rel: "manifest", href: "manifest.webmanifest" + end + + application.meta.each do |name, content| + next if name == "charset" + meta name: name, content: content + end + + unless application.theme.blank? + meta name: "theme-color", content: application.theme + end + + if generate_icons? + ICON_SIZES.each do |size| + link href: path_for_asset("icon-#{size}x#{size}.png"), + size: "#{size}x#{size}", + type: "image/png", + rel: "icon" + end + + {152, 167, 180}.each do |size| + link href: path_for_asset("icon-#{size}x#{size}.png"), + rel: "apple-touch-icon-precomposed" + end + end + + link rel: "stylesheet", href: path_for_asset("index.css") + raw application.head + end + + body do + if config.live_reload + script src: path_for_asset("live-reload.js") + end + + script type: "module" do + raw <<-TEXT + import Program from "#{path_for_asset("index.js")}" + Program() + TEXT + end + + noscript do + text "This application requires JavaScript." + end + + if item = config.test + script do + raw %(window.TEST_ID = "#{item[:id]}";) + end + + div id: "root" + end + end + end + end + end + end + + def generate_manifest + files["manifest.webmanifest"] = ->do + icons = + if generate_icons? + ICON_SIZES.map do |size| + { + "src" => "icon-#{size}x#{size}.png", + "sizes" => "#{size}x#{size}", + "type" => "image/png", + } + end + else + %w[] + end + { + "orientation" => application.orientation, + "display" => application.display, + "background_color" => application.theme, + "theme_color" => application.theme, + "name" => application.name, + "short_name" => application.name, + "icons" => icons, + "start_url" => "/", + }.to_pretty_json + end + end + + def generate_icons? + !config.skip_icons && + Process.find_executable("convert") && + File.exists?(json.application.icon) + end + + def generate_icons + return unless generate_icons? + + ICON_SIZES.each do |size| + files[path_for_asset("icon-#{size}x#{size}.png")] = + ->{ IconGenerator.convert(json.application.icon, size) } + end + end + + def generate_assets + artifacts + .assets + .uniq(&.real_path) + .select!(&.exists?) + .each do |asset| + path = + path_for_asset(asset.filename(build: config.hash_assets)) + + files[path] = ->{ asset.file_contents } + end + + if Dir.exists?(PUBLIC_DIR) + Dir.glob(Path[PUBLIC_DIR, "**", "*"]).each do |path| + next if File.directory?(path) + + parts = + Path[path].parts.tap(&.shift) + + files["/#{parts.join("/")}"] = ->{ File.read(path) } + end + end + + files[path_for_asset("runtime.js")] = + if runtime_path = config.runtime_path + ->{ File.read(runtime_path) } + elsif config.test + ->{ Assets.read("runtime_test.js") } + else + ->{ Assets.read("runtime.js") } + end + + if config.live_reload + files[path_for_asset("live-reload.js")] = + ->{ Assets.read("live-reload.js") } + end + end + + def path_for_asset(filename : String) : String + "#{config.relative ? "" : "/"}#{ASSET_DIR}/#{filename}" + end + + def bundle_name(node : Ast::Node | Bundle) : String + @bundle_names[node] ||= begin + case node + when Ast::Directives::FileBased + node.filename(build: config.hash_assets) + when Bundle::Index + "index.js" + else + "#{@bundle_counter += 1}.js" + end + end + end + + def path_for_import(node : Ast::Node | Bundle) : String + "./#{bundle_name(node)}" + end + + def path_for_bundle(node : Ast::Node | Bundle) : String + path_for_asset(bundle_name(node)) + end + end +end diff --git a/src/cli.cr b/src/cli.cr index 327a75f52..e4543dc0a 100644 --- a/src/cli.cr +++ b/src/cli.cr @@ -9,12 +9,11 @@ module Mint class Cli < Admiral::Command include Command - define_help description: "Mint" + define_help description: "Mint Programming Language" register_sub_command "sandbox-server", type: SandboxServer register_sub_command highlight, type: Highlight register_sub_command install, type: Install - register_sub_command compile, type: Compile register_sub_command version, type: Version register_sub_command format, type: Format register_sub_command build, type: Build @@ -23,7 +22,6 @@ module Mint register_sub_command init, type: Init register_sub_command lint, type: Lint register_sub_command test, type: Test - register_sub_command docs, type: Docs register_sub_command loc, type: Loc register_sub_command ls, type: Ls diff --git a/src/commands/build.cr b/src/commands/build.cr index 3b925b80c..d49f1b1e3 100644 --- a/src/commands/build.cr +++ b/src/commands/build.cr @@ -3,58 +3,133 @@ module Mint class Build < Admiral::Command include Command - define_help description: "Builds the project for production" + define_help description: "Builds the project for production." + + define_flag runtime : String, + description: "If specified, the supplied runtime will be used instead of the default." + + define_flag no_optimize : Bool, + description: "If specified, the resulting JavaScript code will not be optimized.", + default: false define_flag relative : Bool, - description: "If specified the URLs in the index.html will be in relative format", + description: "If specified, the URLs in the HTML will be in relative format.", default: false, short: "r" - define_flag skip_manifest : Bool, - description: "If specified the web manifest will not be generated", + define_flag skip_icons : Bool, + description: "If specified, the application icons will not be generated.", default: false - define_flag skip_service_worker : Bool, - description: "If specified the service worker functionality will be disabled", + define_flag generate_manifest : Bool, + description: "If specified, the web manifest will be generated.", default: false - define_flag skip_icons : Bool, - description: "If specified the application icons will not be generated", + define_flag verbose : Bool, + description: "If specified, all written files will be logged.", default: false - define_flag minify : Bool, - description: "If specified the resulting JavaScript code will be minified", - default: true, - short: "m" - - define_flag inline : Bool, - description: "If specified the JavaScript and CSS will be inlined with the html", - default: false, - short: "i" - - define_flag runtime : String, - description: "Will use supplied runtime path instead of the default distribution", - required: false - define_flag watch : Bool, - description: "Enables watch mode for build", + description: "If specified, will build on every change.", default: false, short: "w" + define_flag env : String, + description: "Loads the given .env file.", + short: "e" + + define_flag timings : Bool, + description: "If specified, timings will be printed.", + default: false + def run - execute "Building for production" do - Builder.new( - flags.relative, - flags.skip_manifest, - flags.skip_service_worker, - flags.skip_icons, - flags.minify, - flags.inline, - flags.runtime, - flags.watch - ) + execute "Building for production...", env: flags.env do + # Initialize the workspace from the current working directory. + # We don't check everything to speed things up so only the hot + # path is checked. + workspace = Workspace.current + workspace.check_everything = false + workspace.check_env = true + + # Check if we have dependencies installed. + workspace.json.check_dependencies! + + # On any change we copy the build to the dist directory. + workspace.on("change") do |result| + terminal.reset if flags.watch + + case result + in Ast + terminal.puts "Building for production..." + terminal.divider + + terminal.measure %(#{COG} Clearing the "#{DIST_DIR}" directory...") do + FileUtils.rm_rf DIST_DIR + end + + files = + terminal.measure "#{COG} Building..." do + Bundler.new( + artifacts: workspace.type_checker.artifacts, + json: workspace.json, + config: Bundler::Config.new( + generate_manifest: flags.generate_manifest, + skip_icons: flags.skip_icons, + optimize: !flags.no_optimize, + runtime_path: flags.runtime, + relative: flags.relative, + include_program: true, + live_reload: false, + hash_assets: true, + test: nil)).bundle + end || {} of String => Proc(String) + + bundle_size = 0 + + files.keys.sort_by!(&.size).reverse!.each do |path| + chopped = + path.lchop('/') + + content = + files[path].call + + size = + content.bytesize + + proc = + ->{ File.write_p(Path[DIST_DIR, chopped], content) } + + bundle_size += + size + + if flags.verbose + terminal.measure "#{COG} Writing #{chopped} (#{size.humanize_bytes(format: :JEDEC)})..." do + proc.call + end + else + proc.call + end + end + + terminal.divider + terminal.puts "Bundle size: #{bundle_size.humanize_bytes(format: :JEDEC)}" + terminal.puts "Files: #{files.size}" + + if flags.timings + terminal.divider + Logger.print(terminal) + end + in Error + terminal.print result.to_terminal + end + end + + # Do the initial parsing and type checking. + workspace.update_cache + # Start wathing for changes if the flag is set. if flags.watch + workspace.watch sleep end end diff --git a/src/commands/clean.cr b/src/commands/clean.cr index 304513ca4..4def28636 100644 --- a/src/commands/clean.cr +++ b/src/commands/clean.cr @@ -3,16 +3,15 @@ module Mint class Clean < Admiral::Command include Command - define_help description: "Removes artifacts (directories) created by Mint" + define_help description: "Removes artifacts (directories) created by Mint." - define_flag global : Bool, - description: "If specified, cleans global artifacts used to cache Mint packages", - default: false, - short: "g" + define_flag package_cache : Bool, + description: "If specified, cleans the package cache directory.", + default: false def run execute "Removing directories" do - ArtifactCleaner.clean flags.global + ArtifactCleaner.clean flags.package_cache end end end diff --git a/src/commands/command.cr b/src/commands/command.cr index a2202bc17..9ada0fb3b 100644 --- a/src/commands/command.cr +++ b/src/commands/command.cr @@ -1,13 +1,7 @@ module Mint class Cli < Admiral::Command module Command - macro included - define_flag env : String, - description: "Loads the given .env file", - short: "e" - end - - def execute(message, &) + def execute(message, *, env : String? = nil, & : -> T) : T? forall T # On Ctrl+C and abort and exit Signal::INT.trap do terminal.puts @@ -25,14 +19,17 @@ module Mint position = terminal.position + # Have a variable for the result of the command. + result = nil + begin # Load environment variables - Env.init(flags.env) do |file| + Env.init(env) do |file| terminal.puts "#{COG} Loaded environment variables from: #{file}" end # Measure elapsed time of a command - elapsed = Time.measure { yield } + elapsed = Time.measure { result = yield } rescue CliException # In case of a CLI exception just exit error nil, position @@ -51,6 +48,8 @@ module Mint # Print all done mssage terminal.divider terminal.puts "All done in #{formatted}!" + + result end # Handles an error diff --git a/src/commands/compile.cr b/src/commands/compile.cr deleted file mode 100644 index 1cdca52cc..000000000 --- a/src/commands/compile.cr +++ /dev/null @@ -1,77 +0,0 @@ -module Mint - class Cli < Admiral::Command - class Compile < Admiral::Command - include Command - - define_help description: "Compiles the project into a single JavaScript file" - - define_flag output : String, - description: "The output file", - default: "program.js", - required: false, - short: "o" - - define_flag minify : Bool, - description: "If specified the resulting JavaScript code will be minified", - default: true, - short: "m" - - define_flag runtime : String, - description: "Will use supplied runtime path instead of the default distribution", - required: false - - def run - execute "Compiling" do - File.write(flags.output, compile(flags.minify, flags.runtime)) - end - end - - def compile(optimize, runtime_path) - json = - MintJson.parse_current - - runtime = - if runtime_path - Cli.runtime_file_not_found(runtime_path) unless File.exists?(runtime_path) - File.read(runtime_path) - else - Assets.read("runtime.js") - end - - sources = - Dir.glob(SourceFiles.all) - - ast = - Ast.new - .merge(Core.ast) - - terminal.measure " #{ARROW} Parsing #{sources.size} source files..." do - sources.reduce(ast) do |memo, file| - memo.merge Parser.parse(file) - end - end - - type_checker = - TypeChecker.new(ast, web_components: json.web_components.keys) - - terminal.measure " #{ARROW} Type checking..." do - type_checker.check - end - - compiled = nil - - terminal.measure " #{ARROW} Compiling..." do - compiled = Compiler.compile_embed type_checker.artifacts, { - css_prefix: json.application.css_prefix, - web_components: json.web_components, - relative: false, - optimize: optimize, - build: true, - } - end - - runtime + compiled.to_s - end - end - end -end diff --git a/src/commands/docs.cr b/src/commands/docs.cr deleted file mode 100644 index 27220ffb4..000000000 --- a/src/commands/docs.cr +++ /dev/null @@ -1,17 +0,0 @@ -module Mint - class Cli < Admiral::Command - class Docs < Admiral::Command - include Command - - define_help description: "Starts the documentation server" - - register_sub_command generate, type: DocsGenerate - - def run - execute "Running the documentation server" do - DocumentationServer.start - end - end - end - end -end diff --git a/src/commands/docs_generate.cr b/src/commands/docs_generate.cr deleted file mode 100644 index 1b1f68384..000000000 --- a/src/commands/docs_generate.cr +++ /dev/null @@ -1,36 +0,0 @@ -module Mint - class Cli < Admiral::Command - class DocsGenerate < Admiral::Command - include Command - - define_help description: "Starts the documentation server" - - define_flag output : String, - description: "The output filename", - default: "docs.json", - required: false, - short: "o" - - def run - execute "Generating Documentation" do - current = - MintJson.parse_current - - ast = - Ast.new - - current.source_files.each do |file| - ast.merge(Parser.parse(File.read(file), file)) - end - - ast.normalize - - json = - DocumentationGenerator.new.generate(current, ast) - - File.write(flags.output, json) - end - end - end - end -end diff --git a/src/commands/format.cr b/src/commands/format.cr index 7b02fda0a..dfc41a509 100644 --- a/src/commands/format.cr +++ b/src/commands/format.cr @@ -3,30 +3,56 @@ module Mint class Format < Admiral::Command include Command - define_help description: "Formats source files" + # The status of a file. + enum Status + NotFormatted + Formatted + Same + end - define_argument pattern, - description: "The pattern which determines which files to format" + define_help description: "Formats .mint files." - define_flag stdin : Bool, - description: "Formats Mint code from STDIN", - default: false + define_argument pattern : String, + description: "The pattern which determines which files to format." define_flag check : Bool, - description: "Checks that formatting code produces no changes", + description: "Checks that formatting code produces no changes.", + default: false + + define_flag stdin : Bool, + description: "Formats code from STDIN and writes it to STDOUT.", default: false def run if flags.stdin format_stdin else - all_formatted = true + failed = + execute "Formatting files" do + result = + format_files - execute "Formatting files" do - all_formatted = format_files - end + if result.empty? + terminal.puts "Nothing to format!" + else + if result.all?(&.first.==(Status::Same)) + terminal.puts "All files are formatted!" + else + result.each do |(status, file)| + case status + when Status::NotFormatted + terminal.puts "Not formatted: #{file}" + when Status::Formatted + terminal.puts "Formatted: #{file}" + end + end + end + end + + result.any?(&.first.==(Status::NotFormatted)) + end - exit(1) if flags.check && !all_formatted + exit(1) if flags.check && failed end end @@ -38,67 +64,46 @@ module Mint Parser.parse(input, "stdin.mint") formatted = - Formatter.new(MintJson.parse_current.formatter_config).format(artifact) + Formatter.new(config).format(artifact) terminal.puts formatted rescue error : Error - error(error.to_terminal, terminal.position) + error error.to_terminal, terminal.position end private def format_files - current = - MintJson.parse_current? - - files = - if pattern_argument = arguments.pattern.presence - Dir.glob(pattern_argument) - elsif current - format_directories = - current.source_directories | current.test_directories - - format_directories_patterns = - format_directories.map do |dir| - SourceFiles.glob_pattern(dir) - end - Dir.glob(format_directories_patterns) + pattern = + arguments.pattern.presence || json.try do |item| + (item.source_directories | item.test_directories) + .map(&->SourceFiles.glob_pattern(String)) end - if files.try(&.empty?) - terminal.puts "Nothing to format!" - true - else - all_formatted = true + Dir.glob(pattern || "").map do |file| + artifact = + Parser.parse(file) - files.not_nil!.each do |file| - artifact = - Parser.parse(file) + formatted = + Formatter.new(config).format(artifact) - config = - if current - MintJson.parse_current.formatter_config - else - Formatter::Config.new - end - - formatted = - Formatter.new(config).format(artifact) + next {Status::Same, file} if formatted == File.read(file) - unless formatted == File.read(file) - if flags.check - terminal.puts "Not formatted: #{file}" - else - File.write(file, formatted) - terminal.puts "Formatted: #{file}" - end - all_formatted = false - end + if flags.check + {Status::NotFormatted, file} + else + File.write(file, formatted) + {Status::Formatted, file} end - - terminal.puts "All files are formatted!" if all_formatted - all_formatted end - rescue error : Error - raise error + end + + # We try to honor the config of the current project but + # allow for formatting without one using defaults. + private def config + json.try(&.formatter_config) || Formatter::Config.new + end + + private def json + MintJson.parse_current? end end end diff --git a/src/commands/highlight.cr b/src/commands/highlight.cr index 6b1195f0a..64f4f5957 100644 --- a/src/commands/highlight.cr +++ b/src/commands/highlight.cr @@ -3,12 +3,12 @@ module Mint class Highlight < Admiral::Command include Command - define_help description: "Returns the syntax highlighted version of the given file" + define_help description: "Returns the syntax highlighted version of the given file." - define_argument path, description: "The path to the file" + define_argument path, description: "The path to the file." define_flag html : Bool, - description: "If specified, print the highlighted code as HTML", + description: "If specified, print the highlighted code as HTML.", default: false def run diff --git a/src/commands/init.cr b/src/commands/init.cr index 0fe980e28..0374d894f 100644 --- a/src/commands/init.cr +++ b/src/commands/init.cr @@ -3,22 +3,25 @@ module Mint class Init < Admiral::Command include Command - define_help description: "Initializes a new project" + define_help description: "Initializes a new project." + + define_flag bare : Bool, + description: "If speficied, an empty project will be generated.", + default: false define_argument name, - description: "The name of the new project", - required: false + description: "The name of the new project." def run - name = arguments.name.presence - if name - execute "Initializing a new project" do - Scaffold.run(name) - end - else - execute "Please provide project name" do - terminal.puts "Example: mint init my-project-name" - end + execute "Initializing a new project" do + name = arguments.name.presence + + loop do + terminal.puts "Please provide a name for the project (for example my-project):" + break if name = gets.presence + end unless name + + Scaffold.new(name: name, bare: flags.bare) if name end end end diff --git a/src/commands/install.cr b/src/commands/install.cr index 33bc6fd55..e761d987a 100644 --- a/src/commands/install.cr +++ b/src/commands/install.cr @@ -3,10 +3,10 @@ module Mint class Install < Admiral::Command include Command - define_help description: "Installs dependencies" + define_help description: "Installs dependencies." def run - execute "Installing dependencies" do + execute "Installing dependencies." do Installer.new end end diff --git a/src/commands/lint.cr b/src/commands/lint.cr index e6b991633..5c1a3027f 100644 --- a/src/commands/lint.cr +++ b/src/commands/lint.cr @@ -3,23 +3,20 @@ module Mint class Lint < Admiral::Command include Command - define_help description: "Lints the project for syntax and type errors" + define_help description: "Lints the project for syntax and type errors." define_flag json : Bool, - description: "Output errors in a JSON format", - default: false, - required: false + description: "Output errors in a JSON format.", + default: false def run - succeeded = nil - if flags.json - Colorize.enabled = false - succeeded = lint - else - execute "Linting" do - succeeded = lint + succeeded = + if flags.json + lint + else + execute "Linting" { lint } end - end + exit(1) unless succeeded end @@ -29,52 +26,39 @@ module Mint sources.reduce(ast) do |memo, file| begin - parsed = - Parser.parse(file) - - memo.merge(parsed) - rescue ex - errors << ex + memo.merge(Parser.parse(file)) + rescue error : Error + errors << error end + memo end - rescue ex - errors << ex end protected def type_check(ast, errors) : Nil - type_checker = - TypeChecker.new(ast) - - loop do - type_checker.check - rescue ex - errors << ex - else - break - end - rescue ex - errors << ex + TypeChecker.new(ast).tap(&.check) + rescue error : Error + errors << error end def lint - errors = [] of Exception + errors = + [] of Error ast = - Ast.new - .merge(Core.ast) + Ast.new.merge(Core.ast) parse(ast, errors) type_check(ast, errors) if errors.empty? if flags.json - terminal.puts errors.compact_map(&.message.presence).to_json + terminal.puts errors.compact_map(&.to_terminal.to_s.uncolorize).to_json else if errors.empty? terminal.puts "No errors were detected!" else errors.each do |error| - terminal.puts error + terminal.print error.to_terminal end end end diff --git a/src/commands/loc.cr b/src/commands/loc.cr index 26b803ebb..2224d4687 100644 --- a/src/commands/loc.cr +++ b/src/commands/loc.cr @@ -3,10 +3,10 @@ module Mint class Loc < Admiral::Command include Command - define_help description: "Counts Lines of Code" + define_help description: "Counts Lines of Code." def run - execute "Counting Lines of Code" do + execute "Counting Lines of Code." do file_count = files.size.to_s.colorize.mode(:bold) @@ -18,17 +18,14 @@ module Mint end end - def files + private def files Dir.glob(SourceFiles.all).to_a end - def count + private def count files.reduce(0) do |memo, file| count = - File - .read(file) - .lines - .count(&.presence) + File.read(file).lines.count(&.presence) count + memo end diff --git a/src/commands/ls.cr b/src/commands/ls.cr index 1a45f9eb3..67de589ed 100644 --- a/src/commands/ls.cr +++ b/src/commands/ls.cr @@ -1,12 +1,14 @@ module Mint class Cli < Admiral::Command class Ls < Admiral::Command - define_help description: "Language Server" + define_help description: "Language Server." def run - Colorize.enabled = false + Colorize.enabled = + false - server = LS::Server.new(STDIN, STDOUT) + server = + LS::Server.new(STDIN, STDOUT) loop do server.read diff --git a/src/commands/sandbox_server.cr b/src/commands/sandbox_server.cr index 934e67a55..82b556dff 100644 --- a/src/commands/sandbox_server.cr +++ b/src/commands/sandbox_server.cr @@ -1,27 +1,25 @@ module Mint class Cli < Admiral::Command class SandboxServer < Admiral::Command - define_help description: "Server for compiling sandbox applications" + include Command + + define_help description: "Server for compiling sandbox applications." define_flag host : String, - description: "Change the host the server binds to. (Default: 0.0.0.0)", + description: "The host the server binds to.", default: ENV["HOST"]? || "0.0.0.0", - required: false, short: "h" define_flag port : Int32, - description: "Change the port the server binds to. (Default: 3003)", + description: "The port the server binds to.", default: (ENV["PORT"]? || "3003").to_i, - required: false, short: "p" - define_flag runtime : String, - description: "Will use supplied runtime path instead of the default distribution", - required: false - def run - server = Mint::SandboxServer.new(flags.host, flags.port, flags.runtime) - server.start + execute "Running the sandbox server" do + # NOTE: The command and the server itself has the same name. + Mint::SandboxServer.new(flags.host, flags.port) + end end end end diff --git a/src/commands/start.cr b/src/commands/start.cr index 7ede9d61a..e8fceec66 100644 --- a/src/commands/start.cr +++ b/src/commands/start.cr @@ -3,34 +3,38 @@ module Mint class Start < Admiral::Command include Command - define_help description: "Starts the development server" + define_help description: "Starts the development server." - define_flag auto_format : Bool, - description: "Auto formats the source files when running development server", - required: false, + define_flag format : Bool, + description: "Formats the source files when they change.", default: false + define_flag reload : Bool, + description: "Reload the browser when something changes.", + default: true, + short: "r" + define_flag host : String, - description: "Change the host to serve the application on. (Default: 127.0.0.1)", - default: ENV["HOST"]? || "127.0.0.1", - required: false, + description: "The host to serve the application on.", + default: ENV["HOST"]? || "0.0.0.0", short: "h" define_flag port : Int32, - description: "Change the port to serve the application on. (Default: 3000)", + description: "The port to serve the application on.", default: (ENV["PORT"]? || "3000").to_i, - required: false, short: "p" - define_flag live_reload : Bool, - description: "Whether or not to reload the browser when something changes. (Default true)", - required: false, - default: true, - short: "r" + define_flag env : String, + description: "Loads the given .env file.", + short: "e" def run - execute "Running the development server" do - Reactor.start flags.host, flags.port, flags.auto_format, flags.live_reload + execute "Running the development server", env: flags.env do + Reactor.new( + format: flags.format, + reload: flags.reload, + host: flags.host, + port: flags.port) end end end diff --git a/src/commands/test.cr b/src/commands/test.cr index 08ee705a2..af2458abd 100644 --- a/src/commands/test.cr +++ b/src/commands/test.cr @@ -3,75 +3,63 @@ module Mint class Test < Admiral::Command include Command - define_help description: "Runs the tests" + define_help description: "Runs the tests defined for the project." - define_flag manual : Bool, - description: "Start the test server for manual testing", - default: false, - short: "m" + define_flag runtime : String, + description: "If specified, the supplied runtime will be used instead of the default." define_flag browser : String, - description: "Which browser to run the tests in (chrome, firefox)", + description: "Which browser to run the tests in (chrome, firefox).", default: "chrome", short: "b" + define_flag browser_host : String, + description: "Target host, useful when hosted on another machine.", + default: ENV["BROWSER_HOST"]? || "127.0.0.1", + short: "x" + + define_flag browser_port : Int32, + description: "Target port, useful when hosted on another machine.", + default: (ENV["BROWSER_PORT"]? || "3001").to_i, + short: "c" + define_flag reporter : String, - description: "Which reporter to use (dot, documentation)", + description: "Which reporter to use (dot, documentation),", default: "dot", short: "r" + define_flag manual : Bool, + description: "Start the test server for manual testing.", + default: false, + short: "m" + + define_flag watch : Bool, + description: "Watch files for changes and rerun tests." + define_flag host : String, - description: "Host to serve the tests on. (Default: 127.0.0.1)", + description: "Host to serve the tests on.", default: ENV["HOST"]? || "127.0.0.1", - required: false, short: "h" define_flag port : Int32, - description: "Port to serve the tests on. (Default: 3001)", + description: "Port to serve the tests on.", default: (ENV["PORT"]? || "3001").to_i, - required: false, short: "p" - define_flag browser_host : String, - description: "Target host, useful when hosted on another machine. (Default: 127.0.0.1)", - default: ENV["BROWSER_HOST"]? || "127.0.0.1", - required: false, - short: "x" - - define_flag browser_port : Int32, - description: "Target port, useful when hosted on another machine. (Default: 3001)", - default: (ENV["BROWSER_PORT"]? || "3001").to_i, - required: false, - short: "c" - - define_flag runtime : String, - description: "Will use supplied runtime path instead of the default distribution", - required: false - - define_flag watch : Bool, - description: "Watch files for changes and rerun tests", - required: false + define_flag env : String, + description: "Loads the given .env file.", + short: "e" define_argument test : String, - description: "The path to the test file to run" + description: "The path to the test file to run." def run - MintJson.parse_current.check_dependencies! - runner = - TestRunner.new(flags, arguments) - - if flags.watch - runner.watch - else - succeeded = nil - - execute "Running Tests" do - succeeded = runner.run + execute "Running Tests", env: flags.env do + TestRunner.new(flags, arguments) end - exit(1) unless succeeded - end + exit(1) if runner.try(&.failed?) end end end diff --git a/src/commands/version.cr b/src/commands/version.cr index 40ac42b63..ca9e795c8 100644 --- a/src/commands/version.cr +++ b/src/commands/version.cr @@ -3,7 +3,7 @@ module Mint class Version < Admiral::Command include Command - define_help description: "Shows version" + define_help description: "Shows version." def run terminal.puts "Mint #{Mint::VERSION}" diff --git a/src/compiler2.cr b/src/compiler2.cr new file mode 100644 index 000000000..e302ea13c --- /dev/null +++ b/src/compiler2.cr @@ -0,0 +1,362 @@ +module Mint + class Compiler2 + include Helpers + + # Represents a compiled item + alias Item = Ast::Node | Builtin | String | Signal | Indent | Raw | + Variable | Ref | Encoder | Decoder | Asset | Deferred + + # Represents an generated idetifier from the parts of the union type. + alias Id = Ast::Node | Variable | Encoder | Decoder + + # Represents compiled code. + alias Compiled = Array(Item) + + # Represents an reference to a file + record Asset, value : Ast::Node | Bundle + + # Represents an reference to a deferred file + record Deferred, value : Ast::Node + + # Represents a Preact signal (https://preactjs.com/guide/v10/signals/). Signals are treated + # differently from vaiables because we will need to access them using the `.value` accessor. + record Signal, value : Ast::Node + + # Represents a reference to an HTML element or other component. They are treated differently + # because they have a `.current` accessor. + record Ref, value : Ast::Node + + # Represents code which needs to be indented. + record Indent, items : Compiled + + # Represents raw code (which does not get modified or indented). + record Raw, value : String + + # Represents a variable. + class Variable; end + + # Represents an encoder. + class Encoder; end + + # Represents a decoder. + class Decoder; end + + enum Bundle + Index + end + + # Builtin functions in the runtime. + enum Builtin + # Pattern matching. + PatternVariable + PatternSpread + PatternRecord + Destructure + Pattern + Match + + # Type variants. + NewVariant + Variant + + # Rendering. + CreateElement + LazyComponent + CreatePortal + Fragment + Lazy + + # Effects. + UseDidUpdate + UseComputed + UseFunction + UseEffect + CreateRef + UseSignal + Computed + UseMemo + UseRef + Signal + Batch + + # Providers. + CreateProvider + Subscriptions + UseId + Uuid + + # Encoders. + EncodeTuple + EncodeArray + EncodeMaybe + EncodeTime + EncodeMap + Encoder + + # Decoders. + DecodeBoolean + DecodeObject + DecodeString + DecodeNumber + DecodeField + DecodeMaybe + DecodeArray + DecodeTuple + DecodeTime + DecodeMap + Decoder + + # Navigation and program. + Navigate + Program + + # Utilities. + NormalizeEvent + BracketAccess + MapAccess + Identity + ToArray + Compare + Define + SetRef + Access + Curry + Load + Or + + # Styles and CSS. + InsertStyles + Style + + # Test + TestOperation + TestContext + TestRender + TestRunner + + # Translations + Translations + Translate + SetLocale + Locale + end + + delegate record_field_lookup, ast, components_touched, to: artifacts + delegate resolve_order, variables, cache, lookups, to: artifacts + + # Contains the generated encoders. + getter encoders = Hash(TypeChecker::Checkable, Compiled).new + + # Contains the generated decoders. + getter decoders = Hash(TypeChecker::Checkable, Compiled).new + + # A set to track already rendered nodes. + getter touched : Set(Ast::Node) = Set(Ast::Node).new + + # Contains the compiled JavaScript tree. + getter compiled = [] of Tuple(Ast::Node, Id, Compiled) + + # The type checker artifacts. + getter artifacts : TypeChecker::Artifacts + + # The style builder instance. + getter style_builder : StyleBuilder + + # The compiler config. + getter config : Bundler::Config + + # The JavaScript builder instance. + getter js : Js + + def initialize(@artifacts, css_prefix, @config) + @js = + Js.new(optimize: config.optimize) + + @style_builder = + StyleBuilder.new(css_prefix: css_prefix, optimize: config.optimize) + end + + # Adds a compiled entity. + def add(node : Ast::Node, id : Id, value : Compiled) + compiled << {node, id, value} + end + + # Adds multiple compiled entities. + def add(items : Array(Tuple(Ast::Node, Id, Compiled) | Nil)) + items.compact.each { |(node, id, compiled)| add(node, id, compiled) } + end + + # Compiles a node. If the node is already compiled or not checked it + # returns an empty compiled node. + def compile(node : Ast::Node, &) : Compiled + if touched.includes?(node) || !node.in?(artifacts.checked) + [] of Item + else + yield.tap { touched.add(node) } + end + end + + # Compiles multiple nodes and joins them with the separator. + def compile(nodes : Array(Ast::Node), separator : String) : Compiled + compile(nodes).intersperse([separator]).flatten + end + + # Compiles multiple nodes. + def compile(nodes : Array(Ast::Node)) : Array(Compiled) + nodes.map { |node| compile(node) } + end + + # Fallback for compiling a node. + def compile(node : Ast::Node) : Compiled + raise "Missing compiler for: #{node.class.to_s.upcase}" + end + + # Resolves a top-level node. + def resolve(node : Ast::Node, &) + return unless node.in?(artifacts.checked) + return if touched.includes?(node) + touched.add(node) + yield + end + + # Resolves top-level nodes. + def resolve(nodes : Array(Ast::Node)) + nodes.map { |node| resolve(node) } + end + + # Fallback resolving nodes. + def resolve(node : Ast::Node) + puts "Missing resolver for: #{node.class.to_s.upcase}" + nil + end + + # Translations + def translations + mapped = + artifacts + .locales + .each_with_object({} of String => Hash(String, Compiled)) do |(key, data), memo| + data.each do |language, node| + if node.in?(artifacts.checked) + memo[language] ||= {} of String => Compiled + memo[language]["'#{key}'"] = compile(node) + end + end + end + + object = + mapped.each_with_object({} of String => Compiled) do |(language, tokens), memo| + memo[language] = js.object(tokens) + end + + if object.empty? + [[] of Item] + else + [ + js.assign([Builtin::Translations, ".value"] of Item, js.object(object)), + js.assign([Builtin::Locale, ".value"] of Item, js.string(object.keys.first)), + ] + end + end + + # Compiles the program call. + def program + main.try do |component| + routes = + compile(ast.routes.flat_map(&.routes)) + + globals = + ast + .components + .select(&.global?) + .each_with_object({} of Item => Compiled) do |item, memo| + memo[item.as(Item)] = [item] of Item + end + + ["export default "] + js.arrow_function do + js.call(Builtin::Program, [ + [component] of Item, + js.object(globals), + ok, + js.array(routes), + ]) + end + end || [] of Item + end + + def inject_css(css : String) + js.call(Builtin::InsertStyles, [[%(`#{css}`)] of Item]) + end + + # Compile test runner. + def test(url, id) + suites = + compile(ast.suites) + + ["export default "] + js.arrow_function do + js.new(Builtin::TestRunner, [ + js.array(suites), + js.string(url), + js.string(id), + ]) + end + end + + # These functions are for looking up entities that the runtime uses + # (Just, Nothing, Err, Ok, Main). + + def main + ast.components.find(&.name.value.==("Main")) + end + + def maybe + ast + .type_definitions + .find!(&.name.value.==("Maybe")) + .tap { |node| resolve node } + end + + def result + ast + .type_definitions + .find!(&.name.value.==("Result")) + .tap { |node| resolve node } + end + + def just + [ + maybe + .fields + .as(Array(Ast::TypeVariant)) + .find!(&.value.value.==("Just")), + ] of Item + end + + def nothing + [ + maybe + .fields + .as(Array(Ast::TypeVariant)) + .find!(&.value.value.==("Nothing")), + ] of Item + end + + def ok + [ + result + .fields + .as(Array(Ast::TypeVariant)) + .find!(&.value.value.==("Ok")), + ] of Item + end + + def err + [ + result + .fields + .as(Array(Ast::TypeVariant)) + .find!(&.value.value.==("Err")), + ] of Item + end + end +end diff --git a/src/compiler2/decoder.cr b/src/compiler2/decoder.cr new file mode 100644 index 000000000..1f63d8dad --- /dev/null +++ b/src/compiler2/decoder.cr @@ -0,0 +1,64 @@ +module Mint + class Compiler2 + def decoder(type : TypeChecker::Record) + @decoders[type] ||= begin + node = + ast.type_definitions.find!(&.name.value.==(type.name)) + + item = + type + .fields + .each_with_object({} of String => Compiled) do |(key, value), memo| + decoder = + self.decoder value + + if mapping = type.mappings[key]? + decoder = js.array([decoder, [%("#{mapping}")] of Item]) + end + + memo[key] = decoder + end + + [ + Decoder.new.tap do |id| + add node, id, js.call(Builtin::Decoder, [js.object(item), ok, err]) + end, + ] of Item + end + end + + def decoder(type : TypeChecker::Type) : Compiled + case type.name + when "Array" + js.call(Builtin::DecodeArray, [decoder(type.parameters.first), ok, err]) + when "Map" + js.call(Builtin::DecodeMap, [decoder(type.parameters.last), ok, err]) + when "Bool" + js.call(Builtin::DecodeBoolean, [ok, err]) + when "Number" + js.call(Builtin::DecodeNumber, [ok, err]) + when "String" + js.call(Builtin::DecodeString, [ok, err]) + when "Time" + js.call(Builtin::DecodeTime, [ok, err]) + when "Object" + js.call(Builtin::DecodeObject, [ok]) + when "Maybe" + js.call( + Builtin::DecodeMaybe, + [decoder(type.parameters.first), ok, err, just, nothing]) + when "Tuple" + decoders = + type.parameters.map { |item| decoder(item) } + + js.call(Builtin::DecodeTuple, [js.array(decoders), ok, err]) + else + raise "Cannot generate a decoder for #{type}!" + end + end + + def decoder(node : TypeChecker::Variable) + raise "Cannot generate a decoder for a type variable!" + end + end +end diff --git a/src/compiler2/encoder.cr b/src/compiler2/encoder.cr new file mode 100644 index 000000000..22e90835f --- /dev/null +++ b/src/compiler2/encoder.cr @@ -0,0 +1,54 @@ +module Mint + class Compiler2 + def encoder(type : TypeChecker::Record) : Compiled + @encoders[type] ||= begin + node = + ast.type_definitions.find!(&.name.value.==(type.name)) + + item = + type + .fields + .each_with_object({} of String => Compiled) do |(key, value), memo| + encoder = + self.encoder value + + if mapping = type.mappings[key]? + encoder = js.array([encoder, [%("#{mapping}")] of Item]) + end + + memo[key] = encoder + end + + [ + Encoder.new.tap do |id| + add node, id, js.call(Builtin::Encoder, [js.object(item)]) + end, + ] of Item + end + end + + def encoder(type : TypeChecker::Type) : Compiled + case type.name + when "Maybe" + js.call(Builtin::EncodeMaybe, [encoder(type.parameters.first), just]) + when "Array" + js.call(Builtin::EncodeArray, [encoder(type.parameters.first)]) + when "Map" + js.call(Builtin::EncodeMap, [encoder(type.parameters.last)]) + when "Time" + [Builtin::EncodeTime] of Item + when "Tuple" + encoders = + type.parameters.map { |item| encoder(item) } + + js.call(Builtin::EncodeTuple, [js.array(encoders)]) + else + [Builtin::Identity] of Item + end + end + + def encoder(node : TypeChecker::Variable) + raise "Cannot generate an encoder for a type variable!" + end + end +end diff --git a/src/compiler2/js.cr b/src/compiler2/js.cr new file mode 100644 index 000000000..7007127f8 --- /dev/null +++ b/src/compiler2/js.cr @@ -0,0 +1,217 @@ +module Mint + class Compiler2 + # This class is resposible for creating a tree of JS code + class Js + # Whether or not to optimize the output. + getter? optimize : Bool = false + + def initialize(@optimize) + end + + # Renders an object. The key can be any item but it's usually a string + # or an identifier. + def object(items : Hash(Item, Compiled)) : Compiled + return ["{}"] of Item if items.empty? + + fields = + join( + items.map { |key, value| [key, optimize? ? ":" : ": "] + value }, + optimize? ? "," : ",\n") + + block(fields) + end + + def null : Compiled + ["null"] of Item + end + + def string(value : String) : Compiled + ["`", Raw.new(value.gsub('`', "\\`").gsub("${", "\\${`")), "`"] of Item + end + + # Renders an object destructuring. + def object_destructuring(items : Array(Compiled)) : Compiled + return ["{}"] of Item if items.empty? + + block(join(items, optimize? ? "," : ",\n")) + end + + # Renders a call. + def call(name : Item | Compiled, arguments : Array(Compiled)) : Compiled + case name + in Compiled + name + ["("] + list(arguments) + [")"] + in Item + [name, "("] + list(arguments) + [")"] + end + end + + # Renders an array. + def array(items : Array(Compiled)) : Compiled + if optimize? || items.size <= 1 + ["["] + list(items) + ["]"] + else + ["[", Indent.new(["\n"] + list(items, multiline: true)), "\n]"] of Item + end + end + + # Renders statements. + def statements(items : Array(Compiled)) : Compiled + join(items.reject(&.empty?), optimize? ? ";" : ";\n") + end + + # Renders a const assignment. + def const(name : Item | Compiled, value : Compiled) : Compiled + ["const "] + assign(name, value) + end + + # Renders multiple const assignments (as one). + def consts(items : Array(Tuple(Ast::Node, Id, Compiled))) : Compiled + if items.size == 1 + _, id, value = + items[0] + + const id, value + else + assigns = + items.map { |(_, id, compiled)| assign(id, compiled) } + + if optimize? + ["const "] + list(assigns, multiline: false) + else + ["const"] + [Indent.new(["\n"] + list(assigns, multiline: true))] of Item + end + end + end + + # Renders an initializer. + def new(name : Item | Compiled, items : Array(Compiled) = [] of Compiled) : Compiled + ["new "] + call(name, items) + end + + # Renders a let assignment with multiple variables. + def let(variables : Array(Variable)) : Compiled + ["let "] + variables.map(&.as(Item)).intersperse(optimize? ? "," : ", ") + end + + # Renders a let assignment. + def let(name : Item | Compiled, value : Compiled) : Compiled + ["let "] + assign(name, value) + end + + # Renders an assignment. + def assign(name : Item | Compiled, value : Compiled) : Compiled + case name + in Compiled + name + [optimize? ? "=" : " = "] + value + in Item + ([name, optimize? ? "=" : " = "] of Item) + value + end + end + + # Renders an if statement. + def if(condition : Compiled, body : Compiled) : Compiled + ["if", optimize? ? "(" : " ("] + condition + [optimize? ? ")" : ") "] + + block(body) + end + + # Renders an tenary operator. + def tenary(condition : Compiled, truthy : Compiled, falsy : Compiled) + ["("] + + condition + + [optimize? ? "?" : " ? "] + + truthy + + [optimize? ? ":" : " : "] + + falsy + + [")"] + end + + # Renders a for statement. + def for(variables : Compiled, subject : Compiled, &) : Compiled + ["for", optimize? ? "(" : " ("] + + variables + + [" of "] + + subject + + [optimize? ? ")" : ") "] + + block(yield) + end + + # Renders a return statement. + def return(item : Compiled) : Compiled + ["return "] + item + end + + # Renders an async immediately invoked function. + def asynciif(&) : Compiled + function([] of Compiled, async: true, invoke: true) { yield } + end + + # Renders an async immediately invoked function. + def iif(&) : Compiled + function([] of Compiled, async: false, invoke: true) { yield } + end + + # Renders an async arrow function. + def async_arrow_function(arguments : Array(Compiled) = [] of Compiled, &) : Compiled + function(arguments, async: true, invoke: false) { yield } + end + + # Renders an arrow function. + def arrow_function(arguments : Array(Compiled) = [] of Compiled, &) : Compiled + function(arguments, async: false, invoke: false) { yield } + end + + # Renders an list (separated by commas). + private def list(arguments : Array(Compiled), *, multiline : Bool = false) : Compiled + if multiline + join(arguments, ",\n") + else + join(arguments, optimize? ? "," : ", ") + end + end + + # Renders a function. + private def function( + arguments : Array(Compiled) = [] of Compiled, *, + async : Bool, invoke : Bool, & + ) + keyword = + if async + "async " + else + "" + end + + items = + block(yield) + + head, tail, parens = + if invoke + ["(", ")", "()"] + else + ["", "", ""] + end + + [head, keyword, "("] + + list(arguments) + + [optimize? ? ")=>" : ") => "] + + items + + [tail, parens] + end + + # Renders a block ({...}). + private def block(items : Compiled) : Compiled + if optimize? + ["{"] + items + ["}"] + else + [Indent.new(["{\n"] + items), "\n}"] of Item + end + end + + # Joins the items with the given separator. + private def join(items : Array(Compiled), separator : String) : Compiled + items.reject(&.empty?).intersperse([separator]).flatten + end + end + end +end diff --git a/src/compiler2/renderer.cr b/src/compiler2/renderer.cr new file mode 100644 index 000000000..793c201de --- /dev/null +++ b/src/compiler2/renderer.cr @@ -0,0 +1,124 @@ +module Mint + class Compiler2 + # This class is responsible to render `Compiled` code. + class Renderer + # The pool for variables (lowercase). + getter pool : NamePool(Ast::Node | Variable | String | Encoder | Decoder, Ast::Node | Bundle) + + # The pool for class variables (uppercase). + getter class_pool : NamePool(Ast::Node | Builtin, Ast::Node | Bundle) + + # A set to track nodes which we rendered. + getter used = Set(Ast::Node | Encoder | Decoder).new + + # A set to track used builtins which will be imported. + getter builtins = Set(Builtin).new + + getter references : ReferencesTracker + getter base : Ast::Node | Bundle + + getter deferred_path : Proc(Ast::Node | Bundle, String) + getter bundle_path : Proc(Ast::Node | Bundle, String) + + # The current indentation depth. + property depth : Int32 = 0 + + def initialize(*, @base, @pool, @class_pool, @bundle_path, @deferred_path, @references) + end + + def import(imports : Hash(String, String), optimize : Bool, path : String) + return "" if imports.empty? + + items = + imports + .map do |(key, value)| + if key == value + key + else + "#{key} as #{value}" + end + end + .sort_by!(&.size).reverse! + + if items.size > 1 && !optimize + %(import {\n#{items.join(",\n").indent}\n} from "#{path}") + else + %(import { #{items.join(",")} } from "#{path}") + end + end + + def render(items : Compiled) : String + String.build do |io| + render(items, io) + end + end + + def render(items : Compiled, io : IO) + items.each do |item| + render(item, io) + end + end + + # We are using a string builder to build the final compiled code. + def render(item : Item, io : IO = IO::Memory.new) + case item + in Signal + used.add(item.value) + + # Signals are special becuse we need to use the `.value` accessor. + io << "#{pool.of(item.value, base)}.value" + in Ref + # Signals are special becuse we need to use the `.current` accessor. + io << "#{pool.of(item.value, base)}.current" + in Ast::Node + scope = + case item + when Ast::Property + references.bundle_of(item) + end || base + + used.add(item) + + # Nodes are compiled into variables. + case item + when Ast::TypeVariant, + Ast::Component, + Ast::Provider + io << class_pool.of(item, scope) + # io << "/* #{Debugger.dbg(item)} */" + else + io << pool.of(item, scope) + end + in Encoder, Decoder + used.add(item) + + io << pool.of(item, base) + in Variable + io << pool.of(item, base) + in Builtin + io << class_pool.of(item, base) + + # We track the builtins here. + builtins.add(item) + in Raw + io << item.value + in String + # Only strings need to be indented, and we copy everything and when + # there is a new line we add the indentation after. + item.each_char do |char| + io << char + io << (" " * depth * 2) if char == '\n' + end + in Deferred + io << "`./#{deferred_path.call(item.value)}`" + in Asset + io << "`#{bundle_path.call(item.value)}`" + in Indent + self.depth += 1 + render(item.items, io) + self.depth -= 1 + end + end + end + end +end diff --git a/src/compiler2/utils.cr b/src/compiler2/utils.cr new file mode 100644 index 000000000..485234b64 --- /dev/null +++ b/src/compiler2/utils.cr @@ -0,0 +1,103 @@ +module Mint + class Compiler2 + def self.tokens_to_lines(ast : Ast) + parts = + SemanticTokenizer.tokenize(ast) + + lines = + [ + [] of String | Tuple(SemanticTokenizer::TokenType, String), + ] + + index = 0 + + processor = + ->(str : String, item : String | Tuple(SemanticTokenizer::TokenType, String)) { + if str.includes?("\n") + parts = + str.split("\n") + + parts.each_with_index do |part, part_index| + not_last = + part_index < (parts.size - 1) + + case item + in String + lines[index].push(not_last ? part.as(String) + "\n" : part) + in Tuple(SemanticTokenizer::TokenType, String) + lines[index].push({item[0], part.as(String)}) + end + + if not_last + index += 1 + lines << [] of String | Tuple(SemanticTokenizer::TokenType, String) + end + end + else + lines[index].push(item) + end + } + + parts.each do |item| + case item + in String + processor.call(item, item) + in Tuple(SemanticTokenizer::TokenType, String) + processor.call(item[1], item) + end + end + + lines + end + + def tokenize(ast : Ast) + mapped = + Compiler2 + .tokens_to_lines(ast) + .map do |parts| + items = + parts.map do |item| + case item + in String + js.string(item) + in Tuple(SemanticTokenizer::TokenType, String) + js.call(Builtin::CreateElement, [ + [%("span")] of Item, + js.object({"className".as(Item) => [ + %("#{item[0].to_s.underscore}"), + ] of Item}), + js.array([js.string(item[1])]), + ]) + end + end + + js.call(Builtin::CreateElement, [ + [%("span")] of Item, + js.object({"className".as(Item) => [%("line")] of Item}), + js.array(items), + ]) + end + + js.call(Builtin::CreateElement, [ + [Builtin::Fragment] of Item, + ["{}"] of Item, + js.array(mapped), + ]) + end + + def parse_svg(contents) + document = + XML.parse(contents) + + svg = + document.first_element_child + + if svg + data = + svg.children.join.strip + + {svg["width"]?, svg["height"]?, svg["viewBox"]?, data} + end + end + end +end diff --git a/src/compilers/array_access.cr b/src/compilers/bracket_access.cr similarity index 90% rename from src/compilers/array_access.cr rename to src/compilers/bracket_access.cr index deccf0763..ea8561e26 100644 --- a/src/compilers/array_access.cr +++ b/src/compilers/bracket_access.cr @@ -1,6 +1,6 @@ module Mint class Compiler - def _compile(node : Ast::ArrayAccess) : String + def _compile(node : Ast::BracketAccess) : String type = cache[node.expression] diff --git a/src/compilers/call.cr b/src/compilers/call.cr index 318473fcb..742f6009c 100644 --- a/src/compilers/call.cr +++ b/src/compilers/call.cr @@ -5,7 +5,7 @@ module Mint compile node.expression arguments = - compile node.arguments.sort_by { |item| argument_order.index(item) || -1 }, ", " + compile node.arguments.sort_by { |item| resolve_order.index(item) || -1 }, ", " case when node.expression.is_a?(Ast::InlineFunction) diff --git a/src/compilers/directives/highlight.cr b/src/compilers/directives/highlight.cr index 3a007045f..dc8a45f77 100644 --- a/src/compilers/directives/highlight.cr +++ b/src/compilers/directives/highlight.cr @@ -17,20 +17,13 @@ module Mint parts.map do |item| case item in String - "`#{skip { escape_for_javascript(item) }}`" + "`#{skip { item.escape_for_javascript }}`" in Tuple(SemanticTokenizer::TokenType, String) - "_h('span', { className: '#{item[0].to_s.underscore}' }, [`#{skip { escape_for_javascript(item[1]) }}`])" + "_h('span', { className: '#{item[0].to_s.underscore}' }, [`#{skip { item[1].escape_for_javascript }}`])" end end "[#{content}, _h(React.Fragment, {}, [#{mapped.join(",\n")}])]" end - - def escape_for_javascript(value : String) - value - .gsub('\\', "\\\\") - .gsub('`', "\\`") - .gsub("${", "\\${") - end end end diff --git a/src/compilers/directives/highlight_file.cr b/src/compilers/directives/highlight_file.cr index ab3f0c09e..c25ff050e 100644 --- a/src/compilers/directives/highlight_file.cr +++ b/src/compilers/directives/highlight_file.cr @@ -14,9 +14,9 @@ module Mint parts.map do |item| case item in String - "`#{skip { escape_for_javascript(item) }}`" + "`#{skip { item.escape_for_javascript }}`" in Tuple(SemanticTokenizer::TokenType, String) - "_h('span', { className: '#{item[0].to_s.underscore}' }, [`#{skip { escape_for_javascript(item[1]) }}`])" + "_h('span', { className: '#{item[0].to_s.underscore}' }, [`#{skip { item[1].escape_for_javascript }}`])" end end diff --git a/src/compilers/member_access.cr b/src/compilers/field_access.cr similarity index 62% rename from src/compilers/member_access.cr rename to src/compilers/field_access.cr index bc2e7d257..4e11dca23 100644 --- a/src/compilers/member_access.cr +++ b/src/compilers/field_access.cr @@ -1,6 +1,6 @@ module Mint class Compiler - def _compile(node : Ast::MemberAccess) : String + def _compile(node : Ast::FieldAccess) : String "((_) => _.#{node.name.value})" end end diff --git a/src/compilers/html_expression.cr b/src/compilers/html_expression.cr deleted file mode 100644 index 29aea775d..000000000 --- a/src/compilers/html_expression.cr +++ /dev/null @@ -1,17 +0,0 @@ -module Mint - class Compiler - def _compile(node : Ast::HtmlExpression) : String - case node.expressions.size - when 0 - "null" - when 1 - compile node.expressions.first - else - children = - compile node.expressions - - "_h(React.Fragment, {}, #{js.array(children)})" - end - end - end -end diff --git a/src/compilers2/access.cr b/src/compilers2/access.cr new file mode 100644 index 000000000..f134ed49a --- /dev/null +++ b/src/compilers2/access.cr @@ -0,0 +1,61 @@ +module Mint + class Compiler2 + def compile(node : Ast::Access) : Compiled + compile node do + if items = variables[node]? + case items[0] + when Ast::TypeVariant + case type = cache[node]? + when nil + [] of Item + else + if type.name == "Function" + js.call(Builtin::NewVariant, [[items[0]] of Item] of Compiled) + else + js.new(items[0], [] of Compiled) + end + end + else + # `subscriptions` is a special case: both the parent and the entity + # is the provider. + case parent = items[1] + when Ast::Provider + case items[0] + when Ast::Provider + return js.call(Builtin::Subscriptions, [[parent.subscription] of Item]) + end + end + + case item = items[0] + when Ast::Get + js.call(item, [] of Compiled) + when Ast::State + [Signal.new(item)] of Item + else + [item] of Item + end + end + elsif item = record_field_lookup[node.field]? + compile(node.expression) + ["."] + [node.field.value] of Item + else + lookup = + lookups[node.field] + + item = + case field = lookup[0] + when Ast::Variable + [Ref.new(lookup[0])] of Item + when Ast::Get + js.call(field, [] of Compiled) + when Ast::State + [Signal.new(field)] of Item + else + [field] of Item + end + + compile(node.expression) + ["."] + item + end + end + end + end +end diff --git a/src/compilers2/argument.cr b/src/compilers2/argument.cr new file mode 100644 index 000000000..eda71dffc --- /dev/null +++ b/src/compilers2/argument.cr @@ -0,0 +1,13 @@ +module Mint + class Compiler2 + def compile(node : Ast::Argument) : Compiled + compile node do + if default = node.default + js.assign(node, compile(default)) + else + [node] of Item + end + end + end + end +end diff --git a/src/compilers2/array_literal.cr b/src/compilers2/array_literal.cr new file mode 100644 index 000000000..b972c2059 --- /dev/null +++ b/src/compilers2/array_literal.cr @@ -0,0 +1,9 @@ +module Mint + class Compiler2 + def compile(node : Ast::ArrayLiteral) : Compiled + compile node do + js.array(compile(node.items)) + end + end + end +end diff --git a/src/compilers2/block.cr b/src/compilers2/block.cr new file mode 100644 index 000000000..4b3f4623d --- /dev/null +++ b/src/compilers2/block.cr @@ -0,0 +1,31 @@ +module Mint + class Compiler2 + def compile(node : Ast::Block, for_function = false) : Compiled + compile node do + expressions = + compile node.expressions.select(Ast::Statement) + + last = + expressions.pop + + if expressions.empty? && !async?(node) + if for_function + js.return(last) + else + last + end + elsif for_function + js.statements(expressions + [js.return(last)]) + elsif async?(node) + js.asynciif do + js.statements(expressions + [js.return(last)]) + end + else + js.iif do + js.statements(expressions + [js.return(last)]) + end + end + end + end + end +end diff --git a/src/compilers2/bool_literal.cr b/src/compilers2/bool_literal.cr new file mode 100644 index 000000000..05863e00c --- /dev/null +++ b/src/compilers2/bool_literal.cr @@ -0,0 +1,9 @@ +module Mint + class Compiler2 + def compile(node : Ast::BoolLiteral) : Compiled + compile node do + [node.value.to_s] of Item + end + end + end +end diff --git a/src/compilers2/bracket_access.cr b/src/compilers2/bracket_access.cr new file mode 100644 index 000000000..34eb078d7 --- /dev/null +++ b/src/compilers2/bracket_access.cr @@ -0,0 +1,29 @@ +module Mint + class Compiler2 + def compile(node : Ast::BracketAccess) : Compiled + compile node do + expression = + compile node.expression + + type = + cache[node.expression] + + index = + compile node.index + + if type.name == "Tuple" && node.index.is_a?(Ast::NumberLiteral) + expression + js.array([index]) + else + accessor = + if type.name == "Map" + Builtin::MapAccess + else + Builtin::BracketAccess + end + + js.call(accessor, [expression, index, just, nothing]) + end + end + end + end +end diff --git a/src/compilers2/builtin.cr b/src/compilers2/builtin.cr new file mode 100644 index 000000000..f44587ec1 --- /dev/null +++ b/src/compilers2/builtin.cr @@ -0,0 +1,50 @@ +module Mint + class Compiler2 + def compile(node : Ast::Builtin) : Compiled + compile node do + case node.value + when "decodeBoolean" + [Builtin::DecodeBoolean] of Item + when "decodeNumber" + [Builtin::DecodeNumber] of Item + when "decodeString" + [Builtin::DecodeString] of Item + when "decodeArray" + [Builtin::DecodeArray] of Item + when "decodeField" + [Builtin::DecodeField] of Item + when "decodeMaybe" + [Builtin::DecodeMaybe] of Item + when "decodeTime" + [Builtin::DecodeTime] of Item + when "locale" + [Builtin::Locale, ".value"] of Item + when "normalizeEvent" + [Builtin::NormalizeEvent] of Item + when "createPortal" + [Builtin::CreatePortal] of Item + when "testContext" + [Builtin::TestContext] of Item + when "testRender" + [Builtin::TestRender] of Item + when "setLocale" + [Builtin::SetLocale] of Item + when "navigate" + [Builtin::Navigate] of Item + when "compare" + [Builtin::Compare] of Item + when "nothing" + nothing + when "just" + just + when "err" + err + when "ok" + ok + else + [] of Item + end + end + end + end +end diff --git a/src/compilers2/call.cr b/src/compilers2/call.cr new file mode 100644 index 000000000..e1716ddf0 --- /dev/null +++ b/src/compilers2/call.cr @@ -0,0 +1,26 @@ +module Mint + class Compiler2 + def compile(node : Ast::Call) : Compiled + compile node do + expression = + compile node.expression + + arguments = + node + .arguments + .sort_by { |item| resolve_order.index(item) || -1 } + .map { |item| compile item } + + receiver = + case + when node.expression.is_a?(Ast::InlineFunction) + ["("] + expression + [")"] + else + expression + end + + js.call(receiver, arguments) + end + end + end +end diff --git a/src/compilers2/case.cr b/src/compilers2/case.cr new file mode 100644 index 000000000..86bba746a --- /dev/null +++ b/src/compilers2/case.cr @@ -0,0 +1,36 @@ +module Mint + class Compiler2 + def compile( + node : Ast::Case, + block : Proc(String, String)? = nil + ) : Compiled + compile node do + condition = + compile node.condition + + branches = + node + .branches + .sort_by(&.pattern.nil?.to_s) + .map { |branch| compile branch, block } + + if node.await + variable = + Variable.new + + js.asynciif do + js.statements([ + js.let(variable, ["await "] + defer(node.condition, condition)), + js.return(js.call(Builtin::Match, [ + [variable] of Item, + js.array(branches), + ])), + ]) + end + else + js.call(Builtin::Match, [condition, js.array(branches)]) + end + end + end + end +end diff --git a/src/compilers2/case_branch.cr b/src/compilers2/case_branch.cr new file mode 100644 index 000000000..82bae6087 --- /dev/null +++ b/src/compilers2/case_branch.cr @@ -0,0 +1,33 @@ +module Mint + class Compiler2 + def compile( + node : Ast::CaseBranch, + block : Proc(String, String)? = nil + ) : Compiled + compile node do + expression = + case item = node.expression + when Array(Ast::CssDefinition) + compile item, block if block + when Ast::Node + compile(item) + end || [] of Item + + if pattern = node.pattern + variables = + [] of Compiled + + matcher = + destructuring(pattern, variables) + + js.array([ + matcher, + js.arrow_function(variables) { js.return(expression) }, + ]) + else + js.array([js.null, js.arrow_function { js.return(expression) }]) + end + end + end + end +end diff --git a/src/compilers2/component.cr b/src/compilers2/component.cr new file mode 100644 index 000000000..ef4fd65b0 --- /dev/null +++ b/src/compilers2/component.cr @@ -0,0 +1,215 @@ +module Mint + class Compiler2 + def resolve(node : Ast::Component) + resolve node do + node.styles.each do |style| + next unless style.in?(@artifacts.checked) + style_builder.process(style, node.name.value.gsub('.', '·')) + end + + styles = + node.styles.compact_map do |style_node| + next unless style_node.in?(@artifacts.checked) + style_builder.compile_style(style_node, self) + end + + did_update = nil + unmount = nil + render = nil + mount = nil + + functions = + node.functions.compact_map do |function| + case function.name.value + when "componentDidUpdate" + did_update = function + nil + when "componentWillUnmount" + unmount = function + nil + when "componentDidMount" + mount = function + nil + when "render" + render = function + nil + else + resolve function + end + end + + constants = + resolve node.constants + + states = + resolve node.states + + gets = + resolve node.gets + + refs = + node.refs.to_h.keys.map do |ref| + method = + if node.global? + Builtin::CreateRef + else + Builtin::UseRef + end + + {ref, ref, js.call(method, [js.new(nothing, [] of Compiled)])} + end + + properties = + node.properties.map do |prop| + name = + if prop.name.value == "children" + ["children: ", prop] of Item + else + [prop] of Item + end + + if default = prop.default + js.assign(name, compile(default)) + else + name + end + end + + exposed = + if components_touched.includes?(node) + items = + (refs + states + gets + functions + constants) + .compact + .map do |item| + [item[0]] of Item + end + + unless items.empty? + variable = + Variable.new + + properties << ["_"] of Item + [ + js.const(variable, js.call(Builtin::UseMemo, [ + js.arrow_function { js.return(js.object_destructuring(items)) }, + js.array([] of Compiled), + ])), + js.tenary( + ["_"] of Item, + js.call(["_"] of Item, [[variable] of Item]), + js.null), + ] + end + end || [] of Compiled + + arguments = + unless properties.empty? + [js.object_destructuring(properties)] + end + + provider_effects = + if node.uses.empty? + [] of Compiled + else + id = Variable.new + + node.uses.map do |use| + data = + if condition = use.condition + js.tenary(compile(condition), compile(use.data), js.null) + else + compile(use.data) + end + + js.call(lookups[use][0], [ + [id] of Item, + js.arrow_function { js.return(data) }, + ]) + end + end + + id = + if id + method = + if node.global? + Builtin::Uuid + else + Builtin::UseId + end + + [{ + node.as(Ast::Node), + id.as(Id), + js.call(method, [] of Compiled), + }] + else + [] of Tuple(Ast::Node, Id, Compiled) + end + + effect = + if mount || unmount + body = [] of Compiled + body << ["("] + compile(mount, skip_const: true) + [")()"] if mount + body << js.return(compile(unmount, skip_const: true)) if unmount + + [ + js.call(Builtin::UseEffect, [ + js.arrow_function([] of Compiled) { js.statements(body) }, + ["[]"] of Item, + ]), + ] + else + [] of Compiled + end + + update_effect = + if did_update + [ + js.call(Builtin::UseDidUpdate, [ + compile(did_update, skip_const: true), + ]), + ] + else + [] of Compiled + end + + items = + if node.global? + refs + states + gets + functions + styles + constants + id + [ + {node, + node, + compile( + render.not_nil!, + skip_const: true, + contents: js.statements( + exposed + effect + update_effect + provider_effects))}, + ] + else + entities = + (refs + states + gets + functions + styles + constants + id).compact + + consts = + if entities.empty? + [] of Compiled + else + [js.consts(entities)] + end + + [{ + node, + node, + compile( + render.not_nil!, + args: arguments, + skip_const: true, + contents: js.statements( + consts + exposed + effect + update_effect + provider_effects + )), + }] + end + + add(items) + end + end + end +end diff --git a/src/compilers2/constant.cr b/src/compilers2/constant.cr new file mode 100644 index 000000000..ba9cdf7ce --- /dev/null +++ b/src/compilers2/constant.cr @@ -0,0 +1,9 @@ +module Mint + class Compiler2 + def resolve(node : Ast::Constant) + resolve node do + {node, node, compile(node.expression)} + end + end + end +end diff --git a/src/compilers2/decode.cr b/src/compilers2/decode.cr new file mode 100644 index 000000000..20b7e2644 --- /dev/null +++ b/src/compilers2/decode.cr @@ -0,0 +1,29 @@ +module Mint + class Compiler2 + def compile(node : Ast::Decode) : Compiled + compile node do + type = + cache[node] + + object = + case type.name + when "Function" + type.parameters.last.parameters.last + when "Result" + type.parameters.last + else + raise "Unkown decoder for type: #{type.name}!" + end + + code = + decoder object + + if item = node.expression + js.call(code, [compile(item)]) + else + code + end + end + end + end +end diff --git a/src/compilers2/defer.cr b/src/compilers2/defer.cr new file mode 100644 index 000000000..04724b940 --- /dev/null +++ b/src/compilers2/defer.cr @@ -0,0 +1,20 @@ +module Mint + class Compiler2 + def compile(node : Ast::Defer) : Compiled + compile node do + add(node, node, compile(node.body)) + + [Deferred.new(node)] of Item + end + end + + def defer(node : Ast::Node, compiled : Compiled) + case type = cache[node] + when TypeChecker::Type + if type.name == "Deferred" + js.call(Builtin::Load, [compiled]) + end + end || compiled + end + end +end diff --git a/src/compilers2/destructuring.cr b/src/compilers2/destructuring.cr new file mode 100644 index 000000000..bd3ee3563 --- /dev/null +++ b/src/compilers2/destructuring.cr @@ -0,0 +1,102 @@ +module Mint + class Compiler2 + def destructuring(node : Ast::ArrayDestructuring, variables : Array(Compiled)) : Compiled + js.array(node.items.map { |item| destructuring(item, variables) }) + end + + def destructuring(node : Ast::TupleDestructuring, variables : Array(Compiled)) : Compiled + js.array(node.items.map { |item| destructuring(item, variables) }) + end + + def destructuring(node : Ast::Variable, variables : Array(Compiled)) : Compiled + variables << [node] of Item + [Builtin::PatternVariable] of Item + end + + def destructuring(node : Ast::Spread, variables : Array(Compiled)) : Compiled + variables << [node] of Item + [Builtin::PatternSpread] of Item + end + + def destructuring(node : Ast::Node, variables : Array(Compiled)) : Compiled + compile(node) + end + + def destructuring(node : Nil, variables : Array(Compiled)) : Compiled + js.null # This means to skip this value when destructuring. + end + + def destructuring( + node : Ast::TypeDestructuring, + variables : Array(Compiled) + ) : Compiled + case item = lookups[node][0] + when Ast::TypeVariant + items = + if item.fields + params = node.items.select(Ast::Variable) + + if !params.empty? + fields = + params.map do |param| + js.array([ + js.string(param.value), + destructuring(param, variables), + ]) + end + + js.call(Builtin::PatternRecord, [js.array(fields)]) + end + end || js.array(node.items.map do |param| + destructuring(param, variables) + end) + + js.call(Builtin::Pattern, [[lookups[node][0]], items]) + when Ast::Constant + [item] of Item + else + compile(item) + end + end + + def match( + condition : Ast::Node, + branches : Array(Tuple(Ast::Node?, Compiled)), + await : Bool + ) : Compiled + items = + branches.map do |(pattern, expression)| + variables = + [] of Compiled + + matcher = + destructuring(pattern, variables) + + result = + js.arrow_function(variables) { js.return(expression) } + + js.array([matcher, result]) + end + + compiled = + compile(condition) + + if await + variable = + Variable.new + + js.asynciif do + js.statements([ + js.let(variable, ["await "] + defer(condition, compiled)), + js.return(js.call(Builtin::Match, [ + [variable] of Item, + js.array(items), + ])), + ]) + end + else + js.call(Builtin::Match, [compiled, js.array(items)]) + end + end + end +end diff --git a/src/compilers2/directives/asset.cr b/src/compilers2/directives/asset.cr new file mode 100644 index 000000000..a7c9a0df2 --- /dev/null +++ b/src/compilers2/directives/asset.cr @@ -0,0 +1,9 @@ +module Mint + class Compiler2 + def compile(node : Ast::Directives::Asset) : Compiled + compile node do + [Asset.new(node)] of Item + end + end + end +end diff --git a/src/compilers2/directives/documentation.cr b/src/compilers2/directives/documentation.cr new file mode 100644 index 000000000..1edb4526f --- /dev/null +++ b/src/compilers2/directives/documentation.cr @@ -0,0 +1,13 @@ +module Mint + class Compiler2 + def compile(node : Ast::Directives::Documentation) : Compiled + compile node do + [ + JSON.build do |json| + DocumentationGenerator.new.generate(lookups[node][0], json) + end, + ] of Item + end + end + end +end diff --git a/src/compilers2/directives/format.cr b/src/compilers2/directives/format.cr new file mode 100644 index 000000000..54349ce0f --- /dev/null +++ b/src/compilers2/directives/format.cr @@ -0,0 +1,17 @@ +module Mint + class Compiler2 + def compile(node : Ast::Directives::Format) : Compiled + compile node do + content = + compile node.content + + formatted = + Formatter.new + .format(node.content, Formatter::BlockFormat::Naked) + .gsub('\\', "\\\\") + + js.array([content, js.string(formatted)]) + end + end + end +end diff --git a/src/compilers2/directives/highlight.cr b/src/compilers2/directives/highlight.cr new file mode 100644 index 000000000..d8514b1b0 --- /dev/null +++ b/src/compilers2/directives/highlight.cr @@ -0,0 +1,18 @@ +module Mint + class Compiler2 + def compile(node : Ast::Directives::Highlight) : Compiled + compile node do + content = + compile node.content + + formatted = + Formatter.new.format(node.content, Formatter::BlockFormat::Naked) + + parser = + Parser.new(formatted, "source.mint").tap(&.parse_any) + + js.array([content, tokenize(parser.ast)]) + end + end + end +end diff --git a/src/compilers2/directives/highlight_file.cr b/src/compilers2/directives/highlight_file.cr new file mode 100644 index 000000000..421b005c8 --- /dev/null +++ b/src/compilers2/directives/highlight_file.cr @@ -0,0 +1,15 @@ +module Mint + class Compiler2 + def compile(node : Ast::Directives::HighlightFile) : Compiled + compile node do + contents = + File.read(node.real_path) + + parser = + Parser.new(contents.strip, node.real_path.to_s).tap(&.parse_any) + + tokenize(parser.ast) + end + end + end +end diff --git a/src/compilers2/directives/inline.cr b/src/compilers2/directives/inline.cr new file mode 100644 index 000000000..688c7be3e --- /dev/null +++ b/src/compilers2/directives/inline.cr @@ -0,0 +1,7 @@ +module Mint + class Compiler2 + def compile(node : Ast::Directives::Inline) : Compiled + ["`", Raw.new(node.file_contents), "`"] of Item + end + end +end diff --git a/src/compilers2/directives/svg.cr b/src/compilers2/directives/svg.cr new file mode 100644 index 000000000..0785cab54 --- /dev/null +++ b/src/compilers2/directives/svg.cr @@ -0,0 +1,33 @@ +module Mint + class Compiler2 + def compile(node : Ast::Directives::Svg) : Compiled + compile node do + resolve node do + parsed = + parse_svg(node.file_contents) + + return [] of Item unless parsed + + width, height, view_box, data = + parsed + + attributes = + js.object({ + "dangerouslySetInnerHTML" => js.object({"__html" => js.string(data)}), + "viewBox" => js.string(view_box.to_s), + "height" => js.string(height.to_s), + "width" => js.string(width.to_s), + } of Item => Compiled) + + add([ + {node, + node, + js.call(Builtin::CreateElement, [js.string("svg"), attributes])}, + ]) + end + + [node] of Item + end + end + end +end diff --git a/src/compilers2/encode.cr b/src/compilers2/encode.cr new file mode 100644 index 000000000..cfd015c21 --- /dev/null +++ b/src/compilers2/encode.cr @@ -0,0 +1,12 @@ +module Mint + class Compiler2 + def compile(node : Ast::Encode) : Compiled + compile node do + code = + encoder cache[node.expression] + + js.call(code, [compile(node.expression)]) + end + end + end +end diff --git a/src/compilers2/env.cr b/src/compilers2/env.cr new file mode 100644 index 000000000..852b28023 --- /dev/null +++ b/src/compilers2/env.cr @@ -0,0 +1,12 @@ +module Mint + class Compiler2 + def compile(node : Ast::Env) : Compiled + compile node do + value = + MINT_ENV[node.name].to_s + + js.string(value) + end + end + end +end diff --git a/src/compilers2/field.cr b/src/compilers2/field.cr new file mode 100644 index 000000000..159c4b6e0 --- /dev/null +++ b/src/compilers2/field.cr @@ -0,0 +1,21 @@ +module Mint + class Compiler2 + def compile(node : Ast::Field) + compile node do + compile node.value + end + end + + def resolve(node : Ast::Field) : Hash(Item, Compiled) + return {} of Item => Compiled unless key = node.key + + value = + compile node.value + + name = + key.value + + {name.as(Item) => value} + end + end +end diff --git a/src/compilers2/field_access.cr b/src/compilers2/field_access.cr new file mode 100644 index 000000000..ff464825a --- /dev/null +++ b/src/compilers2/field_access.cr @@ -0,0 +1,9 @@ +module Mint + class Compiler2 + def compile(node : Ast::FieldAccess) : Compiled + compile node do + js.call(Builtin::Access, [js.string(node.name.value)]) + end + end + end +end diff --git a/src/compilers2/for_expression.cr b/src/compilers2/for_expression.cr new file mode 100644 index 000000000..ca569870c --- /dev/null +++ b/src/compilers2/for_expression.cr @@ -0,0 +1,85 @@ +module Mint + class Compiler2 + def compile(node : Ast::For) : Compiled + compile node do + subject = + compile node.subject + + subject_type = + cache[node.subject] + + body = + compile node.body + + arguments, index_arg = + if (subject_type.name == "Array" && node.arguments.size == 1) || + (subject_type.name == "Set" && node.arguments.size == 1) || + (subject_type.name == "Map" && node.arguments.size == 2) + if node.arguments.size == 1 + { + [node.arguments[0].as(Item)], + nil, + } + else + { + js.array(node.arguments.map { |item| [item] of Item }), + nil, + } + end + else + if node.arguments.size == 2 + { + [node.arguments[0].as(Item)], + node.arguments[1], + } + else + { + js.array(node.arguments[0..1].map { |item| [item] of Item }), + node.arguments[2], + } + end + end + + condition = + node.condition.try do |item| + js.statements([ + js.const("_2".as(Item), compile(item)), + js.if(["!_2"] of Item, ["continue"] of Item), + ]) + end + + index = + if index_arg + js.const(index_arg, ["_i"] of Item) + end + + contents = + if condition + [ + ["_i++"] of Item, + index, + condition, js.call("_0.push", [body]), + ] + else + [ + ["_i++"] of Item, + index, + js.call("_0.push", [body]), + ] + end + + js.iif do + js.statements([ + js.const("_0".as(Item), js.array([] of Compiled)), + js.const("_1".as(Item), subject), + js.let("_i".as(Item), ["-1"] of Item), + js.for(["let "] + arguments, ["_1"] of Item) do + js.statements(contents.compact) + end, + js.return(["_0"] of Item), + ]) + end + end + end + end +end diff --git a/src/compilers2/function.cr b/src/compilers2/function.cr new file mode 100644 index 000000000..5db5afaa5 --- /dev/null +++ b/src/compilers2/function.cr @@ -0,0 +1,44 @@ +module Mint + class Compiler2 + def resolve(node : Ast::Function) + resolve node do + {node, node, compile(node, contents: nil, args: nil, skip_const: true)} + end + end + + def compile(node : Ast::Function) + compile node do + compile(node, contents: nil, args: nil) + end + end + + def compile( + node : Ast::Function, *, + contents : Compiled | Nil = nil, + args : Array(Compiled) | Nil = nil, + skip_const : Bool = false + ) : Compiled + items = + [] of Compiled + + arguments = + args || compile(node.arguments) + + items << contents if contents + items << compile(node.body, for_function: true) + + body = + if async?(node.body) + js.async_arrow_function(arguments) { js.statements(items) } + else + js.arrow_function(arguments) { js.statements(items) } + end + + if skip_const + body + else + js.const(node, body) + end + end + end +end diff --git a/src/compilers2/get.cr b/src/compilers2/get.cr new file mode 100644 index 000000000..d4bd0ce69 --- /dev/null +++ b/src/compilers2/get.cr @@ -0,0 +1,19 @@ +module Mint + class Compiler2 + def resolve(node : Ast::Get) + resolve node do + body = + compile node.body, for_function: true + + body = + if async?(node.body) + js.async_arrow_function([] of Compiled) { body } + else + js.arrow_function([] of Compiled) { body } + end + + {node, node, body} + end + end + end +end diff --git a/src/compilers2/here_document.cr b/src/compilers2/here_document.cr new file mode 100644 index 000000000..e3287cbdf --- /dev/null +++ b/src/compilers2/here_document.cr @@ -0,0 +1,73 @@ +module Mint + class Compiler2 + def compile(node : Ast::HereDocument) : Compiled + compile node do + # We generate a hexdigest of the source code, but this still can + # conflict, so if you find a better solution in the future let us know. + separator = + Digest::MD5.hexdigest(node.source) + + interpolations = + [] of Compiled + + value = + node + .value + .join do |item| + case item + in Ast::Node + interpolations << compile(item) + separator + in String + item + end + end + .lchop('\n') + .lchop('\r') + .lchop("\n\r") + .rstrip + .gsub("\\\#{", "\#{") + + if node.modifier == '#' + document = + Markd::Parser.parse( + value.shrink_to_minimum_leading_whitespace, + Markd::Options.new) + + VDOMRenderer2.render( + replacements: interpolations, + highlight: node.highlight, + separator: separator, + document: document, + js: js) + else + if node.modifier == '~' + value = value.shrink_to_minimum_leading_whitespace + end + + # Compile the non interpolation parts and the + # interpolation parts together into a string. + value = + value + .gsub("\\", "\\\\") + .split(separator) + .map do |item| + raw = + item + .gsub('`', "\\`") + .gsub("${", "\\${") + + [ + Raw.new(raw), + ] of Item + end + + interpolations = + interpolations.map { |item| ["${"] + item + ["}"] } + + ["`"] + value.zip2(interpolations) + ["`"] + end + end + end + end +end diff --git a/src/compilers2/html_attribute.cr b/src/compilers2/html_attribute.cr new file mode 100644 index 000000000..666912af7 --- /dev/null +++ b/src/compilers2/html_attribute.cr @@ -0,0 +1,19 @@ +module Mint + class Compiler2 + def resolve( + node : Ast::HtmlAttribute, *, + is_element = true + ) : Hash(Item, Compiled) + value = + compile node.value + + if node.name.value.downcase == "readonly" && is_element + {"readOnly".as(Item) => value} + elsif lookups[node]?.try(&.first?) + {lookups[node][0].as(Item) => value} + else + { %("#{node.name.value}").as(Item) => value } + end + end + end +end diff --git a/src/compilers2/html_component.cr b/src/compilers2/html_component.cr new file mode 100644 index 000000000..f2b1f117f --- /dev/null +++ b/src/compilers2/html_component.cr @@ -0,0 +1,47 @@ +module Mint + class Compiler2 + def compile(node : Ast::HtmlComponent) : Compiled + compile node do + component = + node.component_node.not_nil! + + children = + unless node.children.empty? + items = + compile node.children + + js.call(Builtin::ToArray, items) + end + + attributes = + node + .attributes + .map { |item| resolve(item, is_element: false) } + .reduce({} of Item => Compiled) { |memo, item| memo.merge(item) } + + node.ref.try do |ref| + attributes["_"] = + js.call(Builtin::SetRef, [[ref] of Item, just]) + end + + if component.async? + js.call(Builtin::CreateElement, [ + [Builtin::LazyComponent] of Item, + js.object({ + "c" => children || js.array([] of Compiled), + "key" => js.string(component.name.value), + "p" => js.object(attributes), + "x" => [component] of Item, + }), + ]) + else + js.call(Builtin::CreateElement, [ + [component] of Item, + js.object(attributes), + children || [] of Item, + ]) + end + end + end + end +end diff --git a/src/compilers2/html_element.cr b/src/compilers2/html_element.cr new file mode 100644 index 000000000..1e399cdc1 --- /dev/null +++ b/src/compilers2/html_element.cr @@ -0,0 +1,92 @@ +module Mint + class Compiler2 + def compile(node : Ast::HtmlElement) : Compiled + compile node do + children = + if node.children.empty? + [] of Item + else + items = + compile node.children + + js.array(items) + end + + attributes = + node + .attributes + .reject(&.name.value.in?("class", "style")) + .map { |item| resolve(item, is_element: true) } + .reduce({} of Item => Compiled) { |memo, item| memo.merge(item) } + + style_nodes = + node.styles.compact_map(&.style_node) + + class_name = + unless style_nodes.empty? + style_nodes.join(' ') do |style_node| + style_builder.prefixed_class_name(style_node) + end + end + + class_name_attribute = + node + .attributes + .find(&.name.value.==("class")) + .try { |attribute| compile(attribute.value) } + + classes = + case + when class_name && class_name_attribute + class_name_attribute + [" + ` #{class_name}`"] + when class_name_attribute + class_name_attribute + when class_name + js.string(class_name) + end + + custom_styles = + node + .attributes + .find(&.name.value.==("style")) + .try { |attribute| compile(attribute.value) } + + styles = [] of Compiled + + node.styles.each do |item| + next unless style = item.style_node + next unless style_builder.any?(style) + + arguments = + item + .arguments + .sort_by { |arg| resolve_order.index(arg) || -1 } + .map { |arg| compile(arg).as(Compiled) } + + styles << js.call(style, arguments) + end + + styles << custom_styles if custom_styles + + if classes + attributes["className"] = classes + end + + unless styles.empty? + attributes["style"] = js.call(Builtin::Style, [js.array(styles)]) + end + + node.ref.try do |ref| + attributes["ref"] = + js.call(Builtin::SetRef, [[ref] of Item, just]) + end + + js.call(Builtin::CreateElement, [ + js.string(node.tag.value), + js.object(attributes), + children, + ]) + end + end + end +end diff --git a/src/compilers2/html_fragment.cr b/src/compilers2/html_fragment.cr new file mode 100644 index 000000000..771c64b23 --- /dev/null +++ b/src/compilers2/html_fragment.cr @@ -0,0 +1,23 @@ +module Mint + class Compiler2 + def compile(node : Ast::HtmlFragment) : Compiled + compile node do + case node.children.size + when 0 + js.null + when 1 + compile node.children.first + else + items = + compile node.children + + js.call(Builtin::CreateElement, [ + [Builtin::Fragment] of Item, + ["{}"] of Item, + js.array(items), + ]) + end + end + end + end +end diff --git a/src/compilers2/if.cr b/src/compilers2/if.cr new file mode 100644 index 000000000..3fb9f3246 --- /dev/null +++ b/src/compilers2/if.cr @@ -0,0 +1,85 @@ +module Mint + class Compiler2 + def compile( + items : Array(Ast::CssDefinition), + block : Proc(String, String)? + ) : Compiled + compiled = + items.each_with_object({} of String => Compiled) do |definition, memo| + variable = + if block + block.call(definition.name) + else + "" + end + + value = + compile definition.value + + memo["[`#{variable}`]"] = value + end + + js.call("Object.assign", [["_"] of Item, js.object(compiled)]) + end + + def compile( + node : Ast::If, + block : Proc(String, String)? = nil + ) : Compiled + compile node do + truthy_item, falsy_item = + node.branches + + truthy = + if truthy_item.expressions.all?(Ast::CssDefinition) + compile( + truthy_item.expressions.select(Ast::CssDefinition), block: block) + else + compile truthy_item + end + + falsy = + case item = falsy_item + when Ast::If + compile item, block: block + when Ast::Block + if item.expressions.all?(Ast::CssDefinition) + compile( + item.expressions.select(Ast::CssDefinition), block: block) + else + compile item + end + else + if truthy_item + case cache[truthy_item].name + when "Array" + ["[]"] of Item + when "String" + ["\"\""] of Item + when "Maybe" + js.new(nothing) + end + end + end || js.null + + case statement = node.condition + when Ast::Statement + case target = statement.target + when Ast::Node + match( + statement.expression, + [ + {target, truthy}, + {nil, falsy}, + ], + statement.await) + else + js.tenary(compile(statement.expression), truthy, falsy) + end + else + js.tenary(compile(node.condition), truthy, falsy) + end + end + end + end +end diff --git a/src/compilers2/inline_function.cr b/src/compilers2/inline_function.cr new file mode 100644 index 000000000..3e804a01d --- /dev/null +++ b/src/compilers2/inline_function.cr @@ -0,0 +1,24 @@ +module Mint + class Compiler2 + def compile(node : Ast::InlineFunction) : Compiled + compile node do + body = + case item = node.body + when Ast::Block + compile item, for_function: true + else + compile item + end + + arguments = + compile node.arguments + + if async?(node.body) + js.async_arrow_function(arguments) { body } + else + js.arrow_function(arguments) { body } + end + end + end + end +end diff --git a/src/compilers2/interpolation.cr b/src/compilers2/interpolation.cr new file mode 100644 index 000000000..5bb765b90 --- /dev/null +++ b/src/compilers2/interpolation.cr @@ -0,0 +1,9 @@ +module Mint + class Compiler2 + def compile(node : Ast::Interpolation) : Compiled + compile node do + compile node.expression + end + end + end +end diff --git a/src/compilers2/js.cr b/src/compilers2/js.cr new file mode 100644 index 000000000..cabf68c58 --- /dev/null +++ b/src/compilers2/js.cr @@ -0,0 +1,33 @@ +module Mint + class Compiler2 + def compile(node : Ast::Js) : Compiled + compile node do + case item = node.value.first? + when String + node.value[0] = item.lstrip + end + + case item = node.value.last? + when String + node.value[node.value.size - 1] = item.rstrip + end + + value = + node.value.flat_map do |entity| + case entity + in Ast::Node + compile entity + in String + entity.gsub("\\`", '`') + end + end + + if value.empty? + ["undefined"] of Item + else + ["("] + value + [")"] + end + end + end + end +end diff --git a/src/compilers2/locale_key.cr b/src/compilers2/locale_key.cr new file mode 100644 index 000000000..949019d69 --- /dev/null +++ b/src/compilers2/locale_key.cr @@ -0,0 +1,9 @@ +module Mint + class Compiler2 + def compile(node : Ast::LocaleKey) : Compiled + compile node do + js.call(Builtin::Translate, [js.string(node.value)]) + end + end + end +end diff --git a/src/compilers2/map.cr b/src/compilers2/map.cr new file mode 100644 index 000000000..9d8afd6a1 --- /dev/null +++ b/src/compilers2/map.cr @@ -0,0 +1,12 @@ +module Mint + class Compiler2 + def compile(node : Ast::Map) : Compiled + compile node do + fields = + compile node.fields + + js.array(fields) + end + end + end +end diff --git a/src/compilers2/map_field.cr b/src/compilers2/map_field.cr new file mode 100644 index 000000000..5f1ec0796 --- /dev/null +++ b/src/compilers2/map_field.cr @@ -0,0 +1,12 @@ +module Mint + class Compiler2 + def compile(node : Ast::MapField) + compile node do + js.array([ + compile(node.key), + compile(node.value), + ]) + end + end + end +end diff --git a/src/compilers2/module.cr b/src/compilers2/module.cr new file mode 100644 index 000000000..ad2aab7a4 --- /dev/null +++ b/src/compilers2/module.cr @@ -0,0 +1,15 @@ +module Mint + class Compiler2 + def resolve(node : Ast::Module) + resolve node do + functions = + resolve node.functions + + constants = + resolve node.constants + + add functions + constants + end + end + end +end diff --git a/src/compilers2/negated_expression.cr b/src/compilers2/negated_expression.cr new file mode 100644 index 000000000..9164fdf27 --- /dev/null +++ b/src/compilers2/negated_expression.cr @@ -0,0 +1,9 @@ +module Mint + class Compiler2 + def compile(node : Ast::NegatedExpression) : Compiled + compile node do + [node.negations] + compile(node.expression) + end + end + end +end diff --git a/src/compilers2/next_call.cr b/src/compilers2/next_call.cr new file mode 100644 index 000000000..cf29edf79 --- /dev/null +++ b/src/compilers2/next_call.cr @@ -0,0 +1,37 @@ +module Mint + class Compiler2 + def compile(node : Ast::NextCall) : Compiled + compile node do + entity = + lookups[node]?.try(&.first?) + + if node.data.fields.empty? + js.null + else + assigns = + node.data.fields.compact_map do |item| + next unless key = item.key + + field = + case entity + when Ast::Component, Ast::Store, Ast::Provider + entity.states.find(&.name.value.==(key.value)) + end + + next unless field + + js.assign(Signal.new(field), compile(item.value)) + end + + if assigns.size > 1 + js.call(Builtin::Batch, [ + js.arrow_function { js.statements(assigns) }, + ]) + else + js.iif { assigns[0] } + end + end + end + end + end +end diff --git a/src/compilers2/number_literal.cr b/src/compilers2/number_literal.cr new file mode 100644 index 000000000..059df4518 --- /dev/null +++ b/src/compilers2/number_literal.cr @@ -0,0 +1,9 @@ +module Mint + class Compiler2 + def compile(node : Ast::NumberLiteral) : Compiled + compile node do + [static_value(node).to_s] of Item + end + end + end +end diff --git a/src/compilers2/operation.cr b/src/compilers2/operation.cr new file mode 100644 index 000000000..f1adc8a08 --- /dev/null +++ b/src/compilers2/operation.cr @@ -0,0 +1,24 @@ +module Mint + class Compiler2 + def compile(node : Ast::Operation) : Compiled + compile node do + left = + compile node.left + + right = + compile node.right + + case node.operator + when "or" + js.call(Builtin::Or, [nothing, err, left, right]) + when "==" + js.call(Builtin::Compare, [left, right]) + when "!=" + ["!"] + js.call(Builtin::Compare, [left, right]) + else + left + [" #{node.operator} "] + right + end + end + end + end +end diff --git a/src/compilers2/parenthesized_expression.cr b/src/compilers2/parenthesized_expression.cr new file mode 100644 index 000000000..a06837154 --- /dev/null +++ b/src/compilers2/parenthesized_expression.cr @@ -0,0 +1,9 @@ +module Mint + class Compiler2 + def compile(node : Ast::ParenthesizedExpression) : Compiled + compile node do + ["("] + compile(node.expression) + [")"] + end + end + end +end diff --git a/src/compilers2/pipe.cr b/src/compilers2/pipe.cr new file mode 100644 index 000000000..becb88a0d --- /dev/null +++ b/src/compilers2/pipe.cr @@ -0,0 +1,9 @@ +module Mint + class Compiler2 + def compile(node : Ast::Pipe) : Compiled + compile node do + compile node.call + end + end + end +end diff --git a/src/compilers2/provider.cr b/src/compilers2/provider.cr new file mode 100644 index 000000000..ec37dcb6e --- /dev/null +++ b/src/compilers2/provider.cr @@ -0,0 +1,41 @@ +module Mint + class Compiler2 + def resolve(node : Ast::Provider) + resolve node do + update = + node.functions.find!(&.name.value.==("update")) + + functions = + resolve(node.functions - [update]) + + constants = + resolve node.constants + + states = + resolve node.states + + gets = + resolve node.gets + + update = + { + node, + node, + js.call(Builtin::CreateProvider, [ + [node.subscription] of Item, + compile(update, skip_const: true), + ]), + } + + subscriptions = + { + node.subscription, + node.subscription, + js.new("Map".as(Item)), + } + + add functions + states + gets + constants + [subscriptions, update] + end + end + end +end diff --git a/src/compilers2/record.cr b/src/compilers2/record.cr new file mode 100644 index 000000000..6f5f25ea2 --- /dev/null +++ b/src/compilers2/record.cr @@ -0,0 +1,14 @@ +module Mint + class Compiler2 + def compile(node : Ast::Record) : Compiled + compile node do + fields = + node.fields + .map { |item| resolve(item) } + .reduce({} of Item => Compiled) { |memo, item| memo.merge(item) } + + js.object(fields) + end + end + end +end diff --git a/src/compilers2/record_update.cr b/src/compilers2/record_update.cr new file mode 100644 index 000000000..e691d4686 --- /dev/null +++ b/src/compilers2/record_update.cr @@ -0,0 +1,20 @@ +module Mint + class Compiler2 + def compile(node : Ast::RecordUpdate) : Compiled + compile node do + expression = + compile node.expression + + fields = + node.fields + .map { |item| resolve(item) } + .reduce({} of String => Compiled) { |memo, item| memo.merge(item) } + .map { |key, value| [key, ": "] + value } + + fields.unshift(["..."] + expression) + + js.object_destructuring(fields) + end + end + end +end diff --git a/src/compilers2/regexp_literal.cr b/src/compilers2/regexp_literal.cr new file mode 100644 index 000000000..ccd5b2bd5 --- /dev/null +++ b/src/compilers2/regexp_literal.cr @@ -0,0 +1,9 @@ +module Mint + class Compiler2 + def compile(node : Ast::RegexpLiteral) : Compiled + compile node do + [static_value(node).to_s] of Item + end + end + end +end diff --git a/src/compilers2/return_call.cr b/src/compilers2/return_call.cr new file mode 100644 index 000000000..a7a348081 --- /dev/null +++ b/src/compilers2/return_call.cr @@ -0,0 +1,9 @@ +module Mint + class Compiler2 + def compile(node : Ast::ReturnCall) : Compiled + compile node do + js.return compile(node.expression) + end + end + end +end diff --git a/src/compilers2/route.cr b/src/compilers2/route.cr new file mode 100644 index 000000000..65179336b --- /dev/null +++ b/src/compilers2/route.cr @@ -0,0 +1,38 @@ +module Mint + class Compiler2 + def compile(node : Ast::Route) : Compiled + compile node do + expression = + compile node.expression + + arguments = + compile node.arguments + + mapping = + node + .arguments + .map { |argument| js.string(argument.name.value) } + + decoders = + node + .arguments + .map { |argument| decoder(cache[argument]) } + + handler = + if async?(node.expression) + js.async_arrow_function(arguments) { js.return(expression) } + else + js.arrow_function(arguments) { js.return(expression) } + end + + js.object({ + "await" => [node.await.to_s] of Item, + "path" => js.string(node.url), + "decoders" => js.array(decoders), + "mapping" => js.array(mapping), + "handler" => handler, + }) + end + end + end +end diff --git a/src/compilers2/state.cr b/src/compilers2/state.cr new file mode 100644 index 000000000..05dad4622 --- /dev/null +++ b/src/compilers2/state.cr @@ -0,0 +1,19 @@ +module Mint + class Compiler2 + def resolve(node : Ast::State) + resolve node do + default = + compile node.default + + method = + if (parent = node.parent).is_a?(Ast::Component) && !parent.global? + Builtin::UseSignal + else + Builtin::Signal + end + + {node, node, js.call(method, [default])} + end + end + end +end diff --git a/src/compilers2/state_setter.cr b/src/compilers2/state_setter.cr new file mode 100644 index 000000000..705a54cc8 --- /dev/null +++ b/src/compilers2/state_setter.cr @@ -0,0 +1,14 @@ +module Mint + class Compiler2 + def compile(node : Ast::StateSetter) : Compiled + compile node do + variable = + Variable.new + + js.arrow_function([[variable] of Item]) do + js.assign(Signal.new(lookups[node].first), [variable] of Item) + end + end + end + end +end diff --git a/src/compilers2/statement.cr b/src/compilers2/statement.cr new file mode 100644 index 000000000..2a6ac0a02 --- /dev/null +++ b/src/compilers2/statement.cr @@ -0,0 +1,59 @@ +module Mint + class Compiler2 + def compile(node : Ast::Statement) : Compiled + compile node do + right, return_call = + case expression = node.expression + when Ast::Operation + case item = expression.right + when Ast::ReturnCall + { + compile(expression.left), + compile(item.expression), + } + end + end || {compile(node.expression), nil} + + right = ["await "] + defer(node.expression, right) if node.await + + if target = node.target + case target + when Ast::Variable + js.const(target, right) + when Ast::TupleDestructuring, + Ast::ArrayDestructuring, + Ast::TypeDestructuring + variables = [] of Compiled + + pattern = + destructuring(target, variables) + + case target + when Ast::TupleDestructuring + if target.items.all?(Ast::Variable) + js.const(js.array(variables), right) + end + end || begin + var = + Variable.new + + const = + js.const(var, js.call(Builtin::Destructure, [right, pattern])) + + return_if = + if return_call + js.if([var, " === false"], js.return(return_call)) + end + + js.statements([ + const, + return_if, + js.const(js.array(variables), [var]), + ].compact) + end + end + end || right + end + end + end +end diff --git a/src/compilers2/store.cr b/src/compilers2/store.cr new file mode 100644 index 000000000..6241e7fc8 --- /dev/null +++ b/src/compilers2/store.cr @@ -0,0 +1,21 @@ +module Mint + class Compiler2 + def resolve(node : Ast::Store) + resolve node do + constants = + resolve node.constants + + functions = + resolve node.functions + + states = + resolve node.states + + gets = + resolve node.gets + + add states + gets + functions + constants + end + end + end +end diff --git a/src/compilers2/string.cr b/src/compilers2/string.cr new file mode 100644 index 000000000..85e6946fc --- /dev/null +++ b/src/compilers2/string.cr @@ -0,0 +1,28 @@ +module Mint + class Compiler2 + def compile( + value : Array(Ast::Node | String), *, + quote_string : Bool = false + ) : Compiled + if value.any?(Ast::Node) + value.map do |part| + case part + when Ast::StringLiteral + compile part, quote: quote_string + else + compile part + end + end.intersperse([" + "]).flatten + else + result = + value.select(String).join(' ') + + compile result + end + end + + def compile(value : String) : Compiled + js.string(value) + end + end +end diff --git a/src/compilers2/string_literal.cr b/src/compilers2/string_literal.cr new file mode 100644 index 000000000..5a82cae50 --- /dev/null +++ b/src/compilers2/string_literal.cr @@ -0,0 +1,27 @@ +module Mint + class Compiler2 + def compile(node : Ast::StringLiteral, quote : Bool = false) : Compiled + value = + node.value.flat_map do |item| + case item + in Ast::Node + ["${"] + compile(item) + ["}"] + in String + [ + item + .gsub('`', "\\`") + .gsub("${", "\\${") + .gsub("\\\"", "\"") + .gsub("\\\#{", "\#{"), + ] + end + end + + if quote + [%(`")] + value + [%("`)] + else + ["`"] + value + ["`"] + end + end + end +end diff --git a/src/compilers2/suite.cr b/src/compilers2/suite.cr new file mode 100644 index 000000000..e514f406a --- /dev/null +++ b/src/compilers2/suite.cr @@ -0,0 +1,30 @@ +module Mint + class Compiler2 + def compile(node : Ast::Suite) : Compiled + compile node do + location = + [Raw.new(node.location.to_json)] + + constants = + resolve node.constants + + functions = + resolve node.functions + + tests = + compile node.tests + + name = + compile node.name + + add(functions + constants) + + js.object({ + "tests" => js.array(tests), + "location" => location, + "name" => name, + }) + end + end + end +end diff --git a/src/compilers2/test.cr b/src/compilers2/test.cr new file mode 100644 index 000000000..a09ffb853 --- /dev/null +++ b/src/compilers2/test.cr @@ -0,0 +1,35 @@ +module Mint + class Compiler2 + def compile(node : Ast::Test) : Compiled + compile node do + location = + [Raw.new(node.location.to_json)] + + name = + compile node.name + + expression = + case operation = node.expression + when Ast::Operation + if (operator = operation.operator).in?("==", "!=") + right = + compile operation.right + + left = + compile operation.left + + js.call( + Builtin::TestOperation, + [left, right, [operator] of (Item)]) + end + end || compile(node.expression) + + js.object({ + "proc" => js.async_arrow_function { js.return(expression) }, + "location" => location, + "name" => name, + }) + end + end + end +end diff --git a/src/compilers2/tuple_literal.cr b/src/compilers2/tuple_literal.cr new file mode 100644 index 000000000..f1bec1ebc --- /dev/null +++ b/src/compilers2/tuple_literal.cr @@ -0,0 +1,9 @@ +module Mint + class Compiler2 + def compile(node : Ast::TupleLiteral) : Compiled + compile node do + js.array(compile(node.items)) + end + end + end +end diff --git a/src/compilers2/type_definition.cr b/src/compilers2/type_definition.cr new file mode 100644 index 000000000..ddc2ecfdd --- /dev/null +++ b/src/compilers2/type_definition.cr @@ -0,0 +1,21 @@ +module Mint + class Compiler2 + def resolve(node : Ast::TypeDefinition) + resolve node do + case fields = node.fields + when Array(Ast::TypeVariant) + fields.map do |option| + args = + if (fields = option.fields) && !option.parameters.empty? + [js.array(fields.map { |item| [%("#{item.key.value}")] of Item })] + else + [[option.parameters.size.to_s] of Item] + end + + add node, option, js.call(Builtin::Variant, args) + end + end + end + end + end +end diff --git a/src/compilers2/unary_minus.cr b/src/compilers2/unary_minus.cr new file mode 100644 index 000000000..d60ef459a --- /dev/null +++ b/src/compilers2/unary_minus.cr @@ -0,0 +1,9 @@ +module Mint + class Compiler2 + def compile(node : Ast::UnaryMinus) : Compiled + compile node do + ["-("] + compile(node.expression) + [")"] + end + end + end +end diff --git a/src/compilers2/variable.cr b/src/compilers2/variable.cr new file mode 100644 index 000000000..d9bae1d33 --- /dev/null +++ b/src/compilers2/variable.cr @@ -0,0 +1,44 @@ +module Mint + class Compiler2 + def compile(node : Ast::Variable) : Compiled + compile node do + if node.value == "void" + ["null"] of Item + else + entity, parent = + variables[node] + + # Subscriptions for providers are handled here + if node.value == "subscriptions" && parent.is_a?(Ast::Provider) + return js.call(Builtin::Subscriptions, [[parent.subscription] of Item]) + end + + case {entity, parent} + when {Ast::Component, Ast::Component}, + {Ast::HtmlElement, Ast::Component} + case parent + when Ast::Component + ref = + parent + .refs + .find! { |(ref, _)| ref.value == node.value }[0] + + [Ref.new(ref)] of Item + else + raise "SHOULD NOT HAPPEN" + end + else + case entity + when Ast::Get + js.call(entity, [] of Compiled) + when Ast::State + [Signal.new(entity)] of Item + else + [entity] of Item + end + end + end + end + end + end +end diff --git a/src/constants.cr b/src/constants.cr index 7fcc224eb..9252f5b44 100644 --- a/src/constants.cr +++ b/src/constants.cr @@ -13,7 +13,7 @@ module Mint WARNING = "⚠".colorize(:yellow).to_s DIAMOND = "◈" - ASSET_DIR = "assets" + ASSET_DIR = "__mint__" DIST_DIR = "dist" PUBLIC_DIR = "public" CSS_DIR = Path[DIST_DIR, "css"].to_s diff --git a/src/debugger.cr b/src/debugger.cr index 21cd3d159..702359316 100644 --- a/src/debugger.cr +++ b/src/debugger.cr @@ -1,5 +1,35 @@ module Mint class Debugger + def self.dbg(node) + name = + node.class.name.sub("Mint::Ast::", "") + + case x = node + when Ast::Route + "Route (#{x.url})" + when Ast::Component + "<#{x.name.value}>" + when Ast::Module, Ast::Store, Ast::Provider, Ast::Type + x.name.value + when Ast::TypeDefinition + "TD: #{x.name.value}" + when Ast::TypeVariant + dbg(x.parent) + "." + x.value.value + when Ast::Function, Ast::Constant, Ast::Get, Ast::State, Ast::Property + pn = + case y = x.parent + when Ast::Component, Ast::Module, Ast::Store, Ast::Provider + y.name.value + else + "" + end + + "#{pn}.#{x.name.value}" + else + name + end + end + def initialize(@scope : TypeChecker::Scope) end diff --git a/src/documentation_server.cr b/src/documentation_server.cr index 740c855f7..43b3d6a51 100644 --- a/src/documentation_server.cr +++ b/src/documentation_server.cr @@ -50,7 +50,7 @@ module Mint setup_kemal - Server.run(name: "Documentation", port: 3002) + # Server.run(name: "Documentation", port: 3002) end def setup_kemal diff --git a/src/errorable.cr b/src/errorable.cr index d2d6966cb..ea24c16ec 100644 --- a/src/errorable.cr +++ b/src/errorable.cr @@ -97,50 +97,22 @@ module Mint end end - def to_html - renderer = Render::Html.new - renderer.title "ERROR (#{name})" - - blocks.each do |element| - case element - # when TypeList - # renderer.type_list element.value - # when StringList - # renderer.list element.value - # when Pre - # renderer.pre element.value - # when Type - # renderer.type element.value - # when Title - # renderer.title element.value - when Error::Snippet - case node = element.value - when TypeChecker::Checkable - renderer.pre node.to_pretty - when Ast::Node - renderer.snippet node - end - when Array(Error::Element) - renderer.block do - element.each do |item| - case item - when Error::Text - text item.value - when Error::Bold - bold item.value - when Error::Code - code item.value - end + def to_html(reload : Bool = false) + HtmlBuilder.build(optimize: true) do + html do + head do + meta charset: "utf-8" + meta content: "width=device-width, initial-scale=1, shrink-to-fit=no", + name: "viewport" + + if reload + script src: "/live-reload.js" end end + + body { pre { code { text to_terminal.to_s.uncolorize } } } end end - - # ameba:disable Lint/UselessAssign - contents = - renderer.io.to_s - - ECR.render("#{__DIR__}/message.ecr") end def to_terminal @@ -149,34 +121,24 @@ module Mint blocks.each do |element| case element - # when TypeList - # renderer.type_list element.value - # when StringList - # renderer.list element.value - # when Pre - # renderer.pre element.value - # when Type - # renderer.type element.value - # when Title - # renderer.title element.value - when Error::Snippet + in Error::Snippet case node = element.value - when TypeChecker::Checkable + in TypeChecker::Checkable renderer.snippet node - when Ast::Node + in Ast::Node renderer.snippet node - when String + in String renderer.snippet node end - when Array(Error::Element) + in Array(Error::Element) renderer.block do element.each do |item| case item - when Error::Text + in Error::Text text item.value - when Error::Bold + in Error::Bold bold item.value - when Error::Code + in Error::Code code item.value end end diff --git a/src/ext/array.cr b/src/ext/array.cr index 8fa943582..0fe439fd6 100644 --- a/src/ext/array.cr +++ b/src/ext/array.cr @@ -6,4 +6,14 @@ class Array(T) def &+(other : Nil) : self self end + + def zip2(other : Array(T)) + map_with_index do |item, index| + [item, other[index]?].compact + end.flatten + end + + def intersperse(separator : T) + flat_map { |item| [item, separator] }.tap(&.pop?) + end end diff --git a/src/ext/dir.cr b/src/ext/dir.cr new file mode 100644 index 000000000..30cecfef4 --- /dev/null +++ b/src/ext/dir.cr @@ -0,0 +1,12 @@ +class Dir + def self.tempdir(&) + path = + Path[tempdir, Random::Secure.hex] + begin + FileUtils.mkdir_p(path) + FileUtils.cd(path) { yield } + ensure + FileUtils.rm_rf(path) + end + end +end diff --git a/src/ext/file.cr b/src/ext/file.cr new file mode 100644 index 000000000..c3adf5590 --- /dev/null +++ b/src/ext/file.cr @@ -0,0 +1,6 @@ +class File + def self.write_p(path, contents) + FileUtils.mkdir_p File.dirname(path) + File.write path, contents + end +end diff --git a/src/ext/libxml.cr b/src/ext/libxml.cr new file mode 100644 index 000000000..3cab8159f --- /dev/null +++ b/src/ext/libxml.cr @@ -0,0 +1,10 @@ +# These add support for writing raw text when builing XML. +lib LibXML + fun xmlTextWriterWriteRaw(TextWriter, content : UInt8*) : Int +end + +class XML::Builder + def raw(content : String) : Nil + call WriteRaw, string_to_unsafe(content) + end +end diff --git a/src/ext/string.cr b/src/ext/string.cr index 82cad06cc..81589338f 100644 --- a/src/ext/string.cr +++ b/src/ext/string.cr @@ -6,6 +6,13 @@ class String .rstrip end + def escape_for_javascript + self + .gsub('\\', "\\\\") + .gsub('`', "\\`") + .gsub("${", "\\${") + end + def last? : Char? self[-1]? end diff --git a/src/formatters/array_access.cr b/src/formatters/bracket_access.cr similarity index 77% rename from src/formatters/array_access.cr rename to src/formatters/bracket_access.cr index dd237a1b0..5530ac6cf 100644 --- a/src/formatters/array_access.cr +++ b/src/formatters/bracket_access.cr @@ -1,6 +1,6 @@ module Mint class Formatter - def format(node : Ast::ArrayAccess) : String + def format(node : Ast::BracketAccess) : String index = format node.index diff --git a/src/formatters/builtin.cr b/src/formatters/builtin.cr new file mode 100644 index 000000000..109c36f12 --- /dev/null +++ b/src/formatters/builtin.cr @@ -0,0 +1,7 @@ +module Mint + class Formatter + def format(node : Ast::Builtin) : String + "%#{node.value}%" + end + end +end diff --git a/src/formatters/comment.cr b/src/formatters/comment.cr index d9722305f..3d3da6924 100644 --- a/src/formatters/comment.cr +++ b/src/formatters/comment.cr @@ -1,25 +1,34 @@ module Mint class Formatter def format(node : Ast::Comment) : String - value = - node - .content - .remove_leading_whitespace - .rstrip + formatted = + if node.type.block? + value = + node + .content + .remove_leading_whitespace + .rstrip - if node.type.block? - if replace_skipped(value).includes?('\n') - "/*\n#{value}\n*/" + if replace_skipped(value).includes?('\n') + "/*\n#{value}\n*/" + else + "/* #{value} */" + end else - "/* #{value} */" - end - else - if value.size > 0 && value[0] != ' ' - "// #{value}" - else - "//#{value}" + value = + node.content + + if value.size > 0 && value[0] != ' ' + "// #{value}" + else + "//#{value}" + end end - end + + [ + formatted, + format(node.next_comment), + ].compact.join("\n") end end end diff --git a/src/formatters/component.cr b/src/formatters/component.cr index 33d8ae5d7..1d5be7fbe 100644 --- a/src/formatters/component.cr +++ b/src/formatters/component.cr @@ -21,10 +21,13 @@ module Mint global = node.global? ? "global " : "" + async = + node.async? ? "async " : "" + comment = node.comment.try { |item| "#{format item}\n" } - "#{comment}#{global}component #{name} {\n#{indent(body)}\n}" + "#{comment}#{async}#{global}component #{name} {\n#{indent(body)}\n}" end end end diff --git a/src/formatters/defer.cr b/src/formatters/defer.cr new file mode 100644 index 000000000..5276d3f22 --- /dev/null +++ b/src/formatters/defer.cr @@ -0,0 +1,10 @@ +module Mint + class Formatter + def format(node : Ast::Defer) : String + body = + format node.body + + "defer #{body}" + end + end +end diff --git a/src/formatters/field_access.cr b/src/formatters/field_access.cr new file mode 100644 index 000000000..7861372a6 --- /dev/null +++ b/src/formatters/field_access.cr @@ -0,0 +1,7 @@ +module Mint + class Formatter + def format(node : Ast::FieldAccess) : String + ".#{node.name.value}(#{format(node.type)})" + end + end +end diff --git a/src/formatters/here_doc.cr b/src/formatters/here_document.cr similarity index 70% rename from src/formatters/here_doc.cr rename to src/formatters/here_document.cr index c71072ce2..73a4a94fd 100644 --- a/src/formatters/here_doc.cr +++ b/src/formatters/here_document.cr @@ -13,7 +13,12 @@ module Mint end end - "<<#{node.modifier}#{node.token}#{value}#{node.token}" + flags = + if node.highlight + "(highlight)" + end + + "<<#{node.modifier}#{node.token}#{flags}#{value}#{node.token}" end end end diff --git a/src/formatters/html.cr b/src/formatters/html.cr index 57cd91785..0d05c277d 100644 --- a/src/formatters/html.cr +++ b/src/formatters/html.cr @@ -1,8 +1,11 @@ module Mint class Formatter - def format(node : Ast::HtmlElement | Ast::HtmlComponent, - prefix : String, - tag : String) : String + def format( + *, + node : Ast::HtmlElement | Ast::HtmlComponent, + prefix : String, + tag : String + ) : String attributes = format node.attributes diff --git a/src/formatters/html_attribute.cr b/src/formatters/html_attribute.cr index 23d256c63..1e9b13087 100644 --- a/src/formatters/html_attribute.cr +++ b/src/formatters/html_attribute.cr @@ -4,23 +4,23 @@ module Mint name = format node.name - value = - case x = node.value + formatted = + case value = node.value when Ast::Block - format x, BlockFormat::Attribute + format value, BlockFormat::Attribute else - format node.value + format value end case node.value when Ast::StringLiteral - if replace_skipped(value).includes?('\n') - "#{name}={\n#{indent(value)}\n}" + if replace_skipped(formatted).includes?('\n') + "#{name}={\n#{indent(formatted)}\n}" else - "#{name}=#{value}" + "#{name}=#{formatted}" end else - "#{name}=#{value}" + "#{name}=#{formatted}" end end end diff --git a/src/formatters/html_expression.cr b/src/formatters/html_expression.cr deleted file mode 100644 index 43e90ab14..000000000 --- a/src/formatters/html_expression.cr +++ /dev/null @@ -1,14 +0,0 @@ -module Mint - class Formatter - def format(node : Ast::HtmlExpression) : String - expressions = - list node.expressions - - if replace_skipped(expressions).includes?('\n') - "<{\n#{indent(expressions)}\n}>" - else - "<{ #{expressions} }>" - end - end - end -end diff --git a/src/formatters/js.cr b/src/formatters/js.cr index 321ef593e..2f234bdee 100644 --- a/src/formatters/js.cr +++ b/src/formatters/js.cr @@ -7,7 +7,7 @@ module Mint when Ast::Interpolation item.source else - format(item).gsub('`', "\\`") + format(item) end end diff --git a/src/formatters/list.cr b/src/formatters/list.cr index fe72e7495..cfa5c4db2 100644 --- a/src/formatters/list.cr +++ b/src/formatters/list.cr @@ -1,17 +1,18 @@ module Mint class Formatter + def list(nodes : Array(Ast::Node), delimeter : String? = nil) : String + list(nodes.zip(format(nodes)).to_a, delimeter) + end + # Formats a list of nodes while preserving # whitespace between them - def list(nodes : Array(Ast::Node)) : String + def list(nodes : Array(Tuple(Ast::Node, String)), delimeter : String? = nil) : String last_formatted = "" last = nil nodes - .sort_by(&.from) - .reduce("") do |memo, node| - # Format the node - formatted = format node - + .sort_by(&.first.from) + .reduce("") do |memo, (node, formatted)| next memo if formatted.empty? # If this is the first node @@ -28,16 +29,22 @@ module Mint separator = case when last.is_a?(Ast::Comment) && node.is_a?(Ast::Comment) - "\n\n" + if last.block? || node.block? + "\n\n" + else + "\n" + end when !last.is_a?(Ast::Comment) && node.is_a?(Ast::Comment) "\n\n" when last.is_a?(Ast::Comment) && node.responds_to?(:comment) && node.comment "\n\n" when last.is_a?(Ast::Comment) "\n" - when replace_skipped(last_formatted).includes?('\n') || - replace_skipped(formatted).includes?('\n') || - space_separated + when space_separated + "\n\n" + when !node.is_a?(Ast::Field) && !last.is_a?(Ast::Field) && + (replace_skipped(last_formatted).includes?('\n') || + replace_skipped(formatted).includes?('\n')) "\n\n" else "\n" @@ -48,7 +55,7 @@ module Mint last_formatted = formatted # Return memo - memo + separator + formatted + "#{memo}#{delimeter}#{separator}#{formatted}" end end end diff --git a/src/formatters/map.cr b/src/formatters/map.cr new file mode 100644 index 000000000..bab25e05c --- /dev/null +++ b/src/formatters/map.cr @@ -0,0 +1,27 @@ +module Mint + class Formatter + def format(node : Ast::Map) : String + body = + format node.fields + + types = + node.types.try do |items| + " of #{format(items[0])} => #{format(items[1])}" + end + + formatted = + if node.fields.size >= 2 || body.any? do |string| + replace_skipped(string).includes?('\n') + end + "{\n#{indent(body.join(",\n"))}\n}" + else + body = + body.join(", ").presence.try { |v| " #{v} " } || " " + + "{#{body}}" + end + + "#{formatted}#{types}" + end + end +end diff --git a/src/formatters/map_field.cr b/src/formatters/map_field.cr new file mode 100644 index 000000000..2d17dd7d1 --- /dev/null +++ b/src/formatters/map_field.cr @@ -0,0 +1,20 @@ +module Mint + class Formatter + def format(node : Ast::MapField) : String + value = + format node.value + + key = + format node.key + + comment = + node.comment.try { |item| "#{format(item)}\n" } + + if replace_skipped(value).includes?('\n') + "#{comment}#{key} =>\n#{indent(value)}" + else + "#{comment}#{key} => #{value}" + end + end + end +end diff --git a/src/formatters/member_access.cr b/src/formatters/member_access.cr deleted file mode 100644 index b7c18a5c6..000000000 --- a/src/formatters/member_access.cr +++ /dev/null @@ -1,7 +0,0 @@ -module Mint - class Formatter - def format(node : Ast::MemberAccess) : String - ".#{node.name.value}" - end - end -end diff --git a/src/formatters/record.cr b/src/formatters/record.cr index ce65d4f31..545ab207c 100644 --- a/src/formatters/record.cr +++ b/src/formatters/record.cr @@ -7,7 +7,7 @@ module Mint if node.fields.size >= 2 || multiline || body.any? do |string| replace_skipped(string).includes?('\n') end - "{\n#{indent(body.join(",\n"))}\n}" + "{\n#{indent(list(node.fields.zip(body), ","))}\n}" else body = body.join(", ").presence.try { |v| " #{v} " } || " " diff --git a/src/formatters/route.cr b/src/formatters/route.cr index 9efdd1b37..06563b3ea 100644 --- a/src/formatters/route.cr +++ b/src/formatters/route.cr @@ -14,7 +14,12 @@ module Mint " (#{args})" end - "#{node.url}#{arguments} #{body}" + await = + if node.await + " await" + end + + "#{node.url}#{arguments}#{await} #{body}" end end end diff --git a/src/formatters/state_setter.cr b/src/formatters/state_setter.cr new file mode 100644 index 000000000..5f9794ea0 --- /dev/null +++ b/src/formatters/state_setter.cr @@ -0,0 +1,13 @@ +module Mint + class Formatter + def format(node : Ast::StateSetter) : String + entity = + node + .entity + .try(&->format(Ast::Id)) + .try { |item| "#{item}" } + + "-> #{entity}#{node.state.value}" + end + end +end diff --git a/src/formatters/tuple_destructuring.cr b/src/formatters/tuple_destructuring.cr index 97f45c4f4..ef0379eee 100644 --- a/src/formatters/tuple_destructuring.cr +++ b/src/formatters/tuple_destructuring.cr @@ -1,7 +1,7 @@ module Mint class Formatter def format(node : Ast::TupleDestructuring) - "#(#{format(node.items, ", ")})" + "{#{format(node.items, ", ")}}" end end end diff --git a/src/formatters/tuple_literal.cr b/src/formatters/tuple_literal.cr index ba26cfc81..7426ed62c 100644 --- a/src/formatters/tuple_literal.cr +++ b/src/formatters/tuple_literal.cr @@ -12,9 +12,9 @@ module Mint format node.items, mutliline ? ",\n" : ", " if mutliline || replace_skipped(items).includes?('\n') - "#(\n#{indent(items)}\n)" + "{\n#{indent(items)}\n}" else - "#(#{items})" + "{#{items}}" end end end diff --git a/src/formatters/type_definition.cr b/src/formatters/type_definition.cr index 584f77a3f..0f185188c 100644 --- a/src/formatters/type_definition.cr +++ b/src/formatters/type_definition.cr @@ -9,7 +9,7 @@ module Mint when Array(Ast::TypeVariant) list node.fields else - format node.fields, ",\n" + list node.fields, "," end comment = diff --git a/src/helpers.cr b/src/helpers.cr index 673385693..5f2aeaa68 100644 --- a/src/helpers.cr +++ b/src/helpers.cr @@ -82,8 +82,7 @@ module Mint node.value.all?(String) when Ast::HtmlAttribute static?(node.value) - when Ast::HtmlExpression, - Ast::Block + when Ast::Block static?(node.expressions) when Ast::Statement static?(node.expression) @@ -121,8 +120,7 @@ module Mint node.value.select(String).join when Ast::HtmlAttribute "#{node.name.value}=#{static_value(node.value)}" - when Ast::HtmlExpression, - Ast::Block + when Ast::Block static_value(node.expressions) when Ast::Statement static_value(node.expression) diff --git a/src/logger.cr b/src/logger.cr new file mode 100644 index 000000000..42949a448 --- /dev/null +++ b/src/logger.cr @@ -0,0 +1,82 @@ +module Mint + # This class if for logging timings. It supports nesting timings + # and printing them in a tree. + module Logger + extend self + + class Log + # The elapsed time of the log. + property elapsed = Time::Span.new(nanoseconds: 0) + + # The child logs. + getter logs = Array(Log).new + + # The mssage. + getter message : String + + def initialize(@message) + end + + # The real time of the log. + def real : Time::Span + elapsed - logs.sum(&.real) + end + + # Processes the logs for printing. + def print : Array(Tuple(String, Time::Span)) + logs + .flat_map(&.print) + .map { |(item, elapsed)| {item.indent, elapsed} } + .unshift({message, real}) + end + end + + # The current log, calls new logs will be nested in this one. + @@current : Log | Array(Log) = [] of Log + + # Prints the gathered logs. + def print(io) + logs = + case item = @@current + in Log + item.print + in Array(Log) + item.flat_map(&.print) + end + + width = + logs.max_of(&.first.size) + + logs.each do |(message, elapsed)| + formatted = + TimeFormat.auto(elapsed).colorize.mode(:bold) + + io.puts "#{message.ljust(width)} | #{formatted}" + end + end + + # Logs the message with the block elapsed time. + def log(message, &) + log = + Log.new(message) + + previous = @@current + @@current = log + + case previous + in Log + previous.logs << log + in Array(Log) + previous << log + end + + start = + Time.monotonic + + yield.tap do + log.elapsed = Time.monotonic - start + @@current = previous + end + end + end +end diff --git a/src/ls/completion_item/constant.cr b/src/ls/completion_item/constant.cr index c7907ff4b..d4a43f20e 100644 --- a/src/ls/completion_item/constant.cr +++ b/src/ls/completion_item/constant.cr @@ -4,7 +4,7 @@ module Mint def completion_item(node : Ast::Constant, parent_name : Ast::Id? = nil) : LSP::CompletionItem name = if parent_name - "#{parent_name.value}:#{node.name.value}" + "#{parent_name.value}.#{node.name.value}" else node.name.value end diff --git a/src/ls/completion_item/function.cr b/src/ls/completion_item/function.cr index 760af5028..a744a11bc 100644 --- a/src/ls/completion_item/function.cr +++ b/src/ls/completion_item/function.cr @@ -16,15 +16,10 @@ module Mint %(${#{index + 1}:#{argument.name.value}}) end - snippet = - <<-MINT - #{name}(#{arguments.join(", ")}) - MINT - LSP::CompletionItem.new( documentation: node.comment.try(&.content).to_s, + insert_text: "#{name}(#{arguments.join(", ")})", kind: LSP::CompletionItemKind::Function, - insert_text: snippet, detail: "Function", filter_text: name, sort_text: name, diff --git a/src/ls/completions/type_definition.cr b/src/ls/completions/type_definition.cr index 407abe392..871810461 100644 --- a/src/ls/completions/type_definition.cr +++ b/src/ls/completions/type_definition.cr @@ -6,7 +6,7 @@ module Mint when Array(Ast::TypeVariant) fields.map do |option| name = - "#{node.name.value}::#{option.value.value}" + "#{node.name.value}.#{option.value.value}" snippet = if option.parameters.empty? diff --git a/src/mint_json.cr b/src/mint_json.cr index e14bc325d..ad9d607ac 100644 --- a/src/mint_json.cr +++ b/src/mint_json.cr @@ -24,14 +24,16 @@ module Mint getter web_components = {} of String => String getter source_directories = %w[] getter test_directories = %w[] - getter external_files = { - "javascripts" => %w[], - "stylesheets" => %w[], - } getter application = Application.new getter root : String getter name = "" + def initialize + @json = "" + @root = "" + @file = "" + end + def initialize(@json : String, @root : String, @file : String) begin @parser = JSON::PullParser.new(@json) @@ -146,8 +148,6 @@ module Mint parse_dependencies when "formatter" parse_formatter - when "external" - parse_external_assets when "web-components" parse_web_components else @@ -395,152 +395,6 @@ module Mint end end - # Parsing external assets (JavaScripts, CSS) - # -------------------------------------------------------------------------- - - def parse_external_assets - @parser.read_object do |key| - case key - when "javascripts" - parse_external_javascripts - when "stylesheets" - parse_external_style_sheets - else - error! :mint_json_external_invalid do - block do - text "The" - bold "external" - text "field contain at least one item." - end - - block do - text "The" - bold "javascripts" - text "field lists all JavaScript files (relative to the mint.json file)" - text "which should be compiled alongside the application." - end - - block do - text "The" - bold "stylesheets" - text "field lists all CSS files (relative to the mint.json file)" - text "which should be included alongside the application." - end - - snippet current_node - end - end - end - end - - def parse_external_javascripts - @parser.read_array { parse_external_javascript } - rescue exception : JSON::ParseException - error! :mint_json_external_javascripts_invalid do - block do - text "The" - bold "javascripts" - text "field should be an array." - end - - block do - text "The" - bold "javascripts" - text "field lists all JavaScript files (relative to the mint.json file)" - text "which should be compiled alongside the application." - end - - snippet node(exception) - end - end - - def parse_external_javascript - location = - @parser.location - - file = - @parser.read_string - - path = - Path[@root, file].to_s - - error! :mint_json_external_javascript_not_exists do - block do - text "The external JavaScript file" - bold path - text "does not exist." - end - - snippet node(location) - end if !File.exists?(path) || Dir.exists?(path) - - @external_files["javascripts"] << path - rescue exception : JSON::ParseException - error! :mint_json_external_javascript_invalid do - block do - text "All entries in the" - bold "javascripts" - text "array should be string." - end - - snippet "I found one that it is not:", node(exception) - end - end - - def parse_external_style_sheets - @parser.read_array { parse_external_style_sheet } - rescue exception : JSON::ParseException - error! :mint_json_external_stylesheets_invalid do - block do - text "The" - bold "stylesheets" - text "field should be an array." - end - - block do - text "The" - bold "stylesheets" - text "field lists all CSS files (relative to the mint.json file)" - text "which should be included alongside the application." - end - - snippet node(exception) - end - end - - def parse_external_style_sheet - location = - @parser.location - - file = - @parser.read_string - - path = - Path[@root, file].to_s - - error! :mint_json_external_stylesheet_not_exists do - block do - text "The external stylesheet file" - bold path - text "does not exist." - end - - snippet node(location) - end unless File.file?(path) - - @external_files["stylesheets"] << file - rescue exception : JSON::ParseException - error! :mint_json_external_stylesheet_invalid do - block do - text "All entries in the" - bold "stylesheets" - text "array should be string." - end - - snippet "I found one that it is not:", node(exception) - end - end - # Parsing the source directories # -------------------------------------------------------------------------- diff --git a/src/parser.cr b/src/parser.cr index fb42bf360..34ef9c8a1 100644 --- a/src/parser.cr +++ b/src/parser.cr @@ -35,6 +35,7 @@ module Mint (yield position, nodes_size, @errors.size).tap do |node| case node when Ast::Node + ast.nodes[nodes_size..-1].each { |child| child.parent ||= node unless child == node } ast.nodes << node if track when Nil ast.operators.delete_at(operators_size...) @@ -170,19 +171,19 @@ module Mint def word!(expected : String) : Bool if word?(expected) @position += expected.size - - if expected.chars.all?(&.ascii_lowercase?) && - !expected.blank? && - expected != "or" - @ast.keywords << {position - expected.size, position} - end - true else false end end + # Consumes a word and saves it as a keyword for syntax highlighting. + def keyword!(expected : String) : Bool + word!(expected).tap do |result| + @ast.keywords << {position - expected.size, position} if result + end + end + # Consumes all available whitespace. def whitespace : Nil chars &.ascii_whitespace? @@ -223,7 +224,7 @@ module Mint ascii_letters_or_numbers end - next if char == '_' + next if char == '_' # If there is an underscore it's a constant... next unless name parse do diff --git a/src/parser/top_level.cr b/src/parser/top_level.cr index 3844ca073..2968caa52 100644 --- a/src/parser/top_level.cr +++ b/src/parser/top_level.cr @@ -50,5 +50,41 @@ module Mint end end end + + def parse_any : Nil + many do + oneof do + module_definition || + type_definition || + html_attribute || + interpolation || + css_font_face || + css_keyframes || + component || + constant || + property || + operator || + provider || + function || + comment || + connect || + locale || + routes || + route || + state || + style || + store || + suite || + test || + get || + use || + statement || + case_branch || + destructuring || + css_node || + expression + end + end + end end end diff --git a/src/parsers/access.cr b/src/parsers/access.cr index 7ba89410b..982b5f943 100644 --- a/src/parsers/access.cr +++ b/src/parsers/access.cr @@ -2,7 +2,7 @@ module Mint class Parser def access(expression : Ast::Node) : Ast::Access? parse do - # TODO: Remove this if chain in 0.21.0 when deprecation ends. + # TODO: Remove this in 0.21.0 type = if word! "::" Ast::Access::Type::DoubleColon diff --git a/src/parsers/array_literal.cr b/src/parsers/array_literal.cr index 1c1f725ef..97acf0c56 100644 --- a/src/parsers/array_literal.cr +++ b/src/parsers/array_literal.cr @@ -19,7 +19,7 @@ module Mint type = parse(track: false) do whitespace - next unless word! "of" + next unless keyword! "of" whitespace next error :array_expected_type_or_variable do diff --git a/src/parsers/base_expression.cr b/src/parsers/base_expression.cr index 7139db1d3..e577dfd7a 100644 --- a/src/parsers/base_expression.cr +++ b/src/parsers/base_expression.cr @@ -12,7 +12,7 @@ module Mint when '(' parenthesized_expression || inline_function when '-', .ascii_number? - number_literal || unary_minus + state_setter || number_literal || unary_minus when '!' negated_expression when '"' @@ -22,7 +22,7 @@ module Mint when '#' tuple_literal when '.' - member_access + field_access when '[' array_literal when ':' @@ -39,14 +39,14 @@ module Mint svg_directive || env when '<' - html_expression || - html_component || + html_component || here_document || html_element || html_fragment when '{' record_update || record || + map || tuple_literal || block else @@ -67,6 +67,8 @@ module Mint decode when "encode" encode + when "defer" + defer else value end @@ -76,7 +78,7 @@ module Mint # We try to chain accesses and calls until we can. # - # TODO: Remove `::`, `:` cases in 0.21.0 when deprecation ends. + # TODO: Remove `::`, `:` cases in 0.21.0 loop do node = if word? "::" @@ -90,7 +92,7 @@ module Mint when '(' call(left) when '[' - array_access(left) + bracket_access(left) end end diff --git a/src/parsers/bool_literal.cr b/src/parsers/bool_literal.cr index a707bcb78..188a854d1 100644 --- a/src/parsers/bool_literal.cr +++ b/src/parsers/bool_literal.cr @@ -4,9 +4,9 @@ module Mint parse do |start_position| value = case - when word! "true" + when keyword! "true" true - when word! "false" + when keyword! "false" false else next diff --git a/src/parsers/array_access.cr b/src/parsers/bracket_access.cr similarity index 54% rename from src/parsers/array_access.cr rename to src/parsers/bracket_access.cr index 1adb89985..c4262c6b8 100644 --- a/src/parsers/array_access.cr +++ b/src/parsers/bracket_access.cr @@ -1,22 +1,22 @@ module Mint class Parser - def array_access(expression : Ast::Node) : Ast::ArrayAccess? + def bracket_access(expression : Ast::Node) : Ast::BracketAccess? parse do |start_position| next unless char! '[' whitespace - next error :array_access_expected_index do - expected "the index of an array access", word + next error :bracket_access_expected_index do + expected "the index of a bracket access", word snippet self end unless index = self.expression whitespace - next error :array_access_expected_closing_bracket do - expected "the closing bracket of an array access", word + next error :bracket_access_expected_closing_bracket do + expected "the closing bracket of a bracket access", word snippet self end unless char! ']' - Ast::ArrayAccess.new( + Ast::BracketAccess.new( expression: expression, from: start_position, to: position, diff --git a/src/parsers/builtin.cr b/src/parsers/builtin.cr new file mode 100644 index 000000000..a489b3d76 --- /dev/null +++ b/src/parsers/builtin.cr @@ -0,0 +1,17 @@ +module Mint + class Parser + def builtin : Ast::Builtin? + parse do |start_position| + next unless char! '%' + next unless value = identifier_variable + next unless char! '%' + + Ast::Builtin.new( + from: start_position, + value: value, + to: position, + file: file) + end + end + end +end diff --git a/src/parsers/case.cr b/src/parsers/case.cr index 8fec12956..263757a8a 100644 --- a/src/parsers/case.cr +++ b/src/parsers/case.cr @@ -2,13 +2,13 @@ module Mint class Parser def case_expression(*, for_css : Bool = false) : Ast::Case? parse do |start_position| - next unless word! "case" + next unless keyword! "case" whitespace parenthesis = char! '(' whitespace - await = word! "await" + await = keyword! "await" whitespace next error :case_expected_condition do diff --git a/src/parsers/comment.cr b/src/parsers/comment.cr index 3d5ced3a1..7804b25d1 100644 --- a/src/parsers/comment.cr +++ b/src/parsers/comment.cr @@ -2,7 +2,7 @@ module Mint class Parser def comment : Ast::Comment? parse do |start_position| - content, type = + content, type, next_comment = if word! "/*" consumed = gather { consume { !word?("*/") && !eof? } }.to_s @@ -12,20 +12,27 @@ module Mint snippet self end unless word! "*/" - {consumed, Ast::Comment::Type::Block} + {consumed, Ast::Comment::Type::Block, nil} elsif word! "//" consumed = gather { consume { char != '\n' && !eof? } }.to_s - {consumed, Ast::Comment::Type::Inline} + comment = + parse do + spaces = gather { whitespace }.to_s + next unless word?("//") && spaces.count('\n') == 1 + self.comment + end + + {consumed, Ast::Comment::Type::Inline, comment} else - {nil, Ast::Comment::Type::Block} + {nil, Ast::Comment::Type::Block, nil} end - whitespace # TODO: Figure out why is this is needed next unless content Ast::Comment.new( + next_comment: next_comment, from: start_position, content: content, to: position, diff --git a/src/parsers/component.cr b/src/parsers/component.cr index 44b675b20..fa82b99cd 100644 --- a/src/parsers/component.cr +++ b/src/parsers/component.cr @@ -3,11 +3,15 @@ module Mint def component : Ast::Component? parse do |start_position, start_nodes_position| comment = self.comment + whitespace + + global = keyword! "global" + whitespace - global = word! "global" + async = keyword! "async" whitespace - next unless word! "component" + next unless keyword! "component" whitespace next error :component_expected_name do @@ -133,6 +137,7 @@ module Mint locales: locales, styles: styles, states: states, + async: async, to: position, file: file, refs: refs, diff --git a/src/parsers/connect.cr b/src/parsers/connect.cr index d53cc5e8b..97473d21d 100644 --- a/src/parsers/connect.cr +++ b/src/parsers/connect.cr @@ -2,7 +2,7 @@ module Mint class Parser def connect : Ast::Connect? parse do |start_position| - next unless word! "connect" + next unless keyword! "connect" whitespace next error :connect_expected_store do @@ -14,7 +14,7 @@ module Mint next error :connect_expected_exposing do expected %(the "exposing" keyword for a connect), word snippet self - end unless word! "exposing" + end unless keyword! "exposing" whitespace keys = diff --git a/src/parsers/connect_variable.cr b/src/parsers/connect_variable.cr index ae7e7c80b..68da2432a 100644 --- a/src/parsers/connect_variable.cr +++ b/src/parsers/connect_variable.cr @@ -6,7 +6,7 @@ module Mint variable(track: false) whitespace - if word! "as" + if keyword! "as" whitespace next error :connect_variable_expected_as do diff --git a/src/parsers/constant.cr b/src/parsers/constant.cr index 347eafa6e..a5824b267 100644 --- a/src/parsers/constant.cr +++ b/src/parsers/constant.cr @@ -5,7 +5,7 @@ module Mint comment = self.comment whitespace - next unless word! "const" + next unless keyword! "const" whitespace next error :constant_expected_name do diff --git a/src/parsers/decode.cr b/src/parsers/decode.cr index 4ab488c11..47782ffac 100644 --- a/src/parsers/decode.cr +++ b/src/parsers/decode.cr @@ -2,10 +2,10 @@ module Mint class Parser def decode : Ast::Decode? parse do |start_position| - next unless word! "decode" + next unless keyword! "decode" whitespace - unless word! "as" + unless keyword! "as" whitespace next error :decode_expected_subject do expected "the subject of a decode expression", word @@ -16,7 +16,7 @@ module Mint next error :decode_expected_as do expected %(the "as" keyword of a decode expression), word snippet self - end unless word! "as" + end unless keyword! "as" end whitespace diff --git a/src/parsers/defer.cr b/src/parsers/defer.cr new file mode 100644 index 000000000..5964bc9d4 --- /dev/null +++ b/src/parsers/defer.cr @@ -0,0 +1,18 @@ +module Mint + class Parser + def defer : Ast::Defer? + parse do |start_position| + next unless keyword! "defer" + + whitespace + next unless body = expression + + Ast::Defer.new( + from: start_position, + to: position, + file: file, + body: body) + end + end + end +end diff --git a/src/parsers/directives/asset.cr b/src/parsers/directives/asset.cr index 30553d6f8..d017eb06d 100644 --- a/src/parsers/directives/asset.cr +++ b/src/parsers/directives/asset.cr @@ -2,7 +2,7 @@ module Mint class Parser def asset_directive : Ast::Directives::Asset? parse do |start_position| - next unless word! "@asset" + next unless keyword! "@asset" next error :asset_directive_expected_opening_parenthesis do expected "the opening parenthesis of an asset directive", word diff --git a/src/parsers/directives/documentation.cr b/src/parsers/directives/documentation.cr index 6391701be..94ca09e98 100644 --- a/src/parsers/directives/documentation.cr +++ b/src/parsers/directives/documentation.cr @@ -2,7 +2,7 @@ module Mint class Parser def documentation_directive : Ast::Directives::Documentation? parse do |start_position| - next unless word! "@documentation" + next unless keyword! "@documentation" next error :documentation_directive_expected_opening_parenthesis do expected "the opening parenthesis of a documentation directive", word diff --git a/src/parsers/directives/format.cr b/src/parsers/directives/format.cr index ebc61e751..76769bf7b 100644 --- a/src/parsers/directives/format.cr +++ b/src/parsers/directives/format.cr @@ -2,7 +2,7 @@ module Mint class Parser def format_directive : Ast::Directives::Format? parse do |start_position| - next unless word! "@format" + next unless keyword! "@format" whitespace content = diff --git a/src/parsers/directives/highlight.cr b/src/parsers/directives/highlight.cr index 2466160f6..a789f5238 100644 --- a/src/parsers/directives/highlight.cr +++ b/src/parsers/directives/highlight.cr @@ -2,7 +2,7 @@ module Mint class Parser def highlight_directive : Ast::Directives::Highlight? parse do |start_position| - next unless word! "@highlight" + next unless keyword! "@highlight" whitespace content = diff --git a/src/parsers/directives/highlight_file.cr b/src/parsers/directives/highlight_file.cr index 538f9d822..95cdf6e0b 100644 --- a/src/parsers/directives/highlight_file.cr +++ b/src/parsers/directives/highlight_file.cr @@ -2,7 +2,7 @@ module Mint class Parser def highlight_file_directive : Ast::Directives::HighlightFile? parse do |start_position| - next unless word! "@highlight-file" + next unless keyword! "@highlight-file" whitespace next error :highlight_file_directive_expected_opening_parenthesis do diff --git a/src/parsers/directives/inline.cr b/src/parsers/directives/inline.cr index 467b775b6..2ffaa6d53 100644 --- a/src/parsers/directives/inline.cr +++ b/src/parsers/directives/inline.cr @@ -2,7 +2,7 @@ module Mint class Parser def inline_directive : Ast::Directives::Inline? parse do |start_position| - next unless word! "@inline" + next unless keyword! "@inline" next error :inline_directive_expected_opening_parenthesis do expected "the opening parenthesis of an inline directive", word diff --git a/src/parsers/directives/svg.cr b/src/parsers/directives/svg.cr index c86925b61..9ff0b29c4 100644 --- a/src/parsers/directives/svg.cr +++ b/src/parsers/directives/svg.cr @@ -2,7 +2,7 @@ module Mint class Parser def svg_directive : Ast::Directives::Svg? parse do |start_position| - next unless word! "@svg" + next unless keyword! "@svg" next error :svg_directive_expected_opening_parenthesis do expected "the opening parenthesis of an svg directive", word diff --git a/src/parsers/encode.cr b/src/parsers/encode.cr index f7dc7d71e..5551f0c7c 100644 --- a/src/parsers/encode.cr +++ b/src/parsers/encode.cr @@ -2,7 +2,7 @@ module Mint class Parser def encode : Ast::Encode? parse do |start_position| - next unless word! "encode" + next unless keyword! "encode" whitespace next error :encode_expected_expression do diff --git a/src/parsers/field.cr b/src/parsers/field.cr index aeb957587..66853458d 100644 --- a/src/parsers/field.cr +++ b/src/parsers/field.cr @@ -3,6 +3,7 @@ module Mint def field(*, key_required : Bool = true) : Ast::Field? parse do |start_position| comment = self.comment + whitespace key = parse(track: false) do diff --git a/src/parsers/field_access.cr b/src/parsers/field_access.cr new file mode 100644 index 000000000..43709a2ed --- /dev/null +++ b/src/parsers/field_access.cr @@ -0,0 +1,39 @@ +module Mint + class Parser + def field_access : Ast::FieldAccess? + parse do |start_position| + next unless char! '.' + + next error :field_access_expected_variable do + expected "the field of the accessed entity of a field access", word + snippet self + end unless name = variable + + whitespace + next error :field_access_expected_opening_parenthesis do + expected "the opening parenthesis of a field access", word + snippet self + end unless char! '(' + + whitespace + next error :field_access_expected_type do + expected "the type of a field access", word + snippet self + end unless type = self.type + + whitespace + next error :field_access_expected_closing_parenthesis do + expected "the closing parentheses of a field access", word + snippet self + end unless char! ')' + + Ast::FieldAccess.new( + from: start_position, + to: position, + type: type, + file: file, + name: name) + end + end + end +end diff --git a/src/parsers/for.cr b/src/parsers/for.cr index 02e80257c..41d1e1283 100644 --- a/src/parsers/for.cr +++ b/src/parsers/for.cr @@ -2,7 +2,7 @@ module Mint class Parser def for_expression : Ast::For? parse do |start_position| - next unless word! "for" + next unless keyword! "for" whitespace parens = char! '(' @@ -15,7 +15,7 @@ module Mint next error :for_expected_of do expected %(the "of" keyword of a for expression), word snippet self - end unless word! "of" + end unless keyword! "of" whitespace next error :for_expected_subject do @@ -49,7 +49,7 @@ module Mint whitespace condition = - if word! "when" + if keyword! "when" whitespace block( diff --git a/src/parsers/function.cr b/src/parsers/function.cr index 5500c315b..bc4763025 100644 --- a/src/parsers/function.cr +++ b/src/parsers/function.cr @@ -3,8 +3,9 @@ module Mint def function : Ast::Function? parse do |start_position| comment = self.comment + whitespace - next unless word! "fun" + next unless keyword! "fun" whitespace next error :function_expected_name do @@ -36,6 +37,7 @@ module Mint snippet self end unless item = self.type || type_variable whitespace + item end diff --git a/src/parsers/get.cr b/src/parsers/get.cr index 2df6308ea..1a39fe1c5 100644 --- a/src/parsers/get.cr +++ b/src/parsers/get.cr @@ -3,8 +3,9 @@ module Mint def get : Ast::Get? parse do |start_position| comment = self.comment + whitespace - next unless word! "get" + next unless keyword! "get" whitespace next error :get_expected_name do @@ -21,6 +22,7 @@ module Mint snippet self end unless item = self.type || type_variable whitespace + item end diff --git a/src/parsers/here_document.cr b/src/parsers/here_document.cr index 161a044a5..e40f93f3f 100644 --- a/src/parsers/here_document.cr +++ b/src/parsers/here_document.cr @@ -11,6 +11,17 @@ module Mint token = identifier_constant + if char!('(') + whitespace + highlight = keyword!("highlight") + + whitespace + next error :here_doc_expected_closing_parenthesis do + expected "the closing parenthesis of here document flags", word + snippet self + end unless char!(')') + end + next error :here_document_expected_start do expected "the start tag of a here document", word snippet self @@ -25,6 +36,7 @@ module Mint Ast::HereDocument.new( from: start_position, + highlight: highlight, modifier: modifier, token: token, value: value, diff --git a/src/parsers/html_attribute.cr b/src/parsers/html_attribute.cr index 553c4e798..649326b56 100644 --- a/src/parsers/html_attribute.cr +++ b/src/parsers/html_attribute.cr @@ -2,6 +2,9 @@ module Mint class Parser def html_attribute(with_dashes : Bool = true) : Ast::HtmlAttribute? parse do |start_position| + # Dash (-) is maily for data attributes (data-value), colon (`:`) is + # for namespaces (xlink:actuate) and we only parse them for HTML + # attributes not component attributes (`with_dashes`). name = variable track: false, extra_chars: with_dashes ? ['-', ':'] : [] of Char next unless name @@ -10,28 +13,23 @@ module Mint snippet self end unless char! '=' - case - when word?("<{") && (value = html_expression) - value - when char == '"' && (value = string_literal) - value - when char == '[' && (value = array_literal) - value - else - value = block( - ->{ error :html_attribute_expected_opening_bracket do - expected "the opening bracket of an HTML attribute", word - snippet self - end }, - ->{ error :html_attribute_expected_closing_bracket do - expected "the closing bracket of an HTML attribute", word - snippet self - end }, - ->{ error :html_attribute_expected_expression do - expected "the expression of an HTML attribute", word - snippet self - end }) - end + value = + html_fragment || + string_literal || + array_literal || + block( + ->{ error :html_attribute_expected_opening_bracket do + expected "the opening bracket of an HTML attribute", word + snippet self + end }, + ->{ error :html_attribute_expected_closing_bracket do + expected "the closing bracket of an HTML attribute", word + snippet self + end }, + ->{ error :html_attribute_expected_expression do + expected "the expression of an HTML attribute", word + snippet self + end }) next unless value diff --git a/src/parsers/html_body.cr b/src/parsers/html_body.cr index 7cf7c1b68..c6e2d81fa 100644 --- a/src/parsers/html_body.cr +++ b/src/parsers/html_body.cr @@ -1,9 +1,12 @@ module Mint class Parser - def html_body(expected_closing_bracket : Proc(Nil), - expected_closing_tag : Proc(Nil), - tag : Ast::Variable | Ast::Id, - with_dashes : Bool) + def html_body( + *, + expected_closing_bracket : Proc(Nil), + expected_closing_tag : Proc(Nil), + tag : Ast::Variable | Ast::Id, + with_dashes : Bool + ) parse(track: false) do attributes = many { html_attribute(with_dashes) } whitespace @@ -15,7 +18,7 @@ module Mint children = [] of Ast::Node unless self_closing - items = many { expression || comment } + items = many { comment || expression } whitespace closing_tag = diff --git a/src/parsers/html_component.cr b/src/parsers/html_component.cr index da3b3013b..67d8f54c1 100644 --- a/src/parsers/html_component.cr +++ b/src/parsers/html_component.cr @@ -6,7 +6,7 @@ module Mint next unless component = id whitespace - if word! "as" + if keyword! "as" whitespace next error :html_component_expected_reference do diff --git a/src/parsers/html_element.cr b/src/parsers/html_element.cr index b74a76c80..b0797a403 100644 --- a/src/parsers/html_element.cr +++ b/src/parsers/html_element.cr @@ -20,7 +20,7 @@ module Mint end whitespace - if word! "as" + if keyword! "as" whitespace next error :html_element_expected_reference do expected "the reference of an HTML element", word diff --git a/src/parsers/html_expression.cr b/src/parsers/html_expression.cr deleted file mode 100644 index 8bc141c39..000000000 --- a/src/parsers/html_expression.cr +++ /dev/null @@ -1,24 +0,0 @@ -module Mint - class Parser - def html_expression : Ast::HtmlExpression? - parse do |start_position| - next unless word! "<{" - - whitespace - expressions = many { expression } - whitespace - - next error :html_expression_expected_closing_tag do - expected "the closing tag of an HTML expression", word - snippet self - end unless word! "}>" - - Ast::HtmlExpression.new( - expressions: expressions, - from: start_position, - to: position, - file: file) - end - end - end -end diff --git a/src/parsers/html_fragment.cr b/src/parsers/html_fragment.cr index 8bba3ec5e..96b2d74f9 100644 --- a/src/parsers/html_fragment.cr +++ b/src/parsers/html_fragment.cr @@ -2,7 +2,8 @@ module Mint class Parser def html_fragment : Ast::HtmlFragment? parse do |start_position| - next unless word! "<>" + # TODO: Remove <{}> in 0.21.0 + next unless word!("<>") || word!("<{") comments = [] of Ast::Comment children = [] of Ast::Node @@ -20,7 +21,7 @@ module Mint next error :html_fragment_expected_closing_tag do expected "the closing tag of an HTML fragment", word snippet self - end unless word! "" + end unless word!("") || word!("}>") # TODO: Remove <{}> in 0.21.0 Ast::HtmlFragment.new( from: start_position, diff --git a/src/parsers/html_style.cr b/src/parsers/html_style.cr index 36aaf5958..55be8286a 100644 --- a/src/parsers/html_style.cr +++ b/src/parsers/html_style.cr @@ -5,11 +5,14 @@ module Mint next unless word! "::" next unless name = variable track: false, extra_chars: ['-'] - arguments = [] of Ast::Node + arguments = [] of Ast::Field if char! '(' whitespace - arguments = list(terminator: ')', separator: ',') { expression } + arguments = list( + terminator: ')', + separator: ',' + ) { field(key_required: false) } whitespace next error :html_style_expected_closing_parenthesis do diff --git a/src/parsers/if.cr b/src/parsers/if.cr index 6ed704384..e2686a89c 100644 --- a/src/parsers/if.cr +++ b/src/parsers/if.cr @@ -2,7 +2,7 @@ module Mint class Parser def if_expression(for_css = false) : Ast::If? parse do |start_position| - next unless word! "if" + next unless keyword! "if" whitespace parens = char! '(' @@ -41,7 +41,7 @@ module Mint falsy = nil whitespace - if word! "else" + if keyword! "else" whitespace unless falsy = if_expression(for_css: for_css) diff --git a/src/parsers/interpolation.cr b/src/parsers/interpolation.cr index ad50e5bfe..53049810f 100644 --- a/src/parsers/interpolation.cr +++ b/src/parsers/interpolation.cr @@ -1,6 +1,10 @@ module Mint class Parser def interpolation : Ast::Interpolation? + interpolation { expression } + end + + def interpolation(& : -> Ast::Node?) : Ast::Interpolation? parse do |start_position| next unless word! "\#{" whitespace @@ -8,7 +12,7 @@ module Mint next error :interpolation_expected_expression do expected "the expression of an interpolation", word snippet self - end unless expression = self.expression + end unless expression = yield whitespace next error :interpolation_expected_closing_bracket do diff --git a/src/parsers/js.cr b/src/parsers/js.cr index 61599c07d..5de49cec5 100644 --- a/src/parsers/js.cr +++ b/src/parsers/js.cr @@ -6,7 +6,7 @@ module Mint value = many(parse_whitespace: false) do - raw('`').try(&.gsub("\\`", '`')) || interpolation + raw('`') || interpolation { builtin || expression } end next error :js_expected_closing_tick do @@ -15,7 +15,7 @@ module Mint end unless char! '`' whitespace - if word! "as" + if keyword! "as" whitespace next error :js_expected_type_or_variable do expected "the type of an inlined JavaScript", word @@ -26,8 +26,8 @@ module Mint Ast::Js.new( from: start_position, value: value, - type: type, to: position, + type: type, file: file) end end diff --git a/src/parsers/locale.cr b/src/parsers/locale.cr index 5b0714bc9..afec5b9a6 100644 --- a/src/parsers/locale.cr +++ b/src/parsers/locale.cr @@ -3,8 +3,9 @@ module Mint def locale : Ast::Locale? parse do |start_position| comment = self.comment + whitespace - next unless word! "locale" + next unless keyword! "locale" whitespace next error :locale_expected_language do diff --git a/src/parsers/map.cr b/src/parsers/map.cr new file mode 100644 index 000000000..7620dd5d2 --- /dev/null +++ b/src/parsers/map.cr @@ -0,0 +1,52 @@ +module Mint + class Parser + def map : Ast::Map? + parse do |start_position| + next unless char! '{' + + fields = [] of Ast::MapField + + unless char! '}' + whitespace + fields = list(terminator: '}', separator: ',') { map_field } + whitespace + + next unless char! '}' + end + + types = + parse do + whitespace + next unless word! "of" + + whitespace + next error :map_expected_key_type do + expected "the type of the keys of a map", word + snippet self + end unless key_type = type || type_variable + + whitespace + next error :map_expected_arrow do + expected "the arrow for the types of a map", word + snippet self + end unless word! "=>" + + whitespace + next error :map_expected_value_type do + expected "the type of the values of a map", word + snippet self + end unless value_type = type || type_variable + + {key_type, value_type} + end + + Ast::Map.new( + from: start_position, + fields: fields, + types: types, + to: position, + file: file) + end + end + end +end diff --git a/src/parsers/map_field.cr b/src/parsers/map_field.cr new file mode 100644 index 000000000..7fa5fcade --- /dev/null +++ b/src/parsers/map_field.cr @@ -0,0 +1,29 @@ +module Mint + class Parser + def map_field : Ast::MapField? + parse do |start_position| + comment = self.comment + + whitespace + next unless key = expression + + whitespace + next unless word! "=>" + + whitespace + next error :map_field_expected_expression do + expected "the value of a map field", word + snippet self + end unless value = expression + + Ast::MapField.new( + from: start_position, + comment: comment, + value: value, + to: position, + file: file, + key: key) + end + end + end +end diff --git a/src/parsers/member_access.cr b/src/parsers/member_access.cr deleted file mode 100644 index 52bbfb0dc..000000000 --- a/src/parsers/member_access.cr +++ /dev/null @@ -1,20 +0,0 @@ -module Mint - class Parser - def member_access : Ast::MemberAccess? - parse do |start_position| - next unless char! '.' - - next error :member_access_expected_variable do - expected "the field of the accessed entity", word - snippet self - end unless name = variable - - Ast::MemberAccess.new( - from: start_position, - to: position, - file: file, - name: name) - end - end - end -end diff --git a/src/parsers/module.cr b/src/parsers/module.cr index 357325191..8eda25f8c 100644 --- a/src/parsers/module.cr +++ b/src/parsers/module.cr @@ -5,7 +5,7 @@ module Mint comment = self.comment whitespace - next unless word! "module" + next unless keyword! "module" whitespace next error :module_expected_name do diff --git a/src/parsers/next_call.cr b/src/parsers/next_call.cr index 0924680fd..23028a75c 100644 --- a/src/parsers/next_call.cr +++ b/src/parsers/next_call.cr @@ -2,7 +2,7 @@ module Mint class Parser def next_call : Ast::NextCall? parse do |start_position| - next unless word! "next" + next unless keyword! "next" whitespace next error :next_call_expected_fields do diff --git a/src/parsers/operator.cr b/src/parsers/operator.cr index e71d44314..37b303a59 100644 --- a/src/parsers/operator.cr +++ b/src/parsers/operator.cr @@ -52,9 +52,14 @@ module Mint next unless operator next if operator != "|>" && !whitespace? - ast.operators << {saved_position, saved_position + operator.size} - whitespace + case operator + when "or" + ast.keywords << {saved_position, saved_position + operator.size} + else + ast.operators << {saved_position, saved_position + operator.size} + end + whitespace operator end end diff --git a/src/parsers/property.cr b/src/parsers/property.cr index f1d0c1703..b2b62a0f7 100644 --- a/src/parsers/property.cr +++ b/src/parsers/property.cr @@ -5,7 +5,7 @@ module Mint comment = self.comment whitespace - next unless word! "property" + next unless keyword! "property" whitespace next error :property_expected_name do diff --git a/src/parsers/provider.cr b/src/parsers/provider.cr index bb04d2b18..9a4645b29 100644 --- a/src/parsers/provider.cr +++ b/src/parsers/provider.cr @@ -3,8 +3,9 @@ module Mint def provider : Ast::Provider? parse do |start_position, start_nodes_position| comment = self.comment + whitespace - next unless word! "provider" + next unless keyword! "provider" whitespace next error :provider_expected_name do diff --git a/src/parsers/record_update.cr b/src/parsers/record_update.cr index 6b19ce750..bff466fea 100644 --- a/src/parsers/record_update.cr +++ b/src/parsers/record_update.cr @@ -10,7 +10,7 @@ module Mint whitespace next unless value - next if word?("|>") # Skip if tuple with a pipe `{ x |> Number.toString }` + next if word?("|>") # Skip if block with a pipe `{ x |> Number.toString }` next unless char! '|' value diff --git a/src/parsers/return.cr b/src/parsers/return.cr index 0ab6b97ea..910733b99 100644 --- a/src/parsers/return.cr +++ b/src/parsers/return.cr @@ -2,7 +2,7 @@ module Mint class Parser def return_call : Ast::ReturnCall? parse do |start_position| - next unless word! "return" + next unless keyword! "return" whitespace next error :return_call_expected_expression do diff --git a/src/parsers/route.cr b/src/parsers/route.cr index 7fe7d535e..3876d140f 100644 --- a/src/parsers/route.cr +++ b/src/parsers/route.cr @@ -8,12 +8,14 @@ module Mint if char! '*' "*" else - gather { chars { |char| !char.in?(' ', '\n', '\r', '\t', '{', '(') } }.to_s + gather do + chars { |char| !char.in?(' ', '\n', '\r', '\t', '{', '(') } + end.to_s end arguments = [] of Ast::Argument - whitespace + if char! '(' arguments = list(terminator: ')', separator: ',') do @@ -28,6 +30,9 @@ module Mint whitespace end + await = keyword! "await" + whitespace + body = block( ->{ error :route_expected_opening_bracket do @@ -49,6 +54,7 @@ module Mint arguments: arguments, from: start_position, expression: body, + await: await, to: position, file: file, url: url) diff --git a/src/parsers/routes.cr b/src/parsers/routes.cr index c90b970e1..d32ad92bf 100644 --- a/src/parsers/routes.cr +++ b/src/parsers/routes.cr @@ -2,7 +2,7 @@ module Mint class Parser def routes : Ast::Routes? parse do |start_position| - next unless word! "routes" + next unless keyword! "routes" whitespace body = diff --git a/src/parsers/state.cr b/src/parsers/state.cr index f3d46316b..c4e9d793e 100644 --- a/src/parsers/state.cr +++ b/src/parsers/state.cr @@ -5,7 +5,7 @@ module Mint comment = self.comment whitespace - next unless word! "state" + next unless keyword! "state" whitespace next error :state_expected_name do diff --git a/src/parsers/state_setter.cr b/src/parsers/state_setter.cr new file mode 100644 index 000000000..8042546a1 --- /dev/null +++ b/src/parsers/state_setter.cr @@ -0,0 +1,27 @@ +module Mint + class Parser + def state_setter : Ast::StateSetter? + parse do |start_position| + next unless word! "->" + whitespace + + next error :state_setter_expected_dot do + expected "the dot of between the entity and the state of a state setter", word + snippet self + end if (entity = id) && !char!('.') + + next error :state_setter_expected_variable do + expected "the state of state setter", word + snippet self + end unless state = variable + + Ast::StateSetter.new( + from: start_position, + entity: entity, + state: state, + to: position, + file: file) + end + end + end +end diff --git a/src/parsers/statement.cr b/src/parsers/statement.cr index 9ea1b13cf..eb5ef1139 100644 --- a/src/parsers/statement.cr +++ b/src/parsers/statement.cr @@ -3,7 +3,7 @@ module Mint def statement : Ast::Statement? parse do |start_position| target = parse(track: false) do - next unless word! "let" + next unless keyword! "let" whitespace value = variable(track: false) || @@ -19,7 +19,7 @@ module Mint end whitespace - await = word! "await" + await = keyword! "await" whitespace next unless body = expression diff --git a/src/parsers/store.cr b/src/parsers/store.cr index 91a364fa5..e0f956ef7 100644 --- a/src/parsers/store.cr +++ b/src/parsers/store.cr @@ -5,7 +5,7 @@ module Mint comment = self.comment whitespace - next unless word! "store" + next unless keyword! "store" whitespace next error :store_expected_name do diff --git a/src/parsers/string_literal.cr b/src/parsers/string_literal.cr index f2868d437..ea0c92997 100644 --- a/src/parsers/string_literal.cr +++ b/src/parsers/string_literal.cr @@ -18,7 +18,7 @@ module Mint snippet self end unless char! '"' - # Lookahead to see if there is a backslash (string separator), if + # Look ahead to see if there is a backslash (string separator), if # parsing fails it will track the whitespace back. broken = parse do @@ -27,6 +27,9 @@ module Mint true end || false + to = + position + # If it's separated try to parse an other part. if broken whitespace @@ -58,8 +61,8 @@ module Mint from: start_position, broken: broken, value: value, - to: position, - file: file) + file: file, + to: to) end end end diff --git a/src/parsers/style.cr b/src/parsers/style.cr index bf7b4fda9..fad5694dc 100644 --- a/src/parsers/style.cr +++ b/src/parsers/style.cr @@ -2,7 +2,7 @@ module Mint class Parser def style : Ast::Style? parse do |start_position| - next unless word! "style" + next unless keyword! "style" whitespace next error :style_expected_name do diff --git a/src/parsers/suite.cr b/src/parsers/suite.cr index 389120629..5c70cea11 100644 --- a/src/parsers/suite.cr +++ b/src/parsers/suite.cr @@ -2,7 +2,7 @@ module Mint class Parser def suite : Ast::Suite? parse do |start_position| - next unless word! "suite" + next unless keyword! "suite" whitespace next error :suite_expected_name do @@ -27,7 +27,7 @@ module Mint snippet self end if items.none?(Ast::Test | Ast::Constant) } - ) { many { function || test || constant || comment } } + ) { many { function || constant || test || comment } } next unless body diff --git a/src/parsers/test.cr b/src/parsers/test.cr index 130925739..cffe00b3a 100644 --- a/src/parsers/test.cr +++ b/src/parsers/test.cr @@ -2,7 +2,7 @@ module Mint class Parser def test : Ast::Test? parse do |start_position| - next unless word! "test" + next unless keyword! "test" whitespace next error :test_expected_name do diff --git a/src/parsers/tuple_destructuring.cr b/src/parsers/tuple_destructuring.cr index 8673d0d1c..6a18609f9 100644 --- a/src/parsers/tuple_destructuring.cr +++ b/src/parsers/tuple_destructuring.cr @@ -2,26 +2,13 @@ module Mint class Parser def tuple_destructuring : Ast::TupleDestructuring? parse do |start_position| - # TODO: Remove this branch in 0.21.0 when deprecation ends. - if char! '{' - whitespace + next unless char! '{' - items = list(terminator: '}', separator: ',') { destructuring } + whitespace + items = list(terminator: '}', separator: ',') { destructuring } - whitespace - next unless char! '}' - elsif word!("#(") - whitespace - items = list(terminator: '}', separator: ',') { destructuring } - whitespace - - next error :tuple_destructuring_expected_closing_parenthesis do - expected "the closing parenthesis of a tuple destructuring", word - snippet self - end unless char! ')' - else - next - end + whitespace + next unless char! '}' Ast::TupleDestructuring.new( from: start_position, diff --git a/src/parsers/tuple_literal.cr b/src/parsers/tuple_literal.cr index 779f6f288..9e59f8177 100644 --- a/src/parsers/tuple_literal.cr +++ b/src/parsers/tuple_literal.cr @@ -2,26 +2,21 @@ module Mint class Parser def tuple_literal : Ast::TupleLiteral? parse do |start_position| - # TODO: Remove this branch in 0.21.0 when deprecation ends. - if char! '{' - whitespace + next unless char! '{' - items = list(terminator: '}', separator: ',') { expression } + whitespace + next unless head = expression - whitespace - next unless char! '}' - elsif word!("#(") - whitespace - items = list(terminator: '}', separator: ',') { expression } - whitespace + whitespace + next unless char! ',' - next error :tuple_literal_expected_closing_parenthesis do - expected "the closing parenthesis of a tuple", word - snippet self - end unless char! ')' - else - next - end + items = + list(terminator: '}', separator: ',') { expression } + + whitespace + next unless char! '}' + + items.unshift(head) Ast::TupleLiteral.new( from: start_position, diff --git a/src/parsers/type_definition.cr b/src/parsers/type_definition.cr index 432d83bf2..10d096f9d 100644 --- a/src/parsers/type_definition.cr +++ b/src/parsers/type_definition.cr @@ -3,9 +3,10 @@ module Mint def type_definition : Ast::TypeDefinition? parse do |start_position| comment = self.comment + whitespace - # TODO: Remove `record` and `enum` in 0.21.0 when deprecation ends. - next unless word!("type") || word!("record") || word!("enum") + # TODO: Remove `record` and `enum` in 0.21.0 + next unless keyword!("type") || keyword!("record") || keyword!("enum") whitespace next error :type_definition_expected_name do diff --git a/src/parsers/type_definition_field.cr b/src/parsers/type_definition_field.cr index 6e588798b..0c2f9ab55 100644 --- a/src/parsers/type_definition_field.cr +++ b/src/parsers/type_definition_field.cr @@ -3,6 +3,7 @@ module Mint def type_definition_field(*, raise_on_colon : Bool = true) : Ast::TypeDefinitionField? parse do |start_position| comment = self.comment + whitespace next unless key = variable whitespace @@ -25,7 +26,7 @@ module Mint mapping = parse(track: false) do whitespace - next unless word! "using" + next unless keyword! "using" whitespace next error :type_definition_field_expected_mapping do diff --git a/src/parsers/type_destructuring.cr b/src/parsers/type_destructuring.cr index b71a8d902..587d43877 100644 --- a/src/parsers/type_destructuring.cr +++ b/src/parsers/type_destructuring.cr @@ -4,10 +4,13 @@ module Mint parse do |start_position| next unless name = id track: false - # TODO: Remove this in 0.21.0 when deprecation ends. + # This means that it's an access of a constant. + next if char == '.' + + # TODO: Remove this in 0.21.0 next if char == ':' && !word?("::") - # TODO: Remove this branch in 0.21.0 when deprecation ends. + # TODO: Remove this branch in 0.21.0 if word! "::" next error :type_destructuring_expected_variant do expected "the type of an type destructuring", word diff --git a/src/parsers/type_variant.cr b/src/parsers/type_variant.cr index cab773156..838c2344d 100644 --- a/src/parsers/type_variant.cr +++ b/src/parsers/type_variant.cr @@ -3,6 +3,7 @@ module Mint def type_variant : Ast::TypeVariant? parse do |start_position| comment = self.comment + whitespace next unless value = id whitespace diff --git a/src/parsers/use.cr b/src/parsers/use.cr index 3b1d6daff..391092531 100644 --- a/src/parsers/use.cr +++ b/src/parsers/use.cr @@ -2,7 +2,7 @@ module Mint class Parser def use : Ast::Use? parse do |start_position| - next unless word! "use" + next unless keyword! "use" whitespace next error :use_expected_provider do @@ -19,7 +19,7 @@ module Mint condition = parse(track: false) do whitespace - next unless word! "when" + next unless keyword! "when" whitespace brackets( diff --git a/src/reactor.cr b/src/reactor.cr index 121bbed9b..707346798 100644 --- a/src/reactor.cr +++ b/src/reactor.cr @@ -1,188 +1,107 @@ module Mint - # Reactor is the development server of Mint, it has the following features: - # * Serve the compiled application script, index file, and favicons - # * Watch all source files (application and packages as well) and if any - # changed it removes its AST from the cache, parses it - # again and then recompile the application script - # * Renders any error as HTML - # * Keeps a cache of ASTs of the parsed files for faster recompilation - # * When --auto-format flag is passed all source files are watched and if - # any changes it formats the file class Reactor - @artifacts : TypeChecker::Artifacts? - @live_reload : Bool - @auto_format : Bool - @error : String? - @host : String - @port : Int32 + # Whether or not to reload the browser after a change is made. + getter? reload : Bool - @sockets = [] of HTTP::WebSocket + # Whether or not to format the files after a change is made. + getter? format : Bool - getter script : String? + # The host to start the server on. + getter host : String - def self.start(host : String, port : Int32, auto_format : Bool, live_reload : Bool) - new host, port, auto_format, live_reload - end + # The port to start the server on. + getter port : Int32 + + # The resulting files of bundling. + @files : Hash(String, Proc(String)) = {} of String => Proc(String) - def initialize(@host, @port, @auto_format, @live_reload) - MintJson.parse_current.check_dependencies! + # The currently connected clients. + @sockets = [] of HTTP::WebSocket + def initialize(*, @host, @port, @format, @reload) + # Initialize the workspace from the current working directory. We don't + # check everything to speed things up so only the hot path is checked. workspace = Workspace.current - workspace.format = auto_format - workspace.check_env = true workspace.check_everything = false + workspace.check_env = true + workspace.format = format? + # Check if we have dependencies installed. + workspace.json.check_dependencies! + + # On any change we update the result and notify all clients to + # reload the application. workspace.on "change" do |result| - case result - when Ast - # Compile. - @script = Compiler.compile workspace.type_checker.artifacts, { - css_prefix: workspace.json.application.css_prefix, - web_components: workspace.json.web_components, - relative: false, - optimize: false, - build: false, - } - - @artifacts = workspace.type_checker.artifacts - @error = nil - when Error - @error = result.to_html - @artifacts = nil - @script = nil - end + @files = + case result + in Ast + Bundler.new( + artifacts: workspace.type_checker.artifacts, + json: workspace.json, + config: Bundler::Config.new( + generate_manifest: false, + include_program: true, + hash_assets: false, + runtime_path: nil, + live_reload: true, + skip_icons: false, + optimize: false, + relative: false, + test: nil), + ).bundle + in Error + error(result) + end - # Notifies all connected sockets to reload the page. @sockets.each(&.send("reload")) end - # Do the initial parsing and type checking. + # Do the initial parsing and type checking and start wathing for changes. workspace.update_cache workspace.watch - setup_kemal - - Server.run "Development", @host, @port - end - - def live_reload - if @live_reload - %() - end - end - - def index - if @error - <<-HTML - - - - - - #{live_reload} - - - #{@error} - - - HTML - else - IndexHtml.render(:development, live_reload: @live_reload) - end - end - - # Sets up the kemal routes... - def setup_kemal - get "/index.js" do |env| - env.response.content_type = "application/javascript" - - script - end - - get "/external-javascripts.js" do |env| - env.response.content_type = "application/javascript" - - SourceFiles.external_javascripts.to_s - end - - get "/external-stylesheets.css" do |env| - env.response.content_type = "text/css" - - SourceFiles.external_stylesheets.to_s - end - - get "/#{ASSET_DIR}/:name" do |env| - filename = - env.params.url["name"] - - asset = - @artifacts.try(&.assets.find(&.filename(build: false).==(filename))) - - next unless asset - - # Set cache to expire in 30 days. - env.response.headers["Cache-Control"] = "max-age=2592000" - - # Try to figure out mime type from name. - env.response.content_type = - MIME.from_filename?(filename).to_s - - asset.file_contents - end - - get "/:name" do |env| - # Set cache to expire in 30 days. - env.response.headers["Cache-Control"] = "max-age=2592000" - - filename = - env.params.url["name"] - - # Try to figure out mime type from name in case it's baked or served - # from public. Later on favicon and fallback content_type is overridden. - env.response.content_type = - MIME.from_filename?(filename).to_s - - path = Path[".", "public", filename] - - # If there is any static file available serve that. - if File.exists?(path) - next File.read(path) + # The websocket handle saves the sockets when they connect and + # removes them when they disconnect. + websocket_handler = + HTTP::WebSocketHandler.new do |socket| + @sockets.push socket.tap(&.on_close { @sockets.delete(socket) }) end - # If there is a baked file serve that. - Assets.read?(filename) || begin - # If it's a favicon generate it and return that. - if match = filename.match(/icon-(\d+)x\d+\.png$/) - env.response.content_type = - "image/png" - - json = - MintJson.parse_current - - IconGenerator.convert(json.application.icon, match[1]) - else - env.response.content_type = - "text/html" - - # Else return the index so push state can work as intended. - index - end + server = + HTTP::Server.new([ + HTTP::CompressHandler.new, + websocket_handler, + ]) do |context| + # Handle the request depending on the result. + content_type, content = + if file = @files[context.request.path]? + { + MIME.from_filename?(context.request.path).to_s || "text/plain", + file.call, + } + else + {"text/html", @files["index.html"].call} + end + + context.response.content_type = content_type + context.response.print content end - end - # If we didn't handle any route return the index as well. - error 404 do |env| - halt env, response: index, status_code: 200 + # Start the server. + Server.run( + server: server, + host: host, + port: port + ) do |host, port| + terminal.puts "#{COG} Development server started on http://#{host}:#{port}/" end + end - # On websocket connections save the socket for notifications. - ws "/" do |socket| - @sockets.push socket - - socket.on_close do - @sockets.delete(socket) - end - end + def error(error) + { + "/live-reload.js" => ->{ Assets.read("live-reload.js") }, + "index.html" => ->{ error.to_html(reload?) }, + } end def terminal diff --git a/src/references_tracker.cr b/src/references_tracker.cr new file mode 100644 index 000000000..30efb91f3 --- /dev/null +++ b/src/references_tracker.cr @@ -0,0 +1,205 @@ +module Mint + class ReferencesTracker + class Node + property parent : Node? + getter node : Ast::Node + + def initialize(@parent, @node) + end + end + + alias Bundles = Hash(Ast::Node | Bundle, Set(Ast::Node)) + alias Bundle = Compiler2::Bundle + + # This hash contains which nodes belong to which bundle. + getter bundles = Bundles.new + + # This hash contains the final mapping of which + # bundle contains which node (inverse of bundles). + @mapping = {} of Ast::Node => Ast::Node | Bundle + + # This tracks what nodes links to the key node.. + @parents = {} of Ast::Node => Set(Ast::Node) + + # This is a map for looking up nodes from AST nodes. + @node_map = {} of Ast::Node => Node + + # This contains all the nodes. + @nodes = [] of Node + + def keep?(node) + case node + when Ast::TypeDefinition, + Ast::HtmlComponent, + Ast::Component, + Ast::Constant, + Ast::Property, + Ast::Function, + Ast::Provider, + Ast::Module, + Ast::Encode, + Ast::Decode, + Ast::Defer, + Ast::State, + Ast::Store, + Ast::Get + true + end + end + + def collapse + @nodes.each do |node| + if keep?(node.node) + parent = + node.parent + + while parent && !keep?(parent.node) + parent = parent.parent + end + + if parent + @parents[parent.node] ||= Set(Ast::Node).new + @parents[parent.node].add(node.node) + end + + node.parent = parent + end + end + + @nodes.select! { |node| keep?(node.node) } + end + + # Adds a dependency link (node depends on target). + def add(node, target) + parent = + @node_map[node] ||= Node.new(nil, node) + + @nodes << (@node_map[target] = Node.new(parent, target)) + end + + # Returns the bundle of the node. + def bundle_of(node : Ast::Node) : Ast::Node | Bundle + @mapping[node]? || Bundle::Index + end + + # Calculates which node belongs to which bundle. + def calculate(nodes : Set(Ast::Node)) : Bundles + # Collapse links, removing not needed ones an repointing. + collapse + + # These will be the bundles, plus the index. + target_bundles = + nodes.select(Ast::Component).select(&.async?) + + nodes.select(Ast::Defer) + + # Get the bundles of the top-level entities. + bundles = + calculate + + # All the nodes that needs to be in a bundle. + target_nodes = + bundles + .values + .flat_map(&.to_a) + + # We gather all the nodes which are used more than once. + multi_uses = + target_nodes + .tally({} of Ast::Node => Int32) + .select { |_, count| count >= 2 } + .keys + .to_set + + # Remove the multi used nodes from the bundles. + bundles.transform_values! { |dependencies| dependencies - multi_uses } + + # Find all the nodes which are not in a target bundle. + not_bundled = + bundles + .reject { |key, _| target_bundles.includes?(key) } + .values + .flat_map(&.to_a) + .to_set + + # The index bundle is the differenc of all the nodes and + # the nodes which are only used by one bundle. + index_bundle = + (nodes - (target_nodes.to_set - multi_uses)) + not_bundled + + # We put together the final bundles. + bundles + .select { |key, _| target_bundles.includes?(key) } + .tap(&.[]=(Bundle::Index, index_bundle)) + .tap(&.each do |bundle, dependencies| + dependencies.each { |node| @mapping[node] = bundle } + @bundles[bundle] = dependencies + end) + end + + # We go through each top-level entity and calculate their dependencies. + private def calculate : Bundles + @node_map + .keys + .each_with_object(Bundles.new) do |node, sets| + case node + when Ast::TypeDefinition, + Ast::Component, + Ast::Provider, + Ast::Module, + Ast::Routes, + Ast::Locale, + Ast::Store, + Ast::Suite, + Ast::Defer + sets[node] = calculate node: node, base: node + end + end + end + + private def calculate( + *, + dependencies = Set(Ast::Node).new, + node : Ast::Node, + base : Ast::Node, + level = 0 + ) : Set(Ast::Node) + dependencies.add(node) + + @parents[node]?.try(&.each do |item| + next if item.is_a?(Ast::Defer) || item.is_a?(Ast::TypeDefinition) + next if item.is_a?(Ast::Component) && item.async? + next if item.is_a?(Ast::Property) && item.parent != base + + dependencies.add(item) + + calculate( + dependencies: dependencies, + level: level + 1, + node: item, + base: base) + end) + + dependencies + end + + def print_bundle_tree(io) + bundles.each do |node, dependencies| + dependencies.each do |item| + io.puts "#{Debugger.dbg(node)} ➔ #{Debugger.dbg(item)}" + end + end + end + + def print_dependency_tree(node, level = 0, io = IO::Memory.new) + if level.zero? + io.puts Debugger.dbg(node) + else + io.puts "➔ #{Debugger.dbg(node)}".indent(level * 2) + end + + @nodes + .select(&.parent.try(&.node.==(node))) + .each { |item| print_dependency_tree(item.node, level + 1, io) } + end + end +end diff --git a/src/render/terminal.cr b/src/render/terminal.cr index 769df69c6..b64e9c8ea 100644 --- a/src/render/terminal.cr +++ b/src/render/terminal.cr @@ -248,6 +248,7 @@ module Mint end def reset + @position = 0 print "\ec" end diff --git a/src/sandbox_server.cr b/src/sandbox_server.cr index eeb12fcbe..2f07296df 100644 --- a/src/sandbox_server.cr +++ b/src/sandbox_server.cr @@ -1,5 +1,6 @@ module Mint class SandboxServer + # Represents a source file. struct File include JSON::Serializable @@ -10,24 +11,28 @@ module Mint end end - struct Application + # Represents a project. + struct Project include JSON::Serializable + @[JSON::Field(key: "activeFile")] + getter active_file : String getter files : Array(File) - def initialize(@files) + def initialize(@files, @active_file) end end + # A handler for allowing cross origin requests. class CORS include HTTP::Handler def call(context) - context.response.headers["Access-Control-Allow-Origin"] = "*" + context.response.headers["Access-Control-Max-Age"] = 1.day.total_seconds.to_i.to_s context.response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, PATCH" + context.response.headers["Access-Control-Allow-Headers"] = "Content-Type" context.response.headers["Access-Control-Allow-Credentials"] = "true" - context.response.headers["Access-Control-Allow-Headers"] = "Authorization, Content-Type" - context.response.headers["Access-Control-Max-Age"] = 1.day.total_seconds.to_i.to_s + context.response.headers["Access-Control-Allow-Origin"] = "*" if context.request.method.upcase == "OPTIONS" context.response.content_type = "text/html; charset=utf-8" @@ -38,91 +43,159 @@ module Mint end end - def initialize(@host = "0.0.0.0", @port = ENV["PORT"]?.try(&.to_i) || 8080, runtime_path : String? = nil) - @runtime = - if runtime_path - Cli.runtime_file_not_found(runtime_path) unless ::File.exists?(runtime_path) - ::File.read(runtime_path) - else - Assets.read("runtime.js") - end - @server = HTTP::Server.new([CORS.new]) do |context| - handle_request(context) + class Ide + class Message + include JSON::Serializable + + property payload : JSON::Any + property type : String end - @formatter = Formatter.new - @core = Core.ast - end - def handle_request(context) - json = - Application.from_json(context.request.body.try(&.gets_to_end).to_s) - - case context.request.path - when "/compile" - context.response.content_type = "text/html; charset=utf-8" - context.response.print html(json) - when "/format" - formatted_files = - json.files.map do |file| - ast = - Parser.parse(file.contents, file.path) + @socket : HTTP::WebSocket + @directory : Path + @id : String - formatted = - @formatter.format(ast) + def initialize(@socket) + @socket.on_message(&->handle_message(String)) + @socket.on_close { close } - File.new(contents: formatted, path: file.path) - end + @id = + Random::Secure.hex - context.response.content_type = "application/json; charset=utf-8" - context.response.print({ - "files" => formatted_files, + @directory = + Path[Dir.tempdir, Random::Secure.hex] + .tap(&->FileUtils.mkdir_p(Path)) + + ::File.write(Path[@directory, "mint.json"], { + "source-directories" => ["."], }.to_json) + + @workspace = Workspace.new(@directory.to_s) + @workspace.check_everything = false + @workspace.on "change" do |result| + bundle = + case result + in Ast + Bundler.new( + artifacts: @workspace.type_checker.artifacts, + json: @workspace.json, + config: Bundler::Config.new( + generate_manifest: false, + include_program: true, + hash_assets: false, + runtime_path: nil, + live_reload: false, + skip_icons: false, + relative: false, + optimize: true, + test: nil), + ).bundle + in Error + {"index.html" => ->{ result.to_html }} + end + + io = + IO::Memory.new + + Compress::Zip::Writer.open(io) do |zip| + bundle.each do |path, contents| + zip.add(path, contents.call) + end + end + + io.rewind + HTTP::Client.post("https://#{@id}.sandbox.mint-lang.com/", body: io) + @socket.send({type: "reload", url: "https://#{@id}.sandbox.mint-lang.com/"}.to_json) + end end - end - def html(json) - ast = - json.files.reduce(@core.dup) do |memo, file| - memo.merge Parser.parse(file.contents, file.path) + def handle_message(raw : String) + message = + Message.from_json(raw) + + case message.type + when "update" + Project.from_json(message.payload.to_json).tap do |project| + project.files.each do |file| + ::File.write(Path[@directory, file.path], file.contents) + end + @workspace.reset_cache + highlight(project.active_file) + end end + rescue + end - artifacts = - TypeChecker.check(ast) - - script = - Compiler.compile(artifacts, { - css_prefix: nil, - relative: false, - optimize: false, - build: false, - }) - - <<-HTML - - - - - - - - - - HTML - - rescue error : Error - error.to_html - rescue error - "Something went wrong: #{error.inspect_with_backtrace}" + def highlight(path) + tokens = + begin + ast = + Parser.parse(Path[@directory, path].to_s) + + SemanticTokenizer.new.tap(&.tokenize(ast)).tokens.map do |token| + type = + case token.type + in SemanticTokenizer::TokenType::TypeParameter + :type_parameter + in SemanticTokenizer::TokenType::Type + :type + in SemanticTokenizer::TokenType::Namespace + :namespace + in SemanticTokenizer::TokenType::Property + :property + in SemanticTokenizer::TokenType::Keyword + :keyword + in SemanticTokenizer::TokenType::Comment + :comment + in SemanticTokenizer::TokenType::Variable + :variable + in SemanticTokenizer::TokenType::Operator + :operator + in SemanticTokenizer::TokenType::String + :string + in SemanticTokenizer::TokenType::Number + :number + in SemanticTokenizer::TokenType::Regexp + :regexp + end + + { + from: token.from, + to: token.to, + type: type, + } + end + rescue e + [] of String + end + + @socket.send({type: "highlight", tokens: tokens}.to_json) + end + + def close + FileUtils.rm_rf(@directory) + end end - def start - address = - @server.bind_tcp @host, @port + def initialize(host, port) + server = + HTTP::Server.new( + [ + CORS.new, + HTTP::WebSocketHandler.new { |socket| Ide.new(socket) }, + ]) + + Server.run( + server: server, + port: port, + host: host + ) do |resolved_host, resolved_port| + terminal.puts "#{COG} Sandbox server started on http://#{resolved_host}:#{resolved_port}/" + end + end - puts "Listening on http://#{address}" - @server.listen + def terminal + Render::Terminal::STDOUT end end end diff --git a/src/scaffold.cr b/src/scaffold.cr new file mode 100644 index 000000000..1596a7b79 --- /dev/null +++ b/src/scaffold.cr @@ -0,0 +1,126 @@ +module Mint + class Scaffold + # The name of the project + getter name : String + + # Whether or not to generate an empty project + getter? bare : Bool + + # The path to the project + getter path : Path + + def initialize(*, @name : String, @bare : Bool) + @path = Path[name].expand + + if File.exists?(path) + terminal.puts "#{WARNING} Directory exists, exiting..." + else + terminal.puts "#{COG} Writing files:" + + write_mint_json + write_files + + show(path, indent: 2) + end + end + + # Writes the files of the project. + private def write_files + if bare? + main = + <<-MAIN + component Main { + fun render : Html { + <> + } + } + MAIN + + File.write_p(Path[path, "source", "Main.mint"], main) + else + Assets.files.each do |file| + next unless file.path.starts_with?("/scaffold/") + File.write_p(Path[path, file.path.lchop("/scaffold/")], file) + end + end + end + + # Writes the `mint.json` of the project. + private def write_mint_json + path = + Path[self.path, "mint.json"] + + json = + (bare? ? json_bare : self.json).to_pretty_json + + File.write_p(path, json) + end + + # Displays the files in the given directory. + private def show(directory : Path, *, indent : Int32 = 0) + files = %w[] + dirs = %w[] + + Dir.each_child(directory) do |child| + path = + Path[directory, child] + + case + when File.directory?(path) + dirs << child + when File.file?(path) + files << child + end + end + + prefix = + "#{" " * indent}#{ARROW} " + + dirs.each do |child| + terminal.puts "#{prefix}#{child}" + + show(Path[directory, child], indent: indent + 2) + end + + files.each do |child| + terminal.puts "#{prefix}#{child}" + end + end + + # The `mint.json` using the `--bare` flag. + private def json_bare + { + "name" => name, + "source-directories" => [ + "source", + ], + } + end + + # The `mint.json`. + private def json + { + "name" => name, + "application" => { + "icon" => "assets/favicon.png", + "head" => "assets/head.html", + "title" => name, + "meta" => { + "viewport" => "width=device-width, initial-scale=1, user-scalable=no", + "charset" => "utf-8", + }, + }, + "source-directories" => [ + "source", + ], + "test-directories" => [ + "tests", + ], + } + end + + private def terminal + Render::Terminal::STDOUT + end + end +end diff --git a/src/scope.cr b/src/scope.cr index b2cf5aec0..b4037c0d3 100644 --- a/src/scope.cr +++ b/src/scope.cr @@ -80,7 +80,7 @@ module Mint when Ast::Store connect.keys.each do |key| @scopes[store][1].items[key.name.value]?.try do |value| - stack[1].items[key.target.try(&.value) || key.name.value] = Target.new(key, value.node) + stack[1].items[key.target.try(&.value) || key.name.value] = value end end end @@ -217,7 +217,6 @@ module Mint case node when Ast::Directives::Documentation, Ast::Directives::HighlightFile, - Ast::Directives::Highlight, Ast::Directives::Inline, Ast::Directives::Asset, Ast::Directives::Svg, @@ -226,9 +225,12 @@ module Mint Ast::TypeDestructuring, Ast::NumberLiteral, Ast::RegexpLiteral, - Ast::MemberAccess, + Ast::FieldAccess, Ast::BoolLiteral, + Ast::StateSetter, Ast::LocaleKey, + Ast::Variable, + Ast::Builtin, Ast::Comment, Ast::Env when Ast::StringLiteral, @@ -243,6 +245,8 @@ module Mint Ast::Decode, Ast::Test build(node.expression, node) + when Ast::Directives::Highlight + build(node.content, node) when Ast::CaseBranch build(node.expression, node) build(node.pattern, node) @@ -256,7 +260,8 @@ module Mint Ast::Property build(node.default, node) when Ast::CssSelector, - Ast::CssNestedAt + Ast::CssNestedAt, + Ast::Defer build(node.body, node) when Ast::Statement build(node.expression, node) @@ -300,8 +305,6 @@ module Mint when Ast::Pipe build(node.expression, node) build(node.argument, node) - when Ast::HtmlExpression - build(node.expressions, node) when Ast::HtmlFragment build(node.children, node) when Ast::HtmlAttribute @@ -314,8 +317,7 @@ module Mint build(node.expression, node) when Ast::Directives::Format build(node.content, node) - when Ast::Variable - when Ast::ArrayAccess + when Ast::BracketAccess build(node.expression, node) case node.index @@ -325,7 +327,8 @@ module Mint when Ast::Use build(node.condition, node) build(node.data, node) - when Ast::Record + when Ast::Record, + Ast::Map build(node.fields, node) when Ast::NextCall build(node.data, node) @@ -335,6 +338,9 @@ module Mint when Ast::Route build(node.expression, node) build(node.arguments, node) + when Ast::MapField + build(node.value, node) + build(node.key, node) when Ast::Field build(node.value, node) diff --git a/src/semantic_tokenizer.cr b/src/semantic_tokenizer.cr index 96e5eee6a..879b52b76 100644 --- a/src/semantic_tokenizer.cr +++ b/src/semantic_tokenizer.cr @@ -23,7 +23,6 @@ module Mint TOKEN_MAP = { Ast::TypeVariable => TokenType::TypeParameter, Ast::Comment => TokenType::Comment, - Ast::StringLiteral => TokenType::String, Ast::RegexpLiteral => TokenType::Regexp, Ast::NumberLiteral => TokenType::Number, Ast::Id => TokenType::Type, @@ -43,11 +42,16 @@ module Mint getter tokens = [] of Token def self.tokenize(ast : Ast) - tokenizer = self.new - tokenizer.tokenize(ast) - parts = [] of String | Tuple(SemanticTokenizer::TokenType, String) - contents = ast.nodes.first.file.contents + + return parts if ast.nodes.empty? + + tokenizer = + self.new.tap(&.tokenize(ast)) + + contents = + ast.nodes.first.file.contents + position = 0 tokenizer.tokens.sort_by(&.from).each do |token| @@ -149,6 +153,60 @@ module Mint add(node.tag, TokenType::Namespace) end + def tokenize(node : Ast::StringLiteral | Ast::HereDocument) + if node.value.size == 0 + add(node, TokenType::String) + else + position = + case node + when Ast::HereDocument + if node.highlight + node.from + node.token.size + 14 + else + node.from + node.token.size + 3 + end + else + node.from + end + + node.value.each_with_index do |item, index| + last = + index == (node.value.size - 1) + + case item + in Ast::Interpolation + # We skip interpolations because they will be process separately + # but we need to proceed the position to it's end, also we need + # to add `#{` as a string which is everything up to the boxed + # expressions start. + add(position, item.expression.from, TokenType::String) + position = item.expression.to + + if last + add(position, node.to, TokenType::String) + end + in String + from = + position + + position = + if last + case node + when Ast::HereDocument + node.to - node.token.size + else + node.to + end + else + position + item.size + end + + add(from, position, TokenType::String) + end + end + end + end + def tokenize(node : Ast::HtmlComponent) node.closing_tag_position.try do |position| add(position, position + node.component.value.size, :type) diff --git a/src/style_builder.cr b/src/style_builder.cr index 6d838bf71..97631626a 100644 --- a/src/style_builder.cr +++ b/src/style_builder.cr @@ -1,22 +1,4 @@ module Mint - # This is a name pool. It returns a unique identifier for a given item of a - # given base item. - # - # In Mint it's used to get variable names for blocks of selectors - # and CSS properties. - class NamePool(T, B) - INITIAL = 'a'.pred.to_s - - @cache = {} of Tuple(B, T) => String - @current = {} of B => String - - def of(subject : T, base : B) - @cache[{base, subject}] ||= begin - @current[base] = (@current[base]? || INITIAL).succ - end - end - end - class StylePool @pool = NamePool(Ast::Style, Nil).new @cache = {} of Ast::Style => String @@ -136,6 +118,82 @@ module Mint end end + class VariableCompiler2 + delegate ifs, variables, variable_name, any?, style_pool, cases, to: @builder + delegate js, compile, to: @compiler + + getter compiler : Compiler2 + getter builder : StyleBuilder + + def initialize(@builder, @compiler) + end + + def compile(node : Ast::Style) + return unless any?(node) + + static = + variables[node]? + .try do |hash| + items = + hash + .each_with_object({} of String => Compiler2::Compiled) do |(key, value), memo| + memo["[`#{key}`]"] = compile value, quote_string: true + end + + js.object(items) unless items.empty? + end || ["{}"] of Compiler2::Item + + compiled_conditions = + begin + all_ifs = + ifs.select(&.first.==(node)) + + all_cases = + cases.select(&.first.==(node)) + + (all_ifs.keys | all_cases.keys).flat_map do |_, selector| + conditions = + all_ifs.select(&.last.==(selector)).values + + all_cases.select(&.last.==(selector)).values + + conditions + .flatten + .sort_by!(&.from) + .map do |item| + proc = + (Proc(String, String).new { |name| + variable = + variable_name name, selector + + selector[name] ||= PropertyValue.new + selector[name].variable = variable + + variable + }).as(Proc(String, String)?) + + case item + when Ast::If, Ast::Case + compile item, proc + else + [] of Compiler2::Item + end + end + end + end + + arguments = + compile node.arguments + + {node, node, js.arrow_function(arguments) do + js.statements([ + js.const("_", static), + js.statements(compiled_conditions), + js.return(["_"] of Compiler2::Item), + ]) + end} + end + end + # This class is responsible to build the CSS of "style" tags by resolving # nested nested at queries and selectors, handling cases of the same rules in # different places. @@ -204,6 +262,12 @@ module Mint .compile(node) end + def compile_style(node : Ast::Style, compiler : Compiler2) + VariableCompiler2 + .new(self, compiler) + .compile(node) + end + def any?(node : Ast::Node) variables[node]? || ifs.any?(&.first.first.==(node)) || diff --git a/src/test_runner.cr b/src/test_runner.cr index f3029e133..3a255030f 100644 --- a/src/test_runner.cr +++ b/src/test_runner.cr @@ -2,136 +2,137 @@ module Mint class TestRunner include Errorable - class Message - include JSON::Serializable + # The resulting files of bundling. + @files : Hash(String, Proc(String)) = {} of String => Proc(String) - property id : String - property type : String - property name : String? - property suite : String? - property result : String? + # The socket of the current testing session. + @socket : HTTP::WebSocket? - property location : Ast::Node::Location? - end - - BROWSER_PATHS = { - firefox: { - "firefox", - "firefox-bin", - "/Applications/Firefox.app/Contents/MacOS/firefox-bin", - }, - chrome: { - "chromium-browser", - "chromium", - "google-chrome", - "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", - }, - } - - @artifacts : TypeChecker::Artifacts? + # The reporter which processes the messages. @reporter : Reporter - @browser_path : String? - @browser : {Process, String}? - @failed = [] of Message - @test_id = Random::Secure.hex - @succeeded = 0 + # Whether or not we are in watch mode. + @watch : Bool - def initialize(@flags : Cli::Test::Flags, @arguments : Cli::Test::Arguments) - @reporter = resolve_reporter - @browser_path = resolve_browser_path unless @flags.manual - @channel = Channel(Nil).new - end + delegate :failed?, to: @reporter - def reset - @failed = [] of Message - @succeeded = 0 - end + def initialize(flags : Cli::Test::Flags, @arguments : Cli::Test::Arguments) + @reporter = resolve_reporter(flags.reporter.downcase) + @browser = Browser.new(flags.browser.downcase) + @watch = flags.watch || flags.manual - def watch workspace = Workspace.current - workspace.on "change" { run_tests } - workspace.watch - - setup_kemal - run_tests - - Server.run "Test", @flags.host, @flags.port, false - end - - def run_tests - @test_id = Random::Secure.hex - cleanup_browser - terminal.reset - - begin - type_checker = TypeChecker.new(ast) - type_checker.check - - @reporter.reset - open_page - rescue error : Error - terminal.reset - terminal.puts error.to_terminal - rescue error - terminal.reset - terminal.puts error.to_s - end - end - - def run : Bool - if ast.try(&.suites.empty?) - terminal.puts - terminal.puts "There are no tests to run!" - return false + workspace.test_path = arguments.test || "*" + workspace.check_env = true + + workspace.on "change" do |result| + case result + in Ast + @files = + Bundler.new( + artifacts: workspace.type_checker.artifacts, + json: MintJson.new, + config: Bundler::Config.new( + runtime_path: flags.runtime, + generate_manifest: false, + include_program: false, + live_reload: false, + hash_assets: true, + skip_icons: true, + optimize: false, + relative: false, + test: { + url: "ws://#{flags.browser_host}:#{flags.browser_port}/", + id: "", + }) + ).bundle + + unless flags.manual + # Stop and cleanup previous browser session + @browser.cleanup + + terminal.puts "#{COG} Starting browser..." unless @watch + + spawn do + @browser.open("http://#{flags.browser_host}:#{flags.browser_port}") + end + end + in Error + terminal.puts(result.to_terminal) + end end - terminal.puts "#{COG} Starting test server..." - setup_kemal + websocket_handler = + HTTP::WebSocketHandler.new do |socket| + # Stop previous socket if there is one. + @socket.try(&.close) + @socket = socket + + # Reset the reporter so the messages are not + # compounded and such. + @reporter.reset + + terminal.reset if @watch + terminal.puts "#{COG} Running tests:" + + socket.on_message do |data| + case data + when "DONE" + finish + else + message = + Message + .from_json(data) + .tap(&->@reporter.process(Message)) + + case message.type + when "CRASHED" + finish + end + end + end + end - unless @flags.manual - terminal.puts "#{COG} Starting browser..." - open_page - end + @server = + HTTP::Server.new([ + websocket_handler, + ]) do |context| + # Handle the request depending on the result. + content_type, content = + if file = @files[context.request.path]? + { + MIME.from_filename?(context.request.path).to_s || "text/plain", + file.call, + } + else + {"text/html", @files["index.html"].call} + end - Server.run "Test", @flags.host, @flags.port + context.response.content_type = content_type + context.response.print content + end - @failed.empty? - end + Server.run( + host: flags.host, + port: flags.port, + server: @server + ) do |host, port| + terminal.puts "#{COG} Test server started: http://#{host}:#{port}/" - def ast - file_argument = - @arguments.test + # Trigger first session + workspace.update_cache - ast = - Ast.new.merge(Core.ast) + if @watch + terminal.puts "#{COG} Waiting for a browser to connect..." - sources = - if file_argument - Dir.glob([file_argument] + SourceFiles.all) - else - Dir.glob(SourceFiles.tests + SourceFiles.all) + # Watch for changes... + workspace.watch end - - sources.uniq!.reduce(ast) do |memo, file| - artifact = - Parser.parse(file) - - memo.merge artifact end end - def script - type_checker = TypeChecker.new(ast) - type_checker.check - - @artifacts = type_checker.artifacts - - Compiler.compile_with_tests(type_checker.artifacts) - end - - def resolve_reporter : Reporter - case @flags.reporter.downcase + private def resolve_reporter(reporter : String) : Reporter + case reporter when "documentation" DocumentationReporter.new when "dot" @@ -140,7 +141,7 @@ module Mint error! :invalid_reporter do block do text "There is no reporter with the name:" - bold @flags.reporter + bold reporter end snippet "The available reporters are:", "documentation, dot" @@ -148,234 +149,16 @@ module Mint end end - def resolve_browser_path : String - paths = - BROWSER_PATHS[@flags.browser.downcase] || [] of String - - path = paths - .compact_map { |item| Process.find_executable(item) } - .first? - - error! :browser_not_found do - block do - text "I cannot find the executable of browser:" - bold @flags.browser - end - - block do - text "Are you sure it's installed properly?" - end - end unless path - - path - end - - def open_process(path, profile_directory) - url = "http://#{@flags.browser_host}:#{@flags.browser_port}" - - case @flags.browser.downcase - when "firefox" - Process.new(path, args: [ - "--headless", - "--remote-debugging-port", "9222", - "--window-size", "1920,1080", - "--profile", profile_directory, - url, - ]) - when "chrome" - Process.new(path, args: [ - "--headless", - "--disable-gpu", - "--remote-debugging-port=9222", - "--window-size=1920,1080", - "--profile-directory=#{profile_directory}", - url, - ]) - else - error! :invalid_browser do - block do - text "I cannot run the tests in the given browser:" - bold @flags.browser - end - - snippet "The available browsers are:", "chrome, firefox" - end - end - end - - def open_browser - return unless browser_path = @browser_path - - profile_directory = Path[Dir.tempdir, Random.new.hex(5)].to_s - Dir.mkdir(profile_directory) - - begin - process = open_process(browser_path, profile_directory) - @browser = {process, profile_directory} - at_exit { cleanup_browser } - @channel.receive - ensure - cleanup_browser - end - end - - def cleanup_browser - @browser.try do |(process, profile_directory)| - process.signal(:kill) rescue nil - FileUtils.rm_rf(profile_directory) - end - - @browser = nil - end - - def open_page - spawn { open_browser } - end - - def setup_kemal - # ameba:disable Lint/UselessAssign - ws_url = - "ws://#{@flags.browser_host}:#{@flags.browser_port}/" - - runtime = - if runtime_path = @flags.runtime - Cli.runtime_file_not_found(runtime_path) unless File.exists?(runtime_path) - ::File.read(runtime_path) - else - Assets.read("runtime.js") - end - - get "/" do - reset - ECR.render("#{__DIR__}/test_runner.ecr") - end - - get "/external-javascripts.js" do |env| - env.response.content_type = "application/javascript" - - SourceFiles.external_javascripts - end - - get "/external-stylesheets.css" do |env| - env.response.content_type = "text/css" - - SourceFiles.external_stylesheets - end - - get "/#{ASSET_DIR}/:name" do |env| - filename = - env.params.url["name"] - - asset = - @artifacts.try(&.assets.find(&.filename(build: false).==(filename))) - - next unless asset - - # Set cache to expire in 30 days. - env.response.headers["Cache-Control"] = "max-age=2592000" - - # Try to figure out mime type from name. - env.response.content_type = - MIME.from_filename?(filename).to_s - - asset.file_contents - end - - get "/runtime.js" do - runtime - end - - get "/tests" do - script - end - - ws "/" do |socket| - terminal.puts "#{COG} Running tests:" - - socket.on_message do |message| - case message - when "DONE" - shutdown - else - data = Message.from_json(message) - handle_message(data) - end - end - end - end - - def handle_message(data : Message) : Nil - return unless data.id == @test_id - - case data.type - when "LOG" - terminal.puts data.result - when "SUITE" - @reporter.suite data.suite - when "SUCCEEDED" - @reporter.succeeded data.name - @succeeded += 1 - when "FAILED" - @reporter.failed data.name, data.result - @failed << data - when "ERRORED" - @reporter.errored data.name, data.result - @failed << data - when "CRASHED" - @reporter.crashed data.result - @failed << data - - @reporter.done - stop_server unless @flags.watch - end - end - - def shutdown - @reporter.done - sum = @succeeded + @failed.size - - terminal.divider - terminal.puts "#{sum} tests" - terminal.puts " #{ARROW} #{@succeeded} passed" - terminal.puts " #{ARROW} #{@failed.size} failed" - - @failed - .group_by(&.suite.to_s) - .to_a - .sort_by!(&.first) - .each do |suite, failures| - terminal.puts (suite.presence || "N/A") - .indent(4) - .colorize(:red) - - failures.each do |failure| - terminal.puts "- #{failure.name}" - .indent(6) - .colorize(:red) - - terminal.puts "|> #{failure.result.presence || "N/A"}" - .indent(8) - .colorize(:red) - - if location = failure.location - terminal.puts "<| #{location.filename}:#{location.start[0]}" - .indent(8) - .colorize(:dark_gray) - end - end - end - - stop_server unless @flags.watch - end + private def finish + @reporter.report - def stop_server - return if @flags.manual + return if @watch - Kemal.config.server.try(&.close) - @channel.send(nil) + @server.close + @browser.stop end - def terminal + private def terminal Render::Terminal::STDOUT end end diff --git a/src/test_runner.ecr b/src/test_runner.ecr deleted file mode 100644 index 45f7d4ef7..000000000 --- a/src/test_runner.ecr +++ /dev/null @@ -1,154 +0,0 @@ - - - - - - - - - - - - -
-
- - diff --git a/src/test_runner/browser.cr b/src/test_runner/browser.cr new file mode 100644 index 000000000..9e61b4c63 --- /dev/null +++ b/src/test_runner/browser.cr @@ -0,0 +1,125 @@ +module Mint + class TestRunner + class Browser + include Errorable + + # The available browsers which we can connect to. + BROWSER_PATHS = { + firefox: [ + "/Applications/Firefox.app/Contents/MacOS/firefox-bin", + "firefox-bin", + "firefox", + ], + chrome: [ + "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", + "chromium-browser", + "google-chrome", + "chromium", + ], + } + + # The data for the browser session (process and profile directory). + @data : Tuple(Process, String)? + @browser : String + @path : String + + def initialize(@browser) + @channel = Channel(Nil).new + @path = resolve + end + + def resolve : String + paths = + BROWSER_PATHS[@browser] || [] of String + + path = + paths + .compact_map { |item| Process.find_executable(item) } + .first? + + error! :browser_not_found do + block do + text "I cannot find the executable of browser:" + bold @browser + end + + block do + text "Are you sure it's installed properly?" + end + end unless path + + path + end + + def open(path) + profile_directory = + Path[Dir.tempdir, Random.new.hex(5)] + .to_s + .tap { |directory| Dir.mkdir(directory) } + + begin + # Start the browser process + process = + start(path, profile_directory) + + # Save the data for cleanup later + @data = + {process, profile_directory} + + # When the program finishes cleanup + # the process and profile directory + at_exit { cleanup } + + # Wait for the signal, this keeps this thread active. + @channel.receive + ensure + cleanup + end + end + + def cleanup + @data.try do |(process, profile_directory)| + process.signal(:kill) rescue nil + FileUtils.rm_rf(profile_directory) + end + + @data = nil + end + + def stop + @channel.send(nil) + end + + def start(url, profile_directory) + case @browser + when "firefox" + Process.new(@path, args: [ + "--remote-debugging-port", "9222", + "--profile", profile_directory, + "--window-size", "1920,1080", + "--headless", + url, + ]) + when "chrome" + Process.new(@path, args: [ + "--profile-directory=#{profile_directory}", + "--remote-debugging-port=9222", + "--window-size=1920,1080", + "--disable-gpu", + "--headless", + url, + ]) + else + error! :invalid_browser do + block do + text "I cannot run the tests in the given browser:" + bold @browser + end + + snippet "The available browsers are:", "chrome, firefox" + end + end + end + end + end +end diff --git a/src/test_runner/documentation_reporter.cr b/src/test_runner/documentation_reporter.cr index a1244d07c..049235abe 100644 --- a/src/test_runner/documentation_reporter.cr +++ b/src/test_runner/documentation_reporter.cr @@ -3,31 +3,20 @@ require "./reporter" module Mint class TestRunner class DocumentationReporter < Reporter - def succeeded(name) - puts "✔ #{name}".colorize(:green).to_s.indent - end - - def failed(name, error) - puts "✘ #{name}".colorize(:red).to_s.indent - puts error.colorize(:red).to_s.indent(4) - end - - def errored(name, error) - puts "An error occurred when running the test #{name}: #{error}".colorize(:red) - end - - def suite(name) - puts name - end - - def done - end - - def reset - end + def process(message : Message) + super - def crashed(message) - puts "❗ An internal error occurred while executing a test: #{message}".colorize(:red) + case message.type + when "SUITE" + terminal.puts message.suite + when "SUCCEEDED" + terminal.puts "✔ #{message.name}".colorize(:green).to_s.indent + when "FAILED" + terminal.puts "✘ #{message.name}".colorize(:red).to_s.indent + terminal.puts message.result.colorize(:red).to_s.indent(4) + when "ERRORED" + terminal.puts "An error occurred when running the test #{message.name}: #{message.result}".colorize(:red) + end end end end diff --git a/src/test_runner/dot_reporter.cr b/src/test_runner/dot_reporter.cr index 6f1f28a9c..9966184e9 100644 --- a/src/test_runner/dot_reporter.cr +++ b/src/test_runner/dot_reporter.cr @@ -3,14 +3,19 @@ require "./reporter" module Mint class TestRunner class DotReporter < Reporter + # The maximum length of a line of dots. private MAX_LINE_LENGTH = 80 + # Characters for some states private SUCCESS_MARKER = ".".colorize(:green) - private FAIL_MARKER = "F".colorize(:red) private ERROR_MARKER = "E".colorize(:red) + private FAIL_MARKER = "F".colorize(:red) + + @count = 0 - def initialize + def reset @count = 0 + super end def with_count(&) @@ -19,38 +24,26 @@ module Mint @count += 1 end - def succeeded(name) - with_count do - print SUCCESS_MARKER - end - end - - def failed(name, error) - with_count do - print FAIL_MARKER - end - end - - def errored(name, error) - with_count do - print ERROR_MARKER - end - end - - def suite(name) - end - - def done + def report puts - end - - def reset - @count = 0 - end + super + end + + def process(message : Message) + case message.type + when "LOG" + # We restart the count because the parent class + # displays the log. + @count = 0 + when "SUCCEEDED" + with_count { print SUCCESS_MARKER } + when "FAILED" + with_count { print FAIL_MARKER } + when "ERRORED" + with_count { print ERROR_MARKER } + end - def crashed(message) - puts - puts "❗ An internal error occurred while executing a test: #{message}".colorize(:red) + super end end end diff --git a/src/test_runner/message.cr b/src/test_runner/message.cr new file mode 100644 index 000000000..4abbdbb8a --- /dev/null +++ b/src/test_runner/message.cr @@ -0,0 +1,15 @@ +module Mint + class TestRunner + include Errorable + + class Message + include JSON::Serializable + + property location : Ast::Node::Location? + property result : String? + property suite : String? + property name : String? + property type : String + end + end +end diff --git a/src/test_runner/reporter.cr b/src/test_runner/reporter.cr index 499aaa349..50e13419f 100644 --- a/src/test_runner/reporter.cr +++ b/src/test_runner/reporter.cr @@ -1,13 +1,70 @@ module Mint class TestRunner - abstract class Reporter - abstract def succeeded(name) - abstract def failed(name, error) - abstract def errored(name, error) - abstract def suite(name) - abstract def done - abstract def reset - abstract def crashed(message) + class Reporter + getter messages = [] of Message + getter? failed = false + + def reset + @messages = [] of Message + end + + def process(message : Message) + @failed = + message.type.in?("FAILED", "ERRORED", "CRASHED") unless @failed + + case message.type + when "FAILED", "ERRORED", "SUCCEEDED" + @messages << message + when "LOG" + terminal.puts message.result + when "CRASHED" + terminal.puts + terminal.puts "❗ An internal error occurred while executing a test: #{message.result}".colorize(:red) + end + end + + def report + succeeded = + @messages.count(&.type.==("SUCCEEDED")) + + failed = + @messages.select(&.type.==("FAILED")) + + terminal.divider + terminal.puts "#{@messages.size} tests" + terminal.puts " #{ARROW} #{succeeded} passed" + terminal.puts " #{ARROW} #{failed.size} failed" + + failed + .group_by(&.suite.to_s) + .to_a + .sort_by!(&.first) + .each do |suite, failures| + terminal.puts (suite.presence || "N/A") + .indent(4) + .colorize(:red) + + failures.each do |failure| + terminal.puts "- #{failure.name}" + .indent(6) + .colorize(:red) + + terminal.puts "|> #{failure.result.presence || "N/A"}" + .indent(8) + .colorize(:red) + + if location = failure.location + terminal.puts "<| #{location.filename}:#{location.start[0]}" + .indent(8) + .colorize(:dark_gray) + end + end + end + end + + private def terminal + Render::Terminal::STDOUT + end end end end diff --git a/src/type_checker.cr b/src/type_checker.cr index 25bf72f3b..06c47aa84 100644 --- a/src/type_checker.cr +++ b/src/type_checker.cr @@ -20,7 +20,7 @@ module Mint OBJECT_ERROR = Type.new("Object.Error") ARRAY = Type.new("Array", [Variable.new("a")] of Checkable) SET = Type.new("Set", [Variable.new("a")] of Checkable) - MAP = Type.new("Map", [Variable.new("a"), Variable.new("a")] of Checkable) + MAP = Type.new("Map", [Variable.new("a"), Variable.new("b")] of Checkable) MAYBE = Type.new("Maybe", [Variable.new("a")] of Checkable) RESULT = Type.new("Result", [Variable.new("a"), Variable.new("b")] of Checkable) EVENT_FUNCTION = Type.new("Function", [EVENT, Variable.new("a")] of Checkable) @@ -49,14 +49,21 @@ module Mint BOOL, ] of Checkable + VALID_HTML = [ + TEXT_CHILDREN, + HTML_CHILDREN, + STRING, + HTML, + ] of Checkable + getter records, artifacts, formatter, web_components getter? check_everything property? checking = true delegate checked, record_field_lookup, component_records, to: artifacts - delegate variables, ast, lookups, cache, scope, to: artifacts - delegate assets, resolve_order, locales, argument_order, to: artifacts + delegate variables, ast, lookups, cache, scope, references, to: artifacts + delegate assets, resolve_order, locales, components_touched, to: artifacts delegate format, to: formatter @@ -69,7 +76,6 @@ module Mint @referee : Ast::Node? @record_name_char : String = 'A'.pred.to_s - @stack = [] of Ast::Node def initialize(ast : Ast, @check_env = true, @web_components = [] of String, @check_everything = true) @@ -85,13 +91,7 @@ module Mint def print_stack @stack.each_with_index do |i, index| - x = case i - when Ast::Component then i.name - when Ast::Function then i.name.value - when Ast::Call then "" - else - i - end + x = Debugger.dbg(i) if index == 0 puts x @@ -105,8 +105,6 @@ module Mint # -------------------------------------------------------------------------- def resolve_records - add_record Record.new("Unit"), Ast::Record.empty - ast.type_definitions.each do |definition| next if definition.fields.is_a?(Array(Ast::TypeVariant)) value = check(definition) @@ -131,7 +129,7 @@ module Mint contents = <<-MINT - record #{name} { + type #{name} { #{compiled_fields} } MINT @@ -169,6 +167,8 @@ module Mint if node && node.fields.is_a?(Array(Ast::TypeDefinitionField)) record = check(node) + cache[node] = record + check!(node) add_record record, node record end @@ -216,7 +216,7 @@ module Mint # scope.scopes[node].each_with_index do |item, index| # puts scope.debug_name(item.node).indent(index * 2) # item.items.each do |key, value| - # puts "#{" " * (index * 2)}#{key} -> #{value.class.name}" + # puts "#{" " * (index * 2)}#{key} -> #{value.node.class.name}" # end # end @@ -228,7 +228,16 @@ module Mint # Helpers for checking things # -------------------------------------------------------------------------- + def track_references(node) + if last = @stack.last? + return if node.is_a?(Ast::Connect) + # puts "Linking #{Debugger.dbg(node)} -> #{Debugger.dbg(last)}" + references.add(last, node) + end + end + def check!(node) + resolve_order << node checked.add(node) if checking? end @@ -252,6 +261,8 @@ module Mint node: node) if @stack.none? { |item| item.is_a?(Ast::Function) || item.is_a?(Ast::InlineFunction) } && @top_level_entity.try { |item| owns?(node, item) } + # save_ref(node) + track_references(node) cached else if @stack.includes?(node) @@ -260,25 +271,29 @@ module Mint VOID when Ast::Function, Ast::InlineFunction static_type_signature(node) - else + when Ast::State + if type = node.type + resolve type + end + end || error! :recursion do snippet "Recursion is only supported in specific cases " \ "at this time. Unfortunatly here is not supported:", node snippet "The previous step in the recursion was here:", @stack.last end - end else invalid_self_reference( referee: @referee.not_nil!, node: node) if @top_level_entity.try { |item| owns?(node, item) } + track_references(node) @stack.push node + # save_ref(node) + result = check(node, *args).as(Checkable) cache[node] = result - resolve_order << node - check! node @stack.delete node diff --git a/src/type_checker/artifacts.cr b/src/type_checker/artifacts.cr index a6cffae97..532e595f7 100644 --- a/src/type_checker/artifacts.cr +++ b/src/type_checker/artifacts.cr @@ -3,20 +3,21 @@ module Mint class Artifacts getter ast, lookups, cache, checked, record_field_lookup, assets getter types, variables, component_records, resolve_order, locales - getter argument_order, scope + getter scope, components_touched, references def initialize(@ast : Ast, @component_records = {} of Ast::Component => Record, + @components_touched = Set(Ast::Component).new, @record_field_lookup = {} of Ast::Node => String, @variables = {} of Ast::Node => Tuple(Ast::Node, Ast::Node), @lookups = {} of Ast::Node => Tuple(Ast::Node, Ast::Node?), @assets = [] of Ast::Directives::Asset, @cache = {} of Ast::Node => Checkable, @locales = {} of String => Hash(String, Ast::Node), - @argument_order = [] of Ast::Node, @resolve_order = [] of Ast::Node, @checked = Set(Ast::Node).new) @scope = Scope.new(@ast) + @references = ReferencesTracker.new end end end diff --git a/src/type_checker/comparer.cr b/src/type_checker/comparer.cr index a6d8ae53e..85545668b 100644 --- a/src/type_checker/comparer.cr +++ b/src/type_checker/comparer.cr @@ -134,17 +134,6 @@ module Mint Type.new(node.name, params, node.label) end - def fresh(node : PartialRecord) - fields = - node - .fields - .each_with_object({} of String => Checkable) do |(key, value), memo| - memo[key] = fresh value - end - - PartialRecord.new(node.name, fields, label: node.label) - end - def fresh(node : Record) fields = node diff --git a/src/type_checker/partial_record.cr b/src/type_checker/partial_record.cr deleted file mode 100644 index 7b0536be8..000000000 --- a/src/type_checker/partial_record.cr +++ /dev/null @@ -1,49 +0,0 @@ -require "./record" - -module Mint - class TypeChecker - class PartialRecord < Record - def to_s(io : IO) - if fields.empty? - io << "(...)" - else - io << '(' - fields.join(io, ", ") do |(key, value), inner_io| - inner_io << key << ": " << value - end - io << ", ...)" - end - end - - def to_pretty - return "(...)" if fields.empty? - - defs = - fields - .map do |key, value| - result = value.to_pretty - if result.includes?('\n') - "#{key}:\n#{value.to_pretty.indent}" - else - "#{key}: #{value.to_pretty}" - end - end - - defs << "..." - - if defs.any?(&.includes?('\n')) || defs.size > 4 - "(\n#{defs.join(",\n").indent})" - else - "(#{defs.join(", ")})" - end - end - - def ==(other : Hash(String, Checkable)) - fields.all? do |key, type| - next false unless other[key]? - !Comparer.compare(other[key], type).nil? - end - end - end - end -end diff --git a/src/type_checkers/access.cr b/src/type_checkers/access.cr index cbf6e9502..e2ef4fed6 100644 --- a/src/type_checkers/access.cr +++ b/src/type_checkers/access.cr @@ -1,12 +1,12 @@ module Mint class TypeChecker - def unwind_access(node : Ast::Access, stack = [] of Ast::Node) : Array(Ast::Node) + def unwind_access(node : Ast::Access, stack = [] of Ast::Variable) : Array(Ast::Variable) case item = node.expression when Ast::Access stack.unshift(item.field) unwind_access(item, stack) - when Ast::Variable - stack.unshift(node.expression) + when Ast::Variable # Value + stack.unshift(item) end stack @@ -41,39 +41,35 @@ module Mint end end + # Maybe.Just -> Type Variant + # Maybe.isJust -> Entity function + # Html.Event.ADD -> Entity Constant + # (() { { a: "B" }}).a -> Record access def check(node : Ast::Access) : Checkable - possibilities = [] of String - - case variable = node.expression - when Ast::Access - stack = unwind_access(node) - target = "" - - loop do - case item = stack.shift? - when Ast::Variable - target += - if target.blank? - item.value - else - "." + item.value - end - - possibilities.unshift target + possibility = + case variable = node.expression + when Ast::Access + stack = + unwind_access(node) + + if stack.empty? + nil else - break + stack.join(".", &.value) end + when Ast::Variable + variable.value end - when Ast::Variable - possibilities << variable.value - end - possibilities.each do |possibility| + # possibilities.each do |possibility| + if possibility if parent = ast.type_definitions.find(&.name.value.==(possibility)) case fields = parent.fields when Array(Ast::TypeVariant) if option = fields.find(&.value.value.==(node.field.value)) variables[node] = {option, parent} + # puts({Debugger.dbg(parent), Debugger.dbg(node)}) + resolve(parent) return to_function_type(option, parent) end end @@ -81,9 +77,9 @@ module Mint if entity = scope.resolve(possibility, node).try(&.node) if entity && possibility[0].ascii_uppercase? - variables[node.expression] = {entity, entity} - check!(entity) if target_node = scope.resolve(node.field.value, entity).try(&.node) + variables[node.expression] = {entity, entity} + check!(entity) variables[node] = {target_node, entity} variables[node.field] = {target_node, entity} return resolve target_node @@ -121,6 +117,7 @@ module Mint component.refs.reduce({} of String => Ast::Node) do |memo, (variable, ref)| case ref when Ast::HtmlComponent + components_touched.add(component) component_records .find(&.first.name.value.==(ref.component.value)) .try do |record| diff --git a/src/type_checkers/argument.cr b/src/type_checkers/argument.cr index 639169075..52bab8041 100644 --- a/src/type_checkers/argument.cr +++ b/src/type_checkers/argument.cr @@ -1,10 +1,30 @@ module Mint class TypeChecker def check(node : Ast::Argument) : Checkable - node.default.try { |default| resolve default } + default = + node.default.try(&->resolve(Ast::Node)) - resolve_type(resolve(node.type)) - .tap(&.label = node.name.try(&.value)) + type = + resolve_type(resolve(node.type)) + .tap(&.label = node.name.try(&.value)) + + case {default, type} + in {Checkable, Checkable} + resolved = + Comparer.compare type, default + + error! :argument_type_mismatch do + block "The type of the default value of an argument does not " \ + "match its type annotation." + + expected type, default + snippet "The argument in question is here:", node + end unless resolved + + resolved + in {Nil, Checkable} + type + end end end end diff --git a/src/type_checkers/arguments.cr b/src/type_checkers/arguments.cr new file mode 100644 index 000000000..bf19ce695 --- /dev/null +++ b/src/type_checkers/arguments.cr @@ -0,0 +1,40 @@ +module Mint + class TypeChecker + def check_arguments(arguments : Array(Ast::Argument)) + was_default = false + + arguments.each do |argument| + name = + argument.name.value + + other = + (arguments - [argument]).find(&.name.value.==(name)) + + error! :function_argument_must_have_a_default_value do + block do + text "The argument" + bold %("#{name}") + text "is declared after one that had a default value." + end + + block "Arguments that come after ones that have a default value must also have a default value." + + snippet "The argument in question is here:", argument + end if was_default && !argument.default + + was_default = true if argument.default + + error! :function_argument_conflict do + block do + text "The argument" + bold %("#{name}") + text "is declared multiple times." + end + + snippet "It is declared here:", other + snippet "It is also declared here:", argument + end if other + end + end + end +end diff --git a/src/type_checkers/array_access.cr b/src/type_checkers/array_access.cr deleted file mode 100644 index e73e4846c..000000000 --- a/src/type_checkers/array_access.cr +++ /dev/null @@ -1,56 +0,0 @@ -module Mint - class TypeChecker - def check(node : Ast::ArrayAccess) : Checkable - index = - node.index - - expression = - node.expression - - type = - resolve expression - - case index - when Ast::NumberLiteral - if type.name == "Tuple" - parameter = - type.parameters[index.value.to_i]? - - error! :array_access_invalid_tuple do - snippet( - "The tuple have only #{type.parameters.size} members, but " \ - "you wanted to access the #{ordinal(index.value.to_i + 1)}" \ - ". The exact type of the tuple is:", type) - snippet "The tuple in question is here:", expression - end unless parameter - - parameter - else - check_array_access(expression, type) - end - end || begin - index_type = - resolve index - - error! :array_access_index_not_number do - block "The type of the index of an array access is not a number." - expected NUMBER, index_type - snippet "The index in question is here:", index - end unless Comparer.compare(index_type, NUMBER) - - check_array_access(expression, type) - end - end - - def check_array_access(expression, type) - error! :array_access_not_an_array do - block "The entity you are trying to access an item from is not an " \ - "array or a tuple." - expected "Array(a), Tuple(...)", type - snippet "The array in question is here:", expression - end unless resolved = Comparer.compare(type, ARRAY) - - Type.new("Maybe", [resolved.parameters.first] of Checkable) - end - end -end diff --git a/src/type_checkers/array_literal.cr b/src/type_checkers/array_literal.cr index eb27206a9..7cd350f0c 100644 --- a/src/type_checkers/array_literal.cr +++ b/src/type_checkers/array_literal.cr @@ -7,11 +7,7 @@ module Mint end if node.items.empty? - if defined_type - defined_type - else - Type.new("Array", [Variable.new("a").as(Checkable)]) - end + defined_type || Type.new("Array", [Variable.new("a").as(Checkable)]) else first = resolve node.items.first diff --git a/src/type_checkers/bracket_access.cr b/src/type_checkers/bracket_access.cr new file mode 100644 index 000000000..a20cebb0a --- /dev/null +++ b/src/type_checkers/bracket_access.cr @@ -0,0 +1,65 @@ +module Mint + class TypeChecker + def check(node : Ast::BracketAccess) : Checkable + index, expression = + node.index, node.expression + + type = + resolve expression + + index_type = + resolve index + + if type.name == "Tuple" + case index + when Ast::NumberLiteral + error! :bracket_access_invalid_tuple_index do + block "The index of an array access for a tuple is a float, " \ + "it can be only integer." + snippet "The access in question is here:", node + end if index.float? + + parameter = + type.parameters[index.value.to_i]? + + error! :bracket_access_invalid_tuple do + snippet "The tuple has only #{type.parameters.size} members, but " \ + "you wanted to access the #{ordinal(index.value.to_i + 1)}" \ + ". The exact type of the tuple is:", type + snippet "The tuple in question is here:", expression + end unless parameter + + parameter + else + error! :bracket_access_invalid_tuple_access do + snippet "Tuples do not support non integer access:", index + snippet "The tuple in question is here:", expression + end + end + elsif type.name == "Map" && type.parameters.size == 2 + error! :bracket_access_index_not_map_key do + block "The type of the index of a bracket access does not match the type of the keys." + expected type.parameters.first, type.parameters.first + snippet "The index in question is here:", index + end unless Comparer.compare(type.parameters.first, index_type) + + Type.new("Maybe", [type.parameters.last] of Checkable) + elsif type.name == "Array" && type.parameters.size == 1 + error! :bracket_access_index_not_number do + block "The type of the index of a bracket access is not a number." + expected NUMBER, index_type + snippet "The index in question is here:", index + end unless Comparer.compare(index_type, NUMBER) + + Type.new("Maybe", [type.parameters.first] of Checkable) + else + error! :bracket_access_not_accessible do + block "The entity you are trying to access an item from is not an " \ + "array, map or a tuple." + expected "Array(a), Map(a, b) or Tuple(...)", type + snippet "The array in question is here:", expression + end + end + end + end +end diff --git a/src/type_checkers/builtin.cr b/src/type_checkers/builtin.cr new file mode 100644 index 000000000..7f3974b9e --- /dev/null +++ b/src/type_checkers/builtin.cr @@ -0,0 +1,21 @@ +module Mint + class TypeChecker + EXPOSED_BUILTINS = %w( + decodeBoolean decodeNumber decodeString decodeArray decodeField decodeMaybe + decodeTime locale normalizeEvent createPortal testContext testRender + setLocale navigate compare nothing just err ok) + + def check(node : Ast::Builtin) : Checkable + error! :unkown_builtin do + block do + text "There is no builtin with the name:" + bold node.value + end + + snippet node + end unless node.value.in?(EXPOSED_BUILTINS) + + VOID + end + end +end diff --git a/src/type_checkers/call.cr b/src/type_checkers/call.cr index 19ba15cd1..2818d44a5 100644 --- a/src/type_checkers/call.cr +++ b/src/type_checkers/call.cr @@ -71,8 +71,6 @@ module Mint end end - argument_order.concat args - args.each_with_index do |argument, index| argument_type = resolve argument @@ -93,9 +91,9 @@ module Mint snippet "The function is expecting the #{ordinal} argument to be:", function_argument_type snippet "Instead it is:", argument_type snippet "The call in question is here:", node - end unless Comparer.compare(function_argument_type, argument_type) + end unless res = Comparer.compare(function_argument_type, argument_type) - parameters << argument_type + parameters << res end if (optional_param_count = argument_size - args.size) > 0 @@ -110,7 +108,11 @@ module Mint error! :impossible_error do block "You have run into an impossible error. Please file an issue " \ - "with a reproducible example in the GithubRepository." + "with a reproducible example in the Github repository." + + snippet "Call type:", call_type + snippet "Function type:", function_type + snippet node end unless result resolve_type(result.parameters.last) diff --git a/src/type_checkers/case.cr b/src/type_checkers/case.cr index 8cd238e75..510bed791 100644 --- a/src/type_checkers/case.cr +++ b/src/type_checkers/case.cr @@ -27,6 +27,7 @@ module Mint unified_branch = Comparer.compare(type, resolved) + error! :case_branch_not_matches do block do text "The return type of the" @@ -96,7 +97,7 @@ module Mint cases = not_matched.map do |variant| - "#{format parent.name}::#{formatter.replace_skipped(format(variant.value))}" + "#{format parent.name}.#{formatter.replace_skipped(format(variant.value))}" end.join('\n') error! :case_type_not_covered do diff --git a/src/type_checkers/connect.cr b/src/type_checkers/connect.cr index 2c41e647f..23d12667e 100644 --- a/src/type_checkers/connect.cr +++ b/src/type_checkers/connect.cr @@ -1,7 +1,8 @@ module Mint class TypeChecker def check(node : Ast::Connect) : Checkable - store = ast.stores.find(&.name.value.==(node.store.value)) + store = + ast.stores.find(&.name.value.==(node.store.value)) error! :connect_not_found_store do block do @@ -16,26 +17,21 @@ module Mint resolve store node.keys.each do |key| - key_value = key.name.value - - found = - store.functions.find(&.name.value.==(key_value)) || - store.states.find(&.name.value.==(key_value)) || - store.gets.find(&.name.value.==(key_value)) || - store.constants.find(&.name.value.==(key_value)) - error! :connect_not_found_member do block do text "The entity" - bold %("#{key_value}") + bold %("#{key.name.value}") text "does not exist in the connected store." end snippet "The connect in question is here:", node - end unless found + end unless found = scope.resolve(key.name.value, store).try(&.node) + + cache[key] = + resolve found - cache[key] = resolve found - lookups[key] = {found, store} + lookups[key] = + {found, store} end VOID diff --git a/src/type_checkers/css_definition.cr b/src/type_checkers/css_definition.cr index 96e54cc13..81bd3ab5a 100644 --- a/src/type_checkers/css_definition.cr +++ b/src/type_checkers/css_definition.cr @@ -1,9 +1,7 @@ module Mint class TypeChecker CSS_PROPERTY_NAMES = - {{ read_file("#{__DIR__}/../assets/css_properties") }} - .strip - .lines + {{ read_file("#{__DIR__}/../assets/css_properties").strip.lines }} def check(node : Ast::CssDefinition) : Checkable node.value.each do |item| diff --git a/src/type_checkers/decode.cr b/src/type_checkers/decode.cr index 8ec678398..88322c606 100644 --- a/src/type_checkers/decode.cr +++ b/src/type_checkers/decode.cr @@ -4,8 +4,6 @@ module Mint type = resolve node.type - raise "" unless type - error! :decode_complex_type do snippet "This type cannot be automatically decoded:", type diff --git a/src/type_checkers/defer.cr b/src/type_checkers/defer.cr new file mode 100644 index 000000000..8ad0b233c --- /dev/null +++ b/src/type_checkers/defer.cr @@ -0,0 +1,10 @@ +module Mint + class TypeChecker + def check(node : Ast::Defer) : Checkable + type = + resolve node.body + + Type.new("Deferred", [type] of Checkable) + end + end +end diff --git a/src/type_checkers/destructuring.cr b/src/type_checkers/destructuring.cr index 780b9c41e..8cb4dc7f5 100644 --- a/src/type_checkers/destructuring.cr +++ b/src/type_checkers/destructuring.cr @@ -133,129 +133,135 @@ module Mint name = node.name.try(&.value) || condition.name - parent = - ast.type_definitions.find(&.name.value.==(name)) - - error! :destructuring_type_missing do - snippet "I could not find the type for a destructuring with the name:", name.to_s - snippet "The destructuring in question is here:", node - end unless parent - - variant = - case fields = parent.fields - when Array(Ast::TypeVariant) - fields.find(&.value.value.==(node.variant.value)) - end - - error! :destructuring_type_variant_missing do - block do - text "I could not find the variant" - bold %("#{node.variant.value}") - text "of type" - bold %("#{parent.name.value}") - text "for a destructuring:" - end - - snippet node - snippet "The type is defined here:", parent - end unless variant - - lookups[node] = {variant, parent} - - type = resolve(parent) + if node.items.empty? && + (entity_name = node.name.try(&.value)) && + (parent = scope.resolve(entity_name, node).try(&.node)) && + (entity = scope.resolve(node.variant.value, parent).try(&.node)) + check!(parent) + lookups[node] = {entity, parent} + return destructure(entity, condition, variables) + elsif parent = ast.type_definitions.find(&.name.value.==(name)) + variant = + case fields = parent.fields + when Array(Ast::TypeVariant) + fields.find(&.value.value.==(node.variant.value)) + end - unified = - Comparer.compare(type, condition) + error! :destructuring_type_variant_missing do + block do + text "I could not find the variant" + bold %("#{node.variant.value}") + text "of type" + bold %("#{parent.name.value}") + text "for a destructuring:" + end - destructuring_type_mismatch( - expected: condition, - node: node, - got: type, - ) unless unified - - case fields = variant.fields - when Array(Ast::TypeDefinitionField) - node.items.each_with_index do |param, index| - case param - when Ast::Variable - found = fields.find do |field| - case param - when Ast::Variable - param.value == field.key.value + snippet node + snippet "The type is defined here:", parent + end unless variant + + lookups[node] = {variant, parent} + + type = resolve(parent) + + unified = + Comparer.compare(type, condition) + + destructuring_type_mismatch( + expected: condition, + node: node, + got: type, + ) unless unified + + case fields = variant.fields + when Array(Ast::TypeDefinitionField) + node.items.each_with_index do |param, index| + case param + when Ast::Variable + found = fields.find do |field| + case param + when Ast::Variable + param.value == field.key.value + end end - end - error! :destructuring_type_field_missing do - snippet "I could not find a field for a destructuring:", param.value - snippet "The destructuring in question is here:", param - end unless found + error! :destructuring_type_field_missing do + snippet "I could not find a field for a destructuring:", param.value + snippet "The destructuring in question is here:", param + end unless found - type = - resolve(found.type) + type = + resolve(found.type) - destructure(param, type, variables) - else - field = - fields[index] + destructure(param, type, variables) + else + field = + fields[index] - type = - resolve(field.type) + type = + resolve(field.type) - destructure(param, type, variables) + destructure(param, type, variables) + end end - end - else - node.items.each_with_index do |param, index| - case param - when Ast::Variable - error! :destructuring_no_parameter do - block do - text "You are trying to destructure the" - bold index.to_s - text "parameter from the type variant:" - bold variant.value.value - end - - block do - text "The variant only has" - bold variant.parameters.size.to_s - text "parameters." + else + node.items.each_with_index do |param, index| + case param + when Ast::Variable + error! :destructuring_no_parameter do + block do + text "You are trying to destructure the" + bold index.to_s + text "parameter from the type variant:" + bold variant.value.value + end + + block do + text "The variant only has" + bold variant.parameters.size.to_s + text "parameters." + end + + snippet "You are trying to destructure it here:", param + snippet "The option is defined here:", variant + end unless variant.parameters[index]? + + variant_type = + resolve(variant.parameters[index]).not_nil! + + mapping = {} of String => Checkable + + parent.parameters.each_with_index do |param2, index2| + mapping[param2.value] = condition.parameters[index2] end - snippet "You are trying to destructure it here:", param - snippet "The option is defined here:", variant - end unless variant.parameters[index]? - - variant_type = - resolve(variant.parameters[index]).not_nil! - - mapping = {} of String => Checkable - - parent.parameters.each_with_index do |param2, index2| - mapping[param2.value] = condition.parameters[index2] + resolved_type = + Comparer.fill(variant_type, mapping).not_nil! + + destructure(param, resolved_type, variables) + else + sub_type = + case item = variant.parameters[index] + when Ast::Type + resolve(item) + when Ast::TypeVariable + unified.parameters[parent.parameters.index! { |variable| variable.value == item.value }] + else + VOID # Can't happen + end + + destructure(param, sub_type, variables) end - - resolved_type = - Comparer.fill(variant_type, mapping).not_nil! - - destructure(param, resolved_type, variables) - else - sub_type = - case item = variant.parameters[index] - when Ast::Type - resolve(item) - when Ast::TypeVariable - unified.parameters[parent.parameters.index! { |variable| variable.value == item.value }] - else - VOID # Can't happen - end - - destructure(param, sub_type, variables) end end + + return variables end - variables + error! :destructuring_type_missing do + snippet "I could not find the type for a destructuring with the name:", name.to_s + snippet "The destructuring in question is here:", node + end end end end diff --git a/src/type_checkers/directives/highlight_file.cr b/src/type_checkers/directives/highlight_file.cr index dd5a8b0da..c89bd62ff 100644 --- a/src/type_checkers/directives/highlight_file.cr +++ b/src/type_checkers/directives/highlight_file.cr @@ -13,24 +13,6 @@ module Mint snippet "The highlight file directive in question is here:", node end unless node.exists? - contents = - File.read(node.real_path) - - parser = Parser.new(contents, node.real_path.to_s) - parser.parse - parser.eof! - - error! :highlight_file_directive_expected_mint do - block "I was expecting a Mint file for a highlight file directive " \ - "but I could not parse it." - - snippet( - "These are the first few lines of the file:", - contents.lines[0..4].join("\n")) - - snippet "The highlight file directive in question is here:", node - end unless parser.errors.empty? - HTML end end diff --git a/src/type_checkers/encode.cr b/src/type_checkers/encode.cr index 326eb845c..d2d4a1396 100644 --- a/src/type_checkers/encode.cr +++ b/src/type_checkers/encode.cr @@ -2,13 +2,11 @@ module Mint class TypeChecker def check(node : Ast::Encode) : Checkable expression = - node.expression.try do |item| - case item - when Ast::Record - resolve item, true - else - resolve item - end + case item = node.expression + when Ast::Record + resolve item, true + else + resolve item end error! :encode_complex_type do diff --git a/src/type_checkers/field_access.cr b/src/type_checkers/field_access.cr new file mode 100644 index 000000000..bb7f61ca7 --- /dev/null +++ b/src/type_checkers/field_access.cr @@ -0,0 +1,29 @@ +module Mint + class TypeChecker + def check(node : Ast::FieldAccess) : Checkable + case type = resolve node.type + when Record + field = + type.fields[node.name.value]? + + error! :field_access_field_not_found do + block do + text "The field" + bold node.name.value + text "does not exists on the type:" + end + + snippet type + snippet "The field access in question is here:", node + end unless field + + Type.new("Function", [type, field] of Checkable) + else + error! :field_access_not_record do + snippet "The type of the accessed entity is not a record:", type + snippet "The field access in question is here:", node + end + end + end + end +end diff --git a/src/type_checkers/function.cr b/src/type_checkers/function.cr index 918de9fae..9931da38a 100644 --- a/src/type_checkers/function.cr +++ b/src/type_checkers/function.cr @@ -1,43 +1,10 @@ module Mint class TypeChecker - def check_arguments(arguments : Array(Ast::Argument)) - was_default = false - - arguments.each do |argument| - name = - argument.name.value - - other = - (arguments - [argument]).find(&.name.value.==(name)) - - error! :function_argument_must_have_a_default_value do - block do - text "The argument" - bold %("#{name}") - text "is declared after one that had a default value." - end - - block "Arguments that come after ones that have a default value must also have a default value." - - snippet "The argument in question is here:", argument - end if was_default && !argument.default - - was_default = true if argument.default - - error! :function_argument_conflict do - block do - text "The argument" - bold %("#{name}") - text "is declared multiple times." - end - - snippet "It is declared here:", other - snippet "It is also declared here:", argument - end if other - end + def check(node : Ast::Function) + check_function(node) end - def check(node : Ast::Function) : Checkable + def check_function(node : Ast::Function | Ast::InlineFunction) : Checkable check_arguments(node.arguments) arguments = @@ -60,8 +27,22 @@ module Mint resolved = Comparer.compare(defined_type, final_type) - error! :function_type_mismatch do - block "The return type of a function does not match its type definition." + error_type, error_entity = + case node + in Ast::Function + { + :function_type_mismatch, + "a function", + } + in Ast::InlineFunction + { + :inline_function_type_mismatch, + "an anonymous function", + } + end + + error! error_type do + block "The return type of #{error_entity} does not match its type definition." snippet "I was expecting:", return_type snippet "Which is defined here:", type diff --git a/src/type_checkers/here_doc.cr b/src/type_checkers/here_document.cr similarity index 86% rename from src/type_checkers/here_doc.cr rename to src/type_checkers/here_document.cr index 9fe0432e9..be292ebdf 100644 --- a/src/type_checkers/here_doc.cr +++ b/src/type_checkers/here_document.cr @@ -1,12 +1,14 @@ module Mint class TypeChecker + # TODO: Show all possible types that can be... def here_doc_interpolation_type_mismatch( + *, + node : Ast::Node, type : Checkable, - got : Checkable, - node : Ast::Node + got : Checkable ) error! :here_doc_interpolation_type_mismatch do - block "An interpolation in here document is causing a mismatch." + block "An interpolation in a here document is causing a mismatch." expected type, got snippet "The interpolation in question is here:", node end @@ -21,8 +23,8 @@ module Mint resolve item here_doc_interpolation_type_mismatch( - type: HTML, got: item_type, + type: HTML, node: item, ) unless Comparer.matches_any?(item_type, [STRING, NUMBER, HTML]) end @@ -37,8 +39,8 @@ module Mint resolve item here_doc_interpolation_type_mismatch( - type: STRING, got: item_type, + type: STRING, node: item, ) unless Comparer.matches_any?(item_type, [STRING, NUMBER]) end diff --git a/src/type_checkers/html_attribute.cr b/src/type_checkers/html_attribute.cr index 67e864933..48d06e222 100644 --- a/src/type_checkers/html_attribute.cr +++ b/src/type_checkers/html_attribute.cr @@ -1,6 +1,6 @@ module Mint class TypeChecker - def check(node : Ast::HtmlAttribute, element : Ast::HtmlFragment) + def check(node : Ast::HtmlAttribute, element : Ast::HtmlFragment) : Checkable got = resolve node.value @@ -29,8 +29,7 @@ module Mint when "ref" error! :html_element_ref_forbidden do snippet %(The use of "ref" attribute is forbidden:), node - snippet "If you want to assign a variable to an element, use the " \ - "as keyword:", "
" + snippet %(Please use the "as" keyword instead:), "
" end when .starts_with?("on") [EVENT_FUNCTION, VOID_FUNCTION] @@ -38,15 +37,8 @@ module Mint [BOOL] when "className" error! :html_element_class_name_forbidden do - block "The className attribute on elements are forbidden." - - block do - text "Please use" - bold "class" - text "instead." - end - - snippet node + snippet %(The "className" attribute on elements are forbidden:), node + snippet %(Please use "class" instead:), %(
) end when "style" [STYLE_MAP, STRING] diff --git a/src/type_checkers/html_content.cr b/src/type_checkers/html_content.cr index 422f5c8a3..ebe0a5e11 100644 --- a/src/type_checkers/html_content.cr +++ b/src/type_checkers/html_content.cr @@ -2,22 +2,17 @@ module Mint class TypeChecker def check_html(nodes : Array(Ast::Node)) : Checkable nodes.each do |child| - type = resolve child + type = + resolve child - if Comparer.compare(HTML, type) || - Comparer.compare(STRING, type) || - Comparer.compare(HTML_CHILDREN, type) || - Comparer.compare(TEXT_CHILDREN, type) - else - error! :html_content_type_mismatch do - block "A child node of an element or component has an invalid type." - block "I was expecting one of the following types:" + error! :html_content_type_mismatch do + block "A child node of an element or component has an invalid type." + block "I was expecting one of the following types:" - snippet "Array(String)\nArray(Html)\nString\nHtml" - snippet "Instead it is:", type - snippet child - end - end + snippet VALID_HTML.map(&.to_mint).join("\n") + snippet "Instead it is:", type + snippet child + end unless Comparer.matches_any?(type, VALID_HTML) end VOID diff --git a/src/type_checkers/html_element.cr b/src/type_checkers/html_element.cr index 2703be3c7..e8f1d7fdb 100644 --- a/src/type_checkers/html_element.cr +++ b/src/type_checkers/html_element.cr @@ -18,7 +18,6 @@ module Mint end node.attributes.each { |attribute| resolve attribute, node } - check_html node.children HTML diff --git a/src/type_checkers/html_expression.cr b/src/type_checkers/html_expression.cr deleted file mode 100644 index eb81e8d8d..000000000 --- a/src/type_checkers/html_expression.cr +++ /dev/null @@ -1,9 +0,0 @@ -module Mint - class TypeChecker - def check(node : Ast::HtmlExpression) : Checkable - check_html node.expressions - - HTML - end - end -end diff --git a/src/type_checkers/html_style.cr b/src/type_checkers/html_style.cr index bd92ef9be..ddda8d22f 100644 --- a/src/type_checkers/html_style.cr +++ b/src/type_checkers/html_style.cr @@ -9,47 +9,10 @@ module Mint "component:", node end unless style - resolve style + type = + resolve style - required_count = - style.arguments.count { |arg| !arg.default } - - error! :html_style_argument_size_mismatch do - block do - text "The style call takes" - bold required_count.to_s - text "arguments, while you tried to call it with" - bold %(#{node.arguments.size}:) - end - - snippet node - end if node.arguments.size > style.arguments.size || - node.arguments.size < required_count - - node.arguments - .zip(style.arguments[0, node.arguments.size]) - .each_with_index do |(call_arg, style_arg), index| - style_arg_type = - resolve(style_arg) - - call_arg_type = - resolve(call_arg) - - error! :html_style_argument_type_mismatch do - ordinal = - ordinal(index + 1) - - block do - text "The" - bold "#{ordinal} argument" - text "to a style call is causing a mismatch." - end - - snippet "The style is expecting the #{ordinal} argument to be:", style_arg_type - snippet "Instead it is:", call_arg_type - snippet "The style call in question is here:", node - end unless Comparer.compare(style_arg_type, call_arg_type) - end + check_call(node, type) lookups[node] = {style, nil} diff --git a/src/type_checkers/if.cr b/src/type_checkers/if.cr index d2ccb331c..ff219a1ee 100644 --- a/src/type_checkers/if.cr +++ b/src/type_checkers/if.cr @@ -4,13 +4,16 @@ module Mint condition = resolve node.condition - variables = + variables, await = case item = node.condition when Ast::Statement - if item.target.is_a?(Ast::TypeDestructuring) - destructure(item.target.as(Ast::TypeDestructuring), condition) + case item.target + when Ast::TupleDestructuring, + Ast::ArrayDestructuring, + Ast::TypeDestructuring + {destructure(item.target, condition), item.await} end - end || [] of VariableScope + end || {[] of VariableScope, false} error! :if_condition_type_mismatch do block do @@ -26,8 +29,8 @@ module Mint truthy_item, falsy_item = node.branches - variables.each do |var| - scope.add(truthy_item, var[0], var[2]) + variables.each do |variable| + scope.add(truthy_item, variable[0], variable[2]) end truthy = @@ -40,8 +43,8 @@ module Mint error! :if_else_type_mismatch do block do text "The" - bold "falsy (else) branch of an if expression" - text "does not match the type of the truthy branch." + bold "else branch of an if expression" + text "does not match the type of the main branch." end expected truthy, falsy @@ -66,16 +69,19 @@ module Mint bold "else branch." end - block "The elese branch can be omitted if the truthy branch returns one of:" + block "The elese branch can only be omitted if the truthy branch returns one of:" snippet VALID_IF_TYPES.map(&.to_pretty).join("\n") block "but it returns" snippet truthy - snippet node end unless Comparer.matches_any?(truthy, VALID_IF_TYPES) end - truthy + if await && truthy.name != "Promise" + Type.new("Promise", [truthy] of Checkable) + else + truthy + end end end end diff --git a/src/type_checkers/inline_function.cr b/src/type_checkers/inline_function.cr index 52f034f72..f128066ec 100644 --- a/src/type_checkers/inline_function.cr +++ b/src/type_checkers/inline_function.cr @@ -1,44 +1,7 @@ module Mint class TypeChecker - def check(node : Ast::InlineFunction) : Checkable - check_arguments(node.arguments) - - body_type = - resolve node.body - - arguments = - resolve node.arguments - - final_type = - Type.new("Function", arguments + [body_type]) - - resolved_type = - if type = node.type - return_type = - resolve type - - defined_type = - Comparer.normalize(Type.new("Function", arguments + [return_type])) - - resolved = - Comparer.compare(defined_type, final_type) - - error! :inline_function_type_mismatch do - block "The return type of an anonymous function does not match its type definition." - - snippet "I was expecting:", return_type - snippet "Which is defined here:", type - snippet "Instead it is:", body_type - snippet "Which is returned here:", node.body.expressions.last - end unless resolved - - Comparer.normalize(defined_type) - else - Comparer.normalize(final_type) - end - - resolved_type.optional_count = node.arguments.count(&.default) - resolved_type + def check(node : Ast::InlineFunction) + check_function(node) end end end diff --git a/src/type_checkers/css_interpolation.cr b/src/type_checkers/interpolation.cr similarity index 100% rename from src/type_checkers/css_interpolation.cr rename to src/type_checkers/interpolation.cr diff --git a/src/type_checkers/locale.cr b/src/type_checkers/locale.cr index ed992beaa..45330b9e1 100644 --- a/src/type_checkers/locale.cr +++ b/src/type_checkers/locale.cr @@ -2,11 +2,19 @@ module Mint class TypeChecker def check_locale(node : Ast::Locale) node.fields.each do |field| - check_locale_record(field, nil, node.language) + check_locale_record( + language: node.language, + prefix: nil, + node: field) end end - def check_locale_record(node : Ast::Field, prefix : String?, language : String) + def check_locale_record( + *, + language : String, + node : Ast::Field, + prefix : String? + ) return unless key = node.key field_prefix = @@ -19,7 +27,10 @@ module Mint case item = node.value when Ast::Record item.fields.each do |field| - check_locale_record(field, field_prefix, language) + check_locale_record( + prefix: field_prefix, + language: language, + node: field) end else locales[field_prefix] ||= {} of String => Ast::Node diff --git a/src/type_checkers/map.cr b/src/type_checkers/map.cr new file mode 100644 index 000000000..ac8f68e7f --- /dev/null +++ b/src/type_checkers/map.cr @@ -0,0 +1,81 @@ +module Mint + class TypeChecker + def check(node : Ast::Map) : Checkable + defined_type = + node.types.try do |types| + Type.new("Map", [ + resolve(types[0]), + resolve(types[1]), + ] of Checkable) + end + + if node.fields.empty? + defined_type || MAP + else + first = + node.fields.first.try do |field| + check! field + {resolve(field.key), resolve(field.value)} + end + + rest = + node.fields[1..node.fields.size] + + rest.each_with_index do |item, index| + type = + item.try do |field| + check! field + {resolve(field.key), resolve(field.value)} + end + + return error! :map_key_not_matches do + block do + text "The key of the" + bold "#{ordinal(index + 2)} field" + text "of a map does not match the type of the 1st fields key." + end + + snippet "I was expecting the type of the 1st fields key:", first[0] + snippet "Instead it is:", type[0] + snippet "The item in question is here:", item + end unless Comparer.compare(type[0], first[0]) + + return error! :map_value_not_matches do + block do + text "The value of the" + bold "#{ordinal(index + 2)} field" + text "of a map does not match the type of the 1st fields value." + end + + snippet "I was expecting the type of the 1st fields value:", first[1] + snippet "Instead it is:", type[1] + snippet "The item in question is here:", item + end unless Comparer.compare(type[1], first[1]) + end + + inferred_type = + Comparer.normalize(Type.new("Map", [first[0], first[1]])) + + if defined_type + final_type = + Comparer.compare(inferred_type, defined_type) + + error! :map_not_matches_defined_type do + block do + text "The" + bold "defined type" + text "of an map does not match the type of its fields." + end + + expected defined_type, inferred_type + snippet "The map in question is here:", node + end unless final_type + + final_type + else + inferred_type + end + end + end + end +end diff --git a/src/type_checkers/member_access.cr b/src/type_checkers/member_access.cr deleted file mode 100644 index 93865abc7..000000000 --- a/src/type_checkers/member_access.cr +++ /dev/null @@ -1,13 +0,0 @@ -module Mint - class TypeChecker - def check(node : Ast::MemberAccess) : Checkable - variable = - Variable.new("a") - - access = - PartialRecord.new("", {node.name.value => variable} of String => Checkable) - - Type.new("Function", [access, variable] of Checkable) - end - end -end diff --git a/src/type_checkers/operation.cr b/src/type_checkers/operation.cr index 16ef66973..1f6a06e2b 100644 --- a/src/type_checkers/operation.cr +++ b/src/type_checkers/operation.cr @@ -54,9 +54,27 @@ module Mint end end + def operation_bool_type_mismatch( + value : TypeChecker::Checkable, + operator : String, + node : Ast::Node, + side : String + ) + error! :operation_bool_type_mismatch do + block do + text "The type of the" + bold side + text "operand does not match the type of an operation." + end + + expected TypeChecker::BOOL, value + snippet "The operation in question is here:", node + end + end + def check(node : Ast::Operation) : Checkable case node.operator - when "!=", "==", "<", ">", "<=", ">=", "&&", "||" + when "!=", "==" right = resolve node.right left = resolve node.left @@ -67,6 +85,25 @@ module Mint ) unless Comparer.compare(left, right) BOOL + when "&&", "||" + right = resolve node.right + left = resolve node.left + + operation_bool_type_mismatch( + operator: node.operator, + side: "left", + value: left, + node: node, + ) unless Comparer.compare(left, BOOL) + + operation_bool_type_mismatch( + operator: node.operator, + side: "right", + value: right, + node: node, + ) unless Comparer.compare(right, BOOL) + + left when "+" right = resolve node.right left = resolve node.left @@ -92,7 +129,7 @@ module Mint ) unless Comparer.compare(left, right) left - when "-", "*", "/", "%", "**" + when "-", "*", "/", "%", "**", "<", ">", "<=", ">=" right = resolve node.right left = resolve node.left @@ -110,13 +147,12 @@ module Mint node: node, ) unless Comparer.compare(right, NUMBER) - operation_type_mismatch( - right: right, - left: left, - node: node, - ) unless Comparer.compare(left, right) - - NUMBER + case node.operator + when "-", "*", "/", "%", "**" + NUMBER + else + BOOL + end when "|>" error! :operation_pipe_ambiguous do block "I cannot determine the order of the operands because the " \ diff --git a/src/type_checkers/state_setter.cr b/src/type_checkers/state_setter.cr new file mode 100644 index 000000000..ee9b4376b --- /dev/null +++ b/src/type_checkers/state_setter.cr @@ -0,0 +1,30 @@ +module Mint + class TypeChecker + def check(node : Ast::StateSetter) : Checkable + entity = + if name = node.entity.try(&.value) + ast.components.find(&.name.==(name)) || + ast.providers.find(&.name.==(name)) || + ast.stores.find(&.name.==(name)) + end || node + + case item = scope.resolve(node.state.value, entity).try(&.node) + when Ast::State + type = + resolve(item) + + lookups[node] = {item, nil} + Type.new("Function", [type, VOID_PROMISE]) + else + error! :state_setter_state_not_found do + block do + text "Could not find the state with the name:" + bold node.state.value + end + + snippet node + end + end + end + end +end diff --git a/src/type_checkers/statement.cr b/src/type_checkers/statement.cr index a9fd2d91e..4fb97fb04 100644 --- a/src/type_checkers/statement.cr +++ b/src/type_checkers/statement.cr @@ -29,10 +29,12 @@ module Mint type = resolve node.expression - type = - type.parameters.first if node.await && type.name == "Promise" - - type + if (node.await && type.name == "Promise") || + (node.await && type.name == "Deferred") + type.parameters.first + else + type + end end end end diff --git a/src/type_checkers/style.cr b/src/type_checkers/style.cr index 3104fed33..50a9ff4b9 100644 --- a/src/type_checkers/style.cr +++ b/src/type_checkers/style.cr @@ -1,10 +1,16 @@ module Mint class TypeChecker def check(node : Ast::Style) : Checkable - resolve node.arguments + check_arguments(node.arguments) + resolve node.body - VOID + arguments = resolve node.arguments + arguments << VOID + + type = Type.new("Function", arguments) + type.optional_count = node.arguments.count(&.default) + type end end end diff --git a/src/type_checkers/variable.cr b/src/type_checkers/variable.cr index 357f7292c..78fab41db 100644 --- a/src/type_checkers/variable.cr +++ b/src/type_checkers/variable.cr @@ -3,7 +3,7 @@ module Mint RESERVED = %w(break case class const continue debugger default delete do else export extends for if import in instanceof new return super - switch this throw typeof var while yield state) + switch throw typeof var while yield state) def check(node : Ast::Variable) : Checkable if node.value == "void" @@ -36,6 +36,7 @@ module Mint when item[0].is_a?(Ast::HtmlElement) && item[1].is_a?(Ast::Component) Type.new("Maybe", [Type.new("Dom.Element")] of Checkable) when item[0].is_a?(Ast::Component) && item[1].is_a?(Ast::Component) + components_touched.add(item[0].as(Ast::Component)) Type.new("Maybe", [component_records[item[0]]] of Checkable) else case value = item[0] diff --git a/src/utils/ast_watcher.cr b/src/utils/ast_watcher.cr index 17427e280..05b57e592 100644 --- a/src/utils/ast_watcher.cr +++ b/src/utils/ast_watcher.cr @@ -7,8 +7,6 @@ module Mint @pattern = %w[] @progress = false @include_core = true - @external_javascripts : String? - @external_stylesheets : String? def initialize end @@ -30,14 +28,6 @@ module Mint end end - def external_javascripts - @external_javascripts ||= SourceFiles.external_javascripts - end - - def external_stylesheets - @external_stylesheets ||= SourceFiles.external_stylesheets - end - def terminal Render::Terminal::STDOUT end @@ -88,9 +78,6 @@ module Mint source_watcher = Watcher.new(@pattern) - static_watcher = - Watcher.new(SourceFiles.external_files) - spawn do # When the mint.json changes Watcher.watch(%w[mint.json]) do @@ -106,9 +93,6 @@ module Mint @cache = {} of String => Ast - static_watcher.pattern = - SourceFiles.external_files - # Update the pattern on the watcher. source_watcher.pattern = @pattern @@ -117,15 +101,6 @@ module Mint end end - spawn do - static_watcher.watch do - @external_javascripts = nil - @external_stylesheets = nil - - @channel.send(nil) - end - end - spawn do # When a source files change source_watcher.watch do |files| diff --git a/src/utils/html_builder.cr b/src/utils/html_builder.cr new file mode 100644 index 000000000..312729a8f --- /dev/null +++ b/src/utils/html_builder.cr @@ -0,0 +1,48 @@ +module Mint + # A simple class for building HTML using the built-in `XML::Builder`. + # + # We only support tags that we actually need, which are deletaged to the + # `XML::Builder#element` method. - <% if @live_reload %> - - <% end %> - <% else %> - <% unless @no_service_worker %> - - <% end %> - <% end %> - - <% if SourceFiles.external_javascripts? %> - <% if @inline %> - - <% end %> - <% end %> - - <% if @inline %> - - <% else %> - - <% end %> - - - - diff --git a/src/utils/markd_vdom_renderer2.cr b/src/utils/markd_vdom_renderer2.cr new file mode 100644 index 000000000..b9ff41ea5 --- /dev/null +++ b/src/utils/markd_vdom_renderer2.cr @@ -0,0 +1,270 @@ +require "uri" + +module Mint + class Compiler2 + # This is a Virtual DOM renderer for markdown using Markd shard. + # + # The AST for the markdown is a tree where each node refers to the parent + # node, next sibling and previous sibling. + # + # We walk the nodes and create a tree of nodes and then using the JavaScript + # builder to render them. + class VDOMRenderer2 + def self.render( + *, + replacements : Array(Compiled), + highlight : Bool? = nil, + document : Markd::Node, + separator : String, + js : Js + ) : Compiled + render( + node: self.new.render(document, separator, highlight), + replacements: replacements, + separator: separator, + js: js) + end + + def self.render( + replacements : Array(Compiled), + node : Node | String, + separator : String, + js : Js + ) : Compiled + case node + in String + if node == separator + replacements.shift + else + js.string(node.gsub("\\", "\\\\")) + end + in Node + attributes = + node + .attributes + .transform_values { |value| [%("#{value}")] of Item } + + children = + node.children.map do |item| + render( + replacements: replacements, + separator: separator, + node: item, + js: js) + end + + tag = + case node.tag + in Builtin + node.tag + in String + %('#{node.tag}') + end + + js.call(Builtin::CreateElement, [ + [tag] of Item, + js.object(attributes), + js.array(children), + ]) + end + end + + class Node + getter attributes : Hash(String, String) + getter children : Array(Node | String) + getter tag : Builtin | String + + def initialize( + @tag : Builtin | String, *, + @attributes = {} of String => String, + @children = [] of Node | String + ) + end + end + + HEADINGS = %w(h1 h2 h3 h4 h5 h6) + + getter stack : Array(Node) = [] of Node + + def render(document : Markd::Node, separator : String, highlight : Bool?) + walker = + document.walker + + while event = walker.next + node, entering = event + + # If we are in a list we don't add a

tag if all the list + # items have only one paragraph (that what "thight" is). + next if (grand_parent = node.parent?.try &.parent?) && + node.type == Markd::Node::Type::Paragraph && + grand_parent.type.list? && + grand_parent.data["tight"] + + if entering + # Construct the node from the Markd::Node + item = + case node.type + in Markd::Node::Type::Document then Node.new(Builtin::Fragment) + in Markd::Node::Type::BlockQuote then Node.new("blockquote") + in Markd::Node::Type::Strong then Node.new("strong") + in Markd::Node::Type::Emphasis then Node.new("em") + in Markd::Node::Type::Item then Node.new("li") + in Markd::Node::Type::ThematicBreak then Node.new("hr") + in Markd::Node::Type::LineBreak then Node.new("br") + in Markd::Node::Type::Paragraph then Node.new("p") + in Markd::Node::Type::Heading + Node.new(HEADINGS[node.data["level"].as(Int32) - 1]) + in Markd::Node::Type::Code + Node.new("code", children: [ + node.text.strip, + ] of Node | String) + in Markd::Node::Type::Link + Node.new("a", attributes: { + "href" => node.data["destination"].as(String), + "title" => node.data["title"].as(String).presence, + }.compact) + in Markd::Node::Type::Image + Node.new("img", attributes: { + "src" => node.data["destination"].as(String), + "alt" => node.first_child.text, + }) + in Markd::Node::Type::List + attributes = + {} of String => String + + if start = node.data["start"].as(Int32) + attributes["start"] = start.to_s unless start == 1 + end + + Node.new( + node.data["type"] == "bullet" ? "ul" : "ol", + attributes: attributes) + in Markd::Node::Type::CodeBlock + languages = + node.fence_language.try(&.split) + + language = + languages.try(&.first?).try(&.strip.presence) + + attributes = + {} of String => String + + attributes["class"] = + "language-#{language}" if language + + children = + if highlight + if language == "mint" + parser = Parser.new(node.text.strip, "source.mint") + parser.parse_any + + unless parser.ast.nodes.empty? + Compiler2 + .tokens_to_lines(parser.ast) + .map do |parts| + items = + parts.map do |part| + case part + in String + part + in Tuple(SemanticTokenizer::TokenType, String) + Node.new("span", + attributes: {"className" => part[0].to_s.underscore}, + children: [part[1]] of Node | String) + end + end + + Node.new("span", + attributes: {"className" => "line"}, + children: items).as(Node | String) + end + end + end || begin + node + .text + .strip + .split("\n").map do |part| + Node.new("span", + attributes: {"className" => "line"}, + children: [part] of Node | String + ).as(Node | String) + end + end + else + [node.text.strip] of Node | String + end + + Node.new("pre", children: [ + Node.new("code", + attributes: attributes, + children: children), + ] of Node | String) + in Markd::Node::Type::HTMLInline, + Markd::Node::Type::HTMLBlock, + Markd::Node::Type::Text + next if (parent = node.parent?) && parent.type.image? + node.text + in Markd::Node::Type::SoftBreak + "\n" + in Markd::Node::Type::CustomInLine, + Markd::Node::Type::CustomBlock + end + + # Push the node to the children of the parent element (the last one + # we entered). + case item + when String + unless item.empty? + if item.includes?(separator) + items = + item.split(separator).intersperse(separator) + + stack.last?.try(&.children.concat(items)) + else + stack.last?.try(&.children.push(item)) + end + end + when Node + stack.last?.try(&.children.push(item)) + end + + # If there is a new block node we push it to the end of the stack, + # so the children can be added there. + case item + when Node + if !node.type.in?( + Markd::Node::Type::ThematicBreak, + Markd::Node::Type::LineBreak, + Markd::Node::Type::CodeBlock, + Markd::Node::Type::Code) + stack.push(item) + end + end + else + # When leaving we remove the current node from the end of the stack, + # but keep at least one, which will be returned in the end. + case node.type + when Markd::Node::Type::ThematicBreak, + Markd::Node::Type::BlockQuote, + Markd::Node::Type::Paragraph, + Markd::Node::Type::CodeBlock, + Markd::Node::Type::Emphasis, + Markd::Node::Type::Document, + Markd::Node::Type::Heading, + Markd::Node::Type::Strong, + Markd::Node::Type::Image, + Markd::Node::Type::Item, + Markd::Node::Type::Code, + Markd::Node::Type::Link, + Markd::Node::Type::List + stack.pop if stack.size > 1 + end + end + end + + # There always will be a node since we only render whole documents. + stack.first + end + end + end +end diff --git a/src/utils/name_pool.cr b/src/utils/name_pool.cr new file mode 100644 index 000000000..d08443fba --- /dev/null +++ b/src/utils/name_pool.cr @@ -0,0 +1,28 @@ +module Mint + # This is a name pool. It returns a unique identifier for a given item of a + # given base item. + # + # In Mint it's used to get variable names for blocks of selectors + # and CSS properties. + class NamePool(T, B) + @cache = {} of Tuple(B, T) => String + @current = {} of B => String + + def initialize(@initial = 'a'.pred.to_s) + end + + def of(subject : T, base : B) + @cache[{base, subject}] ||= next_name(subject, base) + end + + def next_name(subject : T, base : B) + name = @current[base] = (@current[base]? || @initial).succ + + if ["do", "if", "for", "catch", "in"].includes?(name) + next_name(subject, base) + else + name + end + end + end +end diff --git a/src/utils/server.cr b/src/utils/server.cr index 29d233e25..69d38a9ad 100644 --- a/src/utils/server.cr +++ b/src/utils/server.cr @@ -1,50 +1,52 @@ module Mint - # This is a basic Kemal server without option parsing and logging. + # This module contains the logic to present the user with an option to + # run a server on a different port if the original is in use. module Server extend self - def port_open?(ip, port) - client = Socket.tcp(Socket::Family::INET, true) - client.connect(ip, port, 0.25) - client.close - false - rescue - true - end + def run( + *, + host : String = "127.0.0.1", + server : HTTP::Server, + port : Int32 = 3000, + &callback : Proc(String, Int32, Nil) + ) + if port_closed?(host, port) + if STDIN.tty? + terminal.puts "#{COG} Port #{port} is used by a different application!" - def run(name, host = "127.0.0.1", port = 3000, verbose = true) - config = Kemal.config - config.logging = false - config.setup - - if port_open?(host, port) - server = HTTP::Server.new(config.handlers) - terminal.puts "#{COG} #{name} server started on http://#{host}:#{port}/" if verbose - elsif STDIN.tty? - new_port = config.port + 1 - until port_open?(host, new_port) - new_port = new_port + 1 - end - terminal.puts "#{COG} Port #{port} is used by a different application!" - terminal.puts "#{COG} Would you like to to use port #{new_port} instead? (Y/n)" + while port_closed?(host, port) + port += 1 + end + + terminal.puts "#{COG} Would you like to to use port #{port} instead? (Y/n)" - use_new_port = gets - if !use_new_port.nil? && (use_new_port.empty? || use_new_port.downcase == "y") - run(name, host, new_port) + unless gets.to_s.downcase.downcase == "y" + terminal.puts "#{COG} Exiting..." + exit(1) + end else - terminal.puts "#{COG} Exiting..." + terminal.puts "#{COG} Port #{port} is used by a different application!" + exit(1) end - else - terminal.puts "#{COG} Port #{port} is used by a different application!" - exit(1) end - config.server = server - config.running = true - config.server.try(&.listen(host, port)) + callback.call(host, port) + + server.bind_tcp(host, port) + server.listen + end + + private def port_closed?(host, port) + client = Socket.tcp(Socket::Family::INET, true) + client.connect(host, port, 0.25) + client.close + true + rescue + false end - def terminal + private def terminal Render::Terminal::STDOUT end end diff --git a/src/utils/service_worker.cr b/src/utils/service_worker.cr deleted file mode 100644 index 3c146ad79..000000000 --- a/src/utils/service_worker.cr +++ /dev/null @@ -1,52 +0,0 @@ -module Mint - class ServiceWorker - @relative : Bool - @optimize : Bool - @artifacts : TypeChecker::Artifacts - - def initialize(@artifacts, @relative, @optimize) - @js = - Js.new(optimize: @optimize) - end - - protected def path_for(url) - @relative ? url : "/#{url}" - end - - ECR.def_to_s "#{__DIR__}/service_worker.ecr" - - getter files : Array(Path) do - Dir - .glob(Path[DIST_DIR, "**", "*"]) - .compact_map do |file| - Path[file] unless File.directory?(file) - end - .sort! - end - - def precache_urls - files - .join(",\n") do |file| - %('#{path_for(file.relative_to(DIST_DIR))}') - end - end - - def calculate_hash - files - .reduce(OpenSSL::Digest.new("SHA256")) do |digest, file| - digest.file(file) - end.final.hexstring - end - - def get_routes : String - routes = Mint::Compiler - .new(TypeChecker.check(@artifacts.ast)) - .compile_service_worker(@artifacts.ast.routes) - .map do |node| - "...#{node}" - end - - @js.const("routes", "[#{routes.join(", ")}]") - end - end -end diff --git a/src/utils/service_worker.ecr b/src/utils/service_worker.ecr deleted file mode 100644 index 935501be9..000000000 --- a/src/utils/service_worker.ecr +++ /dev/null @@ -1,68 +0,0 @@ -const CACHE = '<%= calculate_hash %>' -const PRECACHE_URLS = [ -<%= precache_urls.indent(2) %> -] -<%= get_routes %> - -// On install precache all static resources -self.addEventListener('install', event => { - event.waitUntil( - caches - .open(CACHE) - .then(cache => - Promise.all( - PRECACHE_URLS.map(url => - cache - .add(url) - .catch(error => console.log(`Could not cache: ${url} - ${error}!`)) - ) - ) - ) - .then(() => self.skipWaiting()) - ) -}) - -// On activate remove all unused caches -self.addEventListener('activate', event => { - event.waitUntil( - caches - .keys() - .then(cacheNames => cacheNames.filter(cacheName => cacheName !== CACHE)) - .then(cachesToDelete => - Promise.all( - cachesToDelete.map(cacheToDelete => caches.delete(cacheToDelete)) - ) - ) - .then(() => self.clients.claim()) - ) -}) - -self.addEventListener('fetch', event => { - const url = event.request.url - const origin = self.location.origin - const isSameOrigin = url.startsWith(origin) - - let response = null - - // If we are on the same origin - if (isSameOrigin) { - // Try to get the response from the cache, - // if not available, check the routing, and if the route exist, - // serve "index.html" file or fetch request otherwise - response = - caches - .match(event.request) - .then(cachedResponse => - cachedResponse - ?? ( - Mint.isMatchingRoute(event.request, routes) - ? caches.match('/index.html') - : fetch(event.request) - ) - ) - } else { - response = fetch(event.request) - } - - event.respondWith(response) -}) diff --git a/src/utils/source_files.cr b/src/utils/source_files.cr index b0a2d069a..4fca210d2 100644 --- a/src/utils/source_files.cr +++ b/src/utils/source_files.cr @@ -20,44 +20,6 @@ module Mint .map { |dir| glob_pattern(dir) } end - def external_javascripts - external_files("javascripts") - .join(";\n") { |file| File.read(file) } - end - - def external_stylesheets - external_files("stylesheets") - .join("\n\n") { |file| File.read(file) } - end - - def external_stylesheets? - !external_files("stylesheets").empty? - end - - def external_javascripts? - !external_files("javascripts").empty? - end - - def external_files - [external_files("javascripts"), external_files("stylesheets")].flatten - end - - def external_files(files_type : String) - %w[].tap do |external_files| - each_package do |json| - files = - json.external_files[files_type] - - external_files.concat files - end - - current_files = - MintJson.parse_current.external_files[files_type] - - external_files.concat current_files - end - end - def each_package(&) pattern = Path[".", ".mint", "packages", "**", "mint.json"] diff --git a/src/workspace.cr b/src/workspace.cr index 548754ed7..b9c7ddb30 100644 --- a/src/workspace.cr +++ b/src/workspace.cr @@ -61,6 +61,12 @@ module Mint property? check_everything : Bool = true property? check_env : Bool = false property? format : Bool = false + getter test_path : String? + + def test_path=(value) + @test_path = value + update_patterns + end def initialize(@root : String) json_path = @@ -80,9 +86,6 @@ module Mint @source_watcher = Watcher.new(all_files_pattern) - @static_watcher = - Watcher.new(all_static_pattern) - @env_watcher = Env.env.try do |file| Watcher.new([file]) @@ -136,13 +139,6 @@ module Mint end def watch - spawn do - # Watches static files - @static_watcher.watch do - call "change", ast - end - end - spawn do # Watches all the `*.mint` files @source_watcher.watch do |files| @@ -183,27 +179,35 @@ module Mint end def files_pattern : Array(String) - json - .source_directories - .map { |dir| Path[root, dir, "**", "*.mint"].to_posix.to_s } - end - - def static_pattern : Array(String) - json - .external_files - .values - .flatten + files = + json + .source_directories + .map { |dir| Path[root, dir, "**", "*.mint"].to_posix.to_s } + + if path = test_path + files + if path == "*" + json + .test_directories + .map { |dir| Path[root, dir, "**", "*.mint"].to_posix.to_s } + else + [path] + end + else + files + end end def update_cache - files.each do |file| - path = - File.realpath(file) + Logger.log "Parsing files" do + files.each do |file| + path = + File.realpath(file) - self[file] ||= process(File.read(path), path) + self[file] ||= process(File.read(path), path) + end end - check! + Logger.log "Type Checking" { check! } @error = nil @@ -222,7 +226,6 @@ module Mint def update(contents, file) self[file] = process(contents, file) - check! @error = nil call "change", ast @@ -267,22 +270,15 @@ module Mint @event_handlers[event]?.try(&.each(&.call(arg))) end - private def reset_cache + def reset_cache @cache = {} of String => Ast update_cache end private def update_patterns - @static_watcher.pattern = all_static_pattern @source_watcher.pattern = all_files_pattern end - private def all_static_pattern : Array(String) - packages - .flat_map(&.static_pattern) - .concat(static_pattern) - end - private def all_files_pattern : Array(String) packages .flat_map(&.files_pattern)