diff --git a/Syntax.md b/Syntax.md index 8d309c5..7931dd4 100644 --- a/Syntax.md +++ b/Syntax.md @@ -91,6 +91,30 @@ with list label, supported by default. They can be activated with the `use_setext_headings` option. +### File metadata + +The Markdown text can start with a YAML table, at the very beginning of the +content, to specify metadata for the file. This table must start with a line +containing only `---` and ends with a line containing only `---` or `...`. The +YAML content must not be empty and must not contain any blank line. + +The YAML content is not part of the rendered HTML, but can be extracted by other +processing systems. + +```md +--- +foo: bar +baz: bin +... +baz +``` + +Is rendered as: + +```html +
baz
+``` + ### Thematic breaks A thematic break (usually rendered as a horizontal line through the page) can diff --git a/cpanfile b/cpanfile index ea7c632..abdd7b0 100644 --- a/cpanfile +++ b/cpanfile @@ -31,6 +31,7 @@ requires 'List::Util', '1.45'; requires 'List::MoreUtils'; requires 'Readonly'; requires 'Unicode::CaseFold'; +requires 'YAML::Tiny'; on 'test' => sub { requires 'JSON'; diff --git a/lib/Markdown/Perl/BlockParser.pm b/lib/Markdown/Perl/BlockParser.pm index 22c82ad..bf24b62 100644 --- a/lib/Markdown/Perl/BlockParser.pm +++ b/lib/Markdown/Perl/BlockParser.pm @@ -15,6 +15,7 @@ use List::MoreUtils 'first_index'; use List::Util 'pairs', 'min'; use Markdown::Perl::HTML 'html_escape', 'decode_entities', 'remove_disallowed_tags'; use Markdown::Perl::Util ':all'; +use YAML::Tiny; our $VERSION = '0.01'; @@ -136,6 +137,9 @@ sub process { # Done at a later stage, as escaped characters don’t have their Markdown # meaning, we need a way to represent that. + # Note: for now, nothing is done with the extracted metadata. + $this->_parse_yaml_metadata() if $this->get_parse_file_metadata eq 'yaml'; + while (defined (my $l = $this->next_line())) { # This field might be set to true at the beginning of the processing, while # we’re looking at the conditions of the currently open containers. @@ -360,6 +364,21 @@ sub _parse_blocks { ## no critic (RequireArgUnpacking) return; } +sub _parse_yaml_metadata { + my ($this) = @_; + + # At this point, pos(md) is guaranteed to be 0. + if ($this->{md} =~ m/^---\n((?:.+\n)+?)(:?---|\.\.\.)\n/gc) { + my $yaml = eval { YAML::Tiny->read_string($1) }; + if ($@) { + pos($this->{md}) = 0; + return; + } + } + + return; +} + # https://spec.commonmark.org/0.30/#atx-headings sub _do_atx_heading { my ($this) = @_; diff --git a/lib/Markdown/Perl/Options.pm b/lib/Markdown/Perl/Options.pm index d881f12..d676645 100644 --- a/lib/Markdown/Perl/Options.pm +++ b/lib/Markdown/Perl/Options.pm @@ -178,9 +178,43 @@ sub _word_list { =head2 Options controlling which top-level blocks are used +=head3 Bdum
\n", 'yaml_table'); +is($yaml->convert("---\nfoo: bar\nbaz: bin\n...\ndum\n"), "dum
\n", 'yaml_table_with_dot'); +is($yaml->convert("---\nfoo: bar\n\n...\ndum\n"), "foo: bar
\n...\ndum
\n", 'yaml_with_empty_line'); +is($yaml->convert("---\n+ foo\n...\ndum\n"), "