packages feed

link-relations (empty) → 0.1.0.0

raw patch · 12 files changed

+1836/−0 lines, 12 filesdep +basedep +bytestringdep +hashablesetup-changed

Dependencies added: base, bytestring, hashable, unordered-containers, uri-bytestring

Files

+ AUTHORS view
@@ -0,0 +1,1 @@+fr33domlover <fr33domlover@riseup.net>
+ COPYING view
@@ -0,0 +1,121 @@+Creative Commons Legal Code++CC0 1.0 Universal++    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE+    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN+    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS+    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES+    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS+    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM+    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED+    HEREUNDER.++Statement of Purpose++The laws of most jurisdictions throughout the world automatically confer+exclusive Copyright and Related Rights (defined below) upon the creator+and subsequent owner(s) (each and all, an "owner") of an original work of+authorship and/or a database (each, a "Work").++Certain owners wish to permanently relinquish those rights to a Work for+the purpose of contributing to a commons of creative, cultural and+scientific works ("Commons") that the public can reliably and without fear+of later claims of infringement build upon, modify, incorporate in other+works, reuse and redistribute as freely as possible in any form whatsoever+and for any purposes, including without limitation commercial purposes.+These owners may contribute to the Commons to promote the ideal of a free+culture and the further production of creative, cultural and scientific+works, or to gain reputation or greater distribution for their Work in+part through the use and efforts of others.++For these and/or other purposes and motivations, and without any+expectation of additional consideration or compensation, the person+associating CC0 with a Work (the "Affirmer"), to the extent that he or she+is an owner of Copyright and Related Rights in the Work, voluntarily+elects to apply CC0 to the Work and publicly distribute the Work under its+terms, with knowledge of his or her Copyright and Related Rights in the+Work and the meaning and intended legal effect of CC0 on those rights.++1. Copyright and Related Rights. A Work made available under CC0 may be+protected by copyright and related or neighboring rights ("Copyright and+Related Rights"). Copyright and Related Rights include, but are not+limited to, the following:++  i. the right to reproduce, adapt, distribute, perform, display,+     communicate, and translate a Work;+ ii. moral rights retained by the original author(s) and/or performer(s);+iii. publicity and privacy rights pertaining to a person's image or+     likeness depicted in a Work;+ iv. rights protecting against unfair competition in regards to a Work,+     subject to the limitations in paragraph 4(a), below;+  v. rights protecting the extraction, dissemination, use and reuse of data+     in a Work;+ vi. database rights (such as those arising under Directive 96/9/EC of the+     European Parliament and of the Council of 11 March 1996 on the legal+     protection of databases, and under any national implementation+     thereof, including any amended or successor version of such+     directive); and+vii. other similar, equivalent or corresponding rights throughout the+     world based on applicable law or treaty, and any national+     implementations thereof.++2. Waiver. To the greatest extent permitted by, but not in contravention+of, applicable law, Affirmer hereby overtly, fully, permanently,+irrevocably and unconditionally waives, abandons, and surrenders all of+Affirmer's Copyright and Related Rights and associated claims and causes+of action, whether now known or unknown (including existing as well as+future claims and causes of action), in the Work (i) in all territories+worldwide, (ii) for the maximum duration provided by applicable law or+treaty (including future time extensions), (iii) in any current or future+medium and for any number of copies, and (iv) for any purpose whatsoever,+including without limitation commercial, advertising or promotional+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each+member of the public at large and to the detriment of Affirmer's heirs and+successors, fully intending that such Waiver shall not be subject to+revocation, rescission, cancellation, termination, or any other legal or+equitable action to disrupt the quiet enjoyment of the Work by the public+as contemplated by Affirmer's express Statement of Purpose.++3. Public License Fallback. Should any part of the Waiver for any reason+be judged legally invalid or ineffective under applicable law, then the+Waiver shall be preserved to the maximum extent permitted taking into+account Affirmer's express Statement of Purpose. In addition, to the+extent the Waiver is so judged Affirmer hereby grants to each affected+person a royalty-free, non transferable, non sublicensable, non exclusive,+irrevocable and unconditional license to exercise Affirmer's Copyright and+Related Rights in the Work (i) in all territories worldwide, (ii) for the+maximum duration provided by applicable law or treaty (including future+time extensions), (iii) in any current or future medium and for any number+of copies, and (iv) for any purpose whatsoever, including without+limitation commercial, advertising or promotional purposes (the+"License"). The License shall be deemed effective as of the date CC0 was+applied by Affirmer to the Work. Should any part of the License for any+reason be judged legally invalid or ineffective under applicable law, such+partial invalidity or ineffectiveness shall not invalidate the remainder+of the License, and in such case Affirmer hereby affirms that he or she+will not (i) exercise any of his or her remaining Copyright and Related+Rights in the Work or (ii) assert any associated claims and causes of+action with respect to the Work, in either case contrary to Affirmer's+express Statement of Purpose.++4. Limitations and Disclaimers.++ a. No trademark or patent rights held by Affirmer are waived, abandoned,+    surrendered, licensed or otherwise affected by this document.+ b. Affirmer offers the Work as-is and makes no representations or+    warranties of any kind concerning the Work, express, implied,+    statutory or otherwise, including without limitation warranties of+    title, merchantability, fitness for a particular purpose, non+    infringement, or the absence of latent or other defects, accuracy, or+    the present or absence of errors, whether or not discoverable, all to+    the greatest extent permissible under applicable law.+ c. Affirmer disclaims responsibility for clearing rights of other persons+    that may apply to the Work or any use thereof, including without+    limitation any person's Copyright and Related Rights in the Work.+    Further, Affirmer disclaims responsibility for obtaining any necessary+    consents, permissions or other rights required for any use of the+    Work.+ d. Affirmer understands and acknowledges that Creative Commons is not a+    party to this document and has no duty or obligation with respect to+    this CC0 or use of the Work.
+ ChangeLog view
@@ -0,0 +1,17 @@+The changes are recorded by the version control system, Darcs. To see a log+quickly from the terminal, run:++  $ darcs changes --repo http://hub.darcs.net/fr33domlover/link-relations++There is also a web interface at <http://hub.darcs.net> which, among other+things, can display the history log.++To see the log in a local clone, first get a copy of the repository if you+haven't yet:++  $ darcs get http://hub.darcs.net/fr33domlover/link-relations++Then move into the newly created directory and run darcs:++  $ cd link-relations+  $ darcs changes
+ INSTALL view
@@ -0,0 +1,13 @@+Install from Hackage:++    $ cabal install link-relations++Install from unpacked release tarball or source repo:++    $ cd link-relations+    $ cabal install++Just play with it without installing:++    $ cabal build+    $ cabal repl
+ NEWS.md view
@@ -0,0 +1,23 @@+This file lists the user-visible interesting changes between releases. For a+full list of changes to the source, see the ChangeLog.++++link-relations 0.1.0.0 -- 2015-12-15+====================================++General, build and documentation changes:++* (This is the first release, so everything is new)++New APIs, features and enhancements:++* (This is the first release, so everything is a new feature)++Bug fixes:++* (This is just the first release, many bugs haven't been discovered yet)++Dependency changes:++* (This is the first release)
+ README.md view
@@ -0,0 +1,77 @@+See the .cabal file for more info and link to project website the version+control.++The official download location is Hackage.++This library is free software, and is committed to software freedom. It is+released to the public domain using the CC0 Public Domain Dedication. For the+boring "legal" details see the file `COPYING`.++See the file `INSTALL` for hints on installation. The file `ChangeLog` explains+how to see the history log of the changes done in the code. `NEWS.md` provides+a friendly overview of the changes for each release.++# How to Release++This package's source code is auto-generated using 3 files:++1. A Haskell source file template+2. CSV file containing the IANA link relation registry data+3. A Haskell program which embeds the data into the template as Haskell code++All 3 files are found in the `util/` directory.++## (1) Update the source++- To update the non-generated part of the code, edit the template file.+- To update the CSV to a new version, download it from+  <https://www.iana.org/assignments/link-relations/link-relations-1.csv>+- To modify the source generation process, edit the generator program++## (2) Update version and date++If you downloaded a new CSV version, update the `lastUpdated` value in the+generator program. You can find that date at+<http://www.iana.org/assignments/link-relations/link-relations.xhtml>.++Update the package version number in the .cabal file. Use `darcs diff` to+examine the changes in the generated source and pick a version number according+to PVP. The most common change in the registry will probably be new link+relations added, which means new API functions and therefore an increase of the+minor version number (i.e. 3rd number, e.g. /0.1.5.3/ becomes /0.1.6.0/).+That's because the `LinkRelation` constructors themselves aren't exported.++## (3) Adjust other config++Near the top of the generator program file there is a configuration section+(e.g. the update date, file paths, etc.). If you made any changes which require+updates there, make the required modifications.++## (4) Build and test++The generator program depends on the `cassava` package. The other dependencies+are also dependencies of `cassava` (primarily `bytestring` and `vector`), which+means you can install the dependencies like this:++    $ cabal install cassava++Run the generator program from the package toplevel. Either using the+interpreter:++    $ runhaskell util/generate.hs++Or like this, if you installed `cassava` into a sandbox:++    $ cabal exec runhaskell util/generate.hs++Examine the result. Switch between the old generated source and the new one+(which is generated as a separate file in the same directory).++Build the library itself:++    $ cabal build++## (5) Record everything into the Darcs repo, make a tag, make a tarball etc.++As usual. Note that the 3 files in `util/` (i.e. including the CSV data) and+the generated source in `src/`, are all kept in the Darcs repo.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
@@ -0,0 +1,49 @@+name:                link-relations+version:             0.1.0.0+synopsis:            Use web link relation types (RFC 5988) in Haskell+description:+  This library provides access to the IANA registry of link relation types, for+  use in Haskell code in a type-safe manner.+  .+  The registry data can be found at+  <https://www.iana.org/assignments/link-relations>. This package is generated+  from that data.+  .+  To see to which revision of the registry this version of the package+  corresponds, look at the intro comment in "Web.LinkRelations".+homepage:            http://hub.darcs.net/fr33domlover/link-relations+bug-reports:         http://hub.darcs.net/fr33domlover/link-relations/issues+license:             PublicDomain+license-file:        COPYING+author:              fr33domlover+maintainer:          fr33domlover@riseup.net+copyright:           ♡ Copying is an act of love. Please copy, reuse and share.+category:            Data, Web+build-type:          Simple+extra-source-files:  AUTHORS+                     ChangeLog+                     COPYING+                     INSTALL+                     NEWS.md+                     README.md+                     util/template.hs+                     util/link-relations-1.csv+                     util/generate.hs+cabal-version:       >=1.10++source-repository head+  type:                darcs+  location:            http://hub.darcs.net/fr33domlover/link-relations++library+  exposed-modules:     Web.LinkRelations+  -- other-modules:       +  -- other-extensions:    +  build-depends:       base                 >=4.7 && <5+                     , bytestring+                     , hashable+                     , unordered-containers >=0.2.5+                     , uri-bytestring       >=0.1.7+  hs-source-dirs:      src+  default-language:    Haskell2010+  ghc-options:         -Wall
+ src/Web/LinkRelations.hs view
@@ -0,0 +1,916 @@+{- This file is part of link-relations.+ -+ - Written in 2015 by fr33domlover <fr33domlover@riseup.net>.+ - Also includes parts generated from the IANA link relation registry.+ -+ - ♡ Copying is an act of love. Please copy, reuse and share.+ -+ - The author(s) have dedicated all copyright and related and neighboring+ - rights to this software to the public domain worldwide. This software is+ - distributed without any warranty.+ -+ - You should have received a copy of the CC0 Public Domain Dedication along+ - with this software. If not, see+ - <http://creativecommons.org/publicdomain/zero/1.0/>.+ -}++{-# LANGUAGE OverloadedStrings #-}++-- | A simple web link between two web resources, e.g. a hyperlink in a webpage+-- referring to another page, suggests that the resources are somehow related,+-- but it doesn't say /how/ they are related. For example, a blog post may link+-- to the author's main page (relation: author of the post) but also link to+-- the previous post (relation: previous post by chronological order).+--+-- Link relations provide a way to express the relation between resources+-- linked by a web link.+--+-- A link relation type may be represented by a URI, or by a registered link+-- relation name. IANA maintains a+-- <https://www.iana.org/assignments/link-relations registry> of link+-- relations. This module provides access to them through a dedicated+-- 'LinkRelation' datatype.+--+-- This version of the package corresponds to the+-- /2015-01-21/+-- version of the registry.+module Web.LinkRelations+    ( -- * Types and Conversions+      LinkRelation+    , fromURI+    , fromURIStr+    , fromName+    , fromByteString+    , isURI+    , isName+    , toByteString+      -- * Link Relation Identifiers+    , relAbout+    , relAlternate+    , relAppendix+    , relArchives+    , relAuthor+    , relBookmark+    , relCanonical+    , relChapter+    , relCollection+    , relContents+    , relCopyright+    , relCreateForm+    , relCurrent+    , relDerivedfrom+    , relDescribedby+    , relDescribes+    , relDisclosure+    , relDuplicate+    , relEdit+    , relEditForm+    , relEditMedia+    , relEnclosure+    , relFirst+    , relGlossary+    , relHelp+    , relHosts+    , relHub+    , relIcon+    , relIndex+    , relItem+    , relLast+    , relLatestVersion+    , relLicense+    , relLrdd+    , relMemento+    , relMonitor+    , relMonitorGroup+    , relNext+    , relNextArchive+    , relNofollow+    , relNoreferrer+    , relOriginal+    , relPayment+    , relPredecessorVersion+    , relPrefetch+    , relPrev+    , relPreview+    , relPrevious+    , relPrevArchive+    , relPrivacyPolicy+    , relProfile+    , relRelated+    , relReplies+    , relSearch+    , relSection+    , relSelf+    , relService+    , relStart+    , relStylesheet+    , relSubsection+    , relSuccessorVersion+    , relTag+    , relTermsOfService+    , relTimegate+    , relTimemap+    , relType+    , relUp+    , relVersionHistory+    , relVia+    , relWorkingCopy+    , relWorkingCopyOf+    )+where++import Control.Applicative ((<|>))+import URI.ByteString++import qualified Data.ByteString as B+import qualified Data.HashMap.Strict as M++-- | A web link relation type. Either a URI or a registered name.+data LinkRelation+    = FromURI URI+    | RelAbout+    | RelAlternate+    | RelAppendix+    | RelArchives+    | RelAuthor+    | RelBookmark+    | RelCanonical+    | RelChapter+    | RelCollection+    | RelContents+    | RelCopyright+    | RelCreateForm+    | RelCurrent+    | RelDerivedfrom+    | RelDescribedby+    | RelDescribes+    | RelDisclosure+    | RelDuplicate+    | RelEdit+    | RelEditForm+    | RelEditMedia+    | RelEnclosure+    | RelFirst+    | RelGlossary+    | RelHelp+    | RelHosts+    | RelHub+    | RelIcon+    | RelIndex+    | RelItem+    | RelLast+    | RelLatestVersion+    | RelLicense+    | RelLrdd+    | RelMemento+    | RelMonitor+    | RelMonitorGroup+    | RelNext+    | RelNextArchive+    | RelNofollow+    | RelNoreferrer+    | RelOriginal+    | RelPayment+    | RelPredecessorVersion+    | RelPrefetch+    | RelPrev+    | RelPreview+    | RelPrevious+    | RelPrevArchive+    | RelPrivacyPolicy+    | RelProfile+    | RelRelated+    | RelReplies+    | RelSearch+    | RelSection+    | RelSelf+    | RelService+    | RelStart+    | RelStylesheet+    | RelSubsection+    | RelSuccessorVersion+    | RelTag+    | RelTermsOfService+    | RelTimegate+    | RelTimemap+    | RelType+    | RelUp+    | RelVersionHistory+    | RelVia+    | RelWorkingCopy+    | RelWorkingCopyOf+    deriving (Eq, Show)++-- | A mapping from name string to identifiers, for parsing a link relation+-- name from a string.+hashmap :: M.HashMap B.ByteString LinkRelation+hashmap = M.fromList+    [ ("about", RelAbout)+    , ("alternate", RelAlternate)+    , ("appendix", RelAppendix)+    , ("archives", RelArchives)+    , ("author", RelAuthor)+    , ("bookmark", RelBookmark)+    , ("canonical", RelCanonical)+    , ("chapter", RelChapter)+    , ("collection", RelCollection)+    , ("contents", RelContents)+    , ("copyright", RelCopyright)+    , ("create-form", RelCreateForm)+    , ("current", RelCurrent)+    , ("derivedfrom", RelDerivedfrom)+    , ("describedby", RelDescribedby)+    , ("describes", RelDescribes)+    , ("disclosure", RelDisclosure)+    , ("duplicate", RelDuplicate)+    , ("edit", RelEdit)+    , ("edit-form", RelEditForm)+    , ("edit-media", RelEditMedia)+    , ("enclosure", RelEnclosure)+    , ("first", RelFirst)+    , ("glossary", RelGlossary)+    , ("help", RelHelp)+    , ("hosts", RelHosts)+    , ("hub", RelHub)+    , ("icon", RelIcon)+    , ("index", RelIndex)+    , ("item", RelItem)+    , ("last", RelLast)+    , ("latest-version", RelLatestVersion)+    , ("license", RelLicense)+    , ("lrdd", RelLrdd)+    , ("memento", RelMemento)+    , ("monitor", RelMonitor)+    , ("monitor-group", RelMonitorGroup)+    , ("next", RelNext)+    , ("next-archive", RelNextArchive)+    , ("nofollow", RelNofollow)+    , ("noreferrer", RelNoreferrer)+    , ("original", RelOriginal)+    , ("payment", RelPayment)+    , ("predecessor-version", RelPredecessorVersion)+    , ("prefetch", RelPrefetch)+    , ("prev", RelPrev)+    , ("preview", RelPreview)+    , ("previous", RelPrevious)+    , ("prev-archive", RelPrevArchive)+    , ("privacy-policy", RelPrivacyPolicy)+    , ("profile", RelProfile)+    , ("related", RelRelated)+    , ("replies", RelReplies)+    , ("search", RelSearch)+    , ("section", RelSection)+    , ("self", RelSelf)+    , ("service", RelService)+    , ("start", RelStart)+    , ("stylesheet", RelStylesheet)+    , ("subsection", RelSubsection)+    , ("successor-version", RelSuccessorVersion)+    , ("tag", RelTag)+    , ("terms-of-service", RelTermsOfService)+    , ("timegate", RelTimegate)+    , ("timemap", RelTimemap)+    , ("type", RelType)+    , ("up", RelUp)+    , ("version-history", RelVersionHistory)+    , ("via", RelVia)+    , ("working-copy", RelWorkingCopy)+    , ("working-copy-of", RelWorkingCopyOf)+    ]++-- | Create a link relation type from a URI.+fromURI :: URI -> LinkRelation+fromURI = FromURI++-- | Try to parse a string into a URI, returning a link relation if successful.+fromURIStr :: B.ByteString -> Maybe LinkRelation+fromURIStr s =+    case parseURI laxURIParserOptions s of+        Left _  -> Nothing+        Right u -> Just $ fromURI u++-- | Try to match a given link relation name against the registered names.+-- Return the matching link relation if successful.+fromName :: B.ByteString -> Maybe LinkRelation+fromName s = M.lookup s hashmap++-- | Try to parse the given string as a link relation, either as a registered+-- name or as a URI. If both fail, return 'Nothing'.+fromByteString :: B.ByteString -> Maybe LinkRelation+fromByteString s = fromName s <|> fromURIStr s++-- | Get the official registered name of a link relation (if it's a name) or+-- its URI string (if it's a URI).+toByteString :: LinkRelation -> B.ByteString+toByteString lr =+    case lr of+        FromURI u -> serializeURI' u+        RelAbout -> "about"+        RelAlternate -> "alternate"+        RelAppendix -> "appendix"+        RelArchives -> "archives"+        RelAuthor -> "author"+        RelBookmark -> "bookmark"+        RelCanonical -> "canonical"+        RelChapter -> "chapter"+        RelCollection -> "collection"+        RelContents -> "contents"+        RelCopyright -> "copyright"+        RelCreateForm -> "create-form"+        RelCurrent -> "current"+        RelDerivedfrom -> "derivedfrom"+        RelDescribedby -> "describedby"+        RelDescribes -> "describes"+        RelDisclosure -> "disclosure"+        RelDuplicate -> "duplicate"+        RelEdit -> "edit"+        RelEditForm -> "edit-form"+        RelEditMedia -> "edit-media"+        RelEnclosure -> "enclosure"+        RelFirst -> "first"+        RelGlossary -> "glossary"+        RelHelp -> "help"+        RelHosts -> "hosts"+        RelHub -> "hub"+        RelIcon -> "icon"+        RelIndex -> "index"+        RelItem -> "item"+        RelLast -> "last"+        RelLatestVersion -> "latest-version"+        RelLicense -> "license"+        RelLrdd -> "lrdd"+        RelMemento -> "memento"+        RelMonitor -> "monitor"+        RelMonitorGroup -> "monitor-group"+        RelNext -> "next"+        RelNextArchive -> "next-archive"+        RelNofollow -> "nofollow"+        RelNoreferrer -> "noreferrer"+        RelOriginal -> "original"+        RelPayment -> "payment"+        RelPredecessorVersion -> "predecessor-version"+        RelPrefetch -> "prefetch"+        RelPrev -> "prev"+        RelPreview -> "preview"+        RelPrevious -> "previous"+        RelPrevArchive -> "prev-archive"+        RelPrivacyPolicy -> "privacy-policy"+        RelProfile -> "profile"+        RelRelated -> "related"+        RelReplies -> "replies"+        RelSearch -> "search"+        RelSection -> "section"+        RelSelf -> "self"+        RelService -> "service"+        RelStart -> "start"+        RelStylesheet -> "stylesheet"+        RelSubsection -> "subsection"+        RelSuccessorVersion -> "successor-version"+        RelTag -> "tag"+        RelTermsOfService -> "terms-of-service"+        RelTimegate -> "timegate"+        RelTimemap -> "timemap"+        RelType -> "type"+        RelUp -> "up"+        RelVersionHistory -> "version-history"+        RelVia -> "via"+        RelWorkingCopy -> "working-copy"+        RelWorkingCopyOf -> "working-copy-of"++-- | Check whether a link relation is represented by a URI, i.e. is not a link+-- relation registered name.+isURI :: LinkRelation -> Bool+isURI (FromURI _) = True+isURI _           = False++-- | Check whether a link relation is represented by a registered name, i.e. is+-- not a URI.+isName :: LinkRelation -> Bool+isName = not . isURI++-- | Refers to a resource that is the subject of the link\'s context.+--+-- Reference: <https://www.iana.org/go/rfc6903 RFC 6903>, section 2+relAbout :: LinkRelation+relAbout = RelAbout++-- | Refers to a substitute for this context+--+-- Reference: <http://www.w3.org/TR/html5/links.html#link-type-alternate>+relAlternate :: LinkRelation+relAlternate = RelAlternate++-- | Refers to an appendix.+--+-- Reference: <http://www.w3.org/TR/1999/REC-html401-19991224>+relAppendix :: LinkRelation+relAppendix = RelAppendix++-- | Refers to a collection of records, documents, or other materials of+-- historical interest.+--+-- Reference:+-- <http://www.w3.org/TR/2011/WD-html5-20110113/links.html#rel-archives>+relArchives :: LinkRelation+relArchives = RelArchives++-- | Refers to the context\'s author.+--+-- Reference: <http://www.w3.org/TR/html5/links.html#link-type-author>+relAuthor :: LinkRelation+relAuthor = RelAuthor++-- | Gives a permanent link to use for bookmarking purposes.+--+-- Reference: <http://www.w3.org/TR/html5/links.html#link-type-bookmark>+relBookmark :: LinkRelation+relBookmark = RelBookmark++-- | Designates the preferred version of a resource (the IRI and its contents).+--+-- Reference: <https://www.iana.org/go/rfc6596 RFC 6596>+relCanonical :: LinkRelation+relCanonical = RelCanonical++-- | Refers to a chapter in a collection of resources.+--+-- Reference: <http://www.w3.org/TR/1999/REC-html401-19991224>+relChapter :: LinkRelation+relChapter = RelChapter++-- | The target IRI points to a resource which represents the collection+-- resource for the context IRI.+--+-- Reference: <https://www.iana.org/go/rfc6573 RFC 6573>+relCollection :: LinkRelation+relCollection = RelCollection++-- | Refers to a table of contents.+--+-- Reference: <http://www.w3.org/TR/1999/REC-html401-19991224>+relContents :: LinkRelation+relContents = RelContents++-- | Refers to a copyright statement that applies to the link\'s context.+--+-- Reference: <http://www.w3.org/TR/1999/REC-html401-19991224>+relCopyright :: LinkRelation+relCopyright = RelCopyright++-- | The target IRI points to a resource where a submission form can be+-- obtained.+--+-- Reference: <https://www.iana.org/go/rfc6861 RFC 6861>+relCreateForm :: LinkRelation+relCreateForm = RelCreateForm++-- | Refers to a resource containing the most recent item(s) in a collection of+-- resources.+--+-- Reference: <https://www.iana.org/go/rfc5005 RFC 5005>+relCurrent :: LinkRelation+relCurrent = RelCurrent++-- | The target IRI points to a resource from which this material was derived.+--+-- Reference:+-- <https://www.iana.org/go/draft-hoffman-xml2rfc draft-hoffman-xml2rfc>+relDerivedfrom :: LinkRelation+relDerivedfrom = RelDerivedfrom++-- | Refers to a resource providing information about the link\'s context.+--+-- Reference: <http://www.w3.org/TR/powder-dr/#assoc-linking>+relDescribedby :: LinkRelation+relDescribedby = RelDescribedby++-- | The relationship A \'describes\' B asserts that resource A provides a+-- description of resource B. There are no constraints on the format or+-- representation of either A or B, neither are there any further constraints+-- on either resource.+--+-- Reference: <https://www.iana.org/go/rfc6892 RFC 6892>+--+-- Note: This link relation type is the inverse of the \'describedby\' relation+-- type. While \'describedby\' establishes a relation from the described+-- resource back to the resource that describes it, \'describes\' established a+-- relation from the describing resource to the resource it describes. If B is+-- \'describedby\' A, then A \'describes\' B.+relDescribes :: LinkRelation+relDescribes = RelDescribes++-- | Refers to a list of patent disclosures made with respect to material for+-- which \'disclosure\' relation is specified.+--+-- Reference: <https://www.iana.org/go/rfc6579 RFC 6579>+relDisclosure :: LinkRelation+relDisclosure = RelDisclosure++-- | Refers to a resource whose available representations are byte-for-byte+-- identical with the corresponding representations of the context IRI.+--+-- Reference: <https://www.iana.org/go/rfc6249 RFC 6249>+--+-- Note: This relation is for static resources. That is, an HTTP GET request on+-- any duplicate will return the same representation. It does not make sense+-- for dynamic or POSTable resources and should not be used for them.+relDuplicate :: LinkRelation+relDuplicate = RelDuplicate++-- | Refers to a resource that can be used to edit the link\'s context.+--+-- Reference: <https://www.iana.org/go/rfc5023 RFC 5023>+relEdit :: LinkRelation+relEdit = RelEdit++-- | The target IRI points to a resource where a submission form for editing+-- associated resource can be obtained.+--+-- Reference: <https://www.iana.org/go/rfc6861 RFC 6861>+relEditForm :: LinkRelation+relEditForm = RelEditForm++-- | Refers to a resource that can be used to edit media associated with the+-- link\'s context.+--+-- Reference: <https://www.iana.org/go/rfc5023 RFC 5023>+relEditMedia :: LinkRelation+relEditMedia = RelEditMedia++-- | Identifies a related resource that is potentially large and might require+-- special handling.+--+-- Reference: <https://www.iana.org/go/rfc4287 RFC 4287>+relEnclosure :: LinkRelation+relEnclosure = RelEnclosure++-- | An IRI that refers to the furthest preceding resource in a series of+-- resources.+--+-- Reference: <https://www.iana.org/go/rfc5988 RFC 5988>+--+-- Note: This relation type registration did not indicate a reference.+-- Originally requested by Mark Nottingham in December 2004.+relFirst :: LinkRelation+relFirst = RelFirst++-- | Refers to a glossary of terms.+--+-- Reference: <http://www.w3.org/TR/1999/REC-html401-19991224>+relGlossary :: LinkRelation+relGlossary = RelGlossary++-- | Refers to context-sensitive help.+--+-- Reference: <http://www.w3.org/TR/html5/links.html#link-type-help>+relHelp :: LinkRelation+relHelp = RelHelp++-- | Refers to a resource hosted by the server indicated by the link context.+--+-- Reference: <https://www.iana.org/go/rfc6690 RFC 6690>+--+-- Note: This relation is used in CoRE where links are retrieved as a+-- \"\/.well-known\/core\" resource representation, and is the default relation+-- type in the CoRE Link Format.+relHosts :: LinkRelation+relHosts = RelHosts++-- | Refers to a hub that enables registration for notification of updates to+-- the context.+--+-- Reference: <http://pubsubhubbub.googlecode.com>+--+-- Note: This relation type was requested by Brett Slatkin.+relHub :: LinkRelation+relHub = RelHub++-- | Refers to an icon representing the link\'s context.+--+-- Reference: <http://www.w3.org/TR/html5/links.html#link-type-icon>+relIcon :: LinkRelation+relIcon = RelIcon++-- | Refers to an index.+--+-- Reference: <http://www.w3.org/TR/1999/REC-html401-19991224>+relIndex :: LinkRelation+relIndex = RelIndex++-- | The target IRI points to a resource that is a member of the collection+-- represented by the context IRI.+--+-- Reference: <https://www.iana.org/go/rfc6573 RFC 6573>+relItem :: LinkRelation+relItem = RelItem++-- | An IRI that refers to the furthest following resource in a series of+-- resources.+--+-- Reference: <https://www.iana.org/go/rfc5988 RFC 5988>+--+-- Note: This relation type registration did not indicate a reference.+-- Originally requested by Mark Nottingham in December 2004.+relLast :: LinkRelation+relLast = RelLast++-- | Points to a resource containing the latest (e.g., current) version of the+-- context.+--+-- Reference: <https://www.iana.org/go/rfc5829 RFC 5829>+relLatestVersion :: LinkRelation+relLatestVersion = RelLatestVersion++-- | Refers to a license associated with this context.+--+-- Reference: <https://www.iana.org/go/rfc4946 RFC 4946>+--+-- Note: For implications of use in HTML, see:+-- http:\/\/www.w3.org\/TR\/html5\/links.html#link-type-license+relLicense :: LinkRelation+relLicense = RelLicense++-- | Refers to further information about the link\'s context, expressed as a+-- LRDD (\"Link-based Resource Descriptor Document\") resource. See+-- <https://www.iana.org/go/rfc6415 RFC 6415> for information about processing+-- this relation type in host-meta documents. When used elsewhere, it refers to+-- additional links and other metadata. Multiple instances indicate additional+-- LRDD resources. LRDD resources MUST have an \"application\/xrd+xml\"+-- representation, and MAY have others.+--+-- Reference: <https://www.iana.org/go/rfc6415 RFC 6415>+relLrdd :: LinkRelation+relLrdd = RelLrdd++-- | The Target IRI points to a Memento, a fixed resource that will not change+-- state anymore.+--+-- Reference: <https://www.iana.org/go/rfc7089 RFC 7089>+--+-- Note: A Memento for an Original Resource is a resource that encapsulates a+-- prior state of the Original Resource.+relMemento :: LinkRelation+relMemento = RelMemento++-- | Refers to a resource that can be used to monitor changes in an HTTP+-- resource.+--+-- Reference: <https://www.iana.org/go/rfc5989 RFC 5989>+relMonitor :: LinkRelation+relMonitor = RelMonitor++-- | Refers to a resource that can be used to monitor changes in a specified+-- group of HTTP resources.+--+-- Reference: <https://www.iana.org/go/rfc5989 RFC 5989>+relMonitorGroup :: LinkRelation+relMonitorGroup = RelMonitorGroup++-- | Indicates that the link\'s context is a part of a series, and that the+-- next in the series is the link target.+--+-- Reference: <http://www.w3.org/TR/html5/links.html#link-type-next>+relNext :: LinkRelation+relNext = RelNext++-- | Refers to the immediately following archive resource.+--+-- Reference: <https://www.iana.org/go/rfc5005 RFC 5005>+relNextArchive :: LinkRelation+relNextArchive = RelNextArchive++-- | Indicates that the context’s original author or publisher does not+-- endorse the link target.+--+-- Reference: <http://www.w3.org/TR/html5/links.html#link-type-nofollow>+relNofollow :: LinkRelation+relNofollow = RelNofollow++-- | Indicates that no referrer information is to be leaked when following the+-- link.+--+-- Reference: <http://www.w3.org/TR/html5/links.html#link-type-noreferrer>+relNoreferrer :: LinkRelation+relNoreferrer = RelNoreferrer++-- | The Target IRI points to an Original Resource.+--+-- Reference: <https://www.iana.org/go/rfc7089 RFC 7089>+--+-- Note: An Original Resource is a resource that exists or used to exist, and+-- for which access to one of its prior states may be required.+relOriginal :: LinkRelation+relOriginal = RelOriginal++-- | Indicates a resource where payment is accepted.+--+-- Reference: <https://www.iana.org/go/rfc5988 RFC 5988>+--+-- Note: This relation type registration did not indicate a reference.+-- Requested by Joshua Kinberg and Robert Sayre. It is meant as a general way+-- to facilitate acts of payment, and thus this specification makes no+-- assumptions on the type of payment or transaction protocol. Examples may+-- include a web page where donations are accepted or where goods and services+-- are available for purchase. rel=\"payment\" is not intended to initiate an+-- automated transaction. In Atom documents, a link element with a+-- rel=\"payment\" attribute may exist at the feed\/channel level and\/or the+-- entry\/item level. For example, a rel=\"payment\" link at the feed\/channel+-- level may point to a \"tip jar\" URI, whereas an entry\/ item containing a+-- book review may include a rel=\"payment\" link that points to the location+-- where the book may be purchased through an online retailer.+relPayment :: LinkRelation+relPayment = RelPayment++-- | Points to a resource containing the predecessor version in the version+-- history.+--+-- Reference: <https://www.iana.org/go/rfc5829 RFC 5829>+relPredecessorVersion :: LinkRelation+relPredecessorVersion = RelPredecessorVersion++-- | Indicates that the link target should be preemptively cached.+--+-- Reference: <http://www.w3.org/TR/html5/links.html#link-type-prefetch>+relPrefetch :: LinkRelation+relPrefetch = RelPrefetch++-- | Indicates that the link\'s context is a part of a series, and that the+-- previous in the series is the link target.+--+-- Reference: <http://www.w3.org/TR/html5/links.html#link-type-prev>+relPrev :: LinkRelation+relPrev = RelPrev++-- | Refers to a resource that provides a preview of the link\'s context.+--+-- Reference: <https://www.iana.org/go/rfc6903 RFC 6903>, section 3+relPreview :: LinkRelation+relPreview = RelPreview++-- | Refers to the previous resource in an ordered series of resources. Synonym+-- for \"prev\".+--+-- Reference: <http://www.w3.org/TR/1999/REC-html401-19991224>+relPrevious :: LinkRelation+relPrevious = RelPrevious++-- | Refers to the immediately preceding archive resource.+--+-- Reference: <https://www.iana.org/go/rfc5005 RFC 5005>+relPrevArchive :: LinkRelation+relPrevArchive = RelPrevArchive++-- | Refers to a privacy policy associated with the link\'s context.+--+-- Reference: <https://www.iana.org/go/rfc6903 RFC 6903>, section 4+relPrivacyPolicy :: LinkRelation+relPrivacyPolicy = RelPrivacyPolicy++-- | Identifying that a resource representation conforms to a certain profile,+-- without affecting the non-profile semantics of the resource representation.+--+-- Reference: <https://www.iana.org/go/rfc6906 RFC 6906>+--+-- Note: Profile URIs are primarily intended to be used as identifiers, and+-- thus clients SHOULD NOT indiscriminately access profile URIs.+relProfile :: LinkRelation+relProfile = RelProfile++-- | Identifies a related resource.+--+-- Reference: <https://www.iana.org/go/rfc4287 RFC 4287>+relRelated :: LinkRelation+relRelated = RelRelated++-- | Identifies a resource that is a reply to the context of the link.+--+-- Reference: <https://www.iana.org/go/rfc4685 RFC 4685>+relReplies :: LinkRelation+relReplies = RelReplies++-- | Refers to a resource that can be used to search through the link\'s+-- context and related resources.+--+-- Reference: <http://www.opensearch.org/Specifications/OpenSearch/1.1>+relSearch :: LinkRelation+relSearch = RelSearch++-- | Refers to a section in a collection of resources.+--+-- Reference: <http://www.w3.org/TR/1999/REC-html401-19991224>+relSection :: LinkRelation+relSection = RelSection++-- | Conveys an identifier for the link\'s context.+--+-- Reference: <https://www.iana.org/go/rfc4287 RFC 4287>+relSelf :: LinkRelation+relSelf = RelSelf++-- | Indicates a URI that can be used to retrieve a service document.+--+-- Reference: <https://www.iana.org/go/rfc5023 RFC 5023>+--+-- Note: When used in an Atom document, this relation type specifies Atom+-- Publishing Protocol service documents by default. Requested by James Snell.+relService :: LinkRelation+relService = RelService++-- | Refers to the first resource in a collection of resources.+--+-- Reference: <http://www.w3.org/TR/1999/REC-html401-19991224>+relStart :: LinkRelation+relStart = RelStart++-- | Refers to a stylesheet.+--+-- Reference: <http://www.w3.org/TR/html5/links.html#link-type-stylesheet>+relStylesheet :: LinkRelation+relStylesheet = RelStylesheet++-- | Refers to a resource serving as a subsection in a collection of resources.+--+-- Reference: <http://www.w3.org/TR/1999/REC-html401-19991224>+relSubsection :: LinkRelation+relSubsection = RelSubsection++-- | Points to a resource containing the successor version in the version+-- history.+--+-- Reference: <https://www.iana.org/go/rfc5829 RFC 5829>+relSuccessorVersion :: LinkRelation+relSuccessorVersion = RelSuccessorVersion++-- | Gives a tag (identified by the given address) that applies to the current+-- document.+--+-- Reference: <http://www.w3.org/TR/html5/links.html#link-type-tag>+relTag :: LinkRelation+relTag = RelTag++-- | Refers to the terms of service associated with the link\'s context.+--+-- Reference: <https://www.iana.org/go/rfc6903 RFC 6903>, section 5+relTermsOfService :: LinkRelation+relTermsOfService = RelTermsOfService++-- | The Target IRI points to a TimeGate for an Original Resource.+--+-- Reference: <https://www.iana.org/go/rfc7089 RFC 7089>+--+-- Note: A TimeGate for an Original Resource is a resource that is capable of+-- datetime negotiation to support access to prior states of the Original+-- Resource.+relTimegate :: LinkRelation+relTimegate = RelTimegate++-- | The Target IRI points to a TimeMap for an Original Resource.+--+-- Reference: <https://www.iana.org/go/rfc7089 RFC 7089>+--+-- Note: A TimeMap for an Original Resource is a resource from which a list of+-- URIs of Mementos of the Original Resource is available.+relTimemap :: LinkRelation+relTimemap = RelTimemap++-- | Refers to a resource identifying the abstract semantic type of which the+-- link\'s context is considered to be an instance.+--+-- Reference: <https://www.iana.org/go/rfc6903 RFC 6903>, section 6+relType :: LinkRelation+relType = RelType++-- | Refers to a parent document in a hierarchy of documents.+--+-- Reference: <https://www.iana.org/go/rfc5988 RFC 5988>+--+-- Note: This relation type registration did not indicate a reference.+-- Requested by Noah Slater.+relUp :: LinkRelation+relUp = RelUp++-- | Points to a resource containing the version history for the context.+--+-- Reference: <https://www.iana.org/go/rfc5829 RFC 5829>+relVersionHistory :: LinkRelation+relVersionHistory = RelVersionHistory++-- | Identifies a resource that is the source of the information in the link\'s+-- context.+--+-- Reference: <https://www.iana.org/go/rfc4287 RFC 4287>+relVia :: LinkRelation+relVia = RelVia++-- | Points to a working copy for this resource.+--+-- Reference: <https://www.iana.org/go/rfc5829 RFC 5829>+relWorkingCopy :: LinkRelation+relWorkingCopy = RelWorkingCopy++-- | Points to the versioned resource from which this working copy was+-- obtained.+--+-- Reference: <https://www.iana.org/go/rfc5829 RFC 5829>+relWorkingCopyOf :: LinkRelation+relWorkingCopyOf = RelWorkingCopyOf
+ util/generate.hs view
@@ -0,0 +1,353 @@+{- This file is part of link-relations.+ -+ - Written in 2015 by fr33domlover <fr33domlover@riseup.net>.+ -+ - ♡ Copying is an act of love. Please copy, reuse and share.+ -+ - The author(s) have dedicated all copyright and related and neighboring+ - rights to this software to the public domain worldwide. This software is+ - distributed without any warranty.+ -+ - You should have received a copy of the CC0 Public Domain Dedication along+ - with this software. If not, see+ - <http://creativecommons.org/publicdomain/zero/1.0/>.+ -}++{-# LANGUAGE OverloadedStrings #-}++module Main where++import Control.Applicative+import Control.Monad (guard, liftM)+import Data.Char (toUpper)+import Data.Csv+import Data.Foldable (mapM_)+import Data.Int (Int64)+import Data.List (intercalate)+import Data.Maybe (fromMaybe)+import Data.Monoid ((<>), mconcat)+import Prelude hiding (mapM_)++import qualified Data.ByteString.Lazy as BL+import qualified Data.ByteString.Lazy.Char8 as BLC+import qualified Data.Vector as V (length, toList)++-------------------------------------------------------------------------------+-- Configuration+-------------------------------------------------------------------------------++-- | The IANA link relations registry data.+csvFile :: FilePath+csvFile = "util/link-relations-1.csv"++-- | Haskell source template into which the data needs to be inserted.+hsTemplateFile :: FilePath+hsTemplateFile = "util/template.hs"++-- | Where to write the result of writing formatted data into the template.+outputFile :: FilePath+outputFile = "src/Web/LinkRelations.hs.new"++-- | Y-M-D date specifying the time of the last update to the IANA registry.+lastUpdated :: BL.ByteString+lastUpdated = "2015-01-21"++-------------------------------------------------------------------------------+-- Types+-------------------------------------------------------------------------------++data LinkRelInfo = LinkRelInfo+    { lrName        :: BL.ByteString+    , lrDescription :: BL.ByteString+    , lrReferences  :: BL.ByteString+    , lrNotes       :: BL.ByteString+    }+    deriving (Show)++instance FromRecord LinkRelInfo where+    parseRecord v =+        if V.length v == 4+            then LinkRelInfo <$>+                 v .! 0 <*>+                 v .! 1 <*>+                 v .! 2 <*>+                 v .! 3+            else empty++data TemplateLine = TemplText BL.ByteString | TemplVar BL.ByteString++-------------------------------------------------------------------------------+-- Utilities+-------------------------------------------------------------------------------++-- | Like 'map', but applies one function to the first element and a different+-- function to the rest of the elements.+mapSep :: (a -> b) -> (a -> b) -> [a] -> [b]+mapSep _ _ []     = []+mapSep f g (x:xs) = f x : map g xs++-- | Like 'BLC.map', but applies the function /only/ to the first byte.+mapFstB :: (Char -> Char) -> BL.ByteString -> BL.ByteString+mapFstB f s =+    case BLC.uncons s of+        Nothing     -> s+        Just (c, r) -> f c `BLC.cons` r++--mapTail :: (a -> a) -> [a] -> [a]+--mapTail _ []     = []+--mapTail f (x:xs) = x : map f xs++-- | Convert @this-is-some-name@ to @ThisIsSomeName@.+toCamel :: BL.ByteString -> BL.ByteString+toCamel = mconcat . map (mapFstB toUpper) . BLC.split '-'++-- | Apply a function to the first element.+applyFst :: (a -> c) -> (a, b) -> (c, b)+applyFst f (x, y) = (f x, y)++-- | Break a list of words into two lists. The first is the maximal prefix+-- whose length (including spaces between words) is at most N (unless the first+-- word is longer than N, in which case that word is returned), and the second+-- list is the rest of the word list.+breakN :: Int64 -> [BL.ByteString] -> ([BL.ByteString], [BL.ByteString])+breakN len ws = applyFst reverse $ f 0 [] ws+    where+    f _ xs []       = (xs, [])+    f n [] (y:ys)   =+        let l = n + BL.length y -- 'n' should be 0 here+        in  if len <= l+                then ([y], ys)+                else f l [y] ys+    f n xs r@(y:ys) =+        let l = n + 1 + BL.length y+        in  if len < l+                then (xs, r)+                else f l (y:xs) ys++-- | Apply 'breakN' repeatedly on a word list, splitting it into a list of+-- word-lists.+splitN :: Int64 -> [BL.ByteString] -> [[BL.ByteString]]+splitN len = f+    where+    f ws =+        case breakN len ws of+            (xs, []) -> [xs]+            (xs, ys) -> xs : f ys++-- | Read a text file into a list of lines.+readLines :: FilePath -> IO [BL.ByteString]+readLines = liftM BLC.lines . BL.readFile++-------------------------------------------------------------------------------+-- Haddock Comments+-------------------------------------------------------------------------------++-- | Try to detect a link by suffix. Return remaining prefix and a suffix to+-- append after link conversion.+stripLinkSuffix :: BL.ByteString -> Maybe (BL.ByteString, BL.ByteString)+stripLinkSuffix w =+    case BLC.unsnoc w of+        Just (t, ']') -> Just (t, BL.empty)+        Just (t, ',') ->+            case BLC.unsnoc t of+                Just (r, ']') -> Just (r, BLC.singleton ',')+                _             -> Nothing+        _             -> Nothing++-- | If the given word is a link, convert to haddock format.+detectLink :: BL.ByteString -> Maybe BL.ByteString+detectLink w =+    let rfcPrefix = "[RFC"+        rfcDrop = 4+        httpPrefix = "[http"+        httpDrop = 1+        otherPrefix = "["+        otherDrop = 1+        iana = "<https://www.iana.org/go/"+    in  case stripLinkSuffix w of+            Just (t, r)+                | rfcPrefix `BL.isPrefixOf` t  -> Just $+                    let num = BL.drop rfcDrop t+                    in  iana <> "rfc" <> num <> " RFC " <> num <> ">" <> r+                | httpPrefix `BL.isPrefixOf` t -> Just $+                    "<" <> BL.drop httpDrop t <> ">" <> r+                | otherPrefix `BL.isPrefixOf` t  -> Just $+                    let name = BL.drop otherDrop t+                    in  iana <> name <> " " <> name <> ">" <> r+                | otherwise                    -> Nothing+            Nothing -> Nothing++-- | Escape some formatting characters in a non-link word.+escapeWord :: BL.ByteString -> BL.ByteString+escapeWord = BLC.foldr f BL.empty+    where+    f c s =+        if c `elem` ['/', '"', '\'']+            then '\\' `BLC.cons` c `BLC.cons` s+            else c `BLC.cons` s++-- | Convert links, espcape characters, do some comment text processing.+processWords :: [BL.ByteString] -> [BL.ByteString]+processWords = map $ \ s -> fromMaybe (escapeWord s) $ detectLink s++-- | Format a paragraph as haddock identifier comment lines.+toComment :: BL.ByteString -> [BL.ByteString]+toComment s =+    let mkFirst = ("-- | " <>) . BLC.unwords+        mkRest = ("-- " <>) . BLC.unwords+    in  case breakN 74 $ processWords $ BLC.words s of+            (xs, []) -> [mkFirst xs]+            (xs, ys) -> mkFirst xs : map mkRest (splitN 76 ys)++-- | Format a paragraph as haddock identifier non-first comment lines.+toCommentCont :: BL.ByteString -> [BL.ByteString]+toCommentCont =+    let mkline = ("-- " <>) . BLC.unwords+    in  map mkline . splitN 76 . processWords . BLC.words++-------------------------------------------------------------------------------+-- Registry Data+-------------------------------------------------------------------------------++-- | Given the CSV file path, read it into a list of linkrel records.+readData :: FilePath -> IO [LinkRelInfo]+readData file = do+    csv <- BL.readFile file+    case decode HasHeader csv of+        Left err  -> error $ "CSV parsing failed: " ++ err+        Right lrs -> return $ V.toList lrs++-------------------------------------------------------------------------------+-- Template+-------------------------------------------------------------------------------++-- | Detect whether a template line is literal text or a variable.+parseLine :: BL.ByteString -> TemplateLine+parseLine s = fromMaybe (TemplText s) $ do+    (h, t) <- BLC.uncons s+    guard $ h == '$'+    (h', t') <- BLC.uncons t+    guard $ h' == '{'+    (i, l) <- BLC.unsnoc t'+    guard $ l == '}'+    return $ TemplVar i++-- | Interpolate the variable values into a template.+render :: (BL.ByteString -> BL.ByteString) -> [TemplateLine] -> BL.ByteString+render f =+    let g (TemplText s) = s `BLC.snoc` '\n'+        g (TemplVar v) = f v+    in  mconcat . map g++-- | Read and parse a template file.+readTemplate :: FilePath -> IO [TemplateLine]+readTemplate = liftM (map parseLine) . readLines++-------------------------------------------------------------------------------+-- Haskell Code Generation+-------------------------------------------------------------------------------++-- date -----------------------------------------------------------------------++-- | Registry revision date to insert into haddock comment.+varDate :: BL.ByteString+varDate = "-- /" <> lastUpdated <> "/\n"++-- exports --------------------------------------------------------------------++-- | Given a linkrel name, get a matching Haskell variable name.+toSymName :: BL.ByteString -> BL.ByteString+toSymName = ("rel" <>) . toCamel++-- | Given a linkrel name, format an export source line.+formatExport :: BL.ByteString -> BL.ByteString+formatExport = ("    , " <>) . toSymName++-- | Given a list of linkrel names, get the exports text.+mkVarExports :: [BL.ByteString] -> BL.ByteString+mkVarExports = BLC.unlines . map formatExport++-- ctors ----------------------------------------------------------------------++-- | Given a linkrel name, get a matching data constructor name.+toCtorName :: BL.ByteString -> BL.ByteString+toCtorName = ("Rel" <>) . toCamel++-- | Given a linkrel name, format a data constructor source line.+formatCtor :: BL.ByteString -> BL.ByteString+formatCtor = ("    | " <>) . toCtorName++-- | Given a list of linkrel names, get the constructors text.+mkVarCtors :: [BL.ByteString] -> BL.ByteString+mkVarCtors = BLC.unlines . map formatCtor++-- hashmap --------------------------------------------------------------------++-- | Given a linkrel name, format a hashmap pair source line.+formatPair :: Bool -> BL.ByteString -> BL.ByteString+formatPair first name =+    let c = if first then "[" else ","+    in  "    " <> c <> " (\"" <> name <> "\", " <> toCtorName name <> ")"++-- | Given a list of linkrel names, get the hashmap text.+mkVarHashmap :: [BL.ByteString] -> BL.ByteString+mkVarHashmap = BLC.unlines . mapSep (formatPair True) (formatPair False)++-- tostr ----------------------------------------------------------------------++-- | Given a linkrel name, format a to-string source line.+formatMatch :: BL.ByteString -> BL.ByteString+formatMatch name = "        " <> toCtorName name <> " -> \"" <> name <> "\""++-- | Given a list of linkrel names, get the tostr text.+mkVarTostr :: [BL.ByteString] -> BL.ByteString+mkVarTostr = BLC.unlines . map formatMatch++-- rels -----------------------------------------------------------------------++-- | Given a linkrel, format a haddock comment.+formatRelComment :: LinkRelInfo -> [BL.ByteString]+formatRelComment lr =+    let fmt pref s =+            if BL.null s+                then []+                else "--" : toCommentCont (pref <> s)+    in  toComment (lrDescription lr) +++        fmt "Reference: " (lrReferences lr) +++        fmt "Note: " (lrNotes lr)++-- | Given a linkrel, format relation symbol lines.+formatRel :: LinkRelInfo -> [BL.ByteString]+formatRel lr =+    let name = lrName lr+        sym = toSymName name+        ctor = toCtorName name+    in  formatRelComment lr +++        [ sym <> " :: LinkRelation"+        , sym <> " = " <> ctor+        ]++-- | Given a list of linkrels , get the rels text.+mkVarRels :: [LinkRelInfo] -> BL.ByteString+mkVarRels = BLC.unlines . intercalate [BL.empty] . map formatRel++-------------------------------------------------------------------------------+-- Main+-------------------------------------------------------------------------------++main :: IO ()+main = do+    lrs <- readData csvFile+    templ <- readTemplate hsTemplateFile+    let lrNames = map lrName lrs+        getVar s+            | s == "date"    = varDate+            | s == "exports" = mkVarExports lrNames+            | s == "ctors"   = mkVarCtors lrNames+            | s == "hashmap" = mkVarHashmap lrNames+            | s == "tostr"   = mkVarTostr lrNames+            | s == "rels"    = mkVarRels lrs+            | otherwise      =+                error $ "No value defined for variable " ++ show s+    BL.writeFile outputFile $ render getVar templ+    putStrLn "Done."
@@ -0,0 +1,153 @@+Relation Name,Description,Reference,Notes
+about,Refers to a resource that is the subject of the link's context.,"[RFC6903], section 2",
+alternate,Refers to a substitute for this context,[http://www.w3.org/TR/html5/links.html#link-type-alternate],
+appendix,Refers to an appendix.,[http://www.w3.org/TR/1999/REC-html401-19991224],
+archives,"Refers to a collection of records, documents, or other+      materials of historical interest.",[http://www.w3.org/TR/2011/WD-html5-20110113/links.html#rel-archives],
+author,Refers to the context's author.,[http://www.w3.org/TR/html5/links.html#link-type-author],
+bookmark,Gives a permanent link to use for bookmarking purposes.,[http://www.w3.org/TR/html5/links.html#link-type-bookmark],
+canonical,Designates the preferred version of a resource (the IRI and its contents).,[RFC6596],
+chapter,Refers to a chapter in a collection of resources.,[http://www.w3.org/TR/1999/REC-html401-19991224],
+collection,The target IRI points to a resource which represents the collection resource for the context IRI.,[RFC6573],
+contents,Refers to a table of contents.,[http://www.w3.org/TR/1999/REC-html401-19991224],
+copyright,"Refers to a copyright statement that applies to the+    link's context.",[http://www.w3.org/TR/1999/REC-html401-19991224],
+create-form,The target IRI points to a resource where a submission form can be obtained.,[RFC6861],
+current,"Refers to a resource containing the most recent+      item(s) in a collection of resources.",[RFC5005],
+derivedfrom,The target IRI points to a resource from which this material was derived.,[draft-hoffman-xml2rfc],
+describedby,"Refers to a resource providing information about the+      link's context.",[http://www.w3.org/TR/powder-dr/#assoc-linking],
+describes,"The relationship A 'describes' B asserts that+      resource A provides a description of resource B. There are no+      constraints on the format or representation of either A or B,+      neither are there any further constraints on either resource.",[RFC6892],"This link relation type is the inverse of the 'describedby'+        relation type.  While 'describedby' establishes a relation from+        the described resource back to the resource that describes it,+        'describes' established a relation from the describing resource to+        the resource it describes.  If B is 'describedby' A, then A+        'describes' B."
+disclosure,Refers to a list of patent disclosures made with respect to material for which 'disclosure' relation is specified.,[RFC6579],
+duplicate,"Refers to a resource whose available representations+      are byte-for-byte identical with the corresponding representations of+      the context IRI.",[RFC6249],"This relation is for static resources.  That is, an HTTP GET+      request on any duplicate will return the same representation.  It+      does not make sense for dynamic or POSTable resources and should not+      be used for them."
+edit,"Refers to a resource that can be used to edit the+      link's context.",[RFC5023],
+edit-form,"The target IRI points to a resource where a submission form for+      editing associated resource can be obtained.",[RFC6861],
+edit-media,"Refers to a resource that can be used to edit media+      associated with the link's context.",[RFC5023],
+enclosure,"Identifies a related resource that is potentially+      large and might require special handling.",[RFC4287],
+first,"An IRI that refers to the furthest preceding resource+    in a series of resources.",[RFC5988],"This relation type registration did not indicate a+      reference.  Originally requested by Mark Nottingham in December+      2004."
+glossary,Refers to a glossary of terms.,[http://www.w3.org/TR/1999/REC-html401-19991224],
+help,Refers to context-sensitive help.,[http://www.w3.org/TR/html5/links.html#link-type-help],
+hosts,"Refers to a resource hosted by the server indicated by+      the link context.",[RFC6690],"This relation is used in CoRE where links are retrieved as a+      ""/.well-known/core"" resource representation, and is the default+      relation type in the CoRE Link Format."
+hub,"Refers to a hub that enables registration for+    notification of updates to the context.",[http://pubsubhubbub.googlecode.com],This relation type was requested by Brett Slatkin.
+icon,Refers to an icon representing the link's context.,[http://www.w3.org/TR/html5/links.html#link-type-icon],
+index,Refers to an index.,[http://www.w3.org/TR/1999/REC-html401-19991224],
+item,The target IRI points to a resource that is a member of the collection represented by the context IRI.,[RFC6573],
+last,"An IRI that refers to the furthest following resource+      in a series of resources.",[RFC5988],"This relation type registration did not indicate a+      reference. Originally requested by Mark Nottingham in December+      2004."
+latest-version,"Points to a resource containing the latest (e.g.,+      current) version of the context.",[RFC5829],
+license,Refers to a license associated with this context.,[RFC4946],"For implications of use in HTML, see: +      http://www.w3.org/TR/html5/links.html#link-type-license"
+lrdd,"Refers to further information about the link's context,+      expressed as a LRDD (""Link-based Resource Descriptor Document"")+      resource.  See [RFC6415] for information about+      processing this relation type in host-meta documents. When used+      elsewhere, it refers to additional links and other metadata.+      Multiple instances indicate additional LRDD resources. LRDD+      resources MUST have an ""application/xrd+xml"" representation, and+      MAY have others.",[RFC6415],
+memento,"The Target IRI points to a Memento, a fixed resource that will not change state anymore.",[RFC7089],"A Memento for an Original Resource is a resource that+      encapsulates a prior state of the Original Resource."
+monitor,Refers to a resource that can be used to monitor changes in an HTTP resource.,[RFC5989],
+monitor-group,Refers to a resource that can be used to monitor changes in a specified group of HTTP resources.,[RFC5989],
+next,"Indicates that the link's context is a part of a series, and+      that the next in the series is the link target.",[http://www.w3.org/TR/html5/links.html#link-type-next],
+next-archive,Refers to the immediately following archive resource.,[RFC5005],
+nofollow,Indicates that the context’s original author or publisher does not endorse the link target.,[http://www.w3.org/TR/html5/links.html#link-type-nofollow],
+noreferrer,Indicates that no referrer information is to be leaked when following the link.,[http://www.w3.org/TR/html5/links.html#link-type-noreferrer],
+original,The Target IRI points to an Original Resource.,[RFC7089],"An Original Resource is a resource that exists or used to+      exist, and for which access to one of its prior states may be+      required."
+payment,Indicates a resource where payment is accepted.,[RFC5988],"This relation type registration did not indicate a+      reference.  Requested by Joshua Kinberg and Robert Sayre.  It is+      meant as a general way to facilitate acts of payment, and thus+      this specification makes no assumptions on the type of payment or+      transaction protocol.  Examples may include a web page where+      donations are accepted or where goods and services are available+      for purchase. rel=""payment"" is not intended to initiate an+      automated transaction.  In Atom documents, a link element with a+      rel=""payment"" attribute may exist at the feed/channel level and/or+      the entry/item level.  For example, a rel=""payment"" link at the+      feed/channel level may point to a ""tip jar"" URI, whereas an entry/+      item containing a book review may include a rel=""payment"" link+      that points to the location where the book may be purchased+      through an online retailer."
+predecessor-version,"Points to a resource containing the predecessor+      version in the version history.",[RFC5829],
+prefetch,Indicates that the link target should be preemptively cached.,[http://www.w3.org/TR/html5/links.html#link-type-prefetch],
+prev,"Indicates that the link's context is a part of a series, and+      that the previous in the series is the link target.",[http://www.w3.org/TR/html5/links.html#link-type-prev],
+preview,Refers to a resource that provides a preview of the link's context.,"[RFC6903], section 3",
+previous,"Refers to the previous resource in an ordered series+      of resources.  Synonym for ""prev"".",[http://www.w3.org/TR/1999/REC-html401-19991224],
+prev-archive,Refers to the immediately preceding archive resource.,[RFC5005],
+privacy-policy,Refers to a privacy policy associated with the link's context.,"[RFC6903], section 4",
+profile,"Identifying that a resource representation conforms+to a certain profile, without affecting the non-profile semantics+of the resource representation.",[RFC6906],"Profile URIs are primarily intended to be used as+identifiers, and thus clients SHOULD NOT indiscriminately access+profile URIs."
+related,Identifies a related resource.,[RFC4287],
+replies,"Identifies a resource that is a reply to the context+      of the link.",[RFC4685],
+search,"Refers to a resource that can be used to search through+      the link's context and related resources.",[http://www.opensearch.org/Specifications/OpenSearch/1.1],
+section,Refers to a section in a collection of resources.,[http://www.w3.org/TR/1999/REC-html401-19991224],
+self,Conveys an identifier for the link's context.,[RFC4287],
+service,"Indicates a URI that can be used to retrieve a+      service document.",[RFC5023],"When used in an Atom document, this relation type specifies+      Atom Publishing Protocol service documents by default.  Requested+      by James Snell."
+start,"Refers to the first resource in a collection of+      resources.",[http://www.w3.org/TR/1999/REC-html401-19991224],
+stylesheet,Refers to a stylesheet.,[http://www.w3.org/TR/html5/links.html#link-type-stylesheet],
+subsection,"Refers to a resource serving as a subsection in a+      collection of resources.",[http://www.w3.org/TR/1999/REC-html401-19991224],
+successor-version,"Points to a resource containing the successor version+      in the version history.",[RFC5829],
+tag,"Gives a tag (identified by the given address) that applies to+      the current document.",[http://www.w3.org/TR/html5/links.html#link-type-tag],
+terms-of-service,Refers to the terms of service associated with the link's context.,"[RFC6903], section 5",
+timegate,The Target IRI points to a TimeGate for an Original Resource.,[RFC7089],"A TimeGate for an Original Resource is a resource that is+      capable of datetime negotiation to support access to prior states+      of the Original Resource."
+timemap,The Target IRI points to a TimeMap for an Original Resource.,[RFC7089],"A TimeMap for an Original Resource is a resource from which+      a list of URIs of Mementos of the Original Resource is available."
+type,Refers to a resource identifying the abstract semantic type of which the link's context is considered to be an instance.,"[RFC6903], section 6",
+up,"Refers to a parent document in a hierarchy of+      documents.",[RFC5988],"This relation type registration did not indicate a+      reference.  Requested by Noah Slater."
+version-history,"Points to a resource containing the version history+      for the context.",[RFC5829],
+via,"Identifies a resource that is the source of the+      information in the link's context.",[RFC4287],
+working-copy,Points to a working copy for this resource.,[RFC5829],
+working-copy-of,"Points to the versioned resource from which this+      working copy was obtained.",[RFC5829],
+ util/template.hs view
@@ -0,0 +1,111 @@+{- This file is part of link-relations.+ -+ - Written in 2015 by fr33domlover <fr33domlover@riseup.net>.+ - Also includes parts generated from the IANA link relation registry.+ -+ - ♡ Copying is an act of love. Please copy, reuse and share.+ -+ - The author(s) have dedicated all copyright and related and neighboring+ - rights to this software to the public domain worldwide. This software is+ - distributed without any warranty.+ -+ - You should have received a copy of the CC0 Public Domain Dedication along+ - with this software. If not, see+ - <http://creativecommons.org/publicdomain/zero/1.0/>.+ -}++{-# LANGUAGE OverloadedStrings #-}++-- | A simple web link between two web resources, e.g. a hyperlink in a webpage+-- referring to another page, suggests that the resources are somehow related,+-- but it doesn't say /how/ they are related. For example, a blog post may link+-- to the author's main page (relation: author of the post) but also link to+-- the previous post (relation: previous post by chronological order).+--+-- Link relations provide a way to express the relation between resources+-- linked by a web link.+--+-- A link relation type may be represented by a URI, or by a registered link+-- relation name. IANA maintains a+-- <https://www.iana.org/assignments/link-relations registry> of link+-- relations. This module provides access to them through a dedicated+-- 'LinkRelation' datatype.+--+-- This version of the package corresponds to the+${date}+-- version of the registry.+module Web.LinkRelations+    ( -- * Types and Conversions+      LinkRelation+    , fromURI+    , fromURIStr+    , fromName+    , fromByteString+    , isURI+    , isName+    , toByteString+      -- * Link Relation Identifiers+${exports}+    )+where++import Control.Applicative ((<|>))+import URI.ByteString++import qualified Data.ByteString as B+import qualified Data.HashMap.Strict as M++-- | A web link relation type. Either a URI or a registered name.+data LinkRelation+    = FromURI URI+${ctors}+    deriving (Eq, Show)++-- | A mapping from name string to identifiers, for parsing a link relation+-- name from a string.+hashmap :: M.HashMap B.ByteString LinkRelation+hashmap = M.fromList+${hashmap}+    ]++-- | Create a link relation type from a URI.+fromURI :: URI -> LinkRelation+fromURI = FromURI++-- | Try to parse a string into a URI, returning a link relation if successful.+fromURIStr :: B.ByteString -> Maybe LinkRelation+fromURIStr s =+    case parseURI laxURIParserOptions s of+        Left _  -> Nothing+        Right u -> Just $ fromURI u++-- | Try to match a given link relation name against the registered names.+-- Return the matching link relation if successful.+fromName :: B.ByteString -> Maybe LinkRelation+fromName s = M.lookup s hashmap++-- | Try to parse the given string as a link relation, either as a registered+-- name or as a URI. If both fail, return 'Nothing'.+fromByteString :: B.ByteString -> Maybe LinkRelation+fromByteString s = fromName s <|> fromURIStr s++-- | Get the official registered name of a link relation (if it's a name) or+-- its URI string (if it's a URI).+toByteString :: LinkRelation -> B.ByteString+toByteString lr =+    case lr of+        FromURI u -> serializeURI' u+${tostr}++-- | Check whether a link relation is represented by a URI, i.e. is not a link+-- relation registered name.+isURI :: LinkRelation -> Bool+isURI (FromURI _) = True+isURI _           = False++-- | Check whether a link relation is represented by a registered name, i.e. is+-- not a URI.+isName :: LinkRelation -> Bool+isName = not . isURI++${rels}