obsidian-parser 0.5.4 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 37cfdc15ab5d67c4ac5972db19df269b71a20c516bc43bc9014daccdf42879eb
4
- data.tar.gz: ed67a9489d6e3ed05df0b72d14773b5674945ae993b51386e76634023629de74
3
+ metadata.gz: 5882ab166c0770a2b52258e31fbaea89646292b0288f60116373072e389a375e
4
+ data.tar.gz: 37139895344d860500ae5b29135645adf4b34dcfa8e395d5d2c41f6029870d4f
5
5
  SHA512:
6
- metadata.gz: 1b39d82790d769bda1434db80434715715c9be20b9fae0fd9f9c51147354e9f8adb46062b3500ff07d1084d3435ab764fc7f27a22481dfc48447ef0524802cec
7
- data.tar.gz: acd7d36cac25c162da92a939e132033afd2b4585af490c188505295b9d51134a3073b47fc8e457777a984facec6884230c6b5e2188554be1a56a0a26f8ceec8e
6
+ metadata.gz: 6b3254e1c0f267646c7846568c48a6070615488130a335f46a01e7f1e3b1ab03e2ceb22aa090a379164ec2f81e0632217cec53e9bc61577c78240f04f7eee739
7
+ data.tar.gz: 5afe24ce2c30d488e4d89a5d57d421a8b4b65aefe915ab48a37f16c22d8cc5a04f147e5dd804772630377cbd01a73c07f5dfa421550c6dbf0ee9559980d45a6f
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.6.0] - 2023-08-03
4
+ - Replace Kramdown with Markly
5
+ - Enabled support for Github Flavored Markdown tables and tasklists
6
+ - Rename `MarkdownContent` -> `MarkdownDocument`, `ObsidianFlavoredMarkdown` -> `MarkdownParser`
7
+
3
8
  ## [0.5.4] - 2023-08-02
4
9
  - Fix page getting clobbered when wikilinks point to non-existent pages.
5
10
  - Expand `[[foo/index]]` wiklinks to `[foo](foo)`.
data/Gemfile.lock CHANGED
@@ -1,9 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- obsidian-parser (0.5.4)
5
- kramdown (~> 2.4)
6
- kramdown-parser-gfm (~> 1.1)
4
+ obsidian-parser (0.6.0)
5
+ markly (~> 0.7.0)
7
6
 
8
7
  GEM
9
8
  remote: https://rubygems.org/
@@ -12,12 +11,9 @@ GEM
12
11
  coderay (1.1.3)
13
12
  diff-lcs (1.5.0)
14
13
  json (2.6.3)
15
- kramdown (2.4.0)
16
- rexml
17
- kramdown-parser-gfm (1.1.0)
18
- kramdown (~> 2.0)
19
14
  language_server-protocol (3.17.0.3)
20
15
  lint_roller (1.1.0)
16
+ markly (0.7.0)
21
17
  method_source (1.0.0)
22
18
  parallel (1.23.0)
23
19
  parser (3.2.2.3)
@@ -0,0 +1,40 @@
1
+ class HtmlRenderer < Markly::Renderer::HTML
2
+ def header(node)
3
+ block do
4
+ out("<h", node.header_level, " id=\"", header_id(node), "\">",
5
+ :children, "</h", node.header_level, ">")
6
+ end
7
+ end
8
+
9
+ private
10
+
11
+ def header_id(node)
12
+ # Taken from Kramdown
13
+ # https://github.com/gettalong/kramdown/blob/bd678ecb59f70778fdb3b08bdcd39e2ab7379b45/lib/kramdown/converter/base.rb
14
+ gen_id = extract_text(node).gsub(/^[^a-zA-Z]+/, "")
15
+ gen_id.tr!("^a-zA-Z0-9 -", "")
16
+ gen_id.tr!(" ", "-")
17
+ gen_id.downcase!
18
+
19
+ gen_id = "section" if gen_id.empty?
20
+
21
+ @used_ids ||= {}
22
+ if @used_ids.key?(gen_id)
23
+ gen_id += "-#{@used_ids[gen_id] += 1}"
24
+ else
25
+ @used_ids[gen_id] = 0
26
+ end
27
+
28
+ gen_id
29
+ end
30
+
31
+ def extract_text(node)
32
+ node.each do |subnode|
33
+ if subnode.type == :text
34
+ return subnode.string_content
35
+ end
36
+ end
37
+
38
+ ""
39
+ end
40
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Obsidian
4
+ class MarkdownDocument
5
+ def initialize(path, root, markdown_parser:)
6
+ @path = path
7
+ @root = root
8
+ @markdown_parser = markdown_parser
9
+ end
10
+
11
+ def generate_html
12
+ markdown = @path.read
13
+ @markdown_parser.parse(markdown, root: @root).to_html
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "markly"
4
+
5
+ module Obsidian
6
+ class MarkdownParser
7
+ WIKILINK_SYNTAX = %r{
8
+ \[\[
9
+ (?<target>[^\]\#|]*) # link target
10
+ (?:
11
+ \#(?<fragment>[^|\]]*) # optional heading fragment
12
+ )?
13
+ (?:
14
+ \|(?<text>[^\]]*) # optional link display text
15
+ )?
16
+ \]\]
17
+ }x
18
+
19
+ def initialize(renderer: HtmlRenderer.new)
20
+ @renderer = renderer
21
+ end
22
+
23
+ # Convert Obsidian-flavored-markdown syntax to something parseable
24
+ # (i.e. with Github-flavored-markdown syntax)
25
+ def expand_wikilinks(markdown_text, root:)
26
+ markdown_text.gsub(WIKILINK_SYNTAX) do |s|
27
+ text = $~[:text]
28
+ target = $~[:target]
29
+ fragment = $~[:fragment]
30
+ page = root.find_in_tree(target)
31
+
32
+ if page.nil?
33
+ text.nil? ? target.split("/").last : text
34
+ else
35
+ display_text = text.nil? ? page.slug.split("/").last : text
36
+ href = fragment.nil? ? page.slug : "#{page.slug}##{fragment}"
37
+
38
+ "[#{display_text}](#{href})"
39
+ end
40
+ end
41
+ end
42
+
43
+ def parse(markdown_text, root: nil)
44
+ normalized = expand_wikilinks(markdown_text, root: root)
45
+ document = Markly.parse(normalized, flags: Markly::SMART | Markly::UNSAFE | Markly::HARD_BREAKS, extensions: [:table, :tasklist, :autolink])
46
+ Obsidian::ParsedMarkdownDocument.new(document, renderer: renderer)
47
+ end
48
+
49
+ private
50
+
51
+ attr_reader :renderer
52
+ end
53
+ end
@@ -2,39 +2,39 @@
2
2
 
3
3
  module Obsidian
4
4
  class ParsedMarkdownDocument
5
- def initialize(document)
5
+ def initialize(document, renderer:)
6
6
  @document = document
7
+ @renderer = renderer
7
8
  end
8
9
 
9
10
  def extract_links
10
- _extract_links(document.root)
11
+ results = []
12
+
13
+ document.walk do |node|
14
+ if node.type == :link
15
+ text = _extract_text_content(node)
16
+ href = node.url
17
+ results << [href, text]
18
+ end
19
+ end
20
+
21
+ results
11
22
  end
12
23
 
13
24
  def to_html
14
- document.to_html
25
+ renderer.render(document)
15
26
  end
16
27
 
17
28
  private
18
29
 
19
30
  attr_reader :document
20
-
21
- def _extract_links(element)
22
- if element.type == :a
23
- [[element.attr["href"], _extract_text_content(element)]]
24
- elsif !element.children.empty?
25
- element.children.flat_map { |child| _extract_links(child) }
26
- else
27
- []
28
- end
29
- end
31
+ attr_reader :renderer
30
32
 
31
33
  def _extract_text_content(element)
32
34
  if element.type == :text
33
- element.value
34
- elsif !element.children.empty?
35
- element.children.map { |child| _extract_text_content(child) }.join
35
+ element.string_content
36
36
  else
37
- ""
37
+ element.each.map { |child| _extract_text_content(child) }.join
38
38
  end
39
39
  end
40
40
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Obsidian
4
4
  class Parser
5
- VERSION = "0.5.4"
5
+ VERSION = "0.6.0"
6
6
  end
7
7
  end
@@ -2,9 +2,10 @@
2
2
 
3
3
  require_relative "parser/version"
4
4
  require_relative "parser/parsed_markdown_document"
5
- require_relative "parser/obsidian_flavored_markdown"
5
+ require_relative "parser/markdown_parser"
6
6
  require_relative "parser/page"
7
- require_relative "parser/markdown_content"
7
+ require_relative "parser/markdown_document"
8
+ require_relative "parser/html_renderer"
8
9
 
9
10
  require "forwardable"
10
11
 
@@ -20,6 +21,7 @@ module Obsidian
20
21
 
21
22
  def initialize(vault_directory)
22
23
  @index = Obsidian::Page.create_root
24
+ markdown_parser = MarkdownParser.new
23
25
 
24
26
  vault_directory.glob("**/*.md").each do |path|
25
27
  dirname, basename = path.relative_path_from(vault_directory).split
@@ -39,7 +41,7 @@ module Obsidian
39
41
  @index.add_page(
40
42
  slug,
41
43
  last_modified: path.mtime,
42
- content: MarkdownContent.new(path, @index)
44
+ content: MarkdownDocument.new(path, @index, markdown_parser: markdown_parser)
43
45
  )
44
46
  end
45
47
 
metadata CHANGED
@@ -1,43 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: obsidian-parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.4
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mat Moore
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-08-02 00:00:00.000000000 Z
11
+ date: 2023-08-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: kramdown
14
+ name: markly
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.4'
19
+ version: 0.7.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2.4'
27
- - !ruby/object:Gem::Dependency
28
- name: kramdown-parser-gfm
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.1'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '1.1'
26
+ version: 0.7.0
41
27
  description:
42
28
  email:
43
29
  - matmoore@users.noreply.github.com
@@ -56,8 +42,9 @@ files:
56
42
  - README.md
57
43
  - Rakefile
58
44
  - lib/obsidian/parser.rb
59
- - lib/obsidian/parser/markdown_content.rb
60
- - lib/obsidian/parser/obsidian_flavored_markdown.rb
45
+ - lib/obsidian/parser/html_renderer.rb
46
+ - lib/obsidian/parser/markdown_document.rb
47
+ - lib/obsidian/parser/markdown_parser.rb
61
48
  - lib/obsidian/parser/page.rb
62
49
  - lib/obsidian/parser/parsed_markdown_document.rb
63
50
  - lib/obsidian/parser/version.rb
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Obsidian
4
- class MarkdownContent
5
- def initialize(path, root)
6
- @path = path
7
- @root = root
8
- end
9
-
10
- def generate_html
11
- markdown = @path.read
12
- Obsidian::ObsidianFlavoredMarkdown.parse(markdown, root: @root).to_html
13
- end
14
- end
15
- end
@@ -1,74 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "kramdown"
4
- require "kramdown-parser-gfm"
5
-
6
- module Obsidian
7
- module ObsidianFlavoredMarkdown
8
- WIKILINK_SYNTAX = %r{
9
- \[\[
10
- (?<target>[^\]\#|]*) # link target
11
- (?:
12
- \#(?<fragment>[^|\]]*) # optional heading fragment
13
- )?
14
- (?:
15
- \|(?<text>[^\]]*) # optional link display text
16
- )?
17
- \]\]
18
- }x
19
-
20
- # Match URLs
21
- # Pattern based on https://gist.github.com/dperini/729294
22
- LONE_URL = %r{
23
- (?<!\S) # not preceeded by a non-whitespace character
24
- https?:// # Protocol
25
- (?:\S+(?::\S*)?@)? # basic auth
26
- (?![-_]) # Not followed by a dash or underscore
27
- (?:[-\w\u00a1-\uffff]{0,63}[^-_]\.)+ # host and domain names
28
- (?:[a-z\u00a1-\uffff]{2,}\.?) # top level domain
29
- (?::\\d{2,5})? # Port number
30
- (?:[/?#]\\S*)? # Resource path
31
- (?!\S) # not followed by a non-whitespace character
32
- }x
33
-
34
- # Workaround for lack of auto-linking in Kramdown.
35
- # Note: this breaks for URLs included in code blocks.
36
- def self.auto_link(markdown_text)
37
- markdown_text.gsub(LONE_URL) do |s|
38
- "<#{s}>" # Kramdown-specific markup
39
- end
40
- end
41
-
42
- # Convert Obsidian-flavored-markdown syntax to something parseable
43
- # (i.e. with Github-flavored-markdown syntax)
44
- def self.expand_wikilinks(markdown_text, root:)
45
- markdown_text.gsub(WIKILINK_SYNTAX) do |s|
46
- text = $~[:text]
47
- target = $~[:target]
48
- fragment = $~[:fragment]
49
- page = root.find_in_tree(target)
50
-
51
- if page.nil?
52
- text.nil? ? target.split("/").last : text
53
- else
54
- display_text = text.nil? ? page.slug.split("/").last : text
55
- href = fragment.nil? ? page.slug : "#{page.slug}##{fragment}"
56
-
57
- "[#{display_text}](#{href})"
58
- end
59
- end
60
- end
61
-
62
- def self.normalize(markdown_text, root: nil)
63
- auto_linked = auto_link(markdown_text)
64
- return auto_linked if root.nil?
65
-
66
- expand_wikilinks(auto_link(markdown_text), root: root)
67
- end
68
-
69
- def self.parse(markdown_text, root: nil)
70
- document = Kramdown::Document.new(normalize(markdown_text, root: root), input: "GFM")
71
- Obsidian::ParsedMarkdownDocument.new(document)
72
- end
73
- end
74
- end