Skip to content

Commit

Permalink
pretty much rest of the project
Browse files Browse the repository at this point in the history
  • Loading branch information
vuolen committed Aug 13, 2021
1 parent f31438c commit 3da38f8
Show file tree
Hide file tree
Showing 11 changed files with 321 additions and 19 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ writeup
output
node_modules
.purs-repl
dist/out.js

1 change: 1 addition & 0 deletions .psci_modules/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require('$PSCI')['$main']();
38 changes: 38 additions & 0 deletions dist/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!doctype html>

<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<title>URLNote</title>

<style>
html, body {
height: 100%;
margin: 0px;
text-align: center;
}

textarea {
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 10px;
width: 50%;
height: 50%;
border: 3px solid #cccccc;
font-size: 3 rem;
}
</style>

</head>

<body>
<h1>URLNote</h1>
<textarea id="input" placeholder="Type your note here"></textarea>
<b>Share this URL:</b> <br/>
<input id="output" readonly type="url" size="50"></input>
<script src="out.js"></script>
</body>
</html>
18 changes: 18 additions & 0 deletions esbuild.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const PurescriptPlugin = require("esbuild-plugin-purescript");
const path = require("path");

const watch = process.env.DEV ? {
onRebuild(error, result) {
if (error) console.error('watch build failed:', error)
else console.log('watch build succeeded:', result)
}
} : null;

require('esbuild').build({
entryPoints: ['src/index.js'],
bundle: true,
outfile: 'dist/out.js',
plugins: [PurescriptPlugin()],
watch,
minify: true
}).catch(() => process.exit(1))
44 changes: 33 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
{
"name": "urlnote",
"version": "1.0.0",
"description": "A note sharing website that includes all its data in the URL.",
"description": "A text sharing website that includes all its data in the URL.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"dev": "DEV=true node esbuild.js & spago build --watch",
"bundle": "node esbuild.js",
"test": "spago test"
},
"repository": {
"type": "git",
Expand All @@ -17,6 +19,9 @@
},
"homepage": "https://github.com/vuolen/urlnote#readme",
"dependencies": {
"big-integer": "^1.6.48",
"esbuild": "^0.12.19",
"esbuild-plugin-purescript": "^1.1.1",
"purescript": "^0.14.1",
"spago": "^0.20.3"
}
Expand Down
17 changes: 15 additions & 2 deletions spago.dhall
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,21 @@
Welcome to a Spago project!
You can edit this file as you like.
-}
{ name = "my-project"
, dependencies = [ "console", "effect", "psci-support" ]
{ name = "URLNote"
, dependencies =
[ "aff"
, "arrays"
, "bigints"
, "effect"
, "integers"
, "maybe"
, "partial"
, "prelude"
, "psci-support"
, "spec"
, "strings"
, "unordered-collections"
]
, packages = ./packages.dhall
, sources = [ "src/**/*.purs", "test/**/*.purs" ]
}
38 changes: 38 additions & 0 deletions src/URLNote/BaseConversion.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module URLNote.BaseConversion where

import Prelude (class Eq, map, (<<<))
import Data.Array ((!!), range, zip, length)
import Data.HashMap (HashMap, fromArray, lookup)
import Data.Maybe (Maybe)
import Data.Hashable (class Hashable, hash)
import Data.String.CodePoints (CodePoint, codePointFromChar, singleton, toCodePointArray)

-- DIGIT

newtype Digit = Digit CodePoint

derive instance eqDigit :: Eq Digit

instance hashableDigit :: Hashable Digit where
hash (Digit cp) = (hash <<< singleton) cp

-- ALPHABET

data Alphabet = Alphabet Int (HashMap Int Digit) (HashMap Digit Int)

fromCodePointArray :: Array CodePoint -> Alphabet
fromCodePointArray arr = Alphabet n indexToDigitMap digitToIndexMap
where n = length arr
digits = map Digit arr
indices = range 0 n
indexToDigitMap = fromArray (zip indices digits)
digitToIndexMap = fromArray (zip digits indices)

fromString :: String -> Alphabet
fromString = fromCodePointArray <<< toCodePointArray

indexToDigit :: Alphabet -> Int -> Maybe Digit
indexToDigit (Alphabet _ indexToDigitMap _) index = lookup index indexToDigitMap

digitToIndex :: Alphabet -> Digit -> Maybe Int
digitToIndex (Alphabet _ _ digitToIndexMap) index = lookup index digitToIndexMap
76 changes: 76 additions & 0 deletions src/URLNote/Main.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
module URLNote.Main where

import Prelude (otherwise, (<<<), (==), (+), (*), map)
import URLNote.BaseConversion (Alphabet(..), Digit(..), fromString)
import URLNote.BaseConversion as BaseConversion
import Data.String.CodePoints (codePointFromChar, fromCodePointArray, toCodePointArray)
import Data.Char (fromCharCode)
import Data.Array (cons, range)
import Data.Array as Array
import Data.HashMap (lookup)
import Data.BigInt (BigInt, fromInt, toNumber, rem, quot, pow)
import Data.Int (floor)
import Data.Maybe (Maybe(..), fromJust)
import Partial.Unsafe (unsafePartial)

unsnoc :: String -> Maybe {init :: String, last :: Digit}
unsnoc "" = Nothing
unsnoc string = case (Array.unsnoc <<< toCodePointArray) string of
Just {init, last} -> Just {init: (fromCodePointArray init), last: Digit last}
Nothing -> Nothing

base83_alphabet = fromString "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345689-._:/?#[]@!$&'()*+,;=" :: Alphabet
base256_alphabet = BaseConversion.fromCodePointArray (map (unsafePartial (codePointFromChar <<< fromJust <<< fromCharCode)) (range 0 255)) :: Alphabet
base10FFFF_alphabet = BaseConversion.fromCodePointArray (map (unsafePartial (codePointFromChar <<< fromJust <<< fromCharCode)) (range 0 0x10FFFF)) :: Alphabet


-- BigInt constants
bi0 = fromInt 0 :: BigInt
bi1 = fromInt 1 :: BigInt
bi83 = fromInt 83 :: BigInt
bi256 = fromInt 256 :: BigInt

encode :: String -> String
encode string = (toBase83 <<< fromBase10FFFF) string

baseEncoder :: Alphabet -> (BigInt -> String)
baseEncoder (Alphabet base indexToDigitMap _) = encode
where encode :: BigInt -> String
encode num = fromCodePointArray (map (\(Digit x) -> x) (encode' num []))
encode' :: BigInt -> Array Digit -> Array Digit
encode' num digits
| num == bi0 = digits
| otherwise =
let
nextDigit = unsafePartial (fromJust (lookup (floor (toNumber (rem num biBase))) indexToDigitMap))
in
encode' (quot num biBase) (cons nextDigit digits)
biBase = (fromInt base)

baseDecoder :: Alphabet -> (String -> BigInt)
baseDecoder (Alphabet base _ digitToIndexMap) = decode
where decode :: String -> BigInt
decode string = decode' string bi0 bi0
decode' :: String -> BigInt -> BigInt -> BigInt
decode' string index sum = case unsnoc string of
Just {init, last} -> let
nextIndex = unsafePartial (fromJust (lookup last digitToIndexMap))
in
decode' init (index + bi1) (sum + (fromInt nextIndex) * (pow biBase index))
Nothing -> sum
biBase = (fromInt base)

decode :: String -> String
decode string = (toBase10FFFF <<< fromBase83) string

toBase83 :: BigInt -> String
toBase83 = baseEncoder base83_alphabet

toBase10FFFF :: BigInt -> String
toBase10FFFF = baseEncoder base10FFFF_alphabet

fromBase83 :: String -> BigInt
fromBase83 = baseDecoder base83_alphabet

fromBase10FFFF :: String -> BigInt
fromBase10FFFF = baseDecoder base10FFFF_alphabet
15 changes: 15 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { encode, decode } from "./URLNote/Main.purs"

document.getElementById("output").value = window.location.href;

document.getElementById("input").addEventListener("input", (ev) => {
window.location.hash = encode(ev.target.value);
document.getElementById("output").value = window.location.href;
});

const updateTextArea = () => {
document.getElementById("input").value = decode(window.location.hash.substr(1));
}

window.addEventListener("load", updateTextArea);
window.addEventListener("hashchange", updateTextArea);
Loading

0 comments on commit 3da38f8

Please sign in to comment.