packages feed

yarn-lock (empty) → 0.1.0

raw patch · 4 files changed

+256/−0 lines, 4 filesdep +basedep +containersdep +megaparsecsetup-changed

Dependencies added: base, containers, megaparsec, protolude, text

Files

+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2017 Profpatsch <mail@profpatsch.de>+MIT LICENSE++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ src/Yarn/Lock.hs view
@@ -0,0 +1,199 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-|+Module : Yarn.Lock+Description : Parser & Types for yarn.lock files+Maintainer : Profpatsch+Stability : experimental++The <https://yarnpkg.com/ Yarn package manager> improves on npm+in that it writes @yarn.lock@ files that contain a complete+version resolution of all dependencies. This way a deterministic+deployment can be guaranteed.++This module provides a parser for @yarn.lock@ files.+-}+module Yarn.Lock+( Lockfile, PackageKey(..), Package(..), RemoteFile(..)+, PackageEntry, PackageList+, Yarn.Lock.parse+-- | = Parsers+, lockfile+, packageListToLockfile, packageList+, packageEntry, packageKeys, packageKey, package+) where++import Protolude hiding (try)+import Data.String (String)+import Text.Megaparsec as MP+import Text.Megaparsec.Text+import qualified Data.Text as T++import qualified Data.Map.Strict as M++-- | Yarn lockfile.+type Lockfile = M.Map PackageKey Package++-- | Key that indexes package for a specific version.+data PackageKey = PackageKey+  { name      :: Text -- ^ package name+  , npmSemver :: Text -- ^ semver string+  } deriving (Show, Eq, Ord)++-- | The actual package with dependencies and download link.+data Package = Package+  { version              :: Text         -- ^ resolved, specific version+  , resolved             :: RemoteFile   -- ^ download link w/ hash+  , dependencies         :: [PackageKey] -- ^ list of dependencies+  , optionalDependencies :: [PackageKey] -- ^ list of optional dependencies+  } deriving (Eq, Show)++-- | A package download link.+data RemoteFile = RemoteFile+  { url     :: Text+  , sha1sum :: Text }+  deriving (Eq, Show)++-- | A entry as it appears in the yarn.lock representation.+type PackageEntry = ([PackageKey], Package)+-- | Convenience alias.+type PackageList = [PackageEntry]++-- | Convenience function that converts errors to Text.+--+-- The actual parsers are below.+parse :: Text -- ^ name of source file+      -> Text -- ^ input for parser+      -> Either Text Lockfile+parse src inp = first (T.pack . parseErrorPretty)+              $ MP.parse lockfile (T.unpack src) inp++-- TODO: actually use somehow (apart from manual testing)+-- The yarn.lock file should resolve each packageKey exactly once.+--+-- No pkgname/semver combination should appear twice. That means+-- the lengths of the converted map and the list lists need to match.+-- prop_LockfileSameAmountOfKeys :: PackageList -> Bool+-- prop_LockfileSameAmountOfKeys pl = length (packageListToLockfile pl)+--                                    == length (concatMap fst pl)+++-- HALP, I don’t know how to parser.+-- It appears to be a more general format which somewhat resembles yaml.+-- The code below conflates the format & the semantics of yarn.lock files.+-- It should be separated sometime, to make parsing easier.++-- | Convenience function that applies @packageListToLockfile@.+lockfile :: Parser Lockfile+lockfile = packageListToLockfile <$> packageList++-- | The yarn.lock file is basically a hashmap with multi-keyed entries.+--+-- This should press it into our Lockfile Map.+packageListToLockfile :: PackageList -> Lockfile+packageListToLockfile = foldl' go mempty+  where go lf (keys, pkg) = foldl' (\lf' key' -> M.insert key' pkg lf') lf keys++-- | Parse a complete yarn.lock into exaclty the same representation.+--+-- You can apply @packageListToLockfile@ to make it usable.+packageList :: Parser PackageList+packageList = many $ (skipMany (comment <|> eol)) *> packageEntry+                where comment = char '#' *> manyTill anyChar eol++-- | A single PackageEntry.+--+-- @+-- handlebars@^4.0.4:+--   version "4.0.6"+--   resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7"+--   dependencies:+--     async "^1.4.0"+--     optimist "^0.6.1"+--     source-map "^0.4.4"+--   optionalDependencies:+--     uglify-js "^2.6"+-- @+packageEntry :: Parser PackageEntry+packageEntry = (,) <$> packageKeys <*> package <?> "package entry"++-- | The list of PackageKeys that index the same Package+--+-- @+-- align-text@^0.1.1, align-text@^0.1.3:\\n+-- @+packageKeys :: Parser [PackageKey]+packageKeys = sepBy1 packageKey (string ", ") <* (char ':') <* eol <?> "package keys"++-- | A packageKey is @\<package-name\>\@\<semver\>@;+--+-- If the semver contains spaces, it is also quoted with @"@.+packageKey :: Parser PackageKey+packageKey = label "package key" $ inString pkgKey <|> pkgKey+  where+    pkgKey = PackageKey+      -- everything until the version, sep is @+      <$> (someTextUntilSep '@' <?> "package name part of package key")+      -- a version is anything but the , (used for seperating package keys)+      -- or : (used to close the packageKeys line)+      -- could be more specific (version is semver), but I’m lazy+      <*> (someText (noneOf "\",:") <?> "semver part of package key")++-- | Parses the content fields of a package.+package :: Parser Package+package = Package+-- TODO: order shouldn’t matter, horrible indentation scheme+  <$> (indent 2 $ key "version" stringText)+  <*> (indent 2 $ key "resolved" remoteFile)+  <*> (maybe [] identity <$> optional (indent 2 $ dependencyEntries "dependencies"))+  <*> (maybe [] identity <$> optional (indent 2 $ dependencyEntries "optionalDependencies"))+++-- internal parsers++-- | the “resolved”-field contains the link and the hash+remoteFile :: Parser RemoteFile+remoteFile = label "file link with hash" $ RemoteFile+  <$> someTextUntilSep '#'+  <*> stringText++-- | dependency field of a package+dependencyEntries :: String -> Parser [PackageKey]+dependencyEntries key' = label (key' <>" field") $ do+  _ <- string (key' <>":") <* eol+  -- TODO: cool indentation handling+  some (indent 4 dep)+  where+    -- It’s a bit like a key below, but the value of the key is not known.+    -- Here’s where the format should get its own AST, but I’m too lazy right now.+    dep = PackageKey <$> someTextUntilSep ' ' <*> inString stringText <* eol <?> "a dependency entry"++-- | A key-value pair, separated by space. The value is enclosed in "".+--+-- The given parser is used to parse the value and should not parse ".+key :: String -> Parser a -> Parser a+key name' val = label ("key " <> name') $+  string name' *> char ' ' *> inString val  <* eol+++-- text versions of parsers & helpers++someText :: Parser Char -> Parser Text+someText c = T.pack <$> some c++-- | parse everything as inside a string+-- TODO: this breaks the 'between' abstraction, can it be avoided somehow?+inString :: Parser a -> Parser a+inString = between (char '"') (char '"')++-- | function to annotate text inside strings (which should never parse ")+--   symptom of the broken 'between' abstraction+stringText :: Parser Text+stringText = someText (noneOf "\"") <?> "non-empty text without \""++-- | parse some text until seperator is reached+someTextUntilSep :: Char -> Parser Text+someTextUntilSep sep = T.pack <$> someTill anyChar (char sep)++-- | intend by @i@ spaces+indent :: Int -> Parser a -> Parser a+indent i p = try $ count i (char ' ') *> p
+ yarn-lock.cabal view
@@ -0,0 +1,35 @@+-- This file has been generated from package.yaml by hpack version 0.17.0.+--+-- see: https://github.com/sol/hpack++name:           yarn-lock+version:        0.1.0+synopsis:       Represent and parse yarn.lock files+description:    Types and parser for the lock file format of the npm successor yarn.+category:       Data+homepage:       https://github.com/Profpatsch/yaml-lock#readme+bug-reports:    https://github.com/Profpatsch/yaml-lock/issues+author:         Profpatsch+maintainer:     mail@profpatsch.de+license:        MIT+license-file:   LICENSE+build-type:     Simple+cabal-version:  >= 1.10++source-repository head+  type: git+  location: https://github.com/Profpatsch/yaml-lock++library+  hs-source-dirs:+      src+  ghc-options: -Wall+  build-depends:+      base == 4.*+    , containers+    , text+    , megaparsec == 5.*+    , protolude >= 0.1+  exposed-modules:+      Yarn.Lock+  default-language: Haskell2010