diff --git a/bower-json.cabal b/bower-json.cabal
--- a/bower-json.cabal
+++ b/bower-json.cabal
@@ -1,5 +1,5 @@
 name:                bower-json
-version:             0.1.0.0
+version:             0.2.0.0
 synopsis:            bower.json from Haskell
 license:             MIT
 license-file:        LICENSE
@@ -22,7 +22,7 @@
   exposed-modules:   Web.BowerJson
   other-modules:     Web.BowerJson.Utils
   build-depends:     base >=4 && <5
-                   , aeson >=0.6
+                   , aeson >=0.6.1.0
                    , filepath
                    , containers
                    , unordered-containers
diff --git a/src/Web/BowerJson.hs b/src/Web/BowerJson.hs
--- a/src/Web/BowerJson.hs
+++ b/src/Web/BowerJson.hs
@@ -6,15 +6,28 @@
 -- with a parser and related functions.
 --
 -- This code is based on the specification at
---   <https://github.com/bower/bower.json-spec>
+-- <https://github.com/bower/bower.json-spec>.
 
-module Web.BowerJson where
+module Web.BowerJson
+  ( BowerJson(..)
+  , decodeFile
+  , PackageName
+  , runPackageName
+  , mkPackageName
+  , ModuleType(..)
+  , Author(..)
+  , Repository(..)
+  , VersionRange(..)
+  , Version(..)
+  ) where
 
 import Control.Applicative
 import Control.Category ((>>>))
+import Data.List
 import Data.Char
 import Data.Map (Map)
 import qualified Data.Text as T
+import qualified Data.ByteString.Lazy as B
 import qualified Data.HashMap.Strict as HashMap
 import Data.Aeson
 import qualified Data.Aeson.Types as Aeson
@@ -37,7 +50,7 @@
   , bowerDependencies    :: Map PackageName VersionRange
   , bowerDevDependencies :: Map PackageName VersionRange
   , bowerResolutions     :: Map PackageName Version
-  , isPrivate            :: Bool
+  , bowerPrivate         :: Bool
   }
   deriving (Show, Eq, Ord)
 
@@ -60,8 +73,8 @@
                 <*> o .:?  "private"          .!= False
     where
     liftMaybe :: String -> (a -> Maybe b) -> a -> Aeson.Parser b
-    liftMaybe msg f =
-      maybe (fail ("unable to parse a value of type: " ++ msg)) return . f
+    liftMaybe ty f =
+      maybe (fail ("unable to parse a value of type: " ++ ty)) return . f
 
     parsePackageName :: String -> Aeson.Parser PackageName
     parsePackageName = liftMaybe "PackageName" mkPackageName
@@ -70,14 +83,18 @@
       (o' .:? field .!= Object HashMap.empty)
         >>= parseWithArbitraryKeys parsePackageName
 
-------------------
--- Package names
+-- | Read and attempt to decode a bower.json file.
+decodeFile :: FilePath -> IO (Either String BowerJson)
+decodeFile = fmap eitherDecode . B.readFile
 
 -- | A valid package name for a Bower package.
 newtype PackageName
-  = PackageName { runPackageName :: String }
+  = PackageName String
   deriving (Show, Eq, Ord)
 
+runPackageName :: PackageName -> String
+runPackageName (PackageName s) = s
+
 instance FromJSON PackageName where
   parseJSON =
     withText "PackageName" $ \text ->
@@ -85,6 +102,9 @@
         Just pkgName -> return pkgName
         Nothing -> fail ("unable to validate package name: " ++ show text)
 
+-- | A smart constructor for a PackageName. It ensures that the package name
+-- satisfies the restrictions described at
+-- <https://github.com/bower/bower.json-spec#name>.
 mkPackageName :: String -> Maybe PackageName
 mkPackageName str
   | satisfyAll predicates str = Just (PackageName str)
@@ -98,6 +118,9 @@
       , all (\c -> isLower c || isDigit c || c `elem` dashOrDot)
       , headMay >>> isJustAnd (`notElem` dashOrDot)
       , lastMay >>> isJustAnd (`notElem` dashOrDot)
+      , not . isInfixOf "--"
+      , not . isInfixOf ".."
+      , length >>> (<= 50)
       ]
   isJustAnd = maybe False
 
