-- SPDX-FileCopyrightText: 2026 Alexandra de Wit
--
-- SPDX-License-Identifier: MIT
{-# LANGUAGE TypeFamilies #-}

{- | The packument walk for full and selected reads. It emits the fields that
"Ecluse.Core.Registry.Npm.Streaming" emits for the same mode, in the same order, and builds each
retained release once with its keys and strings interned as read.
-}
module Ecluse.Core.Registry.Npm.Reader (
    PackumentRead (..),
    npmWalk,
    releaseUniqueFields,
) where

import Data.Aeson (Value (Null))
import Data.JsonStream.TokenParser (Element (..), TokenResult)

import Ecluse.Core.Registry.Json.Intern (InternTable, Interned (..), entryText, internName, nameBytes, nameText)
import Ecluse.Core.Registry.Json.Shape (Build (..), Members, Mode (..), Shape (..), Trees (..), everyMember, namedMembers, readShape)
import Ecluse.Core.Registry.Json.Walk (FieldStep, Walk (..), Walked (..), eachMember, skipFrom, skipRest, tooDeep, withElement)
import Ecluse.Core.Registry.Json.Walk qualified as Walk
import Ecluse.Core.Registry.Npm.Streaming (NpmContainer (..), NpmFieldOf (..), versionFields)

-- | The whole packument, or one release with its timestamp and the latest tag.
data PackumentRead = WholePackument | OneRelease Text
    deriving stock (PackumentRead -> PackumentRead -> Bool
(PackumentRead -> PackumentRead -> Bool)
-> (PackumentRead -> PackumentRead -> Bool) -> Eq PackumentRead
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PackumentRead -> PackumentRead -> Bool
== :: PackumentRead -> PackumentRead -> Bool
$c/= :: PackumentRead -> PackumentRead -> Bool
/= :: PackumentRead -> PackumentRead -> Bool
Eq, Int -> PackumentRead -> ShowS
[PackumentRead] -> ShowS
PackumentRead -> String
(Int -> PackumentRead -> ShowS)
-> (PackumentRead -> String)
-> ([PackumentRead] -> ShowS)
-> Show PackumentRead
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PackumentRead -> ShowS
showsPrec :: Int -> PackumentRead -> ShowS
$cshow :: PackumentRead -> String
show :: PackumentRead -> String
$cshowList :: [PackumentRead] -> ShowS
showList :: [PackumentRead] -> ShowS
Show)

{- | Members whose values differ in every release, so the table keeps them as read. A name matches
at any depth, so a rarer member such as @_npmUser.url@ is kept as read too.
-}
releaseUniqueFields :: [Text]
releaseUniqueFields :: [Text]
releaseUniqueFields = [Text
"tarball", Text
"shasum", Text
"integrity", Text
"sig", Text
"url"]

{- | Walk one packument into the builder, passing each field to the step as it completes. Only a
release the consumer keeps enters the table, and only the first of each member it repeats.
-}
npmWalk :: (Build b r, Result r ~ Walked s) => b -> Int -> PackumentRead -> FieldStep s (NpmFieldOf (Built b)) r -> (s -> Text -> Bool) -> InternTable -> s -> TokenResult -> r
{-# INLINE npmWalk #-}
npmWalk :: forall b r s.
(Build b r, Result r ~ Walked s) =>
b
-> Int
-> PackumentRead
-> FieldStep s (NpmFieldOf (Built b)) r
-> (s -> Text -> Bool)
-> InternTable
-> s
-> TokenResult
-> r
npmWalk b
build Int
depth PackumentRead
mode FieldStep s (NpmFieldOf (Built b)) r
step s -> Text -> Bool
keeps InternTable
table0 s
initial = TokenResult -> r
start
  where
    start :: TokenResult -> r
start TokenResult
tokens
        | Int
depth Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 = TokenResult -> (Element -> TokenResult -> r) -> r
forall r.
Walk r =>
TokenResult -> (Element -> TokenResult -> r) -> r
withElement TokenResult
tokens Element -> TokenResult -> r
forall r. Walk r => Element -> TokenResult -> r
tooDeep
        | Bool
otherwise = TokenResult -> (Element -> TokenResult -> r) -> r
forall r.
Walk r =>
TokenResult -> (Element -> TokenResult -> r) -> r
withElement TokenResult
tokens ((Element -> TokenResult -> r) -> r)
-> (Element -> TokenResult -> r) -> r
forall a b. (a -> b) -> a -> b
$ \Element
element TokenResult
rest -> case Element
element of
            Element
ObjectBegin -> (Walked s
 -> Name -> TokenResult -> (Walked s -> TokenResult -> r) -> r)
-> (Walked s -> TokenResult -> r) -> Walked s -> TokenResult -> r
forall r st.
Walk r =>
(st -> Name -> TokenResult -> (st -> TokenResult -> r) -> r)
-> (st -> TokenResult -> r) -> st -> TokenResult -> r
eachMember Walked s
-> Name -> TokenResult -> (Walked s -> TokenResult -> r) -> r
topField (\Walked s
walked TokenResult
_ -> Result r -> r
forall r. Walk r => Result r -> r
finish Walked s
Result r
walked) (InternTable -> s -> Walked s
forall s. InternTable -> s -> Walked s
Walked InternTable
table0 s
initial) TokenResult
rest
            Element
_ -> Element -> TokenResult -> (TokenResult -> r) -> r
forall r.
Walk r =>
Element -> TokenResult -> (TokenResult -> r) -> r
skipFrom Element
element TokenResult
rest (r -> TokenResult -> r
forall a b. a -> b -> a
const (Result r -> r
forall r. Walk r => Result r -> r
finish (InternTable -> s -> Walked s
forall s. InternTable -> s -> Walked s
Walked InternTable
table0 s
initial)))
    topField :: Walked s
-> Name -> TokenResult -> (Walked s -> TokenResult -> r) -> r
topField (Walked InternTable
table s
acc) Name
name TokenResult
after Walked s -> TokenResult -> r
continue = case Name -> ByteString
nameBytes Name
name of
        ByteString
"name" -> TokenResult -> (Element -> TokenResult -> r) -> r
forall r.
Walk r =>
TokenResult -> (Element -> TokenResult -> r) -> r
withElement TokenResult
after ((Element -> TokenResult -> r) -> r)
-> (Element -> TokenResult -> r) -> r
forall a b. (a -> b) -> a -> b
$ \Element
element TokenResult
rest ->
            Trees
-> Shape
-> Mode
-> InternTable
-> Element
-> TokenResult
-> (Built Trees -> InternTable -> TokenResult -> r)
-> r
forall b r.
Build b r =>
b
-> Shape
-> Mode
-> InternTable
-> Element
-> TokenResult
-> (Built b -> InternTable -> TokenResult -> r)
-> r
readShape Trees
Trees (Int -> Shape
Scalar (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)) Mode
Keep InternTable
table Element
element TokenResult
rest ((Built Trees -> InternTable -> TokenResult -> r) -> r)
-> (Built Trees -> InternTable -> TokenResult -> r) -> r
forall a b. (a -> b) -> a -> b
$ \Built Trees
field InternTable
_ TokenResult
afterValue ->
                s -> NpmFieldOf (Built b) -> (s -> r) -> r
emit s
acc (Value -> NpmFieldOf (Built b)
forall release. Value -> NpmFieldOf release
NameField Value
Built Trees
field) (\s
acc' -> Walked s -> TokenResult -> r
continue (InternTable -> s -> Walked s
forall s. InternTable -> s -> Walked s
Walked InternTable
table s
acc') TokenResult
afterValue)
        ByteString
"versions" -> NpmContainer
-> InternTable
-> s
-> TokenResult
-> (Walked s -> TokenResult -> r)
-> (s -> TokenResult -> (Walked s -> TokenResult -> r) -> r)
-> r
container NpmContainer
VersionsContainer InternTable
table s
acc TokenResult
after Walked s -> TokenResult -> r
continue (InternTable
-> s -> TokenResult -> (Walked s -> TokenResult -> r) -> r
releases InternTable
table)
        ByteString
"time" -> NpmContainer
-> InternTable
-> s
-> TokenResult
-> (Walked s -> TokenResult -> r)
-> (s -> TokenResult -> (Walked s -> TokenResult -> r) -> r)
-> r
container NpmContainer
TimeContainer InternTable
table s
acc TokenResult
after Walked s -> TokenResult -> r
continue ((s -> TokenResult -> (Walked s -> TokenResult -> r) -> r) -> r)
-> (s -> TokenResult -> (Walked s -> TokenResult -> r) -> r) -> r
forall a b. (a -> b) -> a -> b
$ case PackumentRead
mode of
            PackumentRead
WholePackument -> (Text -> Value -> NpmFieldOf (Built b))
-> InternTable
-> s
-> TokenResult
-> (Walked s -> TokenResult -> r)
-> r
everyScalar Text -> Value -> NpmFieldOf (Built b)
forall release. Text -> Value -> NpmFieldOf release
TimeField InternTable
table
            OneRelease Text
version -> ByteString
-> (Value -> NpmFieldOf (Built b))
-> InternTable
-> s
-> TokenResult
-> (Walked s -> TokenResult -> r)
-> r
oneScalar (Text -> ByteString
forall a b. ConvertUtf8 a b => a -> b
encodeUtf8 Text
version) (Text -> Value -> NpmFieldOf (Built b)
forall release. Text -> Value -> NpmFieldOf release
TimeField Text
version) InternTable
table
        ByteString
"dist-tags" -> NpmContainer
-> InternTable
-> s
-> TokenResult
-> (Walked s -> TokenResult -> r)
-> (s -> TokenResult -> (Walked s -> TokenResult -> r) -> r)
-> r
container NpmContainer
TagsContainer InternTable
table s
acc TokenResult
after Walked s -> TokenResult -> r
continue ((s -> TokenResult -> (Walked s -> TokenResult -> r) -> r) -> r)
-> (s -> TokenResult -> (Walked s -> TokenResult -> r) -> r) -> r
forall a b. (a -> b) -> a -> b
$ case PackumentRead
mode of
            PackumentRead
WholePackument -> (Text -> Value -> NpmFieldOf (Built b))
-> InternTable
-> s
-> TokenResult
-> (Walked s -> TokenResult -> r)
-> r
everyScalar Text -> Value -> NpmFieldOf (Built b)
forall release. Text -> Value -> NpmFieldOf release
TagField InternTable
table
            OneRelease Text
_ -> ByteString
-> (Value -> NpmFieldOf (Built b))
-> InternTable
-> s
-> TokenResult
-> (Walked s -> TokenResult -> r)
-> r
oneScalar ByteString
"latest" (Text -> Value -> NpmFieldOf (Built b)
forall release. Text -> Value -> NpmFieldOf release
TagField Text
"latest") InternTable
table
        ByteString
_ -> TokenResult -> (Element -> TokenResult -> r) -> r
forall r.
Walk r =>
TokenResult -> (Element -> TokenResult -> r) -> r
withElement TokenResult
after ((Element -> TokenResult -> r) -> r)
-> (Element -> TokenResult -> r) -> r
forall a b. (a -> b) -> a -> b
$ \Element
element TokenResult
afterKey -> Element -> TokenResult -> (TokenResult -> r) -> r
forall r.
Walk r =>
Element -> TokenResult -> (TokenResult -> r) -> r
skipFrom Element
element TokenResult
afterKey (Walked s -> TokenResult -> r
continue (InternTable -> s -> Walked s
forall s. InternTable -> s -> Walked s
Walked InternTable
table s
acc))
    emit :: s -> NpmFieldOf (Built b) -> (s -> r) -> r
emit = FieldStep s (NpmFieldOf (Built b)) r
-> s -> NpmFieldOf (Built b) -> (s -> r) -> r
forall r s field.
Walk r =>
FieldStep s field r -> s -> field -> (s -> r) -> r
Walk.emit FieldStep s (NpmFieldOf (Built b)) r
step
    target :: Maybe ByteString
target = case PackumentRead
mode of
        OneRelease Text
version -> ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (Text -> ByteString
forall a b. ConvertUtf8 a b => a -> b
encodeUtf8 Text
version)
        PackumentRead
WholePackument -> Maybe ByteString
forall a. Maybe a
Nothing

    -- A container's first object claims it. Null claims it empty, and any other value marks it invalid.
    container :: NpmContainer
-> InternTable
-> s
-> TokenResult
-> (Walked s -> TokenResult -> r)
-> (s -> TokenResult -> (Walked s -> TokenResult -> r) -> r)
-> r
container NpmContainer
slot InternTable
table s
acc TokenResult
after Walked s -> TokenResult -> r
continue s -> TokenResult -> (Walked s -> TokenResult -> r) -> r
inner = TokenResult -> (Element -> TokenResult -> r) -> r
forall r.
Walk r =>
TokenResult -> (Element -> TokenResult -> r) -> r
withElement TokenResult
after ((Element -> TokenResult -> r) -> r)
-> (Element -> TokenResult -> r) -> r
forall a b. (a -> b) -> a -> b
$ \Element
element TokenResult
rest ->
        if Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0
            then Element -> TokenResult -> r
forall r. Walk r => Element -> TokenResult -> r
tooDeep Element
element TokenResult
rest
            else case Element
element of
                Element
ObjectBegin -> s -> NpmFieldOf (Built b) -> (s -> r) -> r
emit s
acc (NpmContainer -> NpmFieldOf (Built b)
forall release. NpmContainer -> NpmFieldOf release
BeginContainer NpmContainer
slot) ((s -> r) -> r) -> (s -> r) -> r
forall a b. (a -> b) -> a -> b
$ \s
begun ->
                    s -> TokenResult -> (Walked s -> TokenResult -> r) -> r
inner s
begun TokenResult
rest ((Walked s -> TokenResult -> r) -> r)
-> (Walked s -> TokenResult -> r) -> r
forall a b. (a -> b) -> a -> b
$ \(Walked InternTable
table' s
acc') TokenResult
afterObject ->
                        s -> NpmFieldOf (Built b) -> (s -> r) -> r
emit s
acc' NpmFieldOf (Built b)
forall release. NpmFieldOf release
IgnoredField (\s
ended -> Walked s -> TokenResult -> r
continue (InternTable -> s -> Walked s
forall s. InternTable -> s -> Walked s
Walked InternTable
table' s
ended) TokenResult
afterObject)
                JValue Value
Null -> s -> NpmFieldOf (Built b) -> (s -> r) -> r
emit s
acc (NpmContainer -> NpmFieldOf (Built b)
forall release. NpmContainer -> NpmFieldOf release
BeginContainer NpmContainer
slot) (\s
begun -> Walked s -> TokenResult -> r
continue (InternTable -> s -> Walked s
forall s. InternTable -> s -> Walked s
Walked InternTable
table s
begun) TokenResult
rest)
                Element
_ -> Element -> TokenResult -> (TokenResult -> r) -> r
forall r.
Walk r =>
Element -> TokenResult -> (TokenResult -> r) -> r
skipFrom Element
element TokenResult
rest (\TokenResult
afterValue -> s -> NpmFieldOf (Built b) -> (s -> r) -> r
emit s
acc (NpmContainer -> NpmFieldOf (Built b)
forall release. NpmContainer -> NpmFieldOf release
InvalidContainer NpmContainer
slot) (\s
marked -> Walked s -> TokenResult -> r
continue (InternTable -> s -> Walked s
forall s. InternTable -> s -> Walked s
Walked InternTable
table s
marked) TokenResult
afterValue))

    releases :: InternTable
-> s -> TokenResult -> (Walked s -> TokenResult -> r) -> r
releases InternTable
table s
acc TokenResult
rest Walked s -> TokenResult -> r
done = (Walked s
 -> Name -> TokenResult -> (Walked s -> TokenResult -> r) -> r)
-> (Walked s -> TokenResult -> r) -> Walked s -> TokenResult -> r
forall r st.
Walk r =>
(st -> Name -> TokenResult -> (st -> TokenResult -> r) -> r)
-> (st -> TokenResult -> r) -> st -> TokenResult -> r
eachMember Walked s
-> Name -> TokenResult -> (Walked s -> TokenResult -> r) -> r
release Walked s -> TokenResult -> r
done (InternTable -> s -> Walked s
forall s. InternTable -> s -> Walked s
Walked InternTable
table s
acc) TokenResult
rest
    release :: Walked s
-> Name -> TokenResult -> (Walked s -> TokenResult -> r) -> r
release (Walked InternTable
table s
acc) Name
key TokenResult
after Walked s -> TokenResult -> r
continue = case Maybe ByteString
target of
        Just ByteString
wanted | Name -> ByteString
nameBytes Name
key ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
/= ByteString
wanted -> TokenResult -> (Element -> TokenResult -> r) -> r
forall r.
Walk r =>
TokenResult -> (Element -> TokenResult -> r) -> r
withElement TokenResult
after ((Element -> TokenResult -> r) -> r)
-> (Element -> TokenResult -> r) -> r
forall a b. (a -> b) -> a -> b
$ \Element
element TokenResult
rest ->
            Element -> TokenResult -> (TokenResult -> r) -> r
forall r.
Walk r =>
Element -> TokenResult -> (TokenResult -> r) -> r
skipFrom Element
element TokenResult
rest (\TokenResult
afterValue -> s -> NpmFieldOf (Built b) -> (s -> r) -> r
emit s
acc (Text -> Maybe (Built b) -> NpmFieldOf (Built b)
forall release. Text -> Maybe release -> NpmFieldOf release
VersionField Text
"" Maybe (Built b)
forall a. Maybe a
Nothing) (\s
acc' -> Walked s -> TokenResult -> r
continue (InternTable -> s -> Walked s
forall s. InternTable -> s -> Walked s
Walked InternTable
table s
acc') TokenResult
afterValue))
        Maybe ByteString
_
            | s -> Text -> Bool
keeps s
acc Text
text -> case Name -> InternTable -> Interned
internName Name
key InternTable
table of
                Interned Entry
entry InternTable
keyed -> TokenResult -> (Element -> TokenResult -> r) -> r
forall r.
Walk r =>
TokenResult -> (Element -> TokenResult -> r) -> r
withElement TokenResult
after ((Element -> TokenResult -> r) -> r)
-> (Element -> TokenResult -> r) -> r
forall a b. (a -> b) -> a -> b
$ \Element
element TokenResult
rest ->
                    b
-> Shape
-> Mode
-> InternTable
-> Element
-> TokenResult
-> (Built b -> InternTable -> TokenResult -> r)
-> r
forall b r.
Build b r =>
b
-> Shape
-> Mode
-> InternTable
-> Element
-> TokenResult
-> (Built b -> InternTable -> TokenResult -> r)
-> r
readShape b
build Shape
releaseShape Mode
Share InternTable
keyed Element
element TokenResult
rest ((Built b -> InternTable -> TokenResult -> r) -> r)
-> (Built b -> InternTable -> TokenResult -> r) -> r
forall a b. (a -> b) -> a -> b
$ \Built b
release' InternTable
table' TokenResult
afterValue ->
                        s -> NpmFieldOf (Built b) -> (s -> r) -> r
emit s
acc (Text -> Maybe (Built b) -> NpmFieldOf (Built b)
forall release. Text -> Maybe release -> NpmFieldOf release
VersionField (Entry -> Text
entryText Entry
entry) (Built b -> Maybe (Built b)
forall a. a -> Maybe a
Just Built b
release')) (\s
acc' -> Walked s -> TokenResult -> r
continue (InternTable -> s -> Walked s
forall s. InternTable -> s -> Walked s
Walked InternTable
table' s
acc') TokenResult
afterValue)
            | Bool
otherwise -> TokenResult -> (Element -> TokenResult -> r) -> r
forall r.
Walk r =>
TokenResult -> (Element -> TokenResult -> r) -> r
withElement TokenResult
after ((Element -> TokenResult -> r) -> r)
-> (Element -> TokenResult -> r) -> r
forall a b. (a -> b) -> a -> b
$ \Element
element TokenResult
rest ->
                b
-> Shape
-> Mode
-> InternTable
-> Element
-> TokenResult
-> (Built b -> InternTable -> TokenResult -> r)
-> r
forall b r.
Build b r =>
b
-> Shape
-> Mode
-> InternTable
-> Element
-> TokenResult
-> (Built b -> InternTable -> TokenResult -> r)
-> r
readShape b
build Shape
releaseShape Mode
Keep InternTable
table Element
element TokenResult
rest ((Built b -> InternTable -> TokenResult -> r) -> r)
-> (Built b -> InternTable -> TokenResult -> r) -> r
forall a b. (a -> b) -> a -> b
$ \Built b
release' InternTable
_ TokenResult
afterValue ->
                    s -> NpmFieldOf (Built b) -> (s -> r) -> r
emit s
acc (Text -> Maybe (Built b) -> NpmFieldOf (Built b)
forall release. Text -> Maybe release -> NpmFieldOf release
VersionField Text
text (Built b -> Maybe (Built b)
forall a. a -> Maybe a
Just Built b
release')) (\s
acc' -> Walked s -> TokenResult -> r
continue (InternTable -> s -> Walked s
forall s. InternTable -> s -> Walked s
Walked InternTable
table s
acc') TokenResult
afterValue)
      where
        text :: Text
text = Name -> Text
nameText Name
key

    everyScalar :: (Text -> Value -> NpmFieldOf (Built b))
-> InternTable
-> s
-> TokenResult
-> (Walked s -> TokenResult -> r)
-> r
everyScalar Text -> Value -> NpmFieldOf (Built b)
field InternTable
table s
acc TokenResult
rest Walked s -> TokenResult -> r
done = (Walked s
 -> Name -> TokenResult -> (Walked s -> TokenResult -> r) -> r)
-> (Walked s -> TokenResult -> r) -> Walked s -> TokenResult -> r
forall r st.
Walk r =>
(st -> Name -> TokenResult -> (st -> TokenResult -> r) -> r)
-> (st -> TokenResult -> r) -> st -> TokenResult -> r
eachMember ((Text -> Value -> NpmFieldOf (Built b))
-> Walked s
-> Name
-> TokenResult
-> (Walked s -> TokenResult -> r)
-> r
timestamp Text -> Value -> NpmFieldOf (Built b)
field) Walked s -> TokenResult -> r
done (InternTable -> s -> Walked s
forall s. InternTable -> s -> Walked s
Walked InternTable
table s
acc) TokenResult
rest
    timestamp :: (Text -> Value -> NpmFieldOf (Built b))
-> Walked s
-> Name
-> TokenResult
-> (Walked s -> TokenResult -> r)
-> r
timestamp Text -> Value -> NpmFieldOf (Built b)
field (Walked InternTable
table s
acc) Name
key TokenResult
after Walked s -> TokenResult -> r
continue = TokenResult -> (Element -> TokenResult -> r) -> r
forall r.
Walk r =>
TokenResult -> (Element -> TokenResult -> r) -> r
withElement TokenResult
after ((Element -> TokenResult -> r) -> r)
-> (Element -> TokenResult -> r) -> r
forall a b. (a -> b) -> a -> b
$ \Element
element TokenResult
rest ->
        Trees
-> Shape
-> Mode
-> InternTable
-> Element
-> TokenResult
-> (Built Trees -> InternTable -> TokenResult -> r)
-> r
forall b r.
Build b r =>
b
-> Shape
-> Mode
-> InternTable
-> Element
-> TokenResult
-> (Built b -> InternTable -> TokenResult -> r)
-> r
readShape Trees
Trees (Int -> Shape
Scalar (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2)) Mode
Keep InternTable
table Element
element TokenResult
rest ((Built Trees -> InternTable -> TokenResult -> r) -> r)
-> (Built Trees -> InternTable -> TokenResult -> r) -> r
forall a b. (a -> b) -> a -> b
$ \Built Trees
scalar InternTable
_ TokenResult
afterValue ->
            s -> NpmFieldOf (Built b) -> (s -> r) -> r
emit s
acc (Text -> Value -> NpmFieldOf (Built b)
field (Name -> Text
nameText Name
key) Value
Built Trees
scalar) (\s
acc' -> Walked s -> TokenResult -> r
continue (InternTable -> s -> Walked s
forall s. InternTable -> s -> Walked s
Walked InternTable
table s
acc') TokenResult
afterValue)

    -- json-stream's objectWithKey: the first match yields, and the rest of the object is skipped unread.
    oneScalar :: ByteString
-> (Value -> NpmFieldOf (Built b))
-> InternTable
-> s
-> TokenResult
-> (Walked s -> TokenResult -> r)
-> r
oneScalar ByteString
wanted Value -> NpmFieldOf (Built b)
field InternTable
table s
acc TokenResult
rest Walked s -> TokenResult -> r
done = (Walked s
 -> Name -> TokenResult -> (Walked s -> TokenResult -> r) -> r)
-> (Walked s -> TokenResult -> r) -> Walked s -> TokenResult -> r
forall r st.
Walk r =>
(st -> Name -> TokenResult -> (st -> TokenResult -> r) -> r)
-> (st -> TokenResult -> r) -> st -> TokenResult -> r
eachMember Walked s
-> Name -> TokenResult -> (Walked s -> TokenResult -> r) -> r
visit Walked s -> TokenResult -> r
done (InternTable -> s -> Walked s
forall s. InternTable -> s -> Walked s
Walked InternTable
table s
acc) TokenResult
rest
      where
        visit :: Walked s
-> Name -> TokenResult -> (Walked s -> TokenResult -> r) -> r
visit (Walked InternTable
held s
current) Name
key TokenResult
after Walked s -> TokenResult -> r
continue
            | Name -> ByteString
nameBytes Name
key ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
wanted = TokenResult -> (Element -> TokenResult -> r) -> r
forall r.
Walk r =>
TokenResult -> (Element -> TokenResult -> r) -> r
withElement TokenResult
after ((Element -> TokenResult -> r) -> r)
-> (Element -> TokenResult -> r) -> r
forall a b. (a -> b) -> a -> b
$ \Element
element TokenResult
afterKey ->
                Trees
-> Shape
-> Mode
-> InternTable
-> Element
-> TokenResult
-> (Built Trees -> InternTable -> TokenResult -> r)
-> r
forall b r.
Build b r =>
b
-> Shape
-> Mode
-> InternTable
-> Element
-> TokenResult
-> (Built b -> InternTable -> TokenResult -> r)
-> r
readShape Trees
Trees (Int -> Shape
Scalar (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2)) Mode
Keep InternTable
held Element
element TokenResult
afterKey ((Built Trees -> InternTable -> TokenResult -> r) -> r)
-> (Built Trees -> InternTable -> TokenResult -> r) -> r
forall a b. (a -> b) -> a -> b
$ \Built Trees
scalar InternTable
_ TokenResult
afterValue ->
                    s -> NpmFieldOf (Built b) -> (s -> r) -> r
emit s
current (Value -> NpmFieldOf (Built b)
field Value
Built Trees
scalar) (Int -> TokenResult -> (TokenResult -> r) -> r
forall r. Walk r => Int -> TokenResult -> (TokenResult -> r) -> r
skipRest Int
1 TokenResult
afterValue ((TokenResult -> r) -> r) -> (s -> TokenResult -> r) -> s -> r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Walked s -> TokenResult -> r
done (Walked s -> TokenResult -> r)
-> (s -> Walked s) -> s -> TokenResult -> r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. InternTable -> s -> Walked s
forall s. InternTable -> s -> Walked s
Walked InternTable
held)
            | Bool
otherwise = TokenResult -> (Element -> TokenResult -> r) -> r
forall r.
Walk r =>
TokenResult -> (Element -> TokenResult -> r) -> r
withElement TokenResult
after ((Element -> TokenResult -> r) -> r)
-> (Element -> TokenResult -> r) -> r
forall a b. (a -> b) -> a -> b
$ \Element
element TokenResult
afterKey -> Element -> TokenResult -> (TokenResult -> r) -> r
forall r.
Walk r =>
Element -> TokenResult -> (TokenResult -> r) -> r
skipFrom Element
element TokenResult
afterKey (Walked s -> TokenResult -> r
continue (InternTable -> s -> Walked s
forall s. InternTable -> s -> Walked s
Walked InternTable
held s
current))

    releaseShape :: Shape
releaseShape = Int -> Shape -> Shape
Checked (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2) (Value -> Members -> Shape
ObjectOr Value
Null (Int -> Members
releaseMembers Int
depth))

-- The release fields "Ecluse.Core.Registry.Npm.Streaming" retains for full and selected reads.
releaseMembers :: Int -> Members
releaseMembers :: Int -> Members
releaseMembers Int
depth = [(Text, Shape)] -> Members
namedMembers ([(Text, Shape)]
shapedFields [(Text, Shape)] -> [(Text, Shape)] -> [(Text, Shape)]
forall a. Semigroup a => a -> a -> a
<> [(Text
key, Int -> Shape
Generic (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
3)) | Text
key <- [Text]
versionFields])
  where
    shapedFields :: [(Text, Shape)]
shapedFields =
        [ (Text
"_npmUser", [Text] -> Int -> Shape
personValue [Text
"name", Text
"email", Text
"url"] (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
3))
        , (Text
"license", [Text] -> Int -> Shape
personValue [Text
"type", Text
"url"] (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
3))
        , (Text
"dist", Int -> Members -> Shape
objectValue (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
3) Members
distFields)
        , (Text
"peerDependenciesMeta", Shape
dependencyMeta)
        , (Text
"dependenciesMeta", Shape
dependencyMeta)
        , (Text
"directories", [Text] -> Int -> Shape
fixed [Text
"lib", Text
"bin", Text
"man", Text
"doc", Text
"example", Text
"test"] (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
3))
        , (Text
"devEngines", Int -> Members -> Shape
objectValue (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
3) ([(Text, Shape)] -> Members
namedMembers [(Text
key, Shape
devEngine) | Text
key <- [Text
"cpu", Text
"os", Text
"libc", Text
"runtime", Text
"packageManager"]]))
        , (Text
"publishConfig", Int -> Members -> Shape
objectValue (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
3) Members
publishFields)
        , (Text
"workspaces", Int -> Shape -> Shape -> Shape
ArrayWith (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
3) (Int -> Shape
Scalar (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
4)) (Int -> Members -> Shape
objectValue (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
3) Members
workspaceFields))
        ]
            [(Text, Shape)] -> [(Text, Shape)] -> [(Text, Shape)]
forall a. Semigroup a => a -> a -> a
<> [ (Text
key, Int -> Members -> Shape
objectValue (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
3) (Shape -> Members
everyMember (Int -> Shape
Scalar (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
4))))
               | Text
key <- [Text
"dependencies", Text
"acceptDependencies", Text
"devDependencies", Text
"optionalDependencies", Text
"peerDependencies", Text
"engines", Text
"scripts", Text
"bin", Text
"browser"]
               ]
            [(Text, Shape)] -> [(Text, Shape)] -> [(Text, Shape)]
forall a. Semigroup a => a -> a -> a
<> [ (Text
key, Int -> Shape
Scalar (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
3))
               | Text
key <- [Text
"name", Text
"version", Text
"_hasShrinkwrap", Text
"hasInstallScript", Text
"deprecated", Text
"main", Text
"module", Text
"type", Text
"types", Text
"typings", Text
"gypfile", Text
"preferGlobal", Text
"packageManager", Text
"engineStrict"]
               ]
    personValue :: [Text] -> Int -> Shape
personValue [Text]
keys Int
budget = Int -> Shape -> Shape
StringOr Int
budget ([Text] -> Int -> Shape
fixed [Text]
keys Int
budget)
    objectValue :: Int -> Members -> Shape
objectValue Int
budget Members
members = Int -> Members -> Shape -> Shape
ObjectWith Int
budget Members
members (Int -> Shape
Scalar Int
budget)
    arrayValue :: Int -> Shape -> Shape
arrayValue Int
budget Shape
entry = Int -> Shape -> Shape -> Shape
ArrayWith Int
budget Shape
entry (Int -> Shape
Scalar Int
budget)
    fixed :: [Text] -> Int -> Shape
fixed [Text]
keys Int
budget = Int -> Members -> Shape
objectValue Int
budget ([(Text, Shape)] -> Members
namedMembers [(Text
key, Int -> Shape
Scalar (Int
budget Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)) | Text
key <- [Text]
keys])
    distFields :: Members
distFields =
        [(Text, Shape)] -> Members
namedMembers
            ( [ (Text
"signatures", Int -> Shape -> Shape
arrayValue (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
4) ([Text] -> Int -> Shape
fixed [Text
"keyid", Text
"sig"] (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
5)))
              , (Text
"attestations", Int -> Members -> Shape
objectValue (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
4) ([(Text, Shape)] -> Members
namedMembers [(Text
"url", Int -> Shape
Scalar (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
5)), (Text
"provenance", [Text] -> Int -> Shape
fixed [Text
"predicateType"] (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
5))]))
              ]
                [(Text, Shape)] -> [(Text, Shape)] -> [(Text, Shape)]
forall a. Semigroup a => a -> a -> a
<> [(Text
key, Int -> Shape
Scalar (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
4)) | Text
key <- [Text
"tarball", Text
"shasum", Text
"integrity", Text
"unpackedSize", Text
"fileCount"]]
            )
    dependencyMeta :: Shape
dependencyMeta = Int -> Members -> Shape
objectValue (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
3) (Shape -> Members
everyMember ([Text] -> Int -> Shape
fixed [Text
"optional"] (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
4)))
    devEngine :: Shape
devEngine = Int -> Shape -> Shape -> Shape
ArrayWith (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
4) ([Text] -> Int -> Shape
fixed [Text
"name", Text
"version", Text
"onFail"] (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
5)) ([Text] -> Int -> Shape
fixed [Text
"name", Text
"version", Text
"onFail"] (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
4))
    publishFields :: Members
publishFields = [(Text, Shape)] -> Members
namedMembers [(Text
key, Int -> Shape
Generic (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
4)) | Text
key <- [Text
"registry", Text
"tag", Text
"access", Text
"provenance", Text
"ignore-scripts", Text
"directory", Text
"linkDirectory", Text
"executableFiles", Text
"main", Text
"module", Text
"types", Text
"typings", Text
"exports", Text
"imports", Text
"bin", Text
"browser"]]
    workspaceFields :: Members
workspaceFields = [(Text, Shape)] -> Members
namedMembers [(Text
key, Int -> Shape -> Shape
arrayValue (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
4) (Int -> Shape
Scalar (Int
depth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
5))) | Text
key <- [Text
"packages", Text
"nohoist"]]