diff --git a/bin/solid.pill b/bin/solid.pill index 1f07b5c38..bbd7d2c95 100644 --- a/bin/solid.pill +++ b/bin/solid.pill @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9701b98374a28ae99961871d4204856720e9ee6c3f769c389e6faf38392b95e7 -size 12715787 +oid sha256:8ebc16b420b2ce8e8bf7e6b0c611a102355f9ec013475da3cf66cc078f35e4b3 +size 12458781 diff --git a/pkg/arvo/app/chat-hook.hoon b/pkg/arvo/app/chat-hook.hoon index 47de70ffe..911d402d7 100644 --- a/pkg/arvo/app/chat-hook.hoon +++ b/pkg/arvo/app/chat-hook.hoon @@ -399,56 +399,31 @@ ^- (list card) ?> ?=(^ pax) =/ last (dec (lent pax)) - =/ backlog-start=(unit @ud) - %+ rush - (snag last `(list @ta)`pax) - dem:ag + =/ backlog-latest=(unit @ud) (rush (snag last `(list @ta)`pax) dem:ag) =/ pas `path`(oust [last 1] `(list @ta)`pax) ?> ?=([* ^] pas) ?> (~(has by synced) pas) - :: check if read is permitted ?> (is-permitted src.bol pas) + =/ envs envelopes:(need (chat-scry pas)) + =/ length (lent envs) + =/ latest + ?~ backlog-latest length + ?: (gth u.backlog-latest length) length + (sub length u.backlog-latest) + =. envs (scag latest envs) + =/ =vase !>([%messages pas 0 latest envs]) %- zing :~ [%give %fact ~ %chat-update !>([%create pas])]~ - ?. ?&(?=(^ backlog-start) (~(has by allow-history) pas)) ~ - (paginate-messages pas (need (chat-scry pas)) u.backlog-start) + ?. ?&(?=(^ backlog-latest) (~(has by allow-history) pas)) ~ + [%give %fact ~ %chat-update vase]~ [%give %kick [%backlog pax]~ `src.bol]~ == :: -++ paginate-messages - |= [=path =mailbox start=@ud] - ^- (list card) - =/ cards=(list card) ~ - =/ end (lent envelopes.mailbox) - ?: |((gte start end) =(end 0)) - cards - =. envelopes.mailbox (slag start `(list envelope)`envelopes.mailbox) - |- ^- (list card) - ?~ envelopes.mailbox - cards - ?: (lte end 5.000) - =. cards - %+ snoc cards - %- messages-fact - [path start (lent envelopes.mailbox) envelopes.mailbox] - $(envelopes.mailbox ~) - =. cards - %+ snoc cards - %- messages-fact - :^ path start - (add start 5.000) - (scag 5.000 `(list envelope)`envelopes.mailbox) - =: start (add start 5.000) - end (sub end 5.000) - == - $(envelopes.mailbox (slag 5.000 `(list envelope)`envelopes.mailbox)) -:: ++ fact-invite-update |= [wir=wire fact=invite-update] ^- (quip card _state) :_ state ?+ -.fact ~ - :: %accepted =/ ask-history ?~((chat-scry path.invite.fact) %.y %.n) =* shp ship.invite.fact @@ -644,11 +619,6 @@ ^- card [%pass / %agent [our.bol %invite-store] %poke %invite-action !>(act)] :: -++ messages-fact - |= [=path start=@ud end=@ud envelopes=(list envelope)] - ^- card - [%give %fact ~ %chat-update !>([%messages path start end envelopes])] -:: ++ sec-to-perm |= [pax=path =kind] ^- permission-action diff --git a/pkg/arvo/app/chat-store.hoon b/pkg/arvo/app/chat-store.hoon index b8629d169..16cb2990a 100644 --- a/pkg/arvo/app/chat-store.hoon +++ b/pkg/arvo/app/chat-store.hoon @@ -7,10 +7,12 @@ +$ versioned-state $% state-zero state-one + state-two == :: +$ state-zero [%0 =inbox] +$ state-one [%1 =inbox] ++$ state-two [%2 =inbox] :: +$ diff $% [%chat-initial inbox] @@ -19,7 +21,7 @@ == -- :: -=| state-one +=| state-two =* state - :: %- agent:dbug @@ -38,10 +40,14 @@ ++ on-load |= old-vase=vase =/ old !<(versioned-state old-vase) - ?: ?=(%1 -.old) + ?: ?=(%2 -.old) [~ this(state old)] - :_ this(state [%1 inbox.old]) - [%pass /lo-chst %agent [our.bowl %chat-hook] %poke %noun !>(%store-load)]~ + =/ reversed-inbox=^inbox + %- ~(run by inbox.old) + |= =mailbox + ^- ^mailbox + [config.mailbox (flop envelopes.mailbox)] + [~ this(state [%2 reversed-inbox])] :: ++ on-poke ~/ %chat-store-poke @@ -196,7 +202,7 @@ ?~ mailbox [~ state] =. letter.envelope.act (evaluate-letter [author letter]:envelope.act) - =^ envelope u.mailbox (append-envelope u.mailbox envelope.act) + =^ envelope u.mailbox (prepend-envelope u.mailbox envelope.act) :- (send-diff path.act act(envelope envelope)) state(inbox (~(put by inbox) path.act u.mailbox)) :: @@ -207,20 +213,16 @@ =/ mailbox=(unit mailbox) (~(get by inbox) path.act) ?~ mailbox [~ state] + =. envelopes.act (flop envelopes.act) =/ evaluated-envelopes=(list envelope) ~ |- ^- (quip card _state) ?~ envelopes.act :_ state(inbox (~(put by inbox) path.act u.mailbox)) %+ send-diff path.act - :* %messages - path.act - (sub length.config.u.mailbox (lent evaluated-envelopes)) - length.config.u.mailbox - evaluated-envelopes - == + [%messages path.act 0 (lent evaluated-envelopes) evaluated-envelopes] =. letter.i.envelopes.act (evaluate-letter [author letter]:i.envelopes.act) - =^ envelope u.mailbox (append-envelope u.mailbox i.envelopes.act) - =. evaluated-envelopes (snoc evaluated-envelopes envelope) + =^ envelope u.mailbox (prepend-envelope u.mailbox i.envelopes.act) + =. evaluated-envelopes [envelope evaluated-envelopes] $(envelopes.act t.envelopes.act) :: ++ handle-read @@ -246,12 +248,12 @@ letter(output (eval bol hoon)) letter :: -++ append-envelope +++ prepend-envelope |= [=mailbox =envelope] ^+ [envelope mailbox] =. number.envelope +(length.config.mailbox) =: length.config.mailbox +(length.config.mailbox) - envelopes.mailbox (snoc envelopes.mailbox envelope) + envelopes.mailbox [envelope envelopes.mailbox] == [envelope mailbox] :: diff --git a/pkg/arvo/app/chat-view.hoon b/pkg/arvo/app/chat-view.hoon index f9874ff5c..a967f791b 100644 --- a/pkg/arvo/app/chat-view.hoon +++ b/pkg/arvo/app/chat-view.hoon @@ -121,15 +121,7 @@ %- ~(run by inbox) |= =mailbox ^- ^mailbox - [config.mailbox (truncate-envelopes envelopes.mailbox)] - :: - ++ truncate-envelopes - |= envelopes=(list envelope) - ^- (list envelope) - =/ length (lent envelopes) - ?: (lth length message-limit) - envelopes - (slag (sub length message-limit) envelopes) + [config.mailbox (scag message-limit envelopes.mailbox)] -- :: ++ on-agent diff --git a/pkg/arvo/app/publish.hoon b/pkg/arvo/app/publish.hoon index 427da592e..857d578b3 100644 --- a/pkg/arvo/app/publish.hoon +++ b/pkg/arvo/app/publish.hoon @@ -52,14 +52,25 @@ :: +$ state-two $: our-paths=(list path) - books=(map @tas notebook) - subs=(map [@p @tas] notebook) + books=(map @tas notebook-2) + subs=(map [@p @tas] notebook-2) tile-num=@ud == :: ++$ state-three + $: our-paths=(list path) + books=(map [@p @tas] notebook) + tile-num=@ud + $= limbo + $: notes=(map [@p @tas @tas] note) + comments=(map [@p @tas @tas @da] comment) + == + == +:: +$ versioned-state $% [%1 state-two] [%2 state-two] + [%3 state-three] == :: +$ metadata-delta @@ -75,7 +86,7 @@ == -- :: -=| versioned-state +=| [%3 state-three] =* state - %- agent:dbug ^- agent:gall @@ -110,13 +121,51 @@ ^- (quip card _this) =/ old-state=(each versioned-state tang) (mule |.(!<(versioned-state old))) - ?: ?=(%& -.old-state) - ?- -.p.old-state - %1 - :_ this(state [%2 +.p.old-state]) + =| cards=(list card) + |^ + ?: ?=(%| -.old-state) + =/ zero !<(state-zero old) + =/ rav [%next %t [%da now.bol] /app/publish/notebooks] + =/ tile-json + (frond:enjs:format %notifications (numb:enjs:format 0)) + =/ init-cards=(list card) + :~ [%pass /read/paths %arvo %c %warp our.bol q.byk.bol `rav] + :* %pass /permissions %agent [our.bol %permission-store] %watch + /updates + == + (invite-poke:main [%create /publish]) + :* %pass /invites %agent [our.bol %invite-store] %watch + /invitatory/publish + == + [%give %fact [/publishtile]~ %json !>(tile-json)] + == + =+ ^- [kick-cards=(list card) old-subs=(jug @tas @p)] kick-subs + =/ inv-scry-pax + /(scot %p our.bol)/invite-store/(scot %da now.bol)/invitatory/publish/noun + =/ inv=(unit invitatory) .^((unit invitatory) %gx inv-scry-pax) + =| new-state=state-two + =? tile-num.new-state ?=(^ inv) + ~(wyt by u.inv) + %= $ + old-state [%& %2 new-state] + :: + cards + ;: weld + (kill-builds pubs.zero) + kick-cards + init-cards + (move-files old-subs) + == + == + ?- -.p.old-state + %1 + %= $ + -.p.old-state %2 + :: + cards %- zing %+ turn ~(tap by books.p.old-state) - |= [name=@tas book=notebook] + |= [name=@tas book=notebook-2] ^- (list card) =/ group-host=(unit @p) ?> ?=(^ writers.book) @@ -128,41 +177,56 @@ :: (perm-hook-poke:main [%add-owned writers.book writers.book]) == - :: - %2 - [~ this(state p.old-state)] == - =/ zero !<(state-zero old) - |^ - =/ rav [%next %t [%da now.bol] /app/publish/notebooks] - =/ tile-json - (frond:enjs:format %notifications (numb:enjs:format 0)) - =/ init-cards=(list card) - :~ [%pass /read/paths %arvo %c %warp our.bol q.byk.bol `rav] - :* %pass /permissions %agent [our.bol %permission-store] %watch - /updates - == - (invite-poke:main [%create /publish]) - :* %pass /invites %agent [our.bol %invite-store] %watch - /invitatory/publish - == - [%give %fact [/publishtile]~ %json !>(tile-json)] + :: + %2 + %= $ + p.old-state + =/ new-books=(map [@p @tas] notebook) + %- %~ uni by + %- ~(run by subs.p.old-state) + |= old-notebook=notebook-2 + ^- notebook-3 + (convert-notebook-2-3 old-notebook) + ^- (map [@p @tas] notebook) + %- ~(rep by books.p.old-state) + |= [[key=@tas val=notebook-2] out=(map [@p @tas] notebook)] + ^- (map [@p @tas] notebook) + %+ ~(put by out) + [our.bol key] + (convert-notebook-2-3 val) + [%3 our-paths.p.old-state new-books tile-num.p.old-state [~ ~]] == - =+ ^- [kick-cards=(list card) old-subs=(jug @tas @p)] kick-subs - =/ inv-scry-pax - /(scot %p our.bol)/invite-store/(scot %da now.bol)/invitatory/publish/noun - =/ inv=(unit invitatory) .^((unit invitatory) %gx inv-scry-pax) - =| new-state=state-two - =? tile-num.new-state ?=(^ inv) - ~(wyt by u.inv) - :_ this(state [%2 new-state]) - ;: weld - kill-builds - kick-cards - init-cards - (move-files old-subs) + :: + %3 + [cards this(state p.old-state)] == :: + ++ convert-comment-2-3 + |= prev=comment-2 + ^- comment-3 + %= prev + content [content.prev %.n] + == + :: + ++ convert-note-2-3 + |= prev=note-2 + ^- note-3 + %= prev + comments + [(~(run by comments.prev) convert-comment-2-3) %.n] + == + :: + ++ convert-notebook-2-3 + |= prev=notebook-2 + ^- notebook-3 + %= prev + notes + %- ~(run by notes.prev) + |= =note-2 + (convert-note-2-3 note-2) + == + :: ++ kick-subs ^- [(list card) (jug @tas @p)] =+ ^- [paths=(list path) subs=(jug @tas @p)] @@ -179,9 +243,10 @@ [[%give %kick paths ~]~ subs] :: ++ kill-builds + |= pubs=(map @tas collection-zero) ^- (list card) %- zing - %+ turn ~(tap by pubs.zero) + %+ turn ~(tap by pubs) |= [col-name=@tas col-data=collection-zero] ^- (list card) :- [%pass /collection/[col-name] %arvo %f %kill ~] @@ -247,8 +312,9 @@ =/ book i.t.t.pax =/ note i.t.t.t.pax =/ comm i.t.t.t.t.pax - =/ old=old-comment .^(old-comment %cx (welp our-beak:main pax)) - =/ new=comment [creator.old date-created.old content.old] + =/ old-com .^(old-comment %cx (welp our-beak:main pax)) + =/ new=comment-2 + [creator.old-com date-created.old-com content.old-com] :- car :+ [pax %del ~] @@ -263,13 +329,10 @@ |= [mar=mark vas=vase] ^- (quip card _this) ?+ mar (on-poke:def mar vas) + :: %noun - ?: =(%print-state q.vas) - ~& state - [~ this] - ?: =(%print-bowl q.vas) - ~& bol - [~ this] + ?: =(q.vas %flush-limbo) + [~ this(limbo [~ ~])] [~ this] :: %handle-http-request @@ -306,13 +369,56 @@ == :: ++ on-leave on-leave:def - ++ on-peek on-peek:def + ++ on-peek + |= pax=path + ^- (unit (unit cage)) + ?+ pax (on-peek:def pax) + :: + [%t %limbo ~] + :^ ~ ~ %noun + !> ^- (list path) + %+ weld + %+ turn ~(tap by notes.limbo) + |= [[who=@p book=@tas note=@tas] *] + ^- path + /(scot %p who)/[book]/[note] + %+ turn ~(tap by comments.limbo) + |= [[who=@p book=@tas note=@tas comment=@da] *] + ^- path + /(scot %p who)/[book]/[note]/(scot %ds comment) + :: + [%x %limbo @ @ @ ~] + =/ host=(unit @p) (slaw %p i.t.t.pax) + ?~ host [~ ~] + =/ book-name i.t.t.t.pax + =/ note-name i.t.t.t.t.pax + =/ note (~(get by notes.limbo) u.host book-name note-name) + ?~ note ~ + ``noun+!>(u.note) + :: + [%x %limbo @ @ @ @ ~] + =/ host=(unit @p) (slaw %p i.t.t.pax) + =/ comment-date=(unit @da) (slaw %da i.t.t.t.t.t.pax) + ?~ host [~ ~] + ?~ comment-date [~ ~] + =/ book-name i.t.t.t.pax + =/ note-name i.t.t.t.t.pax + =/ comment + (~(get by comments.limbo) u.host book-name note-name u.comment-date) + ?~ comment ~ + ``noun+!>(u.comment) + == :: ++ on-agent |= [wir=wire sin=sign:agent:gall] ^- (quip card _this) ?- -.sin - %poke-ack (on-agent:def wir sin) + %poke-ack + ?~ p.sin + [~ this] + =^ cards state + (handle-poke-fail:main wir) + [cards this] :: If our subscribe failed, delete notebook associated with subscription if :: it exists :: @@ -324,7 +430,7 @@ =/ who=@p (slav %p i.t.wir) =/ book=@tas i.t.t.wir =/ del [%del-book who book] - :_ this(subs (~(del by subs) who book)) + :_ this(books (~(del by books) who book)) [%give %fact [/primary]~ %publish-primary-delta !>(del)]~ :: Resubscribe to any subscription we get kicked from. The case of actually :: getting banned from a notebook is handled by %watch-ack @@ -470,7 +576,7 @@ ?> ?=([%app %publish %notebooks @ @ %udon ~] pax) =/ book-name i.t.t.t.pax =/ note-name i.t.t.t.t.pax - =/ book (~(get by books) book-name) + =/ book (~(get by books) our.bol book-name) ?~ book [~ state] =/ old-note (~(get by notes.u.book) note-name) @@ -548,7 +654,7 @@ [%app %publish %notebooks @ @ %udon ~] =/ book-name i.t.t.t.pax =/ note-name i.t.t.t.t.pax - =/ book (~(get by books.sty) book-name) + =/ book (~(get by books.sty) our.bol book-name) ?~ book [cad sty] =. notes.u.book (~(del by notes.u.book) note-name) @@ -695,14 +801,20 @@ =/ udon=@t .^(@t %cx (welp our-beak pax)) (form-note note-name udon) :: +++ form-snippet + |= file=@t + ^- @t + =/ front-idx (add 3 (need (find ";>" (trip file)))) + =/ front-matter (cat 3 (end 3 front-idx file) 'dummy text\0a') + =/ body (cut 3 [front-idx (met 3 file)] file) + (of-wain:format (scag 1 (to-wain:format body))) +:: ++ form-note - |= [note-name=@tas udon=@t] + |= [note-name=@tas file=@t] ^- note - =/ front-idx (add 3 (need (find ";>" (trip udon)))) - =/ front-matter - (cat 3 (end 3 front-idx udon) 'dummy text\0a') - =/ body (cut 3 [front-idx (met 3 udon)] udon) - =/ snippet=@t (of-wain:format (scag 1 (to-wain:format body))) + =/ snippet=@t (form-snippet file) + =/ front-idx (add 3 (need (find ";>" (trip file)))) + =/ front-matter (cat 3 (end 3 front-idx file) 'dummy text\0a') =/ meta=(each (map term knot) tang) %- mule |. %- ~(run by inf:(static:cram (ream front-matter))) @@ -739,9 +851,10 @@ date-created last-modified %.y - udon + file snippet ~ + %.n == :: ++ handle-permission-update @@ -751,10 +864,12 @@ [~ state] =/ book=(unit @tas) %+ roll ~(tap by books) - |= [[nom=@tas book=notebook] out=(unit @tas)] - ?: =(path.upd subscribers.book) - `nom - out + |= [[[who=@p nom=@tas] book=notebook] out=(unit @tas)] + ?. =(who our.bol) + out + ?. =(path.upd subscribers.book) + out + `nom ?~ book [~ state] :_ state @@ -822,7 +937,7 @@ =/ book-name i.t.pax ?. (allowed src.bol %read book-name) ~|("not permitted" !!) - =/ book (~(got by books) book-name) + =/ book (~(got by books) our.bol book-name) =/ delta=notebook-delta [%add-book our.bol book-name book] :_ state @@ -834,7 +949,7 @@ |= [who=@p mod=?(%read %write) book=@tas] ^- ? =/ scry-bek /(scot %p our.bol)/permission-store/(scot %da now.bol) - =/ book=notebook (~(got by books) book) + =/ book=notebook (~(got by books) our.bol book) =/ scry-pax ?: =(%read mod) subscribers.book @@ -893,6 +1008,11 @@ [' ==' ~] == :: +++ give-primary-delta + |= del=primary-delta + ^- card + [%give %fact [/primary]~ %publish-primary-delta !>(del)] +:: ++ group-poke |= act=group-action ^- card @@ -1006,14 +1126,161 @@ (generate-invites book (~(del in invitees.group) our.bol)) == :: +++ handle-poke-fail + |= wir=wire + ^- (quip card _state) + ?+ wir + [~ state] + :: new note failed, stash it in limbo + :: + [%forward %new-note @ @ @ ~] + =/ host=@p (slav %p i.t.t.wir) + =/ book-name i.t.t.t.wir + =/ note-name i.t.t.t.t.wir + =/ book (~(get by books) [host book-name]) + ?~ book + [~ state] + =/ note (~(get by notes.u.book) note-name) + ?~ note + [~ state] + =. notes.limbo (~(put by notes.limbo) [host book-name note-name] u.note) + =. notes.u.book (~(del by notes.u.book) note-name) + =/ del [%del-note host book-name note-name] + :- [(give-primary-delta del)]~ + state(books (~(put by books) [host book-name] u.book)) + :: new comment failed, stash it in limbo + :: + [%forward %new-comment @ @ @ @ ~] + =/ host=@p (slav %p i.t.t.wir) + =/ book-name i.t.t.t.wir + =/ note-name i.t.t.t.t.wir + =/ comment-date=@da (slav %da i.t.t.t.t.t.wir) + =/ book (~(get by books) [host book-name]) + ?~ book + [~ state] + =/ note (~(get by notes.u.book) note-name) + ?~ note + [~ state] + =/ comment (~(get by comments.u.note) comment-date) + ?~ comment + [~ state] + =. comments.limbo + %+ ~(put by comments.limbo) + [host book-name note-name comment-date] + u.comment + =. comments.u.note (~(del by comments.u.note) comment-date) + =. notes.u.book (~(put by notes.u.book) note-name u.note) + =/ del [%del-comment host book-name note-name comment-date] + :- [(give-primary-delta del)]~ + state(books (~(put by books) [host book-name] u.book)) + :: edit note failed, restore old version + :: + [%forward %edit-note @ @ @ ~] + =/ host=@p (slav %p i.t.t.wir) + =/ book-name i.t.t.t.wir + =/ note-name i.t.t.t.t.wir + =/ book (~(get by books) [host book-name]) + ?~ book + [~ state] + =/ note (~(get by notes.limbo) host book-name note-name) + ?~ note + [~ state] + =. notes.u.book (~(put by notes.u.book) note-name u.note) + =/ del [%edit-note host book-name note-name u.note] + :- [(give-primary-delta del)]~ + %= state + books (~(put by books) [host book-name] u.book) + notes.limbo (~(del by notes.limbo) host book-name note-name) + == + :: edit comment failed, restore old version + :: + [%forward %new-comment @ @ @ @ ~] + =/ host=@p (slav %p i.t.t.wir) + =/ book-name i.t.t.t.wir + =/ note-name i.t.t.t.t.wir + =/ comment-date=@da (slav %da i.t.t.t.t.t.wir) + =/ book (~(get by books) [host book-name]) + ?~ book + [~ state] + =/ note (~(get by notes.u.book) note-name) + ?~ note + [~ state] + =/ comment + (~(get by comments.limbo) host book-name note-name comment-date) + ?~ comment + [~ state] + =. comments.u.note (~(put by comments.u.note) comment-date u.comment) + =. notes.u.book (~(put by notes.u.book) note-name u.note) + =/ del [%edit-comment host book-name note-name comment-date u.comment] + :- [(give-primary-delta del)]~ + %= state + books (~(put by books) [host book-name] u.book) + :: + comments.limbo + %+ ~(del by comments.limbo) + [host book-name note-name comment-date] + u.comment + == + :: delete note failed, restore old version + :: + [%forward %del-note @ @ @ ~] + =/ host=@p (slav %p i.t.t.wir) + =/ book-name i.t.t.t.wir + =/ note-name i.t.t.t.t.wir + =/ book (~(get by books) [host book-name]) + ?~ book + [~ state] + =/ note (~(get by notes.limbo) host book-name note-name) + ?~ note + [~ state] + =. notes.u.book (~(put by notes.u.book) note-name u.note) + =/ del [%add-note host book-name note-name u.note] + :- [(give-primary-delta del)]~ + %= state + books (~(put by books) [host book-name] u.book) + notes.limbo (~(del by notes.limbo) host book-name note-name) + == + :: delete comment failed, restore old version + :: + [%forward %del-comment @ @ @ @ ~] + =/ host=@p (slav %p i.t.t.wir) + =/ book-name i.t.t.t.wir + =/ note-name i.t.t.t.t.wir + =/ comment-date=@da (slav %da i.t.t.t.t.t.wir) + =/ book (~(get by books) [host book-name]) + ?~ book + [~ state] + =/ note (~(get by notes.u.book) note-name) + ?~ note + [~ state] + =/ comment + (~(get by comments.limbo) host book-name note-name comment-date) + ?~ comment + [~ state] + =. comments.u.note (~(put by comments.u.note) comment-date u.comment) + =. notes.u.book (~(put by notes.u.book) note-name u.note) + =/ del [%add-comment host book-name note-name comment-date u.comment] + :- [(give-primary-delta del)]~ + %= state + books (~(put by books) [host book-name] u.book) + :: + comments.limbo + %+ ~(del by comments.limbo) + [host book-name note-name comment-date] + u.comment + == + == +:: ++ poke-publish-action |= act=action ^- (quip card _state) ?- -.act + :: %new-book: Make groups and save publish info file. + :: %new-book ?. (team:title our.bol src.bol) ~|("action not permitted" !!) - ?: (~(has by books) book.act) + ?: (~(has by books) our.bol book.act) ~|("notebook already exists: {}" !!) =+ ^- [cards=(list card) write-pax=path read-pax=path] (make-groups book.act group.act title.act about.act) @@ -1027,21 +1294,17 @@ =/ pax=path /app/publish/notebooks/[book.act]/publish-info :_ state [(write-file pax %publish-info !>(new-book)) cards] + :: %new-note: + :: If poke is from us, eagerly store new note in books. If poke is to us, + :: save file, otherwise forward the poke. If forwarded poke fails, note is + :: removed from books and stored in limbo. :: %new-note - ?: &(=(src.bol our.bol) !=(our.bol who.act)) - :_ state - [%pass /forward %agent [who.act %publish] %poke %publish-action !>(act)]~ - =/ book=(unit notebook) (~(get by books) book.act) + =/ book=(unit notebook) (~(get by books) who.act book.act) ?~ book ~|("nonexistent notebook {}" !!) ?: (~(has by notes.u.book) note.act) ~|("note already exists: {}" !!) - ?. ?| (team:title our.bol src.bol) - (allowed src.bol %write book.act) - == - ~|("action not permitted" !!) - =/ pax=path /app/publish/notebooks/[book.act]/[note.act]/udon =/ front=(map knot cord) %- my :~ title+title.act @@ -1049,19 +1312,86 @@ date-created+(scot %da now.bol) last-modified+(scot %da now.bol) == - =/ file=@t (add-front-matter front body.act) + =/ file=@t (add-front-matter front body.act) + :: + =^ cards books + ?. =(src.bol our.bol) + [~ books] + =/ new-note=note + :* src.bol + title.act + note.act + now.bol + now.bol + %.y + file + (form-snippet file) + ~ + %.y + == + =/ del=primary-delta [%add-note who.act book.act note.act new-note] + :- [(give-primary-delta del)]~ + %+ ~(put by books) + [who.act book.act] + u.book(notes (~(put by notes.u.book) note.act new-note)) + :: :_ state - [(write-file pax %udon !>(file))]~ + ?. =(who.act our.bol) + =/ poke-wir=wire + /forward/new-note/(scot %p who.act)/[book.act]/[note.act] + :_ cards + [%pass poke-wir %agent [who.act %publish] %poke %publish-action !>(act)] + ?. ?| (team:title our.bol src.bol) + (allowed src.bol %write book.act) + == + ~|("action not permitted" !!) + =/ pax=path /app/publish/notebooks/[book.act]/[note.act]/udon + :_ cards + [(write-file pax %udon !>(file))] + :: %new-comment + :: If poke is from us, eagerly store new comment in books. If poke is to + :: us, save file, otherwise forward the poke. If forwarded poke fails, + :: comment is removed from books and stored in limbo. :: %new-comment - ?: &(=(src.bol our.bol) !=(our.bol who.act)) - :_ state - [%pass /forward %agent [who.act %publish] %poke %publish-action !>(act)]~ - =/ book=(unit notebook) (~(get by books) book.act) + =/ book=(unit notebook) (~(get by books) who.act book.act) ?~ book ~|("nonexistent notebook {}" !!) - ?. (~(has by notes.u.book) note.act) + =/ note=(unit note) (~(get by notes.u.book) note.act) + ?~ note ~|("nonexistent note {}" !!) + =/ new-comment=comment + :* author=src.bol + date-created=now.bol + content=body.act + %.y + == + :: + =^ cards books + ?. =(src.bol our.bol) + [~ books] + =/ new-note + %= u.note + comments (~(put by comments.u.note) now.bol new-comment) + == + =/ del=primary-delta + [%add-comment who.act book.act note.act now.bol new-comment] + :- [(give-primary-delta del)]~ + %+ ~(put by books) + [who.act book.act] + u.book(notes (~(put by notes.u.book) note.act new-note)) + :_ state + ?. =(who.act our.bol) + =/ poke-wir=wire + :~ %forward + %new-comment + (scot %p who.act) + book.act + note.act + (scot %da now.bol) + == + :_ cards + [%pass poke-wir %agent [who.act %publish] %poke %publish-action !>(act)] ?. ?& ?| (team:title our.bol src.bol) (allowed src.bol %read book.act) == @@ -1071,18 +1401,13 @@ =/ pax=path %+ weld /app/publish/notebooks /[book.act]/[note.act]/(scot %da now.bol)/publish-comment - =/ new-comment=comment - :* author=src.bol - date-created=now.bol - content=body.act - == - :_ state - [(write-file pax %publish-comment !>(new-comment))]~ + [(write-file pax %publish-comment !>(new-comment(pending %.n)))]~ + :: %edit-book: Make groups and save publish-info file :: %edit-book ?. (team:title our.bol src.bol) ~|("action not permitted" !!) - =/ book (~(get by books) book.act) + =/ book (~(get by books) our.bol book.act) ?~ book ~|("nonexistent notebook" !!) =+ ^- [cards=(list card) write-pax=path read-pax=path] @@ -1099,24 +1424,18 @@ =/ pax=path /app/publish/notebooks/[book.act]/publish-info :_ state [(write-file pax %publish-info !>(new-info)) cards] + :: %edit-note: + :: If poke is from us, eagerly store new note in books, and place the old + :: note in limbo. If poke is to us, save file, otherwise forward the poke. + :: If forwarded poke fails, old note is restored from limbo. :: %edit-note - ?: &(=(src.bol our.bol) !=(our.bol who.act)) - :_ state - [%pass /forward %agent [who.act %publish] %poke %publish-action !>(act)]~ - =/ book=(unit notebook) (~(get by books) book.act) + =/ book=(unit notebook) (~(get by books) who.act book.act) ?~ book ~|("nonexistent notebook {}" !!) =/ note=(unit note) (~(get by notes.u.book) note.act) ?~ note ~|("nonexistent note: {}" !!) - ?. ?| (team:title our.bol src.bol) - ?& =(author.u.note src.bol) - (allowed src.bol %write book.act) - == - == - ~|("action not permitted" !!) - =/ pax=path /app/publish/notebooks/[book.act]/[note.act]/udon =/ front=(map knot cord) %- my :~ title+title.act @@ -1125,25 +1444,101 @@ last-modified+(scot %da now.bol) == =/ file=@t (add-front-matter front body.act) + :: + =^ cards state + ?. =(src.bol our.bol) + [~ state] + =/ new-note + %= u.note + author src.bol + title title.act + last-edit now.bol + file file + snippet (form-snippet file) + pending %.y + == + =/ del=primary-delta [%edit-note who.act book.act note.act new-note] + :- [(give-primary-delta del)]~ + %= state + notes.limbo + (~(put by notes.limbo) [who.act book.act note.act] u.note) + :: + books + %+ ~(put by books) + [who.act book.act] + u.book(notes (~(put by notes.u.book) note.act new-note)) + == + :: :_ state + ?. =(who.act our.bol) + =/ poke-wir=wire + /forward/edit-note/(scot %p who.act)/[book.act]/[note.act] + :_ cards + [%pass poke-wir %agent [who.act %publish] %poke %publish-action !>(act)] + ?. ?| (team:title our.bol src.bol) + ?& =(author.u.note src.bol) + (allowed src.bol %write book.act) + == + == + ~|("action not permitted" !!) + =/ pax=path /app/publish/notebooks/[book.act]/[note.act]/udon [(write-file pax %udon !>(file))]~ + :: %edit-comment: + :: If poke is from us, eagerly store new comment in books, and place the + :: old note in limbo. If poke is to us, save file, otherwise forward the + :: poke. If forwarded poke fails, old comment is restored from limbo. :: %edit-comment - ?: &(=(src.bol our.bol) !=(our.bol who.act)) - :_ state - [%pass /forward %agent [who.act %publish] %poke %publish-action !>(act)]~ - =/ book=(unit notebook) (~(get by books) book.act) + =/ book=(unit notebook) (~(get by books) who.act book.act) ?~ book ~|("nonexistent notebook {}" !!) - =/ not=(unit note) (~(get by notes.u.book) note.act) - ?~ not + =/ note=(unit note) (~(get by notes.u.book) note.act) + ?~ note ~|("nonexistent note {}" !!) - =/ com=(unit comment) - (~(get by comments.u.not) (slav %da comment.act)) - ?~ com + =/ comment-date (slav %da comment.act) + =/ comment=(unit comment) (~(get by comments.u.note) comment-date) + ?~ comment ~|("nonexistent comment {}" !!) + =/ new-comment + u.comment(content body.act, pending %.y) + :: + =^ cards state + ?. =(src.bol our.bol) + [~ state] + =/ new-note + %= u.note + comments + (~(put by comments.u.note) comment-date new-comment) + == + =/ del=primary-delta + [%edit-comment who.act book.act note.act comment-date new-comment] + :- [(give-primary-delta del)]~ + %= state + books + %+ ~(put by books) + [who.act book.act] + u.book(notes (~(put by notes.u.book) note.act new-note)) + :: + comments.limbo + %+ ~(put by comments.limbo) + [who.act book.act note.act comment-date] + u.comment + == + :: + :_ state + ?. =(who.act our.bol) + =/ poke-wir + :~ %forward + %edit-comment + (scot %p who.act) + book.act + note.act + comment.act + == + :_ cards + [%pass poke-wir %agent [who.act %publish] %poke %publish-action !>(act)] ?. ?| (team:title our.bol src.bol) - ?& =(author.u.com src.bol) + ?& =(author.u.comment src.bol) (allowed src.bol %read book.act) == == @@ -1151,15 +1546,13 @@ =/ pax=path %+ weld /app/publish/notebooks /[book.act]/[note.act]/[comment.act]/publish-comment - =/ new-comment .^(comment %cx (weld our-beak pax)) - =. content.new-comment body.act - :_ state - [(write-file pax %publish-comment !>(new-comment))]~ + [(write-file pax %publish-comment !>(new-comment(pending %.n)))]~ + :: %del-book: Delete whole notebook directory, delete groups and permissions :: %del-book ?. (team:title our.bol src.bol) ~|("action not permitted" !!) - =/ book=(unit notebook) (~(get by books) book.act) + =/ book=(unit notebook) (~(get by books) our.bol book.act) ?~ book ~|("nonexistent notebook {}" !!) =/ pax=path /app/publish/notebooks/[book.act] @@ -1175,17 +1568,36 @@ =? cards =('~' i.subscribers.u.book) [(group-poke [%unbundle subscribers.u.book]) cards] [cards state] + :: %del-note: + :: If poke is from us, eagerly remove note from books, and place the + :: old note in limbo. If poke is to us, save file, otherwise forward the + :: poke. If forwarded poke fails, old note is restored from limbo. :: %del-note - ?: &(=(src.bol our.bol) !=(our.bol who.act)) - :_ state - [%pass /forward %agent [who.act %publish] %poke %publish-action !>(act)]~ - =/ book=(unit notebook) (~(get by books) book.act) + =/ book=(unit notebook) (~(get by books) who.act book.act) ?~ book ~|("nonexistent notebook {}" !!) =/ note=(unit note) (~(get by notes.u.book) note.act) ?~ note ~|("nonexistent note: {}" !!) + :: + =^ cards state + ?. =(src.bol our.bol) + [~ state] + =/ del=primary-delta [%del-note who.act book.act note.act] + =. notes.u.book (~(del by notes.u.book) note.act) + :- [(give-primary-delta del)]~ + %= state + books (~(put by books) [who.act book.act] u.book) + notes.limbo (~(put by notes.limbo) [who.act book.act note.act] u.note) + == + :: + :_ state + ?. =(who.act our.bol) + =/ poke-wir=wire + /forward/del-note/(scot %p who.act)/[book.act]/[note.act] + :_ cards + [%pass poke-wir %agent [who.act %publish] %poke %publish-action !>(act)] ?. ?| (team:title our.bol src.bol) ?& =(author.u.note src.bol) (allowed src.bol %write book.act) @@ -1193,23 +1605,54 @@ == ~|("action not permitted" !!) =/ pax=path /app/publish/notebooks/[book.act]/[note.act]/udon - :_ state [(delete-file pax)]~ + :: %del-comment: + :: If poke is from us, eagerly remove comment from books, and place the + :: old note in limbo. If poke is to us, save file, otherwise forward the + :: poke. If forwarded poke fails, old comment is restored from limbo. :: %del-comment - ?: &(=(src.bol our.bol) !=(our.bol who.act)) - :_ state - [%pass /forward %agent [who.act %publish] %poke %publish-action !>(act)]~ - =/ book=(unit notebook) (~(get by books) book.act) + =/ book=(unit notebook) (~(get by books) who.act book.act) ?~ book ~|("nonexistent notebook {}" !!) =/ note=(unit note) (~(get by notes.u.book) note.act) ?~ note ~|("nonexistent note {}" !!) - =/ comment=(unit comment) - (~(get by comments.u.note) (slav %da comment.act)) + =/ comment-date (slav %da comment.act) + =/ comment=(unit comment) (~(get by comments.u.note) comment-date) ?~ comment ~|("nonexistent comment {}" !!) + :: + =^ cards state + ?. =(src.bol our.bol) + [~ state] + =/ del=primary-delta + [%del-comment who.act book.act note.act comment-date] + =. comments.u.note (~(del by comments.u.note) comment-date) + =. notes.u.book (~(put by notes.u.book) note.act u.note) + :- [(give-primary-delta del)]~ + %= state + books + (~(put by books) [who.act book.act] u.book) + :: + comments.limbo + %+ ~(put by comments.limbo) + [who.act book.act note.act comment-date] + u.comment + == + :: + :_ state + ?. =(who.act our.bol) + =/ poke-wir=wire + :~ %forward + %del-comment + (scot %p who.act) + book.act + note.act + comment.act + == + :_ cards + [%pass poke-wir %agent [who.act %publish] %poke %publish-action !>(act)] ?. ?| (team:title our.bol src.bol) ?& =(author.u.comment src.bol) (allowed src.bol %read book.act) @@ -1219,30 +1662,30 @@ =/ pax=path %+ weld /app/publish/notebooks /[book.act]/[note.act]/[comment.act]/publish-comment - :_ state [(delete-file pax)]~ + :: %subscribe :: %subscribe ?> (team:title our.bol src.bol) =/ wir=wire /subscribe/(scot %p who.act)/[book.act] :_ state [%pass wir %agent [who.act %publish] %watch /notebook/[book.act]]~ + :: %unsubscribe :: %unsubscribe ?> (team:title our.bol src.bol) =/ wir=wire /subscribe/(scot %p who.act)/[book.act] =/ del=primary-delta [%del-book who.act book.act] - :_ state(subs (~(del by subs) who.act book.act)) + :_ state(books (~(del by books) who.act book.act)) :~ `card`[%pass wir %agent [who.act %publish] %leave ~] `card`[%give %fact [/primary]~ %publish-primary-delta !>(del)] == + :: %read :: %read ?> (team:title our.bol src.bol) =/ book=(unit notebook) - ?: =(our.bol who.act) - (~(get by books) book.act) - (~(get by subs) who.act book.act) + (~(get by books) who.act book.act) ?~ book ~|("nonexistent notebook: {}" !!) =/ not=(unit note) (~(get by notes.u.book) note.act) @@ -1252,10 +1695,7 @@ (dec tile-num) =. read.u.not %.y =. notes.u.book (~(put by notes.u.book) note.act u.not) - =? books =(our.bol who.act) - (~(put by books) book.act u.book) - =? subs !=(our.bol who.act) - (~(put by subs) [who.act book.act] u.book) + =. books (~(put by books) [who.act book.act] u.book) =/ jon=json (frond:enjs:format %notifications (numb:enjs:format tile-num)) :_ state @@ -1267,9 +1707,7 @@ ++ get-notebook |= [host=@p book-name=@tas sty=_state] ^- (unit notebook) - ?: =(our.bol host) - (~(get by books.sty) book-name) - (~(get by subs.sty) host book-name) + (~(get by books.sty) host book-name) :: ++ get-unread |= book=notebook @@ -1283,14 +1721,13 @@ ++ emit-updates-and-state |= [host=@p book-name=@tas book=notebook del=notebook-delta sty=_state] ^- (quip card _state) + :_ sty(books (~(put by books.sty) [host book-name] book)) ?: =(our.bol host) - :_ sty(books (~(put by books.sty) book-name book)) :~ [%give %fact [/notebook/[book-name]]~ %publish-notebook-delta !>(del)] [%give %fact [/primary]~ %publish-primary-delta !>(del)] == =/ jon=json (frond:enjs:format %notifications (numb:enjs:format tile-num)) - :_ sty(subs (~(put by subs.sty) [host book-name] book)) :~ [%give %fact [/primary]~ %publish-primary-delta !>(del)] [%give %fact [/publishtile]~ %json !>(jon)] == @@ -1427,6 +1864,17 @@ =/ note (~(get by notes.u.book) note.del) ?~ note [~ sty] + =/ limbo-comment=(unit @da) + %- ~(rep by comments.u.note) + |= [[date=@da com=comment] out=(unit @da)] + ?: ?& =(author.com author.data.del) + =(content.com content.data.del) + =(%.y pending.com) + == + `date + out + =? comments.u.note ?=(^ limbo-comment) + (~(del by comments.u.note) u.limbo-comment) =. comments.u.note (~(put by comments.u.note) comment-date.del data.del) =. notes.u.book (~(put by notes.u.book) note.del u.note) (emit-updates-and-state host.del book.del u.book del sty) @@ -1457,6 +1905,7 @@ == :: %edit-note + =. notes.limbo.sty (~(del by notes.limbo.sty) host.del book.del note.del) =/ book=(unit notebook) (get-notebook host.del book.del sty) ?~ book @@ -1464,6 +1913,8 @@ =/ old-note (~(get by notes.u.book) note.del) ?~ old-note [~ sty] + ?: =(our.bol author.u.old-note) + [~ sty] =/ new-note=note %= data.del date-created date-created.u.old-note @@ -1474,6 +1925,9 @@ (emit-updates-and-state host.del book.del u.book del sty) :: %edit-comment + =. comments.limbo.sty + %- ~(del by comments.limbo.sty) + [host.del book.del note.del comment-date.del] =/ book=(unit notebook) (get-notebook host.del book.del sty) ?~ book @@ -1481,6 +1935,11 @@ =/ note (~(get by notes.u.book) note.del) ?~ note [~ sty] + =/ old-comment (~(get by comments.u.note) comment-date.del) + ?~ old-comment + [~ sty] + ?: =(our.bol author.u.old-comment) + [~ sty] =. comments.u.note (~(put by comments.u.note) comment-date.del data.del) =. notes.u.book (~(put by notes.u.book) note.del u.note) (emit-updates-and-state host.del book.del u.book del sty) @@ -1489,20 +1948,19 @@ =/ book=(unit notebook) (get-notebook host.del book.del sty) ?~ book [~ sty] + :_ sty(books (~(del by books.sty) host.del book.del)) ?. =(our.bol host.del) =. tile-num %+ sub tile-num - (get-unread (~(got by subs) host.del book.del)) + (get-unread (~(got by books) host.del book.del)) =/ jon=json (frond:enjs:format %notifications (numb:enjs:format tile-num.sty)) - :_ sty(subs (~(del by subs.sty) host.del book.del)) %+ welp :~ [%give %fact [/primary]~ %publish-primary-delta !>(del)] [%give %fact [/publishtile]~ %json !>(jon)] == ?: (is-managed writers.u.book) ~ [(metadata-hook-poke [%remove writers.u.book])]~ - :_ sty(books (~(del by books.sty) book.del)) %- zing :~ [%give %fact [/notebook/[book.del]]~ %publish-notebook-delta !>(del)]~ [%give %fact [/primary]~ %publish-primary-delta !>(del)]~ @@ -1513,17 +1971,23 @@ == :: %del-note + =. notes.limbo.sty (~(del by notes.limbo.sty) host.del book.del note.del) =/ book=(unit notebook) (get-notebook host.del book.del sty) ?~ book [~ sty] - =/ not=note (~(got by notes.u.book) note.del) - =? tile-num &(!read.not (gth tile-num 0)) + =/ not=(unit note) (~(get by notes.u.book) note.del) + ?~ not + [~ sty] + =? tile-num &(!read.u.not (gth tile-num 0)) (dec tile-num) =. notes.u.book (~(del by notes.u.book) note.del) (emit-updates-and-state host.del book.del u.book del sty) :: %del-comment + =. comments.limbo.sty + %- ~(del by comments.limbo.sty) + [host.del book.del note.del comment.del] =/ book=(unit notebook) (get-notebook host.del book.del sty) ?~ book @@ -1551,10 +2015,7 @@ |= [host=@p book-name=@tas] ^- (unit json) =, enjs:format - =/ book=(unit notebook) - ?: =(our.bol host) - (~(get by books) book-name) - (~(get by subs) host book-name) + =/ book=(unit notebook) (~(get by books) host book-name) ?~ book ~ =/ notebook-json (notebook-full-json host book-name u.book) @@ -1563,7 +2024,7 @@ (~(uni by p.notebook-json) (notes-page notes.u.book 0 50)) =. p.notebook-json (~(put by p.notebook-json) %subscribers (get-subscribers-json book-name)) - =/ notebooks-json (notebooks-map-json our.bol books subs) + =/ notebooks-json (notebooks-map-json our.bol books) ?> ?=(%o -.notebooks-json) =/ host-books-json (~(got by p.notebooks-json) (scot %p host)) ?> ?=(%o -.host-books-json) @@ -1576,10 +2037,7 @@ |= [host=@p book-name=@tas note-name=@tas] ^- (unit json) =, enjs:format - =/ book=(unit notebook) - ?: =(our.bol host) - (~(get by books) book-name) - (~(get by subs) host book-name) + =/ book=(unit notebook) (~(get by books) host book-name) ?~ book ~ =/ note=(unit note) (~(get by notes.u.book) note-name) @@ -1589,7 +2047,7 @@ ?> ?=(%o -.notebook-json) =/ note-json (note-presentation-json u.book note-name u.note) =. p.notebook-json (~(uni by p.notebook-json) note-json) - =/ notebooks-json (notebooks-map-json our.bol books subs) + =/ notebooks-json (notebooks-map-json our.bol books) ?> ?=(%o -.notebooks-json) =/ host-books-json (~(got by p.notebooks-json) (scot %p host)) ?> ?=(%o -.host-books-json) @@ -1633,7 +2091,7 @@ [[[~ %json] [%'~publish' %notebooks ~]] ~] %- json-response:gen %- json-to-octs - (notebooks-map-json our.bol books subs) + (notebooks-map-json our.bol books) :: :: notes pagination [[[~ %json] [%'~publish' %notes @ @ @ @ ~]] ~] @@ -1641,10 +2099,7 @@ ?~ host not-found:gen =/ book-name i.t.t.t.site.url - =/ book=(unit notebook) - ?: =(our.bol u.host) - (~(get by books) book-name) - (~(get by subs) u.host book-name) + =/ book=(unit notebook) (~(get by books) u.host book-name) ?~ book not-found:gen =/ start (rush i.t.t.t.t.site.url dem) @@ -1664,10 +2119,7 @@ ?~ host not-found:gen =/ book-name i.t.t.t.site.url - =/ book=(unit notebook) - ?: =(our.bol u.host) - (~(get by books) book-name) - (~(get by subs) u.host book-name) + =/ book=(unit notebook) (~(get by books) u.host book-name) ?~ book not-found:gen =/ note-name i.t.t.t.t.site.url @@ -1691,10 +2143,7 @@ ?~ host not-found:gen =/ book-name i.t.t.site.url - =/ book=(unit notebook) - ?: =(our.bol u.host) - (~(get by books) book-name) - (~(get by subs) u.host book-name) + =/ book=(unit notebook) (~(get by books) u.host book-name) ?~ book not-found:gen =/ notebook-json (notebook-full-json u.host book-name u.book) @@ -1713,10 +2162,7 @@ ?~ host not-found:gen =/ book-name i.t.t.site.url - =/ book=(unit notebook) - ?: =(our.bol u.host) - (~(get by books) book-name) - (~(get by subs) u.host book-name) + =/ book=(unit notebook) (~(get by books) u.host book-name) ?~ book not-found:gen =/ note-name i.t.t.t.site.url @@ -1731,7 +2177,7 @@ :: all notebooks, short form, wrapped in html [[~ [%'~publish' ?(~ [%join *] [%new ~])]] ~] =, enjs:format - =/ jon=json (pairs notebooks+(notebooks-map-json our.bol books subs) ~) + =/ jon=json (pairs notebooks+(notebooks-map-json our.bol books) ~) (manx-response:gen (index jon)) :: :: single notebook, with initial 50 notes in short form, wrapped in html diff --git a/pkg/arvo/lib/publish.hoon b/pkg/arvo/lib/publish.hoon index 0bb72ef46..906560825 100644 --- a/pkg/arvo/lib/publish.hoon +++ b/pkg/arvo/lib/publish.hoon @@ -60,11 +60,11 @@ (notebook-short-json book) :: ++ notebooks-map-json - |= [our=@p books=(map @tas notebook) subs=(map [@p @tas] notebook)] + |= [our=@p books=(map [@p @tas] notebook)] ^- json =, enjs:format - =/ subs-notebooks-map=json - %- ~(rep by subs) + =/ notebooks-map=json + %- ~(rep by books) |= [[[host=@p book-name=@tas] book=notebook] out=json] ^- json =/ host-ta (scot %p host) @@ -79,22 +79,9 @@ =. p.u.books (~(put by p.u.books) book-name (notebook-short-json book)) :- %o (~(put by p.out) host-ta u.books) - =? subs-notebooks-map ?=(~ subs-notebooks-map) + =? notebooks-map ?=(~ notebooks-map) [%o ~] - =/ our-notebooks-map=json - %- ~(rep by books) - |= [[book-name=@tas book=notebook] out=json] - ^- json - ?~ out - (frond book-name (notebook-short-json book)) - ?> ?=(%o -.out) - :- %o - (~(put by p.out) book-name (notebook-short-json book)) - ?~ our-notebooks-map - subs-notebooks-map - ?> ?=(%o -.subs-notebooks-map) - :- %o - (~(put by p.subs-notebooks-map) (scot %p our) our-notebooks-map) + notebooks-map :: ++ notebook-short-json |= book=notebook @@ -170,6 +157,7 @@ num-comments+(numb ~(wyt by comments.note)) comments+(comments-page comments.note 0 50) read+b+read.note + pending+b+pending.note == :: ++ notes-by-date @@ -197,6 +185,7 @@ num-comments+(numb ~(wyt by comments.note)) read+b+read.note snippet+s+snippet.note + pending+b+pending.note == :: ++ notes-page @@ -246,5 +235,6 @@ :~ author+s+(scot %p author.com) date-created+(time date-created.com) content+s+content.com + pending+b+pending.com == -- diff --git a/pkg/arvo/mar/publish/comment.hoon b/pkg/arvo/mar/publish/comment.hoon index c2a40cae5..9aabaf7d4 100644 --- a/pkg/arvo/mar/publish/comment.hoon +++ b/pkg/arvo/mar/publish/comment.hoon @@ -44,7 +44,7 @@ %+ cook |= [author=@ @ @ date-created=@da @ content=@t] ^- comment - [author date-created content] + [author date-created content %.n] old-parser == -- diff --git a/pkg/arvo/sur/publish.hoon b/pkg/arvo/sur/publish.hoon index 92baad254..24bc59d99 100644 --- a/pkg/arvo/sur/publish.hoon +++ b/pkg/arvo/sur/publish.hoon @@ -27,13 +27,24 @@ [%read who=@p book=@tas note=@tas] == :: -+$ comment ++$ comment comment-3 +:: ++$ comment-2 $: author=@p date-created=@da content=@t == :: -+$ note ++$ comment-3 + $: author=@p + date-created=@da + content=@t + pending=? + == +:: ++$ note note-3 +:: ++$ note-2 $: author=@p title=@t filename=@tas @@ -42,11 +53,37 @@ read=? file=@t snippet=@t -:: build=(each manx tang) - comments=(map @da comment) + comments=(map @da comment-2) == :: -+$ notebook ++$ note-3 + $: author=@p + title=@t + filename=@tas + date-created=@da + last-edit=@da + read=? + file=@t + snippet=@t + comments=(map @da comment) + pending=? + == +:: ++$ notebook notebook-3 +:: ++$ notebook-2 + $: title=@t + description=@t + comments=? + writers=path + subscribers=path + date-created=@da + notes=(map @tas note-2) + order=(list @tas) + unread=(set @tas) + == +:: ++$ notebook-3 $: title=@t description=@t comments=? diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index 70c2ab4a4..9b809933b 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -1493,10 +1493,12 @@ =| {l/(unit) r/(unit)} |- ^- ? ?~ a & - ?& ?~(l & (gor p.n.a u.l)) - ?~(r & (gor u.r p.n.a)) - ?~(l.a & ?&((mor p.n.a p.n.l.a) $(a l.a, l `p.n.a))) - ?~(r.a & ?&((mor p.n.a p.n.r.a) $(a r.a, r `p.n.a))) + ?& ?~(l & &((gor p.n.a u.l) !=(p.n.a u.l))) + ?~(r & &((gor u.r p.n.a) !=(u.r p.n.a))) + ?~ l.a & + &((mor p.n.a p.n.l.a) !=(p.n.a p.n.l.a) $(a l.a, l `p.n.a)) + ?~ r.a & + &((mor p.n.a p.n.r.a) !=(p.n.a p.n.r.a) $(a r.a, r `p.n.a)) == :: ++ gas :: concatenate diff --git a/pkg/arvo/sys/zuse.hoon b/pkg/arvo/sys/zuse.hoon index 29ed011ca..49aafbbb6 100644 --- a/pkg/arvo/sys/zuse.hoon +++ b/pkg/arvo/sys/zuse.hoon @@ -5836,6 +5836,7 @@ |* wil/(pole fist) |= jon/json ?. ?=({$a *} jon) ~ + ?. =((lent wil) (lent p.jon)) ~ =+ raw=((at-raw wil) p.jon) ?.((za raw) ~ (some (zp raw))) :: diff --git a/pkg/arvo/tests/sys/hoon/map.hoon b/pkg/arvo/tests/sys/hoon/map.hoon index 383291e4a..9f9e15c3d 100644 --- a/pkg/arvo/tests/sys/hoon/map.hoon +++ b/pkg/arvo/tests/sys/hoon/map.hoon @@ -137,6 +137,9 @@ :: doesn't follow horizontal & vertical ordering :: =/ unbalanced-e=(map @ @) [[1 1] [[3 3] ~ ~] [[2 2] ~ ~]] + :: has duplicate keys + :: + =/ duplicates=(map @ @) [[1 1] [[1 2] ~ ~] ~] ;: weld %+ expect-eq !> [%b-a %.y] @@ -156,6 +159,9 @@ %+ expect-eq !> [%u-e %.n] !> [%u-e ~(apt by unbalanced-e)] + %+ expect-eq + !> [%dup %.n] + !> [%dup ~(apt by duplicates)] == :: :: Test bifurcation (i.e. splits map a into two, discarding -.a) diff --git a/pkg/arvo/tests/sys/zuse/format.hoon b/pkg/arvo/tests/sys/zuse/format.hoon new file mode 100644 index 000000000..1ef96550f --- /dev/null +++ b/pkg/arvo/tests/sys/zuse/format.hoon @@ -0,0 +1,693 @@ +/+ *test +=, format +|% +:: split a cord on newlines +:: +++ test-to-wain + ;: weld + :: basic usage + :: + %+ expect-eq + !> ~['hello' 'world'] + !> (to-wain 'hello\0aworld') + :: string with no newlines + :: + %+ expect-eq + !> ~['hey'] + !> (to-wain 'hey') + :: empty string works fine + :: + %+ expect-eq + !> ~[''] + !> (to-wain '') + :: leading/trailing/consecutive newlines all work fine + :: + %+ expect-eq + !> ~['' 'hi' '' '' 'there' ''] + !> (to-wain '\0ahi\0a\0a\0athere\0a') + == +:: join a list of lines (cords) into a single cord +:: +++ test-of-wain + ;: weld + :: basic usage + :: + %+ expect-eq + !> 'hey\0athere\0aworld!' + !> (of-wain ~['hey' 'there' 'world!']) + :: empty list + :: + %+ expect-eq + !> '' + !> (of-wain ~) + :: single list + :: + %+ expect-eq + !> 'hey' + !> (of-wain ~['hey']) + :: list with empties + :: + %+ expect-eq + !> 'hey\0a\0athere' + !> (of-wain ~['hey' '' 'there']) + == +:: join a list of lines (tapes) into a single cord. +:: +:: Appends an extra newline - this matches unix conventions of a +:: trailing newline. Also see #1, #2 +:: +++ test-of-wall + ;: weld + :: basic usage + :: + %+ expect-eq + !> "hey\0athere\0aworld!\0a" + !> (of-wall ~["hey" "there" "world!"]) + :: empty list + :: + %+ expect-eq + !> "" + !> (of-wall ~) + :: single list + :: + %+ expect-eq + !> "hey\0a" + !> (of-wall ~["hey"]) + :: list with empties + :: + %+ expect-eq + !> "hey\0a\0athere\0a" + !> (of-wall ~["hey" "" "there"]) + == +:: encoding and decoding of beams <-> paths + +:: (a beam is a fully-qualified file reference. ship, desk, version, +:: path) +:: +++ test-beam + =/ b=beam [[p=~zod q=%home r=[%ud p=12]] s=/hoon/zuse/sys] + =/ p=path /~zod/home/12/sys/zuse/hoon + ;: weld + :: proper encode + :: + %+ expect-eq + !> p + !> (en-beam b) + :: proper decode + :: + %+ expect-eq + !> (some b) + !> (de-beam p) + :: proper round trip + :: + %+ expect-eq + !> (some b) + !> (de-beam (en-beam b)) + :: path too short + :: + %+ expect-eq + !> ~ + !> (de-beam /~zod/home) + :: invalid ship + :: + %+ expect-eq + !> ~ + !> (de-beam /'~zodisok'/home/12/sys/zuse/hoon) + :: invalid desk + :: + %+ expect-eq + !> ~ + !> (de-beam /~zod/12/12/sys/zuse/hoon) + :: invalid case + :: + %+ expect-eq + !> ~ + !> (de-beam /~zod/home/~zod/sys/zuse/hoon) + == +:: example values used in test +:: +++ ex + |% + ++ nul `json`~ + ++ tru `json`[%b &] + ++ num `json`[%n ~.12] + ++ str `json`[%s 'hey'] + ++ frond `json`(frond:enjs 'foo' num) + ++ obj `json`(pairs:enjs ~[['foo' num] ['bar' str]]) + -- +:: functions for creating `json` values +:: +++ test-enjs + =, enjs + ;: weld + :: numbers + :: + %+ expect-eq + !> num:ex + !> (numb 12) + %+ expect-eq + !> num:ex + !> (numb 0xc) + %+ expect-eq + !> [%n '0'] + !> (numb 0) + :: strings + :: + %+ expect-eq + !> str:ex + !> (tape "hey") + %+ expect-eq + :: uses of-wall, so adds the trailing newline + :: + !> [%s 'hi\0athere\0a'] + !> (wall ~["hi" "there"]) + :: objects + :: + %+ expect-eq + !> [%o (molt ~[['foo' num:ex]])] + !> (frond 'foo' num:ex) + =+ props=~[['foo' num:ex] ['bar' tru:ex]] + %+ expect-eq + !> [%o (molt props)] + !> (pairs props) + :: time - stored as integer number of milliseconds since the unix epoch + :: + %+ expect-eq + !> [%n '1000'] + !> (time ~1970.1.1..0.0.1) + :: ship - store ship identity as a string + :: + %+ expect-eq + !> [%s 'zod'] + !> (ship ~zod) + == +:: dejs - recursive processing of `json` values +:: +:: This version crashes when used on improper input. Prefer using +:: dejs-soft (also tested below) which returns units instead. +:: +:: decoding from null, booleans, numbers, strings +:: +++ test-dejs-primitives + =, dejs + ;: weld + :: null + :: + %+ expect-eq + !> ~ + !> (ul `json`~) + :: booleans + :: + :: bo extracts as-is, bu negates it + :: + %+ expect-eq + !> & + !> (bo tru:ex) + %+ expect-eq + !> | + !> (bu tru:ex) + %- expect-fail + |. (bo num:ex) + %- expect-fail + |. (bu num:ex) + :: integers + :: + :: as @ + :: + %+ expect-eq + !> 12 + !> (ni num:ex) + %- expect-fail + |. (ni tru:ex) + :: as cord + :: + %+ expect-eq + !> '12' + !> (no num:ex) + %- expect-fail + |. (no tru:ex) + :: timestamp - ms since the unix epoch + :: + %+ expect-eq + !> ~1970.1.1..00.00.01 + !> (di [%n ~.1000]) + %- expect-fail + |. (di tru:ex) + :: strings + :: + :: string as tape + :: + %+ expect-eq + !> "hey" + !> (sa str:ex) + %- expect-fail + |. (sa tru:ex) + :: string as cord + :: + %+ expect-eq + !> 'hey' + !> (so str:ex) + %- expect-fail + |. (so tru:ex) + :: string with custom parser + :: + %+ expect-eq + !> ' ' + !> ((su (just ' ')) [%s ' ']) + %- expect-fail + |. ((su (just ' ')) tru:ex) + == +:: decoding arrays +:: +++ test-dejs-arrays + =, dejs + ;: weld + :: ar - as list + :: + %+ expect-eq + !> ~[1 2 3] + !> ((ar ni) [%a ~[[%n '1'] [%n '2'] [%n '3']]]) + %- expect-fail + |. ((ar ni) str:ex) + %- expect-fail + |. ((ar ni) [%a ~[str:ex]]) + :: at - as tuple + :: + :: handlers must match exactly + :: + %+ expect-eq + !> [1 'hey'] + !> ((at ~[ni so]) [%a ~[[%n '1'] [%s 'hey']]]) + :: too few or many handlers crash + :: + %- expect-fail + |. ((at ~[ni so]) [%a ~]) + %- expect-fail + |. ((at ~[ni so]) [%a ~[[%n '1'] [%s 'hey'] [%b &]]]) + :: a nested error will crash + :: + %- expect-fail + |. ((at ~[ni]) [%a ~[[%s 'hey']]]) + == +:: decoding objects +:: +++ test-dejs-objects + =, dejs + ;: weld + :: of - single-property objects + :: + %+ expect-eq + !> ['foo' 12] + !> ((of ~[['foo' ni]]) frond:ex) + %+ expect-eq + !> ['foo' 12] + !> ((of ~[['bar' so] ['foo' ni]]) frond:ex) + %- expect-fail + :: the handler needs to apply properly to the value + :: + |. ((of ~[['foo' ni]]) num:ex) + %- expect-fail + :: the key of the frond needs to exist in the handler list + :: + |. ((of ~[['bar' so]]) frond:ex) + %- expect-fail + :: an object with multiple properties is an error + :: + |. ((of ~[['bar' so] ['foo' ni]]) obj:ex) + :: ot - exact-shape objects to tuple + :: + %+ expect-eq + !> [12 'hey'] + !> ((ot ~[['foo' ni] ['bar' so]]) obj:ex) + %- expect-fail + :: it checks it's called on an actual object + :: + |. ((ot ~[['foo' ni]]) num:ex) + %- expect-fail + :: missing property on the object + :: + |. ((ot ~[['foo' ni] ['baz' so]]) obj:ex) + :: ou - object to tuple, with optional properties. value handlers + :: + :: are passed (unit json) + :: + %+ expect-eq + !> [12 14] + !> ((ou ~[['foo' (uf 14 ni)] ['baz' (uf 14 ni)]]) obj:ex) + :: om - simple object as map + :: + %+ expect-eq + !> (molt ~[['foo' num:ex] ['bar' str:ex]]) + !> ((om same) obj:ex) + :: op - object to map, but run a parsing function on the keys + :: + %+ expect-eq + !> (molt ~[[12 num:ex] [14 str:ex]]) + !> ((op dem same) (pairs:enjs ~[['12' num:ex] ['14' str:ex]])) + == +:: decoder transformers +:: +++ test-dejs-transformers + =, dejs + ;: weld + :: cu - decode, then transform + :: + %+ expect-eq + !> 11 + !> ((cu dec ni) [%n ~.12]) + :: ci - decode, then assert a transformation succeeds + :: + %+ expect-eq + !> 12 + !> ((ci some ni) num:ex) + %- expect-fail + |. ((ci |=(* ~) ni) num:ex) + :: mu - decode if not null + :: + %+ expect-eq + !> ~ + !> ((mu ni) nul:ex) + %+ expect-eq + !> (some 12) + !> ((mu ni) num:ex) + :: pe - add prefix to decoded value + :: + %+ expect-eq + !> ['a' 12] + !> ((pe 'a' ni) num:ex) + :: uf - defaults for empty (unit json) + :: + %+ expect-eq + !> 'nah' + !> ((uf 'nah' ni) ~) + %+ expect-eq + !> 12 + !> ((uf 'nah' ni) (some num:ex)) + :: un - dangerous ensure a (unit json) + :: + %+ expect-eq + !> 12 + !> ((un ni) (some num:ex)) + %- expect-fail + |. ((un ni) ~) + == +:: various unit/collection helpers +:: +++ test-dejs-helpers + =, dejs + =+ all=`(list (unit @))`~[(some 1) (some 2) (some 3)] + =+ nall=`(list (unit @))`~[(some 1) ~ (some 3)] + ;: weld + :: za - are all units in this list full? + :: + %+ expect-eq + !> & + !> (za ~) + %+ expect-eq + !> & + !> (za all) + %+ expect-eq + !> | + !> (za nall) + :: zl - collapse (list (unit)) -> (unit (list)) + :: + %+ expect-eq + !> (some ~[1 2 3]) + !> (zl all) + %+ expect-eq + !> ~ + !> (zl nall) + %+ expect-eq + !> (some ~) + !> (zl ~) + :: zp - force unwrap a (list (unit)) as tuple + :: + %+ expect-eq + !> [1 2 3] + !> (zp all) + %- expect-fail + |. (zp nall) + %- expect-fail + |. (zp ~) + :: zm - collapse a (map @tas (unit *)) -> (unit (map @tas *)) + :: + %+ expect-eq + !> (some (molt ~[['a' 1] ['b' 2]])) + !> (zm (molt ~[['a' (some 1)] ['b' (some 2)]])) + %+ expect-eq + !> ~ + !> (zm (molt ~[['a' `(unit @)`(some 1)] ['b' ~]])) + %+ expect-eq + !> (some ~) + !> (zm ~) + == +:: +:: dejs-soft recursive processing of `json` values +:: +:: These functions return units, which will be nil if the input +:: doesn't match the defined structure. +:: +++ test-dejs-soft-primitives + =, dejs-soft + ;: weld + :: null + :: + %+ expect-eq + !> `~ + !> (ul `json`~) + :: booleans + :: + :: bo extracts as-is, bu negates it + :: + %+ expect-eq + !> `& + !> (bo tru:ex) + %+ expect-eq + !> `| + !> (bu tru:ex) + %+ expect-eq + !> ~ + !> (bo num:ex) + %+ expect-eq + !> ~ + !> (bu num:ex) + :: integers + :: as @ + :: + %+ expect-eq + !> `12 + !> (ni num:ex) + %+ expect-eq + !> ~ + !> (ni tru:ex) + :: as cord + :: + %+ expect-eq + !> `'12' + !> (no num:ex) + %+ expect-eq + !> ~ + !> (no tru:ex) + :: timestamp - ms since the unix epoch + :: + %+ expect-eq + !> `~1970.1.1..00.00.01 + !> (di [%n ~.1000]) + %+ expect-eq + !> ~ + !> (di tru:ex) + :: string as tape + :: + %+ expect-eq + !> `"hey" + !> (sa str:ex) + %+ expect-eq + !> ~ + !> (sa tru:ex) + :: string as cord + :: + %+ expect-eq + !> `'hey' + !> (so str:ex) + %+ expect-eq + !> ~ + !> (so tru:ex) + :: string with custom parser + :: + %+ expect-eq + !> `' ' + !> ((su (just ' ')) [%s ' ']) + %+ expect-eq + !> ~ + !> ((su (just ' ')) tru:ex) + == +:: decoding arrays +:: +++ test-dejs-soft-arrays + =, dejs-soft + ;: weld + :: ar - as list + :: + %+ expect-eq + !> `~[1 2 3] + !> ((ar ni) [%a ~[[%n '1'] [%n '2'] [%n '3']]]) + %+ expect-eq + !> ~ + !> ((ar ni) str:ex) + %+ expect-eq + !> ~ + !> ((ar ni) [%a ~[str:ex]]) + :: at - as tuple + :: + :: handlers must match exactly + :: + %+ expect-eq + !> `[1 'hey'] + !> ((at ~[ni so]) [%a ~[[%n '1'] [%s 'hey']]]) + :: too few or many handlers won't match + :: + %+ expect-eq + !> ~ + !> ((at ~[ni so]) [%a ~]) + %+ expect-eq + !> ~ + !> ((at ~[ni so]) [%a ~[[%n '1'] [%s 'hey'] [%b &]]]) + :: a nested failure to match will propagate upwards + :: + %+ expect-eq + !> ~ + !> ((at ~[ni]) [%a ~[[%s 'hey']]]) + == +:: decoding objects +:: +++ test-dejs-soft-objects + =, dejs-soft + ;: weld + :: of - single-property objects + :: + %+ expect-eq + !> `['foo' 12] + !> ((of ~[['foo' ni]]) frond:ex) + %+ expect-eq + !> `['foo' 12] + !> ((of ~[['bar' so] ['foo' ni]]) frond:ex) + %+ expect-eq + !> ~ + :: the handler needs to apply properly to the value + :: + !> ((of ~[['foo' ni]]) num:ex) + %+ expect-eq + !> ~ + :: the key of the frond needs to exist in the handler list + :: + !> ((of ~[['bar' so]]) frond:ex) + %+ expect-eq + !> ~ + :: an object with multiple properties is an error + :: + !> ((of ~[['bar' so] ['foo' ni]]) obj:ex) + :: ot - exact-shape objects to tuple + :: + %+ expect-eq + !> `[12 'hey'] + !> ((ot ~[['foo' ni] ['bar' so]]) obj:ex) + %+ expect-eq + !> ~ + :: missing property on the object + :: + !> ((ot ~[['foo' ni] ['baz' so]]) obj:ex) + :: om - simple object as map + :: + %+ expect-eq + !> `(molt ~[['foo' num:ex] ['bar' str:ex]]) + !> ((om some) obj:ex) + :: op - object to map, but run a parsing function on the keys + :: + %+ expect-eq + !> `(molt ~[[12 num:ex] [14 str:ex]]) + !> ((op dem some) (pairs:enjs ~[['12' num:ex] ['14' str:ex]])) + == +:: decoder transformers +:: +++ test-dejs-soft-transformers + =, dejs-soft + ;: weld + :: cu - decode, then transform + :: + %+ expect-eq + !> `11 + !> ((cu dec ni) [%n ~.12]) + :: ci - decode, then transform, adapting the transformer to return a + :: unit + :: + %+ expect-eq + !> `12 + !> ((ci some ni) num:ex) + %+ expect-eq + !> ~ + !> ((ci |=(* ~) ni) num:ex) + :: mu - decode if not null + :: + %+ expect-eq + !> `~ + !> ((mu ni) nul:ex) + %+ expect-eq + !> `(some 12) + !> ((mu ni) num:ex) + :: pe - add prefix to decoded value + :: + %+ expect-eq + !> `['a' 12] + !> ((pe 'a' ni) num:ex) + == +:: various unit/collection helpers +:: +++ test-dejs-soft-helpers + =, dejs-soft + =+ all=`(list (unit @))`~[(some 1) (some 2) (some 3)] + =+ nall=`(list (unit @))`~[(some 1) ~ (some 3)] + ;: weld + :: za - are all units in this list full? + :: + %+ expect-eq + !> & + !> (za ~) + %+ expect-eq + !> & + !> (za all) + %+ expect-eq + !> | + !> (za nall) + :: zl - collapse (list (unit)) -> (unit (list)) + :: + %+ expect-eq + !> (some ~[1 2 3]) + !> (zl all) + %+ expect-eq + !> ~ + !> (zl nall) + %+ expect-eq + !> (some ~) + !> (zl ~) + :: zp - force unwrap a (list (unit)) as tuple + :: + %+ expect-eq + !> [1 2 3] + !> (zp all) + %- expect-fail + |. (zp nall) + %- expect-fail + |. (zp ~) + :: zm - collapse a (map @tas (unit *)) -> (unit (map @tas *)) + :: + %+ expect-eq + !> (some (molt ~[['a' 1] ['b' 2]])) + !> (zm (molt ~[['a' (some 1)] ['b' (some 2)]])) + %+ expect-eq + !> ~ + !> (zm (molt ~[['a' `(unit @)`(some 1)] ['b' ~]])) + %+ expect-eq + !> (some ~) + !> (zm ~) + == +-- diff --git a/pkg/arvo/tests/sys/zuse/html.hoon b/pkg/arvo/tests/sys/zuse/html.hoon index be144b750..9d4b6facf 100644 --- a/pkg/arvo/tests/sys/zuse/html.hoon +++ b/pkg/arvo/tests/sys/zuse/html.hoon @@ -1,13 +1,15 @@ -:: tests for html +:: tests for html +:: /+ *test +=, html =, de-xml:html =, en-xml:html |% -:: de-xml takes a cord but en-xml returns a tape? +:: de-xml takes a cord but en-xml returns a tape? :: ++ test-de-xml ;: weld - :: Basic use + :: Basic use :: %+ expect-eq !> ^- manx +:(de-xml:html (crip "My first webpage

Welcome!

Hello, world! We are on the web.\0a
")) @@ -23,14 +25,15 @@ ;script(src "http://unsafely.tracking.you/cookiemonster.js"); == == - :: CDATA sections + :: CDATA sections :: %+ expect-eq !> ^- manx +:(de-xml:html (crip "")) !> ^- manx ;elem: text - :: comments + :: comments + :: %+ expect-eq !> ^- manx ;elem: text @@ -39,7 +42,7 @@ !> ^- manx ;elem; !> +:(de-xml:html (crip "")) - :: entities + :: entities :: %+ expect-eq !> ^- manx @@ -59,13 +62,13 @@ :: ++ test-en-xml ;: weld - :: Entities + :: Entities :: %+ expect-eq !> ">" !> %- en-xml:html ;elem: > - :: Basic use + :: Basic use :: %+ expect-eq !> %- en-xml:html @@ -82,11 +85,788 @@ == == !> "My first webpage

Welcome!

Hello, world!\0aWe are on the web.\0a
" - :: Attributes + :: Attributes :: %+ expect-eq !> "Submit" !> %- en-xml:html ;input(type "submit"): Submit == +:: JSON encoding/decoding +:: +++ from-code-points + |= points=(list @) + (tufa `(list @c)`points) +++ from-code-point + |= point=@ + (tuft point) ++$ json-parse-spec [name=tape input=cord expected=json] ++$ json-parse-rejection-spec [input=cord name=tape] +:: For checking a large list of examples against expected values. +:: It also nicely formats any failures. +:: +++ run-parse-specs + :: legend tells of a man who made the Kessel run in less than 12 + :: parse-specs... + |= specs=(list json-parse-spec) + %- zing + %- turn + :- specs + |= spec=json-parse-spec + ^- tang + =+ result=(expect-eq !>(`expected.spec) !>((de-json:html input.spec))) + ?~ result ~ + `tang`[[%leaf "in {name.spec}:"] result] +:: Checks that a list of examples all fail to parse +:: +++ run-parse-rejection-specs + |= specs=(list json-parse-rejection-spec) + %- zing + %- turn + :- specs + |= spec=json-parse-rejection-spec + ^- tang + =+ result=(expect-eq !>(~) !>((de-json:html input.spec))) + ?~ result ~ + `tang`[[%leaf "in {name.spec}:"] result] +:: example values used in tests +:: +++ ex + |% + ++ two `json`[%n '2'] + ++ tru `json`[%b &] + -- +:: encoding naked values +:: +++ test-en-json-basics + ;: weld + %+ expect-eq + !> "true" + !> (en-json [%b &]) + %+ expect-eq + !> "false" + !> (en-json [%b |]) + %+ expect-eq + !> "null" + !> (en-json ~) + %+ expect-eq + !> "123.45" + !> (en-json [%n '123.45']) + == +:: encoding strings, with proper escaping rules +:: +++ test-en-json-strings + :: A less-confusing representation of theses strings are included in comments + :: + :: Things get confusing with hoon string literal escapes. The + :: version included as a comment is if you opened the json output + :: in a simple text editor. + :: + ;: weld + :: "hello" + :: + %+ expect-eq + !> "\"hello\"" + !> (en-json [%s 'hello']) + :: it escapes quotes + :: "he said \"wow\"" + :: + %+ expect-eq + !> "\"he said \\\"wow\\\"\"" + !> (en-json [%s 'he said "wow"']) + :: it escapes backslashes + :: "Delete C:\\Windows\\System32" + :: + %+ expect-eq + !> "\"Delete C:\\\\Windows\\\\System32\"" + !> (en-json [%s 'Delete C:\\Windows\\System32']) + :: it uses \n for newlines + :: "hello\nworld" + :: + %+ expect-eq + !> "\"hello\\nworld\"" + !> (en-json [%s 'hello\0aworld']) + :: it uses \u encoding for control characters (0x1f and below) + :: "ding!\u0007" + :: + %+ expect-eq + !> "\"ding!\\u0007\"" + !> (en-json [%s 'ding!\07']) + :: it supports null bytes + :: + %+ expect-eq + !> "\"null\\u0000byte\\u0000separator\"" + !> (en-json [%s 'null\00byte\00separator']) + :: inline unicode characters + :: + %+ expect-eq + !> "\"lmao 🤣\"" + !> (en-json [%s 'lmao 🤣']) + == +:: encoding arrays +:: +++ test-en-json-arrays + ;: weld + :: empty array + :: + %+ expect-eq + !> "[]" + !> (en-json [%a ~]) + :: 1 element + :: + %+ expect-eq + !> "[2]" + !> (en-json [%a ~[two:ex]]) + :: multiple elements are comma-separated + :: + %+ expect-eq + !> "[2,2,2]" + !> (en-json [%a ~[two:ex two:ex two:ex]]) + == +:: encoding basic objects +:: +++ test-en-json-objects + :: opening curly braces are escaped to avoid urbit string literal + :: interpolation + :: + ;: weld + :: empty object + :: + %+ expect-eq + !> "\{}" + !> (en-json [%o ~]) + :: one property + :: + %+ expect-eq + !> "\{\"foo\":2}" + !> (en-json [%o (molt ~[['foo' two:ex]])]) + :: multiple properties are comma-separated + :: + %+ expect-eq + !> "\{\"foo\":2,\"bar\":true}" + !> (en-json [%o (molt ~[['foo' two:ex] ['bar' tru:ex]])]) + :: object keys use same encoding logic as strings + :: + %+ expect-eq + :: {"\u0007\"\n\\":true} + :: + !> "\{\"\\u0007\\\"\\n\\\\\":true}" + !> (en-json [%o (molt ~[['\07"\0a\\' tru:ex]])]) + == +:: object encoding stress-test +:: +++ test-en-json-complex-structure + %+ expect-eq + :: [{}, 4, [[], [{foo: {"4": 4, "true": true}}]]] + :: + !> "[\{},4,[[],[\{\"foo\":\{\"4\":4,\"true\":true}}]]]" + !> %- en-json:html + :- %a + :~ [%o ~] + [%n '4'] + :- %a + :~ [%a ~] + :- %a + :~ %+ frond:enjs:format + 'foo' + (pairs:enjs:format ~[['4' [%n '4']] ['true' [%b &]]]) + == + == + == +:: decoding naked values +:: +++ test-de-json-simple-values + =, html + ;: weld + %+ expect-eq + !> `~ + !> (de-json 'null') + %+ expect-eq + !> `[%b &] + !> (de-json 'true') + %+ expect-eq + !> `[%b |] + !> (de-json 'false') + == +:: The following parser test suite (test-de-json-bad-examples and +:: test-en-json-suite) is adapted from https://github.com/nst/JSONTestSuite/ +:: (Copyright (c) 2016 Nicolas Seriot) under the terms of the MIT license. +:: +:: These are all inputs that should be rejected by a valid json parser +:: +++ test-de-json-bad-examples + %- run-parse-rejection-specs + :~ + ['[1 true]' "n_array_1_true_without_comma"] + ['[aÂ]' "n_array_a_invalid_utf8"] + ['["": 1]' "n_array_colon_instead_of_comma"] + ['[""],' "n_array_comma_after_close"] + ['[,1]' "n_array_comma_and_number"] + ['[1,,2]' "n_array_double_comma"] + ['["x",,]' "n_array_double_extra_comma"] + ['["x"]]' "n_array_extra_close"] + ['["",]' "n_array_extra_comma"] + ['["x"' "n_array_incomplete"] + ['[x' "n_array_incomplete_invalid_value"] + ['[3[4]]' "n_array_inner_array_no_comma"] + ['[ˇ]' "n_array_invalid_utf8"] + ['[1:2]' "n_array_items_separated_by_semicolon"] + ['[,]' "n_array_just_comma"] + ['[-]' "n_array_just_minus"] + ['[ , ""]' "n_array_missing_value"] + ['["a",\0a4\0a,1,' "n_array_newlines_unclosed"] + ['[1,]' "n_array_number_and_comma"] + ['[1,,]' "n_array_number_and_several_commas"] + ['["\0b"\\f]' "n_array_spaces_vertical_tab_formfeed"] + ['[*]' "n_array_star_inside"] + ['[""' "n_array_unclosed"] + ['[1,' "n_array_unclosed_trailing_comma"] + ['[1,\0a1\0a,1' "n_array_unclosed_with_new_lines"] + ['[{}' "n_array_unclosed_with_object_inside"] + ['[fals]' "n_incomplete_false"] + ['[nul]' "n_incomplete_null"] + ['[tru]' "n_incomplete_true"] + ['[++1234]' "n_number_++"] + ['[+1]' "n_number_+1"] + ['[+Inf]' "n_number_+Inf"] + ['[-01]' "n_number_-01"] + ['[-1.0.]' "n_number_-1.0."] + ['[-NaN]' "n_number_-NaN"] + ['[.-1]' "n_number_.-1"] + ['[.2e-3]' "n_number_.2e-3"] + ['[0.1.2]' "n_number_0.1.2"] + ['[1 000.0]' "n_number_1_000"] + ['[1eE2]' "n_number_1eE2"] + ['[Inf]' "n_number_Inf"] + ['[NaN]' "n_number_NaN"] + ['[Ôºë]' "n_number_U+FF11_fullwidth_digit_one"] + ['[1+2]' "n_number_expression"] + ['[0x1]' "n_number_hex_1_digit"] + ['[0x42]' "n_number_hex_2_digits"] + ['[Infinity]' "n_number_infinity"] + ['[0e+-1]' "n_number_invalid+-"] + ['[-123.123foo]' "n_number_invalid-negative-real"] + ['[123Â]' "n_number_invalid-utf-8-in-bigger-int"] + ['[1e1Â]' "n_number_invalid-utf-8-in-exponent"] + ['[0Â]' "n_number_invalid-utf-8-in-int"] + ['[-Infinity]' "n_number_minus_infinity"] + ['[-foo]' "n_number_minus_sign_with_trailing_garbage"] + ['[- 1]' "n_number_minus_space_1"] + ['[-012]' "n_number_neg_int_starting_with_zero"] + ['[-.123]' "n_number_neg_real_without_int_part"] + ['[-1x]' "n_number_neg_with_garbage_at_end"] + ['[1ea]' "n_number_real_garbage_after_e"] + ['[1eÂ]' "n_number_real_with_invalid_utf8_after_e"] + ['[.123]' "n_number_starting_with_dot"] + ['[1.2a-3]' "n_number_with_alpha"] + ['[1.8011670033376514H-308]' "n_number_with_alpha_char"] + ['[012]' "n_number_with_leading_zero"] + ['["x", truth]' "n_object_bad_value"] + ['{[: "x"}' "n_object_bracket_key"] + ['{"x", null}' "n_object_comma_instead_of_colon"] + ['{"x"::"b"}' "n_object_double_colon"] + ['{üá®üá≠}' "n_object_emoji"] + ['{"a":"a" 123}' "n_object_garbage_at_end"] + ['{key: \'value\'}' "n_object_key_with_single_quotes"] + ['{"π":"0",}' "n_object_lone_continuation_byte_in_key_and_trailing_comma"] + ['{"a" b}' "n_object_missing_colon"] + ['{:"b"}' "n_object_missing_key"] + ['{"a" "b"}' "n_object_missing_semicolon"] + ['{"a":' "n_object_missing_value"] + ['{"a"' "n_object_no-colon"] + ['{1:1}' "n_object_non_string_key"] + ['{9999E9999:1}' "n_object_non_string_key_but_huge_number_instead"] + ['{null:null,null:null}' "n_object_repeated_null_null"] + ['{"id":0,,,,,}' "n_object_several_trailing_commas"] + ['{\'a\':0}' "n_object_single_quote"] + ['{"id":0,}' "n_object_trailing_comma"] + ['{"a":"b"}/**/' "n_object_trailing_comment"] + ['{"a":"b"}/**//' "n_object_trailing_comment_open"] + ['{"a":"b"}//' "n_object_trailing_comment_slash_open"] + ['{"a":"b"}/' "n_object_trailing_comment_slash_open_incomplete"] + ['{"a":"b",,"c":"d"}' "n_object_two_commas_in_a_row"] + ['{a: "b"}' "n_object_unquoted_key"] + ['{"a":"a' "n_object_unterminated-value"] + ['{ "foo" : "bar", "a" }' "n_object_with_single_string"] + ['{"a":"b"}#' "n_object_with_trailing_garbage"] + [' ' "n_single_space"] + ['["\\uD800\\"]' "n_string_1_surrogate_then_escape"] + ['["\\uD800\\u"]' "n_string_1_surrogate_then_escape_u"] + ['["\\uD800\\u1"]' "n_string_1_surrogate_then_escape_u1"] + ['["\\uD800\\u1x"]' "n_string_1_surrogate_then_escape_u1x"] + ['[√©]' "n_string_accentuated_char_no_quotes"] + ['["\\x00"]' "n_string_escape_x"] + ['["\\\\\\"]' "n_string_escaped_backslash_bad"] + ['["\\\09"]' "n_string_escaped_ctrl_char_tab"] + ['["\\üåÄ"]' "n_string_escaped_emoji"] + ['["\\"]' "n_string_incomplete_escape"] + ['["\\u00A"]' "n_string_incomplete_escaped_character"] + ['["\\uD834\\uDd"]' "n_string_incomplete_surrogate"] + ['["\\uD800\\uD800\\x"]' "n_string_incomplete_surrogate_escape_invalid"] + ['["\\uÂ"]' "n_string_invalid-utf-8-in-escape"] + ['["\\a"]' "n_string_invalid_backslash_esc"] + ['["\\uqqqq"]' "n_string_invalid_unicode_escape"] + ['["\\Â"]' "n_string_invalid_utf8_after_escape"] + ['[\\u0020"asd"]' "n_string_leading_uescaped_thinspace"] + ['[\\n]' "n_string_no_quotes_with_bad_escape"] + ['"' "n_string_single_doublequote"] + ['[\'single quote\']' "n_string_single_quote"] + ['abc' "n_string_single_string_no_double_quotes"] + ['["\\' "n_string_start_escape_unclosed"] + ['["new' "n_string_unescaped_newline"] + ['line"]' "n_string_unescaped_newline"] + ['["\09"]' "n_string_unescaped_tab"] + ['"\\UA66D"' "n_string_unicode_CapitalU"] + ['""x' "n_string_with_trailing_garbage"] + ['[‚ņ]' "n_structure_U+2060_word_joined"] + ['Ôªø' "n_structure_UTF8_BOM_no_data"] + ['<.>' "n_structure_angle_bracket_."] + ['[]' "n_structure_angle_bracket_null"] + ['[1]x' "n_structure_array_trailing_garbage"] + ['[1]]' "n_structure_array_with_extra_array_close"] + ['["asd]' "n_structure_array_with_unclosed_string"] + ['a√•' "n_structure_ascii-unicode-identifier"] + ['[True]' "n_structure_capitalized_True"] + ['1]' "n_structure_close_unopened_array"] + ['{"x": true,' "n_structure_comma_instead_of_closing_brace"] + ['[][]' "n_structure_double_array"] + [']' "n_structure_end_array"] + ['Ôª{}' "n_structure_incomplete_UTF8_BOM"] + ['Â' "n_structure_lone-invalid-utf-8"] + ['[' "n_structure_lone-open-bracket"] + ['["a\00a"]' "n_string_unescaped_crtl_char"] + ['["\\00"]' "n_string_backslash_00"] + == +:: TODO: de-json is accepting a slew of number formats it shouldn't. +:: +:: Tracking issue here: https://github.com/urbit/urbit/issues/1775 +:: Re-enable this test by removing the disable- prefix +:: +++ disable-test-reject-invalid-numbers + %- run-parse-rejection-specs + :~ + ['123\00' "n_multidigit_number_then_00"] + ['[1.]' "n_number_real_without_fractional_part"] + ['[2.e+3]' "n_number_2.e+3"] + ['[2.e-3]' "n_number_2.e-3"] + ['[2.e3]' "n_number_2.e3"] + ['[9.e+]' "n_number_9.e+"] + ['[0.3e+]' "n_number_0.3e+"] + ['[0.3e]' "n_number_0.3e"] + ['[0.e1]' "n_number_0.e1"] + ['[0E+]' "n_number_0_capital_E+"] + ['[0E]' "n_number_0_capital_E"] + ['[0e+]' "n_number_0e+"] + ['[0e]' "n_number_0e"] + ['[1.0e+]' "n_number_1.0e+"] + ['[1.0e-]' "n_number_1.0e-"] + ['[1.0e]' "n_number_1.0e"] + ['[-2.]' "n_number_-2."] + == +:: these are all inputs that should be accepted by a valid parser +:: +++ test-en-json-suite + =+ frond=frond:enjs:format + =+ pairs=pairs:enjs:format + %- run-parse-specs + :~ + :* "y_array_arraysWithSpaces" + '[[] ]' + [%a ~[[%a ~]]] + == + :* "y_array_empty-string" + '[""]' + [%a ~[[%s '']]] + == + :* "y_array_empty" + '[]' + [%a ~] + == + :* "y_array_ending_with_newline" + '["a"]\0a' + [%a ~[[%s 'a']]] + == + :* "y_array_false" + '[false]' + [%a ~[[%b |]]] + == + :* "y_array_heterogeneous" + '[null, 1, "1", {}]' + [%a ~[~ [%n '1'] [%s '1'] [%o ~]]] + == + :* "y_array_null" + '[null]' + [%a ~[~]] + == + :* "y_array_with_1_and_newline" + '[1\0a]' + [%a ~[[%n '1']]] + == + :* "y_array_with_leading_space" + ' [1]' + [%a ~[[%n '1']]] + == + :* "y_array_with_several_null" + '[1,null,null,null,2]' + [%a ~[[%n '1'] ~ ~ ~ [%n '2']]] + == + :* "y_array_with_trailing_space" + '[2] ' + [%a ~[[%n '2']]] + == + :* "y_number" + '[123e65]' + [%a ~[[%n '123e65']]] + == + :* "y_number_0e+1" + '[0e+1]' + [%a ~[[%n '0e+1']]] + == + :* "y_number_0e1" + '[0e1]' + [%a ~[[%n '0e1']]] + == + :* "y_number_after_space" + '[ 4]' + [%a ~[[%n '4']]] + == + :* "y_number_double_close_to_zero" + '[-0.0000000000000000000000000000000000000000000000000000000\ + /00000000000000000000001]' + [%a ~[[%n '-0.0000000000000000000000000000000000000000000000\ + /00000000000000000000000000000001']]] + == + :* "y_number_int_with_exp" + '[20e1]' + [%a ~[[%n '20e1']]] + == + :* "y_number_minus_zero" + '[-0]' + [%a ~[[%n '-0']]] + == + :* "y_number_negative_int" + '[-123]' + [%a ~[[%n '-123']]] + == + :* "y_number_negative_one" + '[-1]' + [%a ~[[%n '-1']]] + == + :* "y_number_negative_zero" + '[-0]' + [%a ~[[%n '-0']]] + == + :* "y_number_real_capital_e" + '[1E22]' + [%a ~[[%n '1E22']]] + == + :* "y_number_real_capital_e_neg_exp" + '[1E-2]' + [%a ~[[%n '1E-2']]] + == + :* "y_number_real_capital_e_pos_exp" + '[1E+2]' + [%a ~[[%n '1E+2']]] + == + :* "y_number_real_exponent" + '[123e45]' + [%a ~[[%n '123e45']]] + == + :* "y_number_real_fraction_exponent" + '[123.456e78]' + [%a ~[[%n '123.456e78']]] + == + :* "y_number_real_neg_exp" + '[1e-2]' + [%a ~[[%n '1e-2']]] + == + :* "y_number_real_pos_exponent" + '[1e+2]' + [%a ~[[%n '1e+2']]] + == + :* "y_number_simple_int" + '[123]' + [%a ~[[%n '123']]] + == + :* "y_number_simple_real" + '[123.456789]' + [%a ~[[%n '123.456789']]] + == + :* "y_object" + '{"asd":"sdf", "dfg":"fgh"}' + (pairs ~[['asd' [%s 'sdf']] ['dfg' [%s ['fgh']]]]) + == + :* "y_object_basic" + '{"asd":"sdf"}' + (frond ['asd' [%s 'sdf']]) + == + :: duplicated keys, it takes the latest one. + :: + :* "y_object_duplicated_key" + '{"a":"b","a":"c"}' + (frond ['a' [%s 'c']]) + == + :* "y_object_duplicated_key_and_value" + '{"a":"b","a":"b"}' + (frond ['a' [%s 'b']]) + == + :* "y_object_empty" + '{}' + [%o ~] + == + :* "y_object_empty_key" + '{"":0}' + (frond ['' [%n '0']]) + == + :* "y_object_extreme_numbers" + '{ "min": -1.0e+28, "max": 1.0e+28 }' + (pairs ~[['min' [%n '-1.0e+28']] ['max' [%n '1.0e+28']]]) + == + =/ long=@t 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' + :* "y_object_long_strings" + '{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], \ + /"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}' + (pairs ~[['id' [%s long]] ['x' [%a ~[(frond ['id' [%s long]])]]]]) + == + :* "y_object_simple" + '{"a":[]}' + (frond 'a' [%a ~]) + == + :* "y_object_string_unicode" + '{"title":"\\u041f\\u043e\\u043b\\u0442\\u043e\\u0440\\u0430 \ + /\\u0417\\u0435\\u043c\\u043b\\u0435\\u043a\\u043e\\u043f\\u0430" }' + (frond 'title' [%s 'Полтора Землекопа']) + == + :* "y_object_with_newlines" + '{\0a"a": "b"\0a}' + (frond 'a' [%s 'b']) + == + :* "y_string_allowed_escapes" + '["\\"\\\\\\/\\b\\f\\n\\r\\t"]' + [%a ~[[%s '"\\/\08\0c\0a\0d\09']]] + == + :* "y_string_backslash_and_u_escaped_zero" + '["\\\\u0000"]' + [%a ~[[%s '\\u0000']]] + == + :* "y_string_backslash_doublequotes" + '["\\""]' + [%a ~[[%s '"']]] + == + :* "y_string_comments" + '["a/*b*/c/*d//e"]' + [%a ~[[%s 'a/*b*/c/*d//e']]] + == + :* "y_string_double_escape_a" + '["\\\\a"]' + [%a ~[[%s '\\a']]] + == + :* "y_string_double_escape_n" + '["\\\\n"]' + [%a ~[[%s '\\n']]] + == + :* "y_string_escaped_control_character" + '["\\u0012"]' + [%a ~[[%s '\12']]] + == + :* "y_string_in_array_with_leading_space" + '[ "asd"]' + [%a ~[[%s 'asd']]] + == + :* "y_string_nonCharacterInUTF-8_U+10FFFF" + '["􏿿"]' + [%a ~[[%s (from-code-point 0x10.ffff)]]] + == + :* "y_string_nonCharacterInUTF-8_U+FFFF" + '["￿"]' + [%a ~[[%s (from-code-point 0xffff)]]] + == + :* "y_string_null_escape" + '["\\u0000"]' + [%a ~[[%s '\00']]] + == + :* "y_string_one-byte-utf-8" + '["\\u002c"]' + [%a ~[[%s '\2c']]] + == + :* "y_string_pi" + '["π"]' + [%a ~[[%s 'π']]] + == + :* "y_string_reservedCharacterInUTF-8_U+1BFFF" + '["𛿿"]' + [%a ~[[%s (from-code-point 0x1.bfff)]]] + == + :* "y_string_simple_ascii" + '["asd "]' + [%a ~[[%s 'asd ']]] + == + :* "y_string_space" + '" "' + [%s ' '] + == + :* "y_string_three-byte-utf-8" + '["\\u0821"]' + [%a ~[[%s (from-code-point 0x821)]]] + == + :* "y_string_two-byte-utf-8" + '["\\u0123"]' + [%a ~[[%s (from-code-point 0x123)]]] + == + :* "y_string_u+2028_line_sep" + '["
"]' + [%a ~[[%s (from-code-point 0x2028)]]] + == + :* "y_string_u+2029_par_sep" + '["
"]' + [%a ~[[%s (from-code-point 0x2029)]]] + == + :* "y_string_unicode_2" + '["⍂㈴⍂"]' + [%a ~[[%s '⍂㈴⍂']]] + == + :* "y_string_unicode_U+2064_invisible_plus" + '["\\u2064"]' + [%a ~[[%s (from-code-point 0x2064)]]] + == + :* "y_string_unicode_escaped_double_quote" + '["\\u0022"]' + [%a ~[[%s (from-code-point 0x22)]]] + == + :* "y_string_utf8" + '["€𝄞"]' + [%a ~[[%s '€𝄞']]] + == + :* "y_structure_lonely_false" + 'false' + [%b |] + == + :* "y_structure_lonely_int" + '42' + [%n '42'] + == + :* "y_structure_lonely_negative_real" + '-0.1' + [%n '-0.1'] + == + :* "y_structure_lonely_null" + 'null' + ~ + == + :* "y_structure_lonely_string" + '"asd"' + [%s 'asd'] + == + :* "y_structure_lonely_true" + 'true' + [%b &] + == + :* "y_structure_string_empty" + '""' + [%s ''] + == + :* "y_structure_trailing_newline" + '["a"]\0a' + [%a ~[[%s 'a']]] + == + :* "y_structure_true_in_array" + '[true]' + [%a ~[[%b &]]] + == + :* "y_structure_whitespace_array" + ' [] ' + [%a ~] + == + == +:: TODO: de-json is rejecting or dropping unicode escape sequences +:: +:: Tracking issue here: https://github.com/urbit/urbit/issues/1776 +:: Re-enable this test by removing the disable- prefix +:: +++ disable-test-parse-unicode-escape-sequences + =+ frond=frond:enjs:format + =+ pairs=pairs:enjs:format + %- run-parse-specs + :~ + :* "y_string_with_del_character" + '["a\7fa"]' + [%a ~[[%s 'a\7fa']]] + == + :* "y_string_unicode_U+FDD0_nonchar" + '["\\uFDD0"]' + [%a ~[[%s (from-code-point 0xfdd0)]]] + == + :* "y_string_unicode_U+FFFE_nonchar" + '["\\uFFFE"]' + [%a ~[[%s (from-code-point 0xfffe)]]] + == + :* "y_string_unicode_U+10FFFE_nonchar" + '["\\uDBFF\\uDFFE"]' + [%a ~[[%s (crip (from-code-points ~[0xdbff 0xdffe]))]]] + == + :* "y_string_unicode_U+1FFFE_nonchar" + '["\\uD83F\\uDFFE"]' + [%a ~[[%s (crip (from-code-points ~[0xd83f 0xdffe]))]]] + == + :* "y_string_unicode_U+200B_ZERO_WIDTH_SPACE" + '["\\u200B"]' + [%a ~[[%s (from-code-point 0x200b)]]] + == + :* "y_string_uEscape" + '["\\u0061\\u30af\\u30EA\\u30b9"]' + [%a ~[[%s (crip (from-code-points ~[0x61 0x30af 0x30ea 0x30b9]))]]] + == + :* "y_string_uescaped_newline" + '["new\\u000Aline"]' + [%a ~[[%s 'new\0aline']]] + == + :* "y_string_unescaped_char_delete" + '["\7f"]' + [%a ~[[%s '\7f']]] + == + :* "y_string_unicode" + '["\\uA66D"]' + [%a ~[[%s (from-code-point 0xa66d)]]] + == + :* "y_string_unicodeEscapedBackslash" + '["\\u005C"]' + [%a ~[[%s (from-code-point 0x5c)]]] + == + :* "y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF" + '["\\uD834\\uDd1e"]' + [%a ~[[%s (crip (from-code-points ~[0xd834 0xdd1e]))]]] + == + :* "y_string_last_surrogates_1_and_2" + '["\\uDBFF\\uDFFF"]' + [%a ~[[%s (crip (from-code-points ~[0xdbff 0xdfff]))]]] + == + :* "y_string_nbsp_uescaped" + '["new\\u00A0line"]' + [%a ~[[%s (crip "new{(from-code-points ~[0xa0])}line")]]] + == + :* "y_string_escaped_noncharacter" + '["\\uFFFF"]' + [%a ~[[%s (from-code-point 0xffff)]]] + == + :* "y_string_escaped_null" + '"foo\\u0000bar"' + [%s 'foo\00bar'] + == + :* "y_object_escaped_null_in_key" + '{"foo\\u0000bar": 42}' + (frond ['foo\00bar' [%n '42']]) + == + :* "y_string_1_2_3_bytes_UTF-8_sequences" + '["\\u0060\\u012a\\u12AB"]' + [%a ~[[%s '`Īካ']]] + == + :* "y_string_accepted_surrogate_pair" + '["\\uD801\\udc37"]' + [%a ~[[%s '𐐷']]] + == + :* "y_string_accepted_surrogate_pairs" + '["\\ud83d\\ude39\\ud83d\\udc8d"]' + [%a ~[[%s '😹💍']]] + == + == -- diff --git a/pkg/interface/.eslintrc.json b/pkg/interface/.eslintrc.json new file mode 100644 index 000000000..e13ac5853 --- /dev/null +++ b/pkg/interface/.eslintrc.json @@ -0,0 +1,147 @@ +{ + "env": { + "browser": true, + "es6": true, + "node": true + }, + "extends": [ + "eslint:recommended", + "plugin:react/recommended" + ], + "settings": { + "react": { + "version": "^16.5.2" + } + }, + "parser": "babel-eslint", + "parserOptions": { + "ecmaVersion": 10, + "requireConfigFile": false, + "sourceType": "module" + }, + "root": true, + "rules": { + "array-bracket-spacing": ["error", "never"], + "arrow-parens": [ + "error", + "as-needed", + { + "requireForBlockBody": true + } + ], + "arrow-spacing": "error", + "block-spacing": ["error", "always"], + "brace-style": ["error", "1tbs"], + "camelcase": [ + "error", + { + "properties": "never" + } + ], + "comma-dangle": ["error", "never"], + "eol-last": ["error", "always"], + "func-name-matching": "error", + "indent": [ + "off", + 2, + { + "ArrayExpression": "off", + "SwitchCase": 1, + "CallExpression": { + "arguments": "off" + }, + "FunctionDeclaration": { + "parameters": "off" + }, + "FunctionExpression": { + "parameters": "off" + }, + "MemberExpression": "off", + "ObjectExpression": "off", + "ImportDeclaration": "off" + } + ], + "handle-callback-err": "off", + "linebreak-style": ["error", "unix"], + "max-statements-per-line": [ + "error", + { + "max": 1 + } + ], + "new-cap": [ + "error", + { + "newIsCap": true, + "capIsNew": false + } + ], + "new-parens": "error", + "no-buffer-constructor": "error", + "no-console": "off", + "no-extra-semi": "off", + "no-fallthrough": "off", + "no-func-assign": "off", + "no-implicit-coercion": "error", + "no-multi-assign": "error", + "no-multiple-empty-lines": [ + "error", + { + "max": 1 + } + ], + "no-nested-ternary": "error", + "no-param-reassign": "off", + "no-return-assign": "error", + "no-return-await": "off", + "no-shadow-restricted-names": "error", + "no-tabs": "error", + "no-trailing-spaces": "error", + "no-unused-vars": [ + "error", + { + "vars": "all", + "args": "none", + "ignoreRestSiblings": false + } + ], + "no-use-before-define": [ + "error", + { + "functions": false, + "classes": false + } + ], + "no-useless-escape": "off", + "no-var": "error", + "nonblock-statement-body-position": ["error", "below"], + "object-curly-spacing": ["error", "always"], + "padded-blocks": ["error", "never"], + "prefer-arrow-callback": "error", + "prefer-const": [ + "error", + { + "destructuring": "all", + "ignoreReadBeforeAssign": true + } + ], + "prefer-template": "off", + "quotes": ["error", "single"], + "semi": ["error", "always"], + "spaced-comment": [ + "error", + "always", + { + "exceptions": ["!"] + } + ], + "space-before-blocks": "error", + "unicode-bom": ["error", "never"], + "valid-jsdoc": "error", + "wrap-iife": ["error", "inside"], + "react/jsx-closing-bracket-location": 1, + "react/jsx-tag-spacing": 1, + "react/jsx-max-props-per-line": ["error", { "maximum": 1, "when": "multiline" }], + "react/prop-types": 0 + } +} diff --git a/pkg/interface/CONTRIBUTING.md b/pkg/interface/CONTRIBUTING.md index efbc190ab..f054e2d89 100644 --- a/pkg/interface/CONTRIBUTING.md +++ b/pkg/interface/CONTRIBUTING.md @@ -36,6 +36,23 @@ Please also ensure your pull request fits our standards for [arvo]: /pkg/arvo [interface]:/pkg/interface +## Linting + +The Urbit interface uses Eslint to lint the JavaScript code. To install the +linter and for usage through the command, do the following: +```bash +$ cd ./pkg/interface +$ npm install +$ npm run lint +``` + +To use the linter, run npm scripts +```bash +$ npm run lint # lints all files in `interface` +$ npm run lint-file ./chat/**/*.js # lints all .js files in `interface/chat` +$ npm run lint-file ./chat/src/index.js # lints a single chosen file +``` + ### Gall Presently, Gall documentation is still in [progress][gall], but a good diff --git a/pkg/interface/chat/src/js/components/chat.js b/pkg/interface/chat/src/js/components/chat.js index 1f3d30978..e53936b79 100644 --- a/pkg/interface/chat/src/js/components/chat.js +++ b/pkg/interface/chat/src/js/components/chat.js @@ -75,8 +75,7 @@ export class ChatScreen extends Component { props.history.push("/~chat"); } else if ( - props.envelopes.length - prevProps.envelopes.length >= - 200 + props.envelopes.length >= prevProps.envelopes.length + 10 ) { this.hasAskedForMessages = false; } @@ -100,24 +99,19 @@ export class ChatScreen extends Component { } if ( - (props.length >= 100 && state.numPages * 100 >= props.length) || + props.envelopes.length >= props.length || this.hasAskedForMessages || props.length <= 0 ) { return; } - let end = props.envelopes[0].number; - if (end > 0) { - let start = end - 400 > 0 ? end - 400 : 0; - - if (start === 0 && end === 1) { - return; - } - + let start = + props.length - props.envelopes[props.envelopes.length - 1].number; + if (start > 0) { + let end = start + 300 < props.length ? start + 300 : props.length; this.hasAskedForMessages = true; - - props.subscription.fetchMessages(start, end - 1, props.station); + props.subscription.fetchMessages(start + 1, end, props.station); } } @@ -182,36 +176,29 @@ export class ChatScreen extends Component { const { props, state } = this; let messages = props.envelopes.slice(0); - let lastMsgNum = messages.length > 0 ? messages.length : 0; if (messages.length > 100 * state.numPages) { - messages = messages.slice( - messages.length - 100 * state.numPages, - messages.length - ); + messages = messages.slice(0, 100 * state.numPages); } let pendingMessages = props.pendingMessages.has(props.station) - ? props.pendingMessages.get(props.station) + ? props.pendingMessages.get(props.station).reverse() : []; pendingMessages.map(function(value) { return (value.pending = true); }); - let reversedMessages = messages.concat(pendingMessages); - reversedMessages = reversedMessages.reverse(); - - reversedMessages = reversedMessages.map((msg, i) => { + let messageElements = pendingMessages.concat(messages).map((msg, i) => { // Render sigil if previous message is not by the same sender let aut = ["author"]; let renderSigil = - _.get(reversedMessages[i + 1], aut) !== + _.get(messages[i + 1], aut) !== _.get(msg, aut, msg.author); let paddingTop = renderSigil; let paddingBot = - _.get(reversedMessages[i - 1], aut) !== + _.get(messages[i - 1], aut) !== _.get(msg, aut, msg.author); return ( @@ -288,7 +275,7 @@ export class ChatScreen extends Component { }}> { ( !(props.station in props.chatSynced) && - (reversedMessages.length > 0) + (messages.length > 0) ) ? ( ) : (
) } - {reversedMessages} + {messageElements}
2) { + if (searchTerm.length > 0) { if (this.state.inviteError === true) { this.setState({ inviteError: false }); } @@ -100,7 +100,7 @@ export class InviteSearch extends Component { let groupMatches = []; if (this.props.groupResults) { groupMatches = this.state.groups.filter(e => { - return (e[0].includes(searchTerm) || e[1].includes(searchTerm)); + return (e[0].includes(searchTerm) || e[1].toLowerCase().includes(searchTerm)); }); } @@ -127,8 +127,8 @@ export class InviteSearch extends Component { isValid = false; } - if (shipMatches.length === 0 && isValid) { - shipMatches.push(searchTerm); + if (isValid && shipMatches.findIndex(s => s === searchTerm) < 0) { + shipMatches.unshift(searchTerm); } } @@ -141,6 +141,15 @@ export class InviteSearch extends Component { this.setState({ selected: newSelection }) } + + if(searchTerm.length < 3) { + groupMatches = groupMatches.filter(([, name]) => + name.toLowerCase().split(' ').some(s => s.startsWith(searchTerm)) + ).sort((a,b) => a[1].length - b[1].length); + + shipMatches = shipMatches.slice(0,3); + } + this.setState({ searchResults: { groups: groupMatches, ships: shipMatches } }); diff --git a/pkg/interface/chat/src/js/reducers/chat-update.js b/pkg/interface/chat/src/js/reducers/chat-update.js index 7175ff628..7ded8c443 100644 --- a/pkg/interface/chat/src/js/reducers/chat-update.js +++ b/pkg/interface/chat/src/js/reducers/chat-update.js @@ -17,7 +17,7 @@ export class ChatUpdateReducer { message(json, state) { let data = _.get(json, 'message', false); if (data) { - state.inbox[data.path].envelopes.push(data.envelope); + state.inbox[data.path].envelopes.unshift(data.envelope); state.inbox[data.path].config.length = state.inbox[data.path].config.length + 1; } @@ -27,9 +27,7 @@ export class ChatUpdateReducer { let data = _.get(json, 'messages', false); if (data) { state.inbox[data.path].envelopes = - data.envelopes.concat(state.inbox[data.path].envelopes); - state.inbox[data.path].config.length = - state.inbox[data.path].config.length + data.envelopes.length; + state.inbox[data.path].envelopes.concat(data.envelopes); } } diff --git a/pkg/interface/groups/src/js/components/lib/invite-search.js b/pkg/interface/groups/src/js/components/lib/invite-search.js index 6dce2d595..adc9bcdd5 100644 --- a/pkg/interface/groups/src/js/components/lib/invite-search.js +++ b/pkg/interface/groups/src/js/components/lib/invite-search.js @@ -89,11 +89,11 @@ export class InviteSearch extends Component { this.setState({ searchValue: event.target.value }); - if (searchTerm.length < 2) { + if (searchTerm.length < 1) { this.setState({ searchResults: { groups: [], ships: [] } }); } - if (searchTerm.length > 2) { + if (searchTerm.length > 0) { if (this.state.inviteError === true) { this.setState({ inviteError: false }); } @@ -101,7 +101,7 @@ export class InviteSearch extends Component { let groupMatches = []; if (this.props.groupResults) { groupMatches = this.state.groups.filter(e => { - return e[0].includes(searchTerm) || e[1].includes(searchTerm); + return e[0].includes(searchTerm) || e[1].toLowerCase().includes(searchTerm); }); } @@ -128,8 +128,8 @@ export class InviteSearch extends Component { isValid = false; } - if (shipMatches.length === 0 && isValid) { - shipMatches.push(searchTerm); + if (isValid && shipMatches.findIndex(s => s === searchTerm) < 0) { + shipMatches.unshift(searchTerm); } } @@ -142,6 +142,15 @@ export class InviteSearch extends Component { this.setState({ selected: newSelection }) } + + if(searchTerm.length < 3) { + groupMatches = groupMatches.filter(([, name]) => + name.toLowerCase().split(' ').some(s => s.startsWith(searchTerm)) + ).sort((a,b) => a[1].length - b[1].length); + + shipMatches = shipMatches.slice(0,3); + } + this.setState({ searchResults: { groups: groupMatches, ships: shipMatches } }); diff --git a/pkg/interface/link/src/js/components/lib/invite-search.js b/pkg/interface/link/src/js/components/lib/invite-search.js index 734639e38..f1d0fc3fb 100644 --- a/pkg/interface/link/src/js/components/lib/invite-search.js +++ b/pkg/interface/link/src/js/components/lib/invite-search.js @@ -89,11 +89,11 @@ export class InviteSearch extends Component { this.setState({ searchValue: event.target.value }); - if (searchTerm.length < 2) { + if (searchTerm.length < 1) { this.setState({ searchResults: { groups: [], ships: [] } }); } - if (searchTerm.length > 2) { + if (searchTerm.length > 0) { if (this.state.inviteError === true) { this.setState({ inviteError: false }); } @@ -101,7 +101,7 @@ export class InviteSearch extends Component { let groupMatches = []; if (this.props.groupResults) { groupMatches = this.state.groups.filter(e => { - return e[0].includes(searchTerm) || e[1].includes(searchTerm); + return e[0].includes(searchTerm) || e[1].toLowerCase().includes(searchTerm); }); } @@ -128,8 +128,8 @@ export class InviteSearch extends Component { isValid = false; } - if (shipMatches.length === 0 && isValid) { - shipMatches.push(searchTerm); + if (isValid && shipMatches.findIndex(s => s === searchTerm) < 0) { + shipMatches.unshift(searchTerm); } } @@ -142,6 +142,14 @@ export class InviteSearch extends Component { this.setState({ selected: newSelection }) } + if(searchTerm.length < 3) { + groupMatches = groupMatches.filter(([, name]) => + name.toLowerCase().split(' ').some(s => s.startsWith(searchTerm)) + ).sort((a,b) => a[1].length - b[1].length); + + shipMatches = shipMatches.slice(0,3); + } + this.setState({ searchResults: { groups: groupMatches, ships: shipMatches } }); diff --git a/pkg/interface/package-lock.json b/pkg/interface/package-lock.json new file mode 100644 index 000000000..a207f6043 --- /dev/null +++ b/pkg/interface/package-lock.json @@ -0,0 +1,1603 @@ +{ + "name": "interface", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/generator": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.5.tgz", + "integrity": "sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ==", + "dev": true, + "requires": { + "@babel/types": "^7.9.5", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz", + "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.9.5" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", + "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", + "dev": true + }, + "@babel/highlight": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", + "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.9.0", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz", + "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==", + "dev": true + }, + "@babel/runtime-corejs3": { + "version": "7.9.2", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.9.2.tgz", + "integrity": "sha512-HHxmgxbIzOfFlZ+tdeRKtaxWOMUoCG5Mu3wKeUmOxjYrwb3AAHgnmtCUbPPK11/raIWLIBK250t8E2BPO0p7jA==", + "dev": true, + "requires": { + "core-js-pure": "^3.0.0", + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" + } + }, + "@babel/traverse": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.5.tgz", + "integrity": "sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.5", + "@babel/helper-function-name": "^7.9.5", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.9.0", + "@babel/types": "^7.9.5", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz", + "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.9.5", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "acorn": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", + "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==", + "dev": true + }, + "acorn-jsx": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", + "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "dev": true + }, + "ajv": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", + "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + }, + "dependencies": { + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true + } + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-includes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + } + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "core-js-pure": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.4.tgz", + "integrity": "sha512-epIhRLkXdgv32xIUFaaAry2wdxZYBi6bgM7cB136dzzXXa+dFyRLTZeLUJxnd8ShrmyVXBub63n2NHo2JAt8Cw==", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + } + } + }, + "eslint-plugin-react": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz", + "integrity": "sha512-SPT8j72CGuAP+JFbT0sJHOB80TX/pu44gQ4vXH/cq+hQTiY2PuZ6IHkqXJV6x1b28GDdo1lbInjKUrrdUf0LOQ==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.2.3", + "object.entries": "^1.1.1", + "object.fromentries": "^2.0.2", + "object.values": "^1.1.1", + "prop-types": "^15.7.2", + "resolve": "^1.15.1", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.2", + "xregexp": "^4.3.0" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + } + } + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.2.0.tgz", + "integrity": "sha512-weltsSqdeWIX9G2qQZz7KlTRJdkkOCTPgLYJUz1Hacf48R4YOwGPHO3+ORfWedqJKbq5WQmsgK90n+pFLIKt/Q==", + "dev": true, + "requires": { + "estraverse": "^5.0.0" + }, + "dependencies": { + "estraverse": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.0.0.tgz", + "integrity": "sha512-j3acdrMzqrxmJTNj5dbr1YbjacrYgAxVMeF0gK16E3j494mOe7xygM/ZLIguEQ0ETwAg2hlJCtHRGav+y0Ny5A==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "fast-deep-equal": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "inquirer": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz", + "integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^3.0.0", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "internal-slot": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.2.tgz", + "integrity": "sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g==", + "dev": true, + "requires": { + "es-abstract": "^1.17.0-next.1", + "has": "^1.0.3", + "side-channel": "^1.0.2" + } + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "jsx-ast-utils": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.2.3.tgz", + "integrity": "sha512-EdIHFMm+1BPynpKOpdPqiOsvnIrInRGJD7bzPZdPkjitQEqpdpUuFpq4T0npZFKTiB3RhWFdGN+oqOJIdhDhQA==", + "dev": true, + "requires": { + "array-includes": "^3.0.3", + "object.assign": "^4.1.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.entries": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.1.tgz", + "integrity": "sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "object.fromentries": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.2.tgz", + "integrity": "sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", + "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==", + "dev": true + }, + "regexp.prototype.flags": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", + "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "resolve": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-async": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.0.tgz", + "integrity": "sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg==", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "rxjs": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz", + "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "side-channel": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.2.tgz", + "integrity": "sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA==", + "dev": true, + "requires": { + "es-abstract": "^1.17.0-next.1", + "object-inspect": "^1.7.0" + } + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "string.prototype.matchall": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.2.tgz", + "integrity": "sha512-N/jp6O5fMf9os0JU3E72Qhf590RSRZU/ungsL/qJUYVTNv7hTG0P/dbPjxINVN9jpscu3nzYwKESU3P3RY5tOg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "has-symbols": "^1.0.1", + "internal-slot": "^1.0.2", + "regexp.prototype.flags": "^1.3.0", + "side-channel": "^1.0.2" + } + }, + "string.prototype.trimend": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.0.tgz", + "integrity": "sha512-EEJnGqa/xNfIg05SxiPSqRS7S9qwDhYts1TSLR1BQfYUfPe1stofgGKvwERK9+9yf+PpfBMlpBaCHucXGPQfUA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimleft": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" + } + }, + "string.prototype.trimright": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + } + }, + "string.prototype.trimstart": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.0.tgz", + "integrity": "sha512-iCP8g01NFYiiBOnwG1Xc3WZLyoo+RuBymwIlWncShXDDJYWN6DbnM3odslBJdgCdRlq94B5s63NWAZlcn2CS4w==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + }, + "strip-json-comments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", + "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "xregexp": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.3.0.tgz", + "integrity": "sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g==", + "dev": true, + "requires": { + "@babel/runtime-corejs3": "^7.8.3" + } + } + } +} diff --git a/pkg/interface/package.json b/pkg/interface/package.json new file mode 100644 index 000000000..ab3d2893a --- /dev/null +++ b/pkg/interface/package.json @@ -0,0 +1,19 @@ +{ + "name": "interface", + "version": "1.0.0", + "description": "", + "main": "index.js", + "dependencies": {}, + "devDependencies": { + "babel-eslint": "^10.1.0", + "eslint": "^6.8.0", + "eslint-plugin-react": "^7.19.0" + }, + "scripts": { + "lint": "eslint ./**/*.js", + "lint-file": "eslint", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} diff --git a/pkg/interface/publish/package-lock.json b/pkg/interface/publish/package-lock.json index 1078d32ec..c849cf82b 100644 --- a/pkg/interface/publish/package-lock.json +++ b/pkg/interface/publish/package-lock.json @@ -3764,6 +3764,11 @@ "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" }, + "mousetrap": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/mousetrap/-/mousetrap-1.6.5.tgz", + "integrity": "sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA==" + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", diff --git a/pkg/interface/publish/package.json b/pkg/interface/publish/package.json index 5dfdec94a..fe5d43f5f 100644 --- a/pkg/interface/publish/package.json +++ b/pkg/interface/publish/package.json @@ -32,6 +32,7 @@ "del": "^5.1.0", "lodash": "^4.17.11", "moment": "^2.20.1", + "mousetrap": "^1.6.5", "react": "^16.5.2", "react-codemirror2": "^6.0.0", "react-dom": "^16.8.6", diff --git a/pkg/interface/publish/src/js/components/lib/invite-search.js b/pkg/interface/publish/src/js/components/lib/invite-search.js index 6f8063b69..a15971102 100644 --- a/pkg/interface/publish/src/js/components/lib/invite-search.js +++ b/pkg/interface/publish/src/js/components/lib/invite-search.js @@ -89,11 +89,11 @@ export class InviteSearch extends Component { this.setState({ searchValue: event.target.value }); - if (searchTerm.length < 2) { + if (searchTerm.length < 1) { this.setState({ searchResults: { groups: [], ships: [] } }); } - if (searchTerm.length > 2) { + if (searchTerm.length > 0) { if (this.state.inviteError === true) { this.setState({ inviteError: false }); } @@ -101,7 +101,7 @@ export class InviteSearch extends Component { let groupMatches = []; if (this.props.groupResults) { groupMatches = this.state.groups.filter(e => { - return e[0].includes(searchTerm) || e[1].includes(searchTerm); + return e[0].includes(searchTerm) || e[1].toLowerCase().includes(searchTerm); }); } @@ -128,8 +128,8 @@ export class InviteSearch extends Component { isValid = false; } - if (shipMatches.length === 0 && isValid) { - shipMatches.push(searchTerm); + if (isValid && shipMatches.findIndex(s => s === searchTerm) < 0) { + shipMatches.unshift(searchTerm); } } @@ -142,6 +142,14 @@ export class InviteSearch extends Component { this.setState({ selected: newSelection }) } + if(searchTerm.length < 3) { + groupMatches = groupMatches.filter(([, name]) => + name.toLowerCase().split(' ').some(s => s.startsWith(searchTerm)) + ).sort((a,b) => a[1].length - b[1].length); + + shipMatches = shipMatches.slice(0,3); + } + this.setState({ searchResults: { groups: groupMatches, ships: shipMatches } }); diff --git a/pkg/interface/publish/src/js/reducers/primary.js b/pkg/interface/publish/src/js/reducers/primary.js index bed201e8a..b483746c6 100644 --- a/pkg/interface/publish/src/js/reducers/primary.js +++ b/pkg/interface/publish/src/js/reducers/primary.js @@ -60,18 +60,22 @@ export class PrimaryReducer { let book = Object.keys(json[host])[0]; let noteId = json[host][book]["note-id"]; if (state.notebooks[host] && state.notebooks[host][book]) { - if (state.notebooks[host][book]["notes-by-date"]) { - state.notebooks[host][book]["notes-by-date"].unshift(noteId); - } else { - state.notebooks[host][book]["notes-by-date"] = [noteId]; - } - if (state.notebooks[host][book].notes) { + if (state.notebooks[host][book].notes[noteId] && + state.notebooks[host][book].notes[noteId].pending) + { + state.notebooks[host][book].notes[noteId].pending = false; + return; + } + if (state.notebooks[host][book]["notes-by-date"]) { + state.notebooks[host][book]["notes-by-date"].unshift(noteId); + } else { + state.notebooks[host][book]["notes-by-date"] = [noteId]; + } state.notebooks[host][book].notes[noteId] = json[host][book]; } else { state.notebooks[host][book].notes = {[noteId]: json[host][book]}; } - state.notebooks[host][book]["num-notes"] += 1; if (!json[host][book].read) { state.notebooks[host][book]["num-unread"] += 1; @@ -79,7 +83,6 @@ export class PrimaryReducer { let prevNoteId = state.notebooks[host][book]["notes-by-date"][1] || null; state.notebooks[host][book].notes[noteId]["prev-note"] = prevNoteId state.notebooks[host][book].notes[noteId]["next-note"] = null; - if (state.notebooks[host][book].notes[prevNoteId]) { state.notebooks[host][book].notes[prevNoteId]["next-note"] = noteId; } @@ -96,10 +99,26 @@ export class PrimaryReducer { state.notebooks[host][book].notes && state.notebooks[host][book].notes[note]) { - state.notebooks[host][book].notes[note]["num-comments"] += 1; + if (state.notebooks[host][book].notes[note].comments) { - state.notebooks[host][book].notes[note].comments.unshift(comment); + let limboCommentIdx = + _.findIndex(state.notebooks[host][book].notes[note].comments, (o) => { + let oldVal = o[Object.keys(o)[0]]; + let newVal = comment[Object.keys(comment)[0]]; + return (oldVal.pending && + (oldVal.author === newVal.author) && + (oldVal.content === newVal.content) + ); + }); + if (limboCommentIdx === -1) { + state.notebooks[host][book].notes[note]["num-comments"] += 1; + state.notebooks[host][book].notes[note].comments.unshift(comment); + } else { + state.notebooks[host][book].notes[note].comments[limboCommentIdx] = + comment; + } } else if (state.notebooks[host][book].notes[note]["num-comments"] === 1) { + state.notebooks[host][book].notes[note]["num-comments"] += 1; state.notebooks[host][book].notes[note].comments = [comment]; } }