diff --git a/CHANGES.md b/CHANGES.md index 6c77b06..435c4a2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,7 +9,12 @@ To be released. - Since this version, it requires GHC 8.8.* at least, and supports GHC 9.0.* at most. - - Now supports several content types besides HTML/XHTML. [[#18]] + - Now supports several content types besides HTML/XHTML. The below list + shows all supported content types: [[#18]] + + - `text/html` (previously non-XHTML mode) + - `application/xhtml+xml` (previously XHTML mode) + - `text/plain` (added) The below Haskell APIs changed: diff --git a/demo/src/Demo.elm b/demo/src/Demo.elm index 8872bdb..9cd949c 100644 --- a/demo/src/Demo.elm +++ b/demo/src/Demo.elm @@ -118,6 +118,7 @@ type alias Source = type ContentType = Html | Xhtml + | PlainText type Options @@ -250,6 +251,9 @@ makeInput source = Xhtml -> "appplication/xhtml+xml" + + PlainText -> + "text/plain" ) ] <| @@ -1325,15 +1329,22 @@ viewOptions model = Xhtml _ -> - Html + PlainText ] <| [ Select.item [ value "text/html", selected <| contentType == Html ] [ text "HTML" ] , Select.item - [ value "application/xhtml+xml", selected <| contentType == Xhtml ] + [ value "application/xhtml+xml" + , selected <| contentType == Xhtml + ] [ text "XHTML" ] + , Select.item + [ value "text/plain" + , selected <| contentType == PlainText + ] + [ text "Plain text" ] ] ] ] diff --git a/package.yaml b/package.yaml index ea5e007..35f877f 100644 --- a/package.yaml +++ b/package.yaml @@ -73,6 +73,7 @@ library: - data-default >= 0.2 && < 1 - filepath >= 1 && < 2 - file-embed >= 0.0.10 && < 0.0.16 + - html-entities >= 1 && < 2 when: - condition: flag(static) || flag(embed-dictionary) then: diff --git a/scripts/deno/mod.ts b/scripts/deno/mod.ts index 2e3f280..679f46d 100644 --- a/scripts/deno/mod.ts +++ b/scripts/deno/mod.ts @@ -35,13 +35,18 @@ export interface Preset { */ export type Dictionary = "kr-stdict"; +export type ContentType = + | "text/html" + | "application/xhtml+xml" + | "plain/text"; + /** * Options for transformation. * See also . */ export interface Options { /** Content type. */ - contentType: "text/html" | "application/xhtml+xml"; + contentType: ContentType; /** Quoting options. */ quote: | "CurvedQuotes" diff --git a/src/Text/Seonbi/ContentTypes.hs b/src/Text/Seonbi/ContentTypes.hs index e684a17..8b292d3 100644 --- a/src/Text/Seonbi/ContentTypes.hs +++ b/src/Text/Seonbi/ContentTypes.hs @@ -7,6 +7,7 @@ module Text.Seonbi.ContentTypes , TextTransformer , asHtmlTransformer , asHtmlTransformer' + , asPlainTextTransformer , asXhtmlTransformer , contentTypeFromText , contentTypes @@ -25,8 +26,11 @@ import Data.CaseInsensitive import Data.Set import Data.Text as ST import Data.Text.Lazy as LT +import Data.Text.Lazy.Builder +import HTMLEntities.Decoder import Text.Seonbi.Html +import qualified Text.Seonbi.Html.TagStack as TagStack -- | Represents a function that transforms an 'HtmlEntity' list. type HtmlTransformer m @@ -73,6 +77,18 @@ asHtmlTransformer = asHtmlTransformer' False asXhtmlTransformer :: (Monad m, MonadFail m) => TransformerTransformer m asXhtmlTransformer = asHtmlTransformer' True +asPlainTextTransformer :: (Monad m, MonadFail m) => TransformerTransformer m +asPlainTextTransformer transformer text' = do + let entities = [HtmlCdata TagStack.empty $ LT.toStrict text'] + output <- transformer entities + return . LT.concat $ + [ case e of + HtmlCdata _ cdata -> LT.fromStrict cdata + HtmlText _ rawText' -> toLazyText $ htmlEncodedText rawText' + _ -> LT.empty + | e <- output + ] + -- | Represents a case-insensitive content type. type ContentType = CI ST.Text @@ -91,6 +107,7 @@ transformers :: (Monad m, MonadFail m) transformers = [ ("text/html", TransformerTransformer' asHtmlTransformer) , ("application/xhtml+xml", TransformerTransformer' asXhtmlTransformer) + , ("text/plain", TransformerTransformer' asPlainTextTransformer) ] -- | Supported content types. diff --git a/test/Text/Seonbi/ContentTypesSpec.hs b/test/Text/Seonbi/ContentTypesSpec.hs index f42a684..1c514aa 100644 --- a/test/Text/Seonbi/ContentTypesSpec.hs +++ b/test/Text/Seonbi/ContentTypesSpec.hs @@ -25,10 +25,15 @@ spec = do specify "asXhtmlTransformer" $ do r <- asXhtmlTransformer textReverser "

foo bar
baz

" r `shouldBe` "

oofrab
zab

" + specify "asPlainTextTransformer" $ do + r <- asPlainTextTransformer textReverser + "

foo bar
baz

" + r `shouldBe` ">p/rb<>me/me< oof>p<" specify "transformWithContentType" $ do let input = "

foo bar

" h <- transformWithContentType "text/html" textReverser input h `shouldBe` "

oofrab

" x <- transformWithContentType "application/xhtml+xml" textReverser input x `shouldBe` "

oofrab

" - + p <- transformWithContentType "text/plain" textReverser input + p `shouldBe` ">p/<>rb<>me/me< oof>p<"