documents.go 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // Package documents defines procedures to load documents from files or
  2. // io.Reader instances and optionally convert them from Markdown to HTML. These
  3. // documents may have metadata headers.
  4. //
  5. // This package treats metadata blocks that fail to parse correctly as document
  6. // content. For additional details on the formats and processing of the
  7. // metadata headers, see the documentation for the metadata package.
  8. package documents
  9. import (
  10. "bytes"
  11. "io"
  12. "os"
  13. "cdop.pt/go/free/platepipe/documents/files"
  14. "cdop.pt/go/free/platepipe/documents/markdown"
  15. "cdop.pt/go/free/platepipe/metadata"
  16. )
  17. // FromFile loads a text or Markdown document from a file whose path is passed
  18. // as the argument.
  19. //
  20. // If the file's extension indicates that the file contains Markdown, the
  21. // content will be converted to HTML. Otherwise, no conversion is made.
  22. func FromFile(file string) ([]byte, map[string]any, error) {
  23. if files.HasKnownMarkdownExt(file) {
  24. return FromMarkdownFile(file)
  25. }
  26. return FromTextFile(file)
  27. }
  28. // FromMarkdownFile loads content/metadata from the given file and returns
  29. // the Markdown content converted to HTML.
  30. func FromMarkdownFile(file string) ([]byte, map[string]any, error) {
  31. r, err := os.Open(file)
  32. if err != nil {
  33. return []byte{}, map[string]any{}, err
  34. }
  35. defer r.Close()
  36. return FromMarkdownStream(r)
  37. }
  38. // FromMarkdownStream loads content/metadata from the given io.Reader and
  39. // returns the Markdown content converted to HTML.
  40. func FromMarkdownStream(r io.Reader) ([]byte, map[string]any, error) {
  41. buf, data, err := FromTextStream(r)
  42. if err != nil {
  43. return []byte{}, map[string]any{}, err
  44. }
  45. var html bytes.Buffer
  46. err = markdown.ToHTML(buf, &html)
  47. if err != nil {
  48. return []byte{}, map[string]any{}, err
  49. }
  50. return html.Bytes(), data, err
  51. }
  52. // FromTextFile loads content/metadata from the given file. No content
  53. // conversion is made.
  54. func FromTextFile(file string) ([]byte, map[string]any, error) {
  55. r, err := os.Open(file)
  56. if err != nil {
  57. return []byte{}, map[string]any{}, err
  58. }
  59. defer r.Close()
  60. return FromTextStream(r)
  61. }
  62. // FromTextStream loads content/metadata from the given io.Reader. No content
  63. // conversion is made.
  64. func FromTextStream(r io.Reader) ([]byte, map[string]any, error) {
  65. buf, err := io.ReadAll(r)
  66. if err != nil {
  67. return []byte{}, map[string]any{}, err
  68. }
  69. present, splitPos := metadata.IsPresent(buf)
  70. if !present {
  71. return buf, map[string]any{}, nil
  72. }
  73. data, err := metadata.FromTomlBuffer(buf[:splitPos])
  74. if err != nil {
  75. // treat parse error as document content, see metadata package doc
  76. return buf, map[string]any{}, nil
  77. }
  78. return buf[splitPos:], data, nil
  79. }