this repo has no description
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

working nix builds

can compile both the react application statically so it can be served by
nginx
and then builds a docker container with nginx for easy deployment to
something like fly.io
I mean since it's static I could probably host it for free on a website
like netlify or something, but I still wanted a docker container for
now.

Notably I did have to move the generated javascript parser into the
mast-react-vite folder so that `buildNpmPackage` was scoped to the
mast-react-vite folder. I'm not sure how to get it working in a truly
monorepo style build working for it yet, but I'm not exactly inclined to
make it super shiny right now either.

+1792 -40
+98 -10
flake.nix
··· 9 9 flake-utils.lib.eachDefaultSystem (system: 10 10 let 11 11 pkgs = import nixpkgs { inherit system; }; 12 - in 13 - { 12 + username = "admin"; 13 + passwordHash = 14 + "$apr1$bhZ6EAAr$E8cv5p/2RUBrxLZD.9Jpi."; # Replace with your hash 15 + 16 + nginxConfig = pkgs.writeText "nginx.conf" '' 17 + worker_processes auto; 18 + daemon off; 19 + 20 + events { 21 + worker_connections 1024; 22 + } 23 + 24 + http { 25 + include ${pkgs.nginx}/conf/mime.types; 26 + 27 + server { 28 + listen 8080; 29 + 30 + location / { 31 + auth_basic "Restricted Content"; 32 + auth_basic_user_file /etc/nginx/htpasswd; 33 + 34 + root /app; 35 + index index.html; 36 + try_files $uri $uri/ /index.html; 37 + } 38 + } 39 + } 40 + ''; 41 + 42 + htpasswd = pkgs.writeText "htpasswd" '' 43 + ${username}:${passwordHash} 44 + ''; 45 + in { 46 + packages = rec { 47 + react = pkgs.buildNpmPackage { 48 + pname = "mast-react"; 49 + version = "0.0.1"; 50 + src = ./mast-react-vite; 51 + 52 + npmDepsHash = "sha256-oqq55MEzXGEiF9UW7rZFyQrkyTPrUEkh2enZmbbZ7Ks="; 53 + buildInputs = with pkgs; [ nodejs typescript ]; 54 + nativeBuildInputs = with pkgs; [ nodejs ]; 55 + 56 + # npmWorkspace = ./mast-react-vite; 57 + npmBuildScript = "build"; 58 + installPhase = '' 59 + mkdir -p $out 60 + cp -r dist $out/ 61 + ''; 62 + }; 63 + react-server = pkgs.dockerTools.buildImage { 64 + name = "react-server"; 65 + tag = "latest"; 66 + 67 + copyToRoot = pkgs.buildEnv { 68 + name = "image-root"; 69 + paths = [ 70 + pkgs.nginx 71 + react 72 + (pkgs.writeScriptBin "start-server" '' 73 + #!/usr/bin/env bash 74 + 75 + # Create necessary directories 76 + mkdir -p /etc/nginx 77 + cp ${htpasswd} /etc/nginx/htpasswd 78 + 79 + # Create app directory and copy built files 80 + mkdir -p /app 81 + cp -r ${react}/* /app/ 82 + 83 + # Start nginx 84 + ${pkgs.nginx}/bin/nginx -c ${nginxConfig} 85 + '') 86 + ]; 87 + pathsToLink = [ "/bin" ]; 88 + }; 89 + 90 + config = { 91 + Cmd = [ "/bin/start-server" ]; 92 + ExposedPorts = { "8080/tcp" = { }; }; 93 + }; 94 + }; 95 + }; 14 96 devShells.default = pkgs.mkShell { 15 - buildInputs = with pkgs; [ 16 - go 17 - pigeon 18 - nodejs 19 - sqlite 20 - ]; 97 + buildInputs = with pkgs; [ go pigeon nodejs sqlite git-bug openssl ]; 21 98 22 99 shellHook = '' 100 + alias start-dev='npm run dev' 101 + alias build-dev='npm run build' 102 + alias clean-dev='rm -rf dist node_modules' 103 + alias ws-server='go run ./server/main.go' 104 + alias gen-pass='openssl passwd -apr1 ' 105 + 23 106 echo "System: ${system}" 107 + echo "Available commands:" 108 + echo " start-dev - Start Vite dev server" 109 + echo " build-dev - Build the application" 110 + echo " clean-dev - Clean build artifacts" 111 + echo " ws-server - Run the websocket server" 112 + echo " gen-pass - Generate a basic_auth password" 24 113 ''; 25 114 }; 26 - } 27 - ); 115 + }); 28 116 }
+219 -4
mast-react-vite/package-lock.json
··· 8 8 "name": "mast-react", 9 9 "version": "0.0.0", 10 10 "dependencies": { 11 + "@radix-ui/react-checkbox": "^1.1.2", 11 12 "@radix-ui/react-icons": "^1.3.0", 12 13 "@tanstack/react-table": "^8.20.5", 13 14 "@vlcn.io/react": "^3.1.0", 14 15 "@vlcn.io/rx-tbl": "^0.15.0", 16 + "@vlcn.io/ws-browserdb": "^0.2.0", 15 17 "class-variance-authority": "^0.7.0", 16 18 "clsx": "^2.1.1", 17 19 "lucide-react": "^0.454.0", ··· 692 694 "node": ">=14" 693 695 } 694 696 }, 697 + "node_modules/@radix-ui/primitive": { 698 + "version": "1.1.0", 699 + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", 700 + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==" 701 + }, 702 + "node_modules/@radix-ui/react-checkbox": { 703 + "version": "1.1.2", 704 + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.1.2.tgz", 705 + "integrity": "sha512-/i0fl686zaJbDQLNKrkCbMyDm6FQMt4jg323k7HuqitoANm9sE23Ql8yOK3Wusk34HSLKDChhMux05FnP6KUkw==", 706 + "dependencies": { 707 + "@radix-ui/primitive": "1.1.0", 708 + "@radix-ui/react-compose-refs": "1.1.0", 709 + "@radix-ui/react-context": "1.1.1", 710 + "@radix-ui/react-presence": "1.1.1", 711 + "@radix-ui/react-primitive": "2.0.0", 712 + "@radix-ui/react-use-controllable-state": "1.1.0", 713 + "@radix-ui/react-use-previous": "1.1.0", 714 + "@radix-ui/react-use-size": "1.1.0" 715 + }, 716 + "peerDependencies": { 717 + "@types/react": "*", 718 + "@types/react-dom": "*", 719 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 720 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 721 + }, 722 + "peerDependenciesMeta": { 723 + "@types/react": { 724 + "optional": true 725 + }, 726 + "@types/react-dom": { 727 + "optional": true 728 + } 729 + } 730 + }, 731 + "node_modules/@radix-ui/react-compose-refs": { 732 + "version": "1.1.0", 733 + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", 734 + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", 735 + "peerDependencies": { 736 + "@types/react": "*", 737 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 738 + }, 739 + "peerDependenciesMeta": { 740 + "@types/react": { 741 + "optional": true 742 + } 743 + } 744 + }, 745 + "node_modules/@radix-ui/react-context": { 746 + "version": "1.1.1", 747 + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", 748 + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", 749 + "peerDependencies": { 750 + "@types/react": "*", 751 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 752 + }, 753 + "peerDependenciesMeta": { 754 + "@types/react": { 755 + "optional": true 756 + } 757 + } 758 + }, 695 759 "node_modules/@radix-ui/react-icons": { 696 760 "version": "1.3.0", 697 761 "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.0.tgz", ··· 700 764 "react": "^16.x || ^17.x || ^18.x" 701 765 } 702 766 }, 767 + "node_modules/@radix-ui/react-presence": { 768 + "version": "1.1.1", 769 + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.1.tgz", 770 + "integrity": "sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==", 771 + "dependencies": { 772 + "@radix-ui/react-compose-refs": "1.1.0", 773 + "@radix-ui/react-use-layout-effect": "1.1.0" 774 + }, 775 + "peerDependencies": { 776 + "@types/react": "*", 777 + "@types/react-dom": "*", 778 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 779 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 780 + }, 781 + "peerDependenciesMeta": { 782 + "@types/react": { 783 + "optional": true 784 + }, 785 + "@types/react-dom": { 786 + "optional": true 787 + } 788 + } 789 + }, 790 + "node_modules/@radix-ui/react-primitive": { 791 + "version": "2.0.0", 792 + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", 793 + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", 794 + "dependencies": { 795 + "@radix-ui/react-slot": "1.1.0" 796 + }, 797 + "peerDependencies": { 798 + "@types/react": "*", 799 + "@types/react-dom": "*", 800 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", 801 + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 802 + }, 803 + "peerDependenciesMeta": { 804 + "@types/react": { 805 + "optional": true 806 + }, 807 + "@types/react-dom": { 808 + "optional": true 809 + } 810 + } 811 + }, 812 + "node_modules/@radix-ui/react-slot": { 813 + "version": "1.1.0", 814 + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", 815 + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", 816 + "dependencies": { 817 + "@radix-ui/react-compose-refs": "1.1.0" 818 + }, 819 + "peerDependencies": { 820 + "@types/react": "*", 821 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 822 + }, 823 + "peerDependenciesMeta": { 824 + "@types/react": { 825 + "optional": true 826 + } 827 + } 828 + }, 829 + "node_modules/@radix-ui/react-use-callback-ref": { 830 + "version": "1.1.0", 831 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", 832 + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", 833 + "peerDependencies": { 834 + "@types/react": "*", 835 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 836 + }, 837 + "peerDependenciesMeta": { 838 + "@types/react": { 839 + "optional": true 840 + } 841 + } 842 + }, 843 + "node_modules/@radix-ui/react-use-controllable-state": { 844 + "version": "1.1.0", 845 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", 846 + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", 847 + "dependencies": { 848 + "@radix-ui/react-use-callback-ref": "1.1.0" 849 + }, 850 + "peerDependencies": { 851 + "@types/react": "*", 852 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 853 + }, 854 + "peerDependenciesMeta": { 855 + "@types/react": { 856 + "optional": true 857 + } 858 + } 859 + }, 860 + "node_modules/@radix-ui/react-use-layout-effect": { 861 + "version": "1.1.0", 862 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", 863 + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", 864 + "peerDependencies": { 865 + "@types/react": "*", 866 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 867 + }, 868 + "peerDependenciesMeta": { 869 + "@types/react": { 870 + "optional": true 871 + } 872 + } 873 + }, 874 + "node_modules/@radix-ui/react-use-previous": { 875 + "version": "1.1.0", 876 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.0.tgz", 877 + "integrity": "sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==", 878 + "peerDependencies": { 879 + "@types/react": "*", 880 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 881 + }, 882 + "peerDependenciesMeta": { 883 + "@types/react": { 884 + "optional": true 885 + } 886 + } 887 + }, 888 + "node_modules/@radix-ui/react-use-size": { 889 + "version": "1.1.0", 890 + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", 891 + "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==", 892 + "dependencies": { 893 + "@radix-ui/react-use-layout-effect": "1.1.0" 894 + }, 895 + "peerDependencies": { 896 + "@types/react": "*", 897 + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" 898 + }, 899 + "peerDependenciesMeta": { 900 + "@types/react": { 901 + "optional": true 902 + } 903 + } 904 + }, 703 905 "node_modules/@rollup/rollup-android-arm-eabi": { 704 906 "version": "4.24.2", 705 907 "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.2.tgz", ··· 1203 1405 "version": "15.7.13", 1204 1406 "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", 1205 1407 "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", 1206 - "dev": true 1408 + "devOptional": true 1207 1409 }, 1208 1410 "node_modules/@types/react": { 1209 1411 "version": "18.3.12", 1210 1412 "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", 1211 1413 "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", 1212 - "dev": true, 1414 + "devOptional": true, 1213 1415 "dependencies": { 1214 1416 "@types/prop-types": "*", 1215 1417 "csstype": "^3.0.2" ··· 1219 1421 "version": "18.3.1", 1220 1422 "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", 1221 1423 "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", 1222 - "dev": true, 1424 + "devOptional": true, 1223 1425 "dependencies": { 1224 1426 "@types/react": "*" 1225 1427 } ··· 1503 1705 "resolved": "https://registry.npmjs.org/@vlcn.io/wa-sqlite/-/wa-sqlite-0.22.0.tgz", 1504 1706 "integrity": "sha512-OujKro0mAqP7/efUeCGB6zBiyMoSCFVe7jQKPF0n47U9ZhOaIW3kQUVCwF+CmzvzQfN1Vl4PrFQRNNxlSwTCNQ==" 1505 1707 }, 1708 + "node_modules/@vlcn.io/ws-browserdb": { 1709 + "version": "0.2.0", 1710 + "resolved": "https://registry.npmjs.org/@vlcn.io/ws-browserdb/-/ws-browserdb-0.2.0.tgz", 1711 + "integrity": "sha512-TKPygQomMPurQ8mwAwEefN5BROw30FagL21S3FzvUunyCybOByysAEoV/OrJ7xNCvYXN9yjg0qyf7iZZfeOsYg==", 1712 + "dependencies": { 1713 + "@types/throttle-debounce": "^5.0.0", 1714 + "@vlcn.io/crsqlite-wasm": "0.16.0", 1715 + "@vlcn.io/rx-tbl": "0.15.0", 1716 + "@vlcn.io/ws-client": "0.2.0", 1717 + "@vlcn.io/ws-common": "0.2.0", 1718 + "@vlcn.io/xplat-api": "0.15.0" 1719 + } 1720 + }, 1506 1721 "node_modules/@vlcn.io/ws-client": { 1507 1722 "version": "0.2.0", 1508 1723 "resolved": "https://registry.npmjs.org/@vlcn.io/ws-client/-/ws-client-0.2.0.tgz", ··· 1909 2124 "version": "3.1.3", 1910 2125 "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", 1911 2126 "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", 1912 - "dev": true 2127 + "devOptional": true 1913 2128 }, 1914 2129 "node_modules/debug": { 1915 2130 "version": "4.3.7",
+3 -1
mast-react-vite/package.json
··· 5 5 "type": "module", 6 6 "scripts": { 7 7 "dev": "vite", 8 - "build": "tsc -b && vite build", 8 + "build": "vite build", 9 9 "lint": "eslint .", 10 10 "preview": "vite preview" 11 11 }, 12 12 "dependencies": { 13 + "@radix-ui/react-checkbox": "^1.1.2", 13 14 "@radix-ui/react-icons": "^1.3.0", 14 15 "@tanstack/react-table": "^8.20.5", 15 16 "@vlcn.io/react": "^3.1.0", 16 17 "@vlcn.io/rx-tbl": "^0.15.0", 18 + "@vlcn.io/ws-browserdb": "^0.2.0", 17 19 "class-variance-authority": "^0.7.0", 18 20 "clsx": "^2.1.1", 19 21 "lucide-react": "^0.454.0",
+13 -7
mast-react-vite/src/App.tsx
··· 1 1 import { useState } from 'react' 2 - import { useCachedState, useQuery } from "@vlcn.io/react"; 2 + import { useQuery } from "@vlcn.io/react"; 3 3 import { 4 4 ColumnDef, 5 - flexRender, 6 - getCoreRowModel, 7 - useReactTable, 8 5 } from "@tanstack/react-table" 9 6 import { DataTable } from "@/components/ui/data-table" 10 - import * as addParser from '../../parser/add_parser.js'; 11 - import * as commandParser from '../../parser/command_parser.js'; 7 + import * as commandParser from '@/lib/command_parser.js'; 12 8 import { Checkbox } from "@/components/ui/checkbox" 13 9 import { Input } from "@/components/ui/input" 14 10 15 - function Marshall(parsed) { 11 + interface MarshalledCommand { 12 + description: string; 13 + tags: string; 14 + project: string; 15 + } 16 + 17 + function Marshall(parsed): MarshalledCommand { 16 18 let project = ""; 17 19 const tags = []; 18 20 for (const attr of parsed.attributes) { ··· 171 173 } 172 174 } 173 175 // React to key presses for selection 176 + // TODO: 177 + // We should use the react way 178 + // Where we update based on changes to newText 179 + // Rather than changes to the input value 174 180 else if (e.target.value.trim() !== "") { 175 181 try { 176 182 const parsed = commandParser.parse(e.target.value);
+78
mast-react-vite/src/Root.tsx
··· 1 + import App from "./App.tsx"; 2 + import schemaContent from "./schemas/main2.sql?raw"; 3 + import { DBProvider } from "@vlcn.io/react"; 4 + import { useEffect, useState } from "react"; 5 + 6 + /** 7 + * Generates a random room name to sync with or pulls one from local storage. 8 + */ 9 + function getRoom(hash: HashBag): string { 10 + return hash.room || localStorage.getItem("room") || newRoom(); 11 + } 12 + 13 + function hashChanged() { 14 + const hash = parseHash(); 15 + const room = getRoom(hash); 16 + if (room != hash.room) { 17 + hash.room = room; 18 + window.location.hash = writeHash(hash); 19 + } 20 + localStorage.setItem("room", room); 21 + return room; 22 + } 23 + const room = hashChanged(); 24 + 25 + export default function Root() { 26 + const [theRoom, setTheRoom] = useState(room); 27 + useEffect(() => { 28 + const cb = () => { 29 + const room = hashChanged(); 30 + if (room != theRoom) { 31 + setTheRoom(room); 32 + } 33 + }; 34 + addEventListener("hashchange", cb); 35 + return () => { 36 + removeEventListener("hashchange", cb); 37 + }; 38 + }, []); // ignore -- theRoom is managed by the effect 39 + 40 + return ( 41 + <DBProvider 42 + dbname={theRoom} 43 + schema={{ 44 + name: "main2.sql", 45 + content: schemaContent, 46 + }} 47 + Render={() => <App dbname={theRoom} />} 48 + ></DBProvider> 49 + ); 50 + } 51 + 52 + type HashBag = { [key: string]: string }; 53 + function parseHash(): HashBag { 54 + const hash = window.location.hash; 55 + const ret: { [key: string]: string } = {}; 56 + if (hash.length > 1) { 57 + const substr = hash.substring(1); 58 + const parts = substr.split(","); 59 + for (const part of parts) { 60 + const [key, value] = part.split("="); 61 + ret[key] = value; 62 + } 63 + } 64 + 65 + return ret; 66 + } 67 + 68 + function writeHash(hash: HashBag) { 69 + const parts = []; 70 + for (const key in hash) { 71 + parts.push(`${key}=${hash[key]}`); 72 + } 73 + return parts.join(","); 74 + } 75 + 76 + function newRoom() { 77 + return crypto.randomUUID().replaceAll("-", ""); 78 + }
+1304
mast-react-vite/src/lib/command_parser.js
··· 1 + // @generated by Peggy 4.1.1. 2 + // 3 + // https://peggyjs.org/ 4 + 5 + 6 + function peg$subclass(child, parent) { 7 + function C() { this.constructor = child; } 8 + C.prototype = parent.prototype; 9 + child.prototype = new C(); 10 + } 11 + 12 + function peg$SyntaxError(message, expected, found, location) { 13 + var self = Error.call(this, message); 14 + // istanbul ignore next Check is a necessary evil to support older environments 15 + if (Object.setPrototypeOf) { 16 + Object.setPrototypeOf(self, peg$SyntaxError.prototype); 17 + } 18 + self.expected = expected; 19 + self.found = found; 20 + self.location = location; 21 + self.name = "SyntaxError"; 22 + return self; 23 + } 24 + 25 + peg$subclass(peg$SyntaxError, Error); 26 + 27 + function peg$padEnd(str, targetLength, padString) { 28 + padString = padString || " "; 29 + if (str.length > targetLength) { return str; } 30 + targetLength -= str.length; 31 + padString += padString.repeat(targetLength); 32 + return str + padString.slice(0, targetLength); 33 + } 34 + 35 + peg$SyntaxError.prototype.format = function(sources) { 36 + var str = "Error: " + this.message; 37 + if (this.location) { 38 + var src = null; 39 + var k; 40 + for (k = 0; k < sources.length; k++) { 41 + if (sources[k].source === this.location.source) { 42 + src = sources[k].text.split(/\r\n|\n|\r/g); 43 + break; 44 + } 45 + } 46 + var s = this.location.start; 47 + var offset_s = (this.location.source && (typeof this.location.source.offset === "function")) 48 + ? this.location.source.offset(s) 49 + : s; 50 + var loc = this.location.source + ":" + offset_s.line + ":" + offset_s.column; 51 + if (src) { 52 + var e = this.location.end; 53 + var filler = peg$padEnd("", offset_s.line.toString().length, ' '); 54 + var line = src[s.line - 1]; 55 + var last = s.line === e.line ? e.column : line.length + 1; 56 + var hatLen = (last - s.column) || 1; 57 + str += "\n --> " + loc + "\n" 58 + + filler + " |\n" 59 + + offset_s.line + " | " + line + "\n" 60 + + filler + " | " + peg$padEnd("", s.column - 1, ' ') 61 + + peg$padEnd("", hatLen, "^"); 62 + } else { 63 + str += "\n at " + loc; 64 + } 65 + } 66 + return str; 67 + }; 68 + 69 + peg$SyntaxError.buildMessage = function(expected, found) { 70 + var DESCRIBE_EXPECTATION_FNS = { 71 + literal: function(expectation) { 72 + return "\"" + literalEscape(expectation.text) + "\""; 73 + }, 74 + 75 + class: function(expectation) { 76 + var escapedParts = expectation.parts.map(function(part) { 77 + return Array.isArray(part) 78 + ? classEscape(part[0]) + "-" + classEscape(part[1]) 79 + : classEscape(part); 80 + }); 81 + 82 + return "[" + (expectation.inverted ? "^" : "") + escapedParts.join("") + "]"; 83 + }, 84 + 85 + any: function() { 86 + return "any character"; 87 + }, 88 + 89 + end: function() { 90 + return "end of input"; 91 + }, 92 + 93 + other: function(expectation) { 94 + return expectation.description; 95 + } 96 + }; 97 + 98 + function hex(ch) { 99 + return ch.charCodeAt(0).toString(16).toUpperCase(); 100 + } 101 + 102 + function literalEscape(s) { 103 + return s 104 + .replace(/\\/g, "\\\\") 105 + .replace(/"/g, "\\\"") 106 + .replace(/\0/g, "\\0") 107 + .replace(/\t/g, "\\t") 108 + .replace(/\n/g, "\\n") 109 + .replace(/\r/g, "\\r") 110 + .replace(/[\x00-\x0F]/g, function(ch) { return "\\x0" + hex(ch); }) 111 + .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x" + hex(ch); }); 112 + } 113 + 114 + function classEscape(s) { 115 + return s 116 + .replace(/\\/g, "\\\\") 117 + .replace(/\]/g, "\\]") 118 + .replace(/\^/g, "\\^") 119 + .replace(/-/g, "\\-") 120 + .replace(/\0/g, "\\0") 121 + .replace(/\t/g, "\\t") 122 + .replace(/\n/g, "\\n") 123 + .replace(/\r/g, "\\r") 124 + .replace(/[\x00-\x0F]/g, function(ch) { return "\\x0" + hex(ch); }) 125 + .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x" + hex(ch); }); 126 + } 127 + 128 + function describeExpectation(expectation) { 129 + return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation); 130 + } 131 + 132 + function describeExpected(expected) { 133 + var descriptions = expected.map(describeExpectation); 134 + var i, j; 135 + 136 + descriptions.sort(); 137 + 138 + if (descriptions.length > 0) { 139 + for (i = 1, j = 1; i < descriptions.length; i++) { 140 + if (descriptions[i - 1] !== descriptions[i]) { 141 + descriptions[j] = descriptions[i]; 142 + j++; 143 + } 144 + } 145 + descriptions.length = j; 146 + } 147 + 148 + switch (descriptions.length) { 149 + case 1: 150 + return descriptions[0]; 151 + 152 + case 2: 153 + return descriptions[0] + " or " + descriptions[1]; 154 + 155 + default: 156 + return descriptions.slice(0, -1).join(", ") 157 + + ", or " 158 + + descriptions[descriptions.length - 1]; 159 + } 160 + } 161 + 162 + function describeFound(found) { 163 + return found ? "\"" + literalEscape(found) + "\"" : "end of input"; 164 + } 165 + 166 + return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found."; 167 + }; 168 + 169 + function peg$parse(input, options) { 170 + options = options !== undefined ? options : {}; 171 + 172 + var peg$FAILED = {}; 173 + var peg$source = options.grammarSource; 174 + 175 + var peg$startRuleFunctions = { Start: peg$parseStart }; 176 + var peg$startRuleFunction = peg$parseStart; 177 + 178 + var peg$c0 = "add"; 179 + var peg$c1 = "done"; 180 + var peg$c2 = "filter"; 181 + var peg$c3 = "-"; 182 + var peg$c4 = ","; 183 + var peg$c5 = "@"; 184 + var peg$c6 = "pro:"; 185 + var peg$c7 = "project:"; 186 + var peg$c8 = "+"; 187 + var peg$c9 = "priority:"; 188 + var peg$c10 = "#"; 189 + var peg$c11 = "am"; 190 + var peg$c12 = "pm"; 191 + 192 + var peg$r0 = /^[HML]/; 193 + var peg$r1 = /^[0-9]/; 194 + var peg$r2 = /^[0-9:]/; 195 + var peg$r3 = /^[a-zA-Z0-9_\-]/; 196 + var peg$r4 = /^[ \t]/; 197 + 198 + var peg$e0 = peg$literalExpectation("add", false); 199 + var peg$e1 = peg$literalExpectation("done", false); 200 + var peg$e2 = peg$literalExpectation("filter", false); 201 + var peg$e3 = peg$literalExpectation("-", false); 202 + var peg$e4 = peg$literalExpectation(",", false); 203 + var peg$e5 = peg$literalExpectation("@", false); 204 + var peg$e6 = peg$literalExpectation("pro:", false); 205 + var peg$e7 = peg$literalExpectation("project:", false); 206 + var peg$e8 = peg$literalExpectation("+", false); 207 + var peg$e9 = peg$literalExpectation("priority:", false); 208 + var peg$e10 = peg$classExpectation(["H", "M", "L"], false, false); 209 + var peg$e11 = peg$literalExpectation("#", false); 210 + var peg$e12 = peg$classExpectation([["0", "9"]], false, false); 211 + var peg$e13 = peg$classExpectation([["0", "9"], ":"], false, false); 212 + var peg$e14 = peg$literalExpectation("am", false); 213 + var peg$e15 = peg$literalExpectation("pm", false); 214 + var peg$e16 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"], "_", "-"], false, false); 215 + var peg$e17 = peg$classExpectation([" ", "\t"], false, false); 216 + var peg$e18 = peg$anyExpectation(); 217 + 218 + var peg$f0 = function(parts) { 219 + return makeCommand('add', null, parts.filter(p => p !== null)); 220 + }; 221 + var peg$f1 = function(filters) { 222 + return makeCommand('done', filters, null); 223 + }; 224 + var peg$f2 = function(filters, moreFilters) { 225 + return makeCommand('filter', [...filters, ...moreFilters], null); 226 + }; 227 + var peg$f3 = function(filters) { 228 + return makeCommand('filter', filters, null); 229 + }; 230 + var peg$f4 = function(first, rest) { 231 + return [first, ...rest.map(r => r[1])]; 232 + }; 233 + var peg$f5 = function(start, end) { 234 + const ids = []; 235 + for (let i = start; i <= end; i++) { 236 + ids.push(i); 237 + } 238 + return ids; 239 + }; 240 + var peg$f6 = function(id) { 241 + return [id]; 242 + }; 243 + var peg$f7 = function(first, rest, trailing) { 244 + const ids = [first, ...rest.map(r => r[1])].flat(); 245 + return { 246 + type: 'id', 247 + ids: ids, 248 + reconstruct: function() { return this.ids.join(','); } 249 + }; 250 + }; 251 + var peg$f8 = function(chars) { 252 + return { 253 + type: "text", 254 + value: chars, 255 + reconstruct: function() { return this.value; } 256 + }; 257 + }; 258 + var peg$f9 = function(value) { 259 + return { 260 + type: "due", 261 + value: value, 262 + reconstruct: function() { return `@${this.value}`; } 263 + }; 264 + }; 265 + var peg$f10 = function(value) { 266 + return { 267 + type: "project", 268 + value: value, 269 + reconstruct: function() { return `+${this.value}`; } 270 + }; 271 + }; 272 + var peg$f11 = function(value) { 273 + return { 274 + type: "priority", 275 + value: value, 276 + reconstruct: function() { return `priority:${this.value}`; } 277 + }; 278 + }; 279 + var peg$f12 = function(value) { 280 + return { 281 + type: "tag", 282 + value: value, 283 + reconstruct: function() { return `#${this.value}`; } 284 + }; 285 + }; 286 + var peg$f13 = function(digits) { 287 + return parseInt(digits.join(''), 10); 288 + }; 289 + var peg$f14 = function(chars) { 290 + return chars.join('') + (text() || ''); 291 + }; 292 + var peg$f15 = function(chars) { 293 + return chars.join(''); 294 + }; 295 + var peg$f16 = function() { 296 + return null; 297 + }; 298 + var peg$currPos = options.peg$currPos | 0; 299 + var peg$savedPos = peg$currPos; 300 + var peg$posDetailsCache = [{ line: 1, column: 1 }]; 301 + var peg$maxFailPos = peg$currPos; 302 + var peg$maxFailExpected = options.peg$maxFailExpected || []; 303 + var peg$silentFails = options.peg$silentFails | 0; 304 + 305 + var peg$result; 306 + 307 + if (options.startRule) { 308 + if (!(options.startRule in peg$startRuleFunctions)) { 309 + throw new Error("Can't start parsing from rule \"" + options.startRule + "\"."); 310 + } 311 + 312 + peg$startRuleFunction = peg$startRuleFunctions[options.startRule]; 313 + } 314 + 315 + function text() { 316 + return input.substring(peg$savedPos, peg$currPos); 317 + } 318 + 319 + function offset() { 320 + return peg$savedPos; 321 + } 322 + 323 + function range() { 324 + return { 325 + source: peg$source, 326 + start: peg$savedPos, 327 + end: peg$currPos 328 + }; 329 + } 330 + 331 + function location() { 332 + return peg$computeLocation(peg$savedPos, peg$currPos); 333 + } 334 + 335 + function expected(description, location) { 336 + location = location !== undefined 337 + ? location 338 + : peg$computeLocation(peg$savedPos, peg$currPos); 339 + 340 + throw peg$buildStructuredError( 341 + [peg$otherExpectation(description)], 342 + input.substring(peg$savedPos, peg$currPos), 343 + location 344 + ); 345 + } 346 + 347 + function error(message, location) { 348 + location = location !== undefined 349 + ? location 350 + : peg$computeLocation(peg$savedPos, peg$currPos); 351 + 352 + throw peg$buildSimpleError(message, location); 353 + } 354 + 355 + function peg$literalExpectation(text, ignoreCase) { 356 + return { type: "literal", text: text, ignoreCase: ignoreCase }; 357 + } 358 + 359 + function peg$classExpectation(parts, inverted, ignoreCase) { 360 + return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase }; 361 + } 362 + 363 + function peg$anyExpectation() { 364 + return { type: "any" }; 365 + } 366 + 367 + function peg$endExpectation() { 368 + return { type: "end" }; 369 + } 370 + 371 + function peg$otherExpectation(description) { 372 + return { type: "other", description: description }; 373 + } 374 + 375 + function peg$computePosDetails(pos) { 376 + var details = peg$posDetailsCache[pos]; 377 + var p; 378 + 379 + if (details) { 380 + return details; 381 + } else { 382 + if (pos >= peg$posDetailsCache.length) { 383 + p = peg$posDetailsCache.length - 1; 384 + } else { 385 + p = pos; 386 + while (!peg$posDetailsCache[--p]) {} 387 + } 388 + 389 + details = peg$posDetailsCache[p]; 390 + details = { 391 + line: details.line, 392 + column: details.column 393 + }; 394 + 395 + while (p < pos) { 396 + if (input.charCodeAt(p) === 10) { 397 + details.line++; 398 + details.column = 1; 399 + } else { 400 + details.column++; 401 + } 402 + 403 + p++; 404 + } 405 + 406 + peg$posDetailsCache[pos] = details; 407 + 408 + return details; 409 + } 410 + } 411 + 412 + function peg$computeLocation(startPos, endPos, offset) { 413 + var startPosDetails = peg$computePosDetails(startPos); 414 + var endPosDetails = peg$computePosDetails(endPos); 415 + 416 + var res = { 417 + source: peg$source, 418 + start: { 419 + offset: startPos, 420 + line: startPosDetails.line, 421 + column: startPosDetails.column 422 + }, 423 + end: { 424 + offset: endPos, 425 + line: endPosDetails.line, 426 + column: endPosDetails.column 427 + } 428 + }; 429 + if (offset && peg$source && (typeof peg$source.offset === "function")) { 430 + res.start = peg$source.offset(res.start); 431 + res.end = peg$source.offset(res.end); 432 + } 433 + return res; 434 + } 435 + 436 + function peg$fail(expected) { 437 + if (peg$currPos < peg$maxFailPos) { return; } 438 + 439 + if (peg$currPos > peg$maxFailPos) { 440 + peg$maxFailPos = peg$currPos; 441 + peg$maxFailExpected = []; 442 + } 443 + 444 + peg$maxFailExpected.push(expected); 445 + } 446 + 447 + function peg$buildSimpleError(message, location) { 448 + return new peg$SyntaxError(message, null, null, location); 449 + } 450 + 451 + function peg$buildStructuredError(expected, found, location) { 452 + return new peg$SyntaxError( 453 + peg$SyntaxError.buildMessage(expected, found), 454 + expected, 455 + found, 456 + location 457 + ); 458 + } 459 + 460 + function peg$parseStart() { 461 + var s0; 462 + 463 + s0 = peg$parseAddCommand(); 464 + if (s0 === peg$FAILED) { 465 + s0 = peg$parseDoneCommand(); 466 + if (s0 === peg$FAILED) { 467 + s0 = peg$parseExplicitFilterCommand(); 468 + if (s0 === peg$FAILED) { 469 + s0 = peg$parseImplicitFilterCommand(); 470 + } 471 + } 472 + } 473 + 474 + return s0; 475 + } 476 + 477 + function peg$parseAddCommand() { 478 + var s0, s1, s2, s3, s4; 479 + 480 + s0 = peg$currPos; 481 + if (input.substr(peg$currPos, 3) === peg$c0) { 482 + s1 = peg$c0; 483 + peg$currPos += 3; 484 + } else { 485 + s1 = peg$FAILED; 486 + if (peg$silentFails === 0) { peg$fail(peg$e0); } 487 + } 488 + if (s1 !== peg$FAILED) { 489 + s2 = peg$parse_(); 490 + if (s2 !== peg$FAILED) { 491 + s3 = []; 492 + s4 = peg$parsePart(); 493 + if (s4 === peg$FAILED) { 494 + s4 = peg$parse_(); 495 + } 496 + if (s4 !== peg$FAILED) { 497 + while (s4 !== peg$FAILED) { 498 + s3.push(s4); 499 + s4 = peg$parsePart(); 500 + if (s4 === peg$FAILED) { 501 + s4 = peg$parse_(); 502 + } 503 + } 504 + } else { 505 + s3 = peg$FAILED; 506 + } 507 + if (s3 !== peg$FAILED) { 508 + s4 = peg$parseEOF(); 509 + if (s4 !== peg$FAILED) { 510 + peg$savedPos = s0; 511 + s0 = peg$f0(s3); 512 + } else { 513 + peg$currPos = s0; 514 + s0 = peg$FAILED; 515 + } 516 + } else { 517 + peg$currPos = s0; 518 + s0 = peg$FAILED; 519 + } 520 + } else { 521 + peg$currPos = s0; 522 + s0 = peg$FAILED; 523 + } 524 + } else { 525 + peg$currPos = s0; 526 + s0 = peg$FAILED; 527 + } 528 + 529 + return s0; 530 + } 531 + 532 + function peg$parseDoneCommand() { 533 + var s0, s1, s2, s3, s4; 534 + 535 + s0 = peg$currPos; 536 + s1 = peg$parseFilters(); 537 + if (s1 !== peg$FAILED) { 538 + s2 = peg$parse_(); 539 + if (s2 !== peg$FAILED) { 540 + if (input.substr(peg$currPos, 4) === peg$c1) { 541 + s3 = peg$c1; 542 + peg$currPos += 4; 543 + } else { 544 + s3 = peg$FAILED; 545 + if (peg$silentFails === 0) { peg$fail(peg$e1); } 546 + } 547 + if (s3 !== peg$FAILED) { 548 + s4 = peg$parseEOF(); 549 + if (s4 !== peg$FAILED) { 550 + peg$savedPos = s0; 551 + s0 = peg$f1(s1); 552 + } else { 553 + peg$currPos = s0; 554 + s0 = peg$FAILED; 555 + } 556 + } else { 557 + peg$currPos = s0; 558 + s0 = peg$FAILED; 559 + } 560 + } else { 561 + peg$currPos = s0; 562 + s0 = peg$FAILED; 563 + } 564 + } else { 565 + peg$currPos = s0; 566 + s0 = peg$FAILED; 567 + } 568 + 569 + return s0; 570 + } 571 + 572 + function peg$parseExplicitFilterCommand() { 573 + var s0, s1, s2, s3, s4, s5, s6; 574 + 575 + s0 = peg$currPos; 576 + s1 = peg$parseFilters(); 577 + if (s1 !== peg$FAILED) { 578 + s2 = peg$parse_(); 579 + if (s2 !== peg$FAILED) { 580 + if (input.substr(peg$currPos, 6) === peg$c2) { 581 + s3 = peg$c2; 582 + peg$currPos += 6; 583 + } else { 584 + s3 = peg$FAILED; 585 + if (peg$silentFails === 0) { peg$fail(peg$e2); } 586 + } 587 + if (s3 !== peg$FAILED) { 588 + s4 = []; 589 + s5 = peg$parse_(); 590 + while (s5 !== peg$FAILED) { 591 + s4.push(s5); 592 + s5 = peg$parse_(); 593 + } 594 + s5 = []; 595 + s6 = peg$parseFilters(); 596 + while (s6 !== peg$FAILED) { 597 + s5.push(s6); 598 + s6 = peg$parseFilters(); 599 + } 600 + s6 = peg$parseEOF(); 601 + if (s6 !== peg$FAILED) { 602 + peg$savedPos = s0; 603 + s0 = peg$f2(s1, s5); 604 + } else { 605 + peg$currPos = s0; 606 + s0 = peg$FAILED; 607 + } 608 + } else { 609 + peg$currPos = s0; 610 + s0 = peg$FAILED; 611 + } 612 + } else { 613 + peg$currPos = s0; 614 + s0 = peg$FAILED; 615 + } 616 + } else { 617 + peg$currPos = s0; 618 + s0 = peg$FAILED; 619 + } 620 + 621 + return s0; 622 + } 623 + 624 + function peg$parseImplicitFilterCommand() { 625 + var s0, s1, s2; 626 + 627 + s0 = peg$currPos; 628 + s1 = []; 629 + s2 = peg$parseFilters(); 630 + if (s2 !== peg$FAILED) { 631 + while (s2 !== peg$FAILED) { 632 + s1.push(s2); 633 + s2 = peg$parseFilters(); 634 + } 635 + } else { 636 + s1 = peg$FAILED; 637 + } 638 + if (s1 !== peg$FAILED) { 639 + s2 = peg$parseEOF(); 640 + if (s2 !== peg$FAILED) { 641 + peg$savedPos = s0; 642 + s0 = peg$f3(s1); 643 + } else { 644 + peg$currPos = s0; 645 + s0 = peg$FAILED; 646 + } 647 + } else { 648 + peg$currPos = s0; 649 + s0 = peg$FAILED; 650 + } 651 + 652 + return s0; 653 + } 654 + 655 + function peg$parseFilters() { 656 + var s0, s1, s2, s3, s4, s5; 657 + 658 + s0 = peg$currPos; 659 + s1 = peg$parseFilter(); 660 + if (s1 !== peg$FAILED) { 661 + s2 = []; 662 + s3 = peg$currPos; 663 + s4 = peg$parse_(); 664 + if (s4 !== peg$FAILED) { 665 + s5 = peg$parseFilter(); 666 + if (s5 !== peg$FAILED) { 667 + s4 = [s4, s5]; 668 + s3 = s4; 669 + } else { 670 + peg$currPos = s3; 671 + s3 = peg$FAILED; 672 + } 673 + } else { 674 + peg$currPos = s3; 675 + s3 = peg$FAILED; 676 + } 677 + while (s3 !== peg$FAILED) { 678 + s2.push(s3); 679 + s3 = peg$currPos; 680 + s4 = peg$parse_(); 681 + if (s4 !== peg$FAILED) { 682 + s5 = peg$parseFilter(); 683 + if (s5 !== peg$FAILED) { 684 + s4 = [s4, s5]; 685 + s3 = s4; 686 + } else { 687 + peg$currPos = s3; 688 + s3 = peg$FAILED; 689 + } 690 + } else { 691 + peg$currPos = s3; 692 + s3 = peg$FAILED; 693 + } 694 + } 695 + peg$savedPos = s0; 696 + s0 = peg$f4(s1, s2); 697 + } else { 698 + peg$currPos = s0; 699 + s0 = peg$FAILED; 700 + } 701 + 702 + return s0; 703 + } 704 + 705 + function peg$parseIdRange() { 706 + var s0, s1, s2, s3; 707 + 708 + s0 = peg$currPos; 709 + s1 = peg$parseInteger(); 710 + if (s1 !== peg$FAILED) { 711 + if (input.charCodeAt(peg$currPos) === 45) { 712 + s2 = peg$c3; 713 + peg$currPos++; 714 + } else { 715 + s2 = peg$FAILED; 716 + if (peg$silentFails === 0) { peg$fail(peg$e3); } 717 + } 718 + if (s2 !== peg$FAILED) { 719 + s3 = peg$parseInteger(); 720 + if (s3 !== peg$FAILED) { 721 + peg$savedPos = s0; 722 + s0 = peg$f5(s1, s3); 723 + } else { 724 + peg$currPos = s0; 725 + s0 = peg$FAILED; 726 + } 727 + } else { 728 + peg$currPos = s0; 729 + s0 = peg$FAILED; 730 + } 731 + } else { 732 + peg$currPos = s0; 733 + s0 = peg$FAILED; 734 + } 735 + 736 + return s0; 737 + } 738 + 739 + function peg$parseSingleId() { 740 + var s0, s1; 741 + 742 + s0 = peg$currPos; 743 + s1 = peg$parseInteger(); 744 + if (s1 !== peg$FAILED) { 745 + peg$savedPos = s0; 746 + s1 = peg$f6(s1); 747 + } 748 + s0 = s1; 749 + 750 + return s0; 751 + } 752 + 753 + function peg$parseFilter() { 754 + var s0; 755 + 756 + s0 = peg$parseIdFilter(); 757 + if (s0 === peg$FAILED) { 758 + s0 = peg$parseTag(); 759 + if (s0 === peg$FAILED) { 760 + s0 = peg$parseProject(); 761 + if (s0 === peg$FAILED) { 762 + s0 = peg$parsePriority(); 763 + if (s0 === peg$FAILED) { 764 + s0 = peg$parseDue(); 765 + } 766 + } 767 + } 768 + } 769 + 770 + return s0; 771 + } 772 + 773 + function peg$parseIdFilter() { 774 + var s0, s1, s2, s3, s4, s5; 775 + 776 + s0 = peg$currPos; 777 + s1 = peg$parseIdRange(); 778 + if (s1 === peg$FAILED) { 779 + s1 = peg$parseSingleId(); 780 + } 781 + if (s1 !== peg$FAILED) { 782 + s2 = []; 783 + s3 = peg$currPos; 784 + if (input.charCodeAt(peg$currPos) === 44) { 785 + s4 = peg$c4; 786 + peg$currPos++; 787 + } else { 788 + s4 = peg$FAILED; 789 + if (peg$silentFails === 0) { peg$fail(peg$e4); } 790 + } 791 + if (s4 !== peg$FAILED) { 792 + s5 = peg$parseIdRange(); 793 + if (s5 === peg$FAILED) { 794 + s5 = peg$parseSingleId(); 795 + } 796 + if (s5 !== peg$FAILED) { 797 + s4 = [s4, s5]; 798 + s3 = s4; 799 + } else { 800 + peg$currPos = s3; 801 + s3 = peg$FAILED; 802 + } 803 + } else { 804 + peg$currPos = s3; 805 + s3 = peg$FAILED; 806 + } 807 + while (s3 !== peg$FAILED) { 808 + s2.push(s3); 809 + s3 = peg$currPos; 810 + if (input.charCodeAt(peg$currPos) === 44) { 811 + s4 = peg$c4; 812 + peg$currPos++; 813 + } else { 814 + s4 = peg$FAILED; 815 + if (peg$silentFails === 0) { peg$fail(peg$e4); } 816 + } 817 + if (s4 !== peg$FAILED) { 818 + s5 = peg$parseIdRange(); 819 + if (s5 === peg$FAILED) { 820 + s5 = peg$parseSingleId(); 821 + } 822 + if (s5 !== peg$FAILED) { 823 + s4 = [s4, s5]; 824 + s3 = s4; 825 + } else { 826 + peg$currPos = s3; 827 + s3 = peg$FAILED; 828 + } 829 + } else { 830 + peg$currPos = s3; 831 + s3 = peg$FAILED; 832 + } 833 + } 834 + if (input.charCodeAt(peg$currPos) === 44) { 835 + s3 = peg$c4; 836 + peg$currPos++; 837 + } else { 838 + s3 = peg$FAILED; 839 + if (peg$silentFails === 0) { peg$fail(peg$e4); } 840 + } 841 + if (s3 === peg$FAILED) { 842 + s3 = null; 843 + } 844 + peg$savedPos = s0; 845 + s0 = peg$f7(s1, s2, s3); 846 + } else { 847 + peg$currPos = s0; 848 + s0 = peg$FAILED; 849 + } 850 + 851 + return s0; 852 + } 853 + 854 + function peg$parsePart() { 855 + var s0; 856 + 857 + s0 = peg$parseAttribute(); 858 + if (s0 === peg$FAILED) { 859 + s0 = peg$parseTextPart(); 860 + } 861 + 862 + return s0; 863 + } 864 + 865 + function peg$parseTextPart() { 866 + var s0, s1; 867 + 868 + s0 = peg$currPos; 869 + s1 = peg$parseWord(); 870 + if (s1 !== peg$FAILED) { 871 + peg$savedPos = s0; 872 + s1 = peg$f8(s1); 873 + } 874 + s0 = s1; 875 + 876 + return s0; 877 + } 878 + 879 + function peg$parseAttribute() { 880 + var s0; 881 + 882 + s0 = peg$parseDue(); 883 + if (s0 === peg$FAILED) { 884 + s0 = peg$parseTag(); 885 + if (s0 === peg$FAILED) { 886 + s0 = peg$parseProject(); 887 + if (s0 === peg$FAILED) { 888 + s0 = peg$parsePriority(); 889 + } 890 + } 891 + } 892 + 893 + return s0; 894 + } 895 + 896 + function peg$parseDue() { 897 + var s0, s1, s2; 898 + 899 + s0 = peg$currPos; 900 + if (input.charCodeAt(peg$currPos) === 64) { 901 + s1 = peg$c5; 902 + peg$currPos++; 903 + } else { 904 + s1 = peg$FAILED; 905 + if (peg$silentFails === 0) { peg$fail(peg$e5); } 906 + } 907 + if (s1 !== peg$FAILED) { 908 + s2 = peg$parseTimeValue(); 909 + if (s2 !== peg$FAILED) { 910 + peg$savedPos = s0; 911 + s0 = peg$f9(s2); 912 + } else { 913 + peg$currPos = s0; 914 + s0 = peg$FAILED; 915 + } 916 + } else { 917 + peg$currPos = s0; 918 + s0 = peg$FAILED; 919 + } 920 + 921 + return s0; 922 + } 923 + 924 + function peg$parseProject() { 925 + var s0, s1, s2; 926 + 927 + s0 = peg$currPos; 928 + if (input.substr(peg$currPos, 4) === peg$c6) { 929 + s1 = peg$c6; 930 + peg$currPos += 4; 931 + } else { 932 + s1 = peg$FAILED; 933 + if (peg$silentFails === 0) { peg$fail(peg$e6); } 934 + } 935 + if (s1 === peg$FAILED) { 936 + if (input.substr(peg$currPos, 8) === peg$c7) { 937 + s1 = peg$c7; 938 + peg$currPos += 8; 939 + } else { 940 + s1 = peg$FAILED; 941 + if (peg$silentFails === 0) { peg$fail(peg$e7); } 942 + } 943 + if (s1 === peg$FAILED) { 944 + if (input.charCodeAt(peg$currPos) === 43) { 945 + s1 = peg$c8; 946 + peg$currPos++; 947 + } else { 948 + s1 = peg$FAILED; 949 + if (peg$silentFails === 0) { peg$fail(peg$e8); } 950 + } 951 + } 952 + } 953 + if (s1 !== peg$FAILED) { 954 + s2 = peg$parseWord(); 955 + if (s2 !== peg$FAILED) { 956 + peg$savedPos = s0; 957 + s0 = peg$f10(s2); 958 + } else { 959 + peg$currPos = s0; 960 + s0 = peg$FAILED; 961 + } 962 + } else { 963 + peg$currPos = s0; 964 + s0 = peg$FAILED; 965 + } 966 + 967 + return s0; 968 + } 969 + 970 + function peg$parsePriority() { 971 + var s0, s1, s2; 972 + 973 + s0 = peg$currPos; 974 + if (input.substr(peg$currPos, 9) === peg$c9) { 975 + s1 = peg$c9; 976 + peg$currPos += 9; 977 + } else { 978 + s1 = peg$FAILED; 979 + if (peg$silentFails === 0) { peg$fail(peg$e9); } 980 + } 981 + if (s1 !== peg$FAILED) { 982 + s2 = input.charAt(peg$currPos); 983 + if (peg$r0.test(s2)) { 984 + peg$currPos++; 985 + } else { 986 + s2 = peg$FAILED; 987 + if (peg$silentFails === 0) { peg$fail(peg$e10); } 988 + } 989 + if (s2 !== peg$FAILED) { 990 + peg$savedPos = s0; 991 + s0 = peg$f11(s2); 992 + } else { 993 + peg$currPos = s0; 994 + s0 = peg$FAILED; 995 + } 996 + } else { 997 + peg$currPos = s0; 998 + s0 = peg$FAILED; 999 + } 1000 + 1001 + return s0; 1002 + } 1003 + 1004 + function peg$parseTag() { 1005 + var s0, s1, s2; 1006 + 1007 + s0 = peg$currPos; 1008 + if (input.charCodeAt(peg$currPos) === 35) { 1009 + s1 = peg$c10; 1010 + peg$currPos++; 1011 + } else { 1012 + s1 = peg$FAILED; 1013 + if (peg$silentFails === 0) { peg$fail(peg$e11); } 1014 + } 1015 + if (s1 !== peg$FAILED) { 1016 + s2 = peg$parseWord(); 1017 + if (s2 !== peg$FAILED) { 1018 + peg$savedPos = s0; 1019 + s0 = peg$f12(s2); 1020 + } else { 1021 + peg$currPos = s0; 1022 + s0 = peg$FAILED; 1023 + } 1024 + } else { 1025 + peg$currPos = s0; 1026 + s0 = peg$FAILED; 1027 + } 1028 + 1029 + return s0; 1030 + } 1031 + 1032 + function peg$parseInteger() { 1033 + var s0, s1, s2; 1034 + 1035 + s0 = peg$currPos; 1036 + s1 = []; 1037 + s2 = input.charAt(peg$currPos); 1038 + if (peg$r1.test(s2)) { 1039 + peg$currPos++; 1040 + } else { 1041 + s2 = peg$FAILED; 1042 + if (peg$silentFails === 0) { peg$fail(peg$e12); } 1043 + } 1044 + if (s2 !== peg$FAILED) { 1045 + while (s2 !== peg$FAILED) { 1046 + s1.push(s2); 1047 + s2 = input.charAt(peg$currPos); 1048 + if (peg$r1.test(s2)) { 1049 + peg$currPos++; 1050 + } else { 1051 + s2 = peg$FAILED; 1052 + if (peg$silentFails === 0) { peg$fail(peg$e12); } 1053 + } 1054 + } 1055 + } else { 1056 + s1 = peg$FAILED; 1057 + } 1058 + if (s1 !== peg$FAILED) { 1059 + peg$savedPos = s0; 1060 + s1 = peg$f13(s1); 1061 + } 1062 + s0 = s1; 1063 + 1064 + return s0; 1065 + } 1066 + 1067 + function peg$parseTimeValue() { 1068 + var s0, s1, s2; 1069 + 1070 + s0 = peg$currPos; 1071 + s1 = []; 1072 + s2 = input.charAt(peg$currPos); 1073 + if (peg$r2.test(s2)) { 1074 + peg$currPos++; 1075 + } else { 1076 + s2 = peg$FAILED; 1077 + if (peg$silentFails === 0) { peg$fail(peg$e13); } 1078 + } 1079 + if (s2 !== peg$FAILED) { 1080 + while (s2 !== peg$FAILED) { 1081 + s1.push(s2); 1082 + s2 = input.charAt(peg$currPos); 1083 + if (peg$r2.test(s2)) { 1084 + peg$currPos++; 1085 + } else { 1086 + s2 = peg$FAILED; 1087 + if (peg$silentFails === 0) { peg$fail(peg$e13); } 1088 + } 1089 + } 1090 + } else { 1091 + s1 = peg$FAILED; 1092 + } 1093 + if (s1 !== peg$FAILED) { 1094 + if (input.substr(peg$currPos, 2) === peg$c11) { 1095 + s2 = peg$c11; 1096 + peg$currPos += 2; 1097 + } else { 1098 + s2 = peg$FAILED; 1099 + if (peg$silentFails === 0) { peg$fail(peg$e14); } 1100 + } 1101 + if (s2 === peg$FAILED) { 1102 + if (input.substr(peg$currPos, 2) === peg$c12) { 1103 + s2 = peg$c12; 1104 + peg$currPos += 2; 1105 + } else { 1106 + s2 = peg$FAILED; 1107 + if (peg$silentFails === 0) { peg$fail(peg$e15); } 1108 + } 1109 + } 1110 + if (s2 === peg$FAILED) { 1111 + s2 = null; 1112 + } 1113 + peg$savedPos = s0; 1114 + s0 = peg$f14(s1); 1115 + } else { 1116 + peg$currPos = s0; 1117 + s0 = peg$FAILED; 1118 + } 1119 + 1120 + return s0; 1121 + } 1122 + 1123 + function peg$parseWord() { 1124 + var s0, s1, s2; 1125 + 1126 + s0 = peg$currPos; 1127 + s1 = []; 1128 + s2 = input.charAt(peg$currPos); 1129 + if (peg$r3.test(s2)) { 1130 + peg$currPos++; 1131 + } else { 1132 + s2 = peg$FAILED; 1133 + if (peg$silentFails === 0) { peg$fail(peg$e16); } 1134 + } 1135 + if (s2 !== peg$FAILED) { 1136 + while (s2 !== peg$FAILED) { 1137 + s1.push(s2); 1138 + s2 = input.charAt(peg$currPos); 1139 + if (peg$r3.test(s2)) { 1140 + peg$currPos++; 1141 + } else { 1142 + s2 = peg$FAILED; 1143 + if (peg$silentFails === 0) { peg$fail(peg$e16); } 1144 + } 1145 + } 1146 + } else { 1147 + s1 = peg$FAILED; 1148 + } 1149 + if (s1 !== peg$FAILED) { 1150 + peg$savedPos = s0; 1151 + s1 = peg$f15(s1); 1152 + } 1153 + s0 = s1; 1154 + 1155 + return s0; 1156 + } 1157 + 1158 + function peg$parse_() { 1159 + var s0, s1, s2; 1160 + 1161 + s0 = peg$currPos; 1162 + s1 = []; 1163 + s2 = input.charAt(peg$currPos); 1164 + if (peg$r4.test(s2)) { 1165 + peg$currPos++; 1166 + } else { 1167 + s2 = peg$FAILED; 1168 + if (peg$silentFails === 0) { peg$fail(peg$e17); } 1169 + } 1170 + if (s2 !== peg$FAILED) { 1171 + while (s2 !== peg$FAILED) { 1172 + s1.push(s2); 1173 + s2 = input.charAt(peg$currPos); 1174 + if (peg$r4.test(s2)) { 1175 + peg$currPos++; 1176 + } else { 1177 + s2 = peg$FAILED; 1178 + if (peg$silentFails === 0) { peg$fail(peg$e17); } 1179 + } 1180 + } 1181 + } else { 1182 + s1 = peg$FAILED; 1183 + } 1184 + if (s1 !== peg$FAILED) { 1185 + peg$savedPos = s0; 1186 + s1 = peg$f16(); 1187 + } 1188 + s0 = s1; 1189 + 1190 + return s0; 1191 + } 1192 + 1193 + function peg$parseEOF() { 1194 + var s0, s1; 1195 + 1196 + s0 = peg$currPos; 1197 + peg$silentFails++; 1198 + if (input.length > peg$currPos) { 1199 + s1 = input.charAt(peg$currPos); 1200 + peg$currPos++; 1201 + } else { 1202 + s1 = peg$FAILED; 1203 + if (peg$silentFails === 0) { peg$fail(peg$e18); } 1204 + } 1205 + peg$silentFails--; 1206 + if (s1 === peg$FAILED) { 1207 + s0 = undefined; 1208 + } else { 1209 + peg$currPos = s0; 1210 + s0 = peg$FAILED; 1211 + } 1212 + 1213 + return s0; 1214 + } 1215 + 1216 + 1217 + function makeCommand(type, filters, parts) { 1218 + 1219 + const validParts = parts || []; 1220 + // Extract pure description (without attributes) 1221 + const description = validParts 1222 + .filter(part => part.type === 'text') 1223 + .map(part => part.value) 1224 + .join(' ') 1225 + .trim(); 1226 + 1227 + // Collect all attributes 1228 + const attributes = validParts 1229 + .filter(part => part.type !== 'text') 1230 + .filter(part => part !== null); 1231 + 1232 + const project = validParts 1233 + .filter(part => part.type === 'project') 1234 + .map(part => part.value) 1235 + .join('') 1236 + .trim(); 1237 + 1238 + const tags = validParts 1239 + .filter(part => part.type === 'tag') 1240 + .map(part => part.value); 1241 + 1242 + 1243 + // Store original parts for reconstruction 1244 + const originalParts = validParts.filter(part => part !== null); 1245 + let validFilters; 1246 + if (!!filters) { 1247 + validFilters = filters.flat(); 1248 + } else { 1249 + validFilters = []; 1250 + } 1251 + 1252 + return { 1253 + type: type, 1254 + description: description || [], 1255 + attributes: attributes || [], 1256 + filters: validFilters, 1257 + project: project, 1258 + tags: JSON.stringify(tags), 1259 + parts: parts || [], 1260 + reconstruct: function() { 1261 + const filterStr = this.filters.map(f => f.reconstruct()).join(','); 1262 + const partsStr = this.parts.map(p => p.reconstruct()).join(' '); 1263 + return [filterStr, this.type, partsStr].filter(Boolean).join(' '); 1264 + } 1265 + }; 1266 + } 1267 + 1268 + peg$result = peg$startRuleFunction(); 1269 + 1270 + if (options.peg$library) { 1271 + return /** @type {any} */ ({ 1272 + peg$result, 1273 + peg$currPos, 1274 + peg$FAILED, 1275 + peg$maxFailExpected, 1276 + peg$maxFailPos 1277 + }); 1278 + } 1279 + if (peg$result !== peg$FAILED && peg$currPos === input.length) { 1280 + return peg$result; 1281 + } else { 1282 + if (peg$result !== peg$FAILED && peg$currPos < input.length) { 1283 + peg$fail(peg$endExpectation()); 1284 + } 1285 + 1286 + throw peg$buildStructuredError( 1287 + peg$maxFailExpected, 1288 + peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null, 1289 + peg$maxFailPos < input.length 1290 + ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1) 1291 + : peg$computeLocation(peg$maxFailPos, peg$maxFailPos) 1292 + ); 1293 + } 1294 + } 1295 + 1296 + const peg$allowedStartRules = [ 1297 + "Start" 1298 + ]; 1299 + 1300 + export { 1301 + peg$allowedStartRules as StartRules, 1302 + peg$SyntaxError as SyntaxError, 1303 + peg$parse as parse 1304 + };
+76 -18
mast-react-vite/src/main.tsx
··· 2 2 import { createRoot } from 'react-dom/client' 3 3 import './index.css' 4 4 import App from "./App.tsx"; 5 + import Root from "./Root.tsx"; 6 + import { start } from "@vlcn.io/ws-client/worker.js"; 7 + import { createDbProvider } from "@vlcn.io/ws-browserdb"; 5 8 6 9 import initWasm from '@vlcn.io/crsqlite-wasm'; 7 10 import wasmUrl from '@vlcn.io/crsqlite-wasm/crsqlite.wasm?url'; 8 11 import tblrx from '@vlcn.io/rx-tbl'; 9 12 10 - const sqlite = await initWasm(() => wasmUrl); 13 + async function initializeDatabase() { 14 + const sqlite = await initWasm(() => wasmUrl); 15 + const db = await sqlite.open("todo.db"); 16 + await db.exec(` 17 + CREATE TABLE IF NOT EXISTS todos ( 18 + id BLOB PRIMARY KEY NOT NULL, 19 + description TEXT, 20 + project text, 21 + tags text, 22 + due text, 23 + wait text, 24 + priority text, 25 + urgency real, 26 + completed INTEGER NOT NULL DEFAULT 0 27 + ); 28 + SELECT crsql_as_crr('todos'); 29 + `); 30 + db.onUpdate(async () => { 31 + const changes = await db.execA(`SELECT * FROM crsql_changes WHERE db_version > 0 AND site_id = crsql_site_id()`); 11 32 12 - const db = await sqlite.open("todo.db"); 13 - await db.exec(` 14 - CREATE TABLE IF NOT EXISTS todos ( 15 - id BLOB PRIMARY KEY NOT NULL, 16 - description TEXT, 17 - project text, 18 - tags text, 19 - due text, 20 - wait text, 21 - priority text, 22 - urgency real, 23 - completed INTEGER NOT NULL DEFAULT 0 24 - ); 25 - SELECT crsql_as_crr('todos'); 26 - `); 33 + sendChangesToServer(changes); 34 + }); 35 + return db; 36 + } 27 37 28 - const rx = tblrx(db); 29 - const ctx = { db, rx }; 38 + const config = { 39 + dbProvider: createDbProvider(), 40 + transportProvider: (dbName) => new WebSocket(`ws://localhost:8080/sync/${dbName}`), 41 + }; 42 + 43 + start(config); 44 + const ws = new WebSocket('ws://localhost:8080/sync'); 45 + 46 + ws.onmessage = async function(event) { 47 + const { type, data } = JSON.parse(event.data); 48 + if (type === 'changes') { 49 + await applyChanges(data); 50 + } 51 + }; 52 + 53 + function sendChangesToServer(changes) { 54 + const formattedChanges = changes.map(change => ({ 55 + TableName: change[0], 56 + PK: Array.isArray(change[1]) ? btoa(String.fromCharCode.apply(null, change[1])) : btoa(change[1]), 57 + ColumnName: change[2], 58 + Value: Array.isArray(change[3]) ? btoa(String.fromCharCode.apply(null, change[3])) : change[3], 59 + ColVersion: Number(change[4]), 60 + DBVersion: Number(change[5]), 61 + SiteID: Array.isArray(change[6]) ? btoa(new TextDecoder('utf8').decode(change[6])) : btoa(change[6]), 62 + CL: Number(change[7]), 63 + Seq: Number(change[8]) 64 + })); 65 + console.log(formattedChanges) 66 + 67 + const message = { 68 + type: "changes", 69 + data: formattedChanges 70 + }; 71 + 72 + ws.send(JSON.stringify(message)); 73 + } 74 + 75 + async function applyChanges(changes) { 76 + const db = initializeDatabase(); 77 + const rx = tblrx(db); 78 + const ctx = { db, rx }; 79 + await db.tx(async (tx) => { 80 + for (const change of changes) { 81 + await tx.exec( 82 + `INSERT INTO crsql_changes VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, 83 + change 84 + ); 85 + } 86 + }); 87 + } 30 88 31 89 document.getElementById("root")!.classList.add("dark"); 32 90
+1
mast-react-vite/tsconfig.json
··· 9 9 } 10 10 ], 11 11 "compilerOptions": { 12 + "noEmitOnError": false, 12 13 "baseUrl": ".", 13 14 "paths": { 14 15 "@/*": [