obsidian-parser 0.5.4 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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