commonmark-simple 0.1.0.0 → 0.2.0.0
raw patch · 3 files changed
+91/−82 lines, 3 filesdep ~basedep ~commonmark-extensionsdep ~commonmark-pandocPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base, commonmark-extensions, commonmark-pandoc
API changes (from Hackage documentation)
- Commonmark.Simple: fullMarkdownSpec :: SyntaxSpec' m il bl => SyntaxSpec m il bl
+ Commonmark.Simple: fullMarkdownSpec :: forall (m :: Type -> Type) il bl. SyntaxSpec' m il bl => SyntaxSpec m il bl
- Commonmark.Simple: parseMarkdownWithFrontMatter :: forall meta m il bl. (FromJSON meta, m ~ Either ParseError, bl ~ Cm () Blocks, il ~ Cm () Inlines) => SyntaxSpec m il bl -> FilePath -> Text -> Either Text (Maybe meta, Pandoc)
+ Commonmark.Simple: parseMarkdownWithFrontMatter :: forall meta (m :: Type -> Type) il bl. (FromJSON meta, m ~ Either ParseError, bl ~ Cm () Blocks, il ~ Cm () Inlines) => SyntaxSpec m il bl -> FilePath -> Text -> Either Text (Maybe meta, Pandoc)
Files
- README.md +1/−0
- commonmark-simple.cabal +10/−9
- src/Commonmark/Simple.hs +80/−73
README.md view
@@ -1,2 +1,3 @@ # commonmark-simple +Wraps [`commonmark-hs`](https://github.com/jgm/commonmark-hs) to give a simple API for parsing real-world Markdown.
commonmark-simple.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: commonmark-simple-version: 0.1.0.0+version: 0.2.0.0 license: MIT copyright: 2022 Sridhar Ratnakumar maintainer: srid@srid.ca@@ -9,14 +9,15 @@ -- TODO: Before hackage release. -- A short (one-line) description of the package.-synopsis: Simple interface to commonmark-hs+synopsis:+ Simple interface to commonmark-hs for parsing real-world Markdown. -- A longer description of the package.-description: Simple interface to parsing Markdown using commonmark-hs+description:+ Simple interface to parsing real-world Markdown using commonmark-hs -- A URL where users can report bugs.-bug-reports: https://github.com/srid/commonmark-simple-+bug-reports: https://github.com/srid/commonmark-simple extra-source-files: LICENSE README.md@@ -24,10 +25,10 @@ library build-depends: , aeson- , base >=4.13.0.0 && <=4.18.0.0+ , base >=4.13.0.0 && <5 , commonmark- , commonmark-extensions- , commonmark-pandoc+ , commonmark-extensions >=0.2.5+ , commonmark-pandoc >=0.2.2 , containers , megaparsec , pandoc-types@@ -48,7 +49,6 @@ -fprint-explicit-foralls -fprint-explicit-kinds default-extensions:- NoStarIsType BangPatterns ConstraintKinds DataKinds@@ -74,6 +74,7 @@ LambdaCase MultiParamTypeClasses MultiWayIf+ NoStarIsType NumericUnderscores OverloadedStrings PolyKinds
src/Commonmark/Simple.hs view
@@ -1,8 +1,12 @@-module Commonmark.Simple- ( parseMarkdownWithFrontMatter,+{- | A simple interface to the `commonmark` package for parsing real-world Markdown++Where 'real-world' means the kind of syntax used in the likes of Obsidian Markdown.+-}+module Commonmark.Simple (+ parseMarkdownWithFrontMatter, parseMarkdown, fullMarkdownSpec,- )+) where import Commonmark qualified as CM@@ -16,94 +20,97 @@ import Text.Pandoc.Builder qualified as B import Text.Pandoc.Definition (Pandoc (..)) --- | Parse a Markdown file using commonmark-hs with all extensions enabled+-- | Like `parseMarkdown` but also parses the YAML frontmatter parseMarkdownWithFrontMatter ::- forall meta m il bl.- ( FromJSON meta,- m ~ Either CM.ParseError,- bl ~ CP.Cm () B.Blocks,- il ~ CP.Cm () B.Inlines- ) =>- CM.SyntaxSpec m il bl ->- -- | Path to file associated with this Markdown- FilePath ->- -- | Markdown text to parse- Text ->- Either Text (Maybe meta, Pandoc)+ forall meta m il bl.+ ( FromJSON meta+ , m ~ Either CM.ParseError+ , bl ~ CP.Cm () B.Blocks+ , il ~ CP.Cm () B.Inlines+ ) =>+ CM.SyntaxSpec m il bl ->+ -- | Path to file associated with this Markdown+ FilePath ->+ -- | Markdown text to parse+ Text ->+ Either Text (Maybe meta, Pandoc) parseMarkdownWithFrontMatter spec fn s = do- (mMeta, markdown) <- partitionMarkdown fn s- mMetaVal <- first show $ (Y.decodeEither' . encodeUtf8) `traverse` mMeta- blocks <- first show $ join $ CM.commonmarkWith @(Either CM.ParseError) spec fn markdown- let doc = Pandoc mempty $ B.toList . CP.unCm @() @B.Blocks $ blocks- pure (mMetaVal, doc)+ (mMeta, markdown) <- partitionMarkdown fn s+ mMetaVal <- first show $ (Y.decodeEither' . encodeUtf8) `traverse` mMeta+ blocks <- first show $ join $ CM.commonmarkWith @(Either CM.ParseError) spec fn markdown+ let doc = Pandoc mempty $ B.toList . CP.unCm @() @B.Blocks $ blocks+ pure (mMetaVal, doc) +-- | Parse a Markdown file using commonmark-hs with all extensions enabled parseMarkdown :: FilePath -> Text -> Either Text Pandoc parseMarkdown fn s = do- cmBlocks <- first show $ join $ CM.commonmarkWith @(Either CM.ParseError) fullMarkdownSpec fn s- let blocks = B.toList . CP.unCm @() @B.Blocks $ cmBlocks- pure $ Pandoc mempty blocks+ cmBlocks <- first show $ join $ CM.commonmarkWith @(Either CM.ParseError) fullMarkdownSpec fn s+ let blocks = B.toList . CP.unCm @() @B.Blocks $ cmBlocks+ pure $ Pandoc mempty blocks type SyntaxSpec' m il bl =- ( Monad m,- CM.IsBlock il bl,- CM.IsInline il,- Typeable m,- Typeable il,- Typeable bl,- CE.HasEmoji il,- CE.HasStrikethrough il,- CE.HasPipeTable il bl,- CE.HasTaskList il bl,- CM.ToPlainText il,- CE.HasFootnote il bl,- CE.HasMath il,- CE.HasDefinitionList il bl,- CE.HasDiv bl,- CE.HasQuoted il,- CE.HasSpan il- )+ ( Monad m+ , CM.IsBlock il bl+ , CM.IsInline il+ , Typeable m+ , Typeable il+ , Typeable bl+ , CE.HasEmoji il+ , CE.HasStrikethrough il+ , CE.HasPipeTable il bl+ , CE.HasTaskList il bl+ , CM.ToPlainText il+ , CE.HasFootnote il bl+ , CE.HasMath il+ , CE.HasDefinitionList il bl+ , CE.HasDiv bl+ , CE.HasQuoted il+ , CE.HasSpan il+ , CE.HasAlerts il bl+ ) -- | GFM + official commonmark extensions fullMarkdownSpec ::- SyntaxSpec' m il bl =>- CM.SyntaxSpec m il bl+ (SyntaxSpec' m il bl) =>+ CM.SyntaxSpec m il bl fullMarkdownSpec =- mconcat- [ CE.gfmExtensions,- CE.fancyListSpec,- CE.footnoteSpec,- CE.mathSpec,- CE.smartPunctuationSpec,- CE.definitionListSpec,- CE.attributesSpec,- CE.rawAttributeSpec,- CE.fencedDivSpec,- CE.bracketedSpanSpec,- CE.autolinkSpec,- CM.defaultSyntaxSpec,- -- as the commonmark documentation states, pipeTableSpec should be placed after- -- fancyListSpec and defaultSyntaxSpec to avoid bad results when parsing- -- non-table lines- CE.pipeTableSpec- ]+ mconcat+ [ CE.gfmExtensions+ , CE.fancyListSpec+ , CE.footnoteSpec+ , CE.mathSpec+ , CE.smartPunctuationSpec+ , CE.definitionListSpec+ , CE.attributesSpec+ , CE.rawAttributeSpec+ , CE.fencedDivSpec+ , CE.bracketedSpanSpec+ , CE.autolinkSpec+ , CM.defaultSyntaxSpec+ , -- as the commonmark documentation states, pipeTableSpec should be placed after+ -- fancyListSpec and defaultSyntaxSpec to avoid bad results when parsing+ -- non-table lines+ CE.pipeTableSpec+ ] --- | Identify metadata block at the top, and split it from markdown body.------ FIXME: https://github.com/srid/neuron/issues/175+{- | Identify metadata block at the top, and split it from markdown body.++FIXME: https://github.com/srid/neuron/issues/175+-} partitionMarkdown :: FilePath -> Text -> Either Text (Maybe Text, Text) partitionMarkdown =- parse (M.try splitP <|> fmap (Nothing,) M.takeRest)+ parse (M.try splitP <|> fmap (Nothing,) M.takeRest) where separatorP :: M.Parsec Void Text () separatorP =- void $ M.string "---" <* M.eol+ void $ M.string "---" <* M.eol splitP :: M.Parsec Void Text (Maybe Text, Text) splitP = do- separatorP- a <- toText <$> manyTill M.anySingle (M.try $ M.eol *> separatorP)- b <- M.takeRest- pure (Just a, b)+ separatorP+ a <- toText <$> manyTill M.anySingle (M.try $ M.eol *> separatorP)+ b <- M.takeRest+ pure (Just a, b) parse :: M.Parsec Void Text a -> String -> Text -> Either Text a parse p fn s =- first (toText . M.errorBundlePretty) $- M.parse (p <* M.eof) fn s+ first (toText . M.errorBundlePretty) $+ M.parse (p <* M.eof) fn s