markawesome 0.9.4 → 0.10.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 +4 -4
- data/CHANGELOG.md +19 -0
- data/lib/markawesome/code_block_protector.rb +54 -0
- data/lib/markawesome/plain_markdown_renderer.rb +113 -0
- data/lib/markawesome/transformer.rb +6 -1
- data/lib/markawesome/transformers/badge_transformer.rb +13 -0
- data/lib/markawesome/transformers/button_transformer.rb +17 -0
- data/lib/markawesome/transformers/callout_transformer.rb +25 -0
- data/lib/markawesome/transformers/card_transformer.rb +26 -0
- data/lib/markawesome/transformers/carousel_transformer.rb +13 -0
- data/lib/markawesome/transformers/comparison_transformer.rb +18 -0
- data/lib/markawesome/transformers/copy_button_transformer.rb +12 -0
- data/lib/markawesome/transformers/details_transformer.rb +14 -0
- data/lib/markawesome/transformers/dialog_transformer.rb +19 -0
- data/lib/markawesome/transformers/icon_transformer.rb +10 -0
- data/lib/markawesome/transformers/image_dialog_transformer.rb +6 -0
- data/lib/markawesome/transformers/layout_transformer.rb +12 -0
- data/lib/markawesome/transformers/popover_transformer.rb +27 -1
- data/lib/markawesome/transformers/tabs_transformer.rb +15 -0
- data/lib/markawesome/transformers/tag_transformer.rb +31 -0
- data/lib/markawesome/version.rb +1 -1
- data/lib/markawesome.rb +2 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 38226847e3635366ea2442b7e2e4702950c72c4511627e865a269bfef5cfe8b5
|
|
4
|
+
data.tar.gz: 59e5e536facf5d39798a70f7cfa04c951c00098309b88f13ab8733d7e225e843
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 96879a70ddcaf0869421dabb3b47e2389d26608014ba52f79b58147b3471c2ab08e91bb3b3397d94db785546d20be8f87cf59ab7f4f6bcb68b9a89e59000e088
|
|
7
|
+
data.tar.gz: 45e4e956d65bd8221fba67f3e26a9a72349a32e608c6ebed4c348cc73e5f7edfaeeadacb399d51714db8385b34f16b23f2c966c07f8e0c5339454d6475bff295
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,25 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.10.0] - 2026-05-05
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `Markawesome::PlainMarkdownRenderer` — alternate output format that degrades each Web Awesome component to its closest plain-markdown equivalent: GFM alerts for callouts, `<details>` for details, sequential `###` sections for tabs, plain links for buttons, bold for badges/tags, and so on. Useful for sites that want to publish a clean-markdown copy of their pages alongside the HTML — for example, per-page `.md` endpoints or an `llms.txt`-style index that tools and LLM consumers can read without parsing `<wa-*>` tags.
|
|
12
|
+
- `Markawesome::CodeBlockProtector` — stateless helper that replaces fenced code blocks with opaque placeholders before transformation and restores them after. Extracted from `jekyll-webawesome`'s hook logic so the same guarantee applies anywhere Markawesome is used (Hugo, Middleman, plain Ruby).
|
|
13
|
+
- `render_as_markdown(content, options = {})` class method on every transformer, sitting alongside the existing `transform` method. `Markawesome::Transformer.process` still emits HTML; `Markawesome::PlainMarkdownRenderer.process` emits clean markdown.
|
|
14
|
+
- `Markawesome::PlainMarkdownRenderer.register_override(:component) { |content, opts| ... }` for swapping in a custom rendering of a single component without forking the gem.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- `Markawesome::Transformer.process` now wraps the pipeline with `CodeBlockProtector.protect/restore`, so fenced code examples that contain `:::`/`^^^`/`@@@` no longer trigger accidental transformation. Previously this protection lived in `jekyll-webawesome`, leaving consumers of Markawesome on other frameworks without it.
|
|
19
|
+
|
|
20
|
+
## [0.9.5] - 2026-03-18
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Added `type='button'` attribute to link-style popover trigger `<button>` elements to satisfy `no-implicit-button-type` HTML validation rule
|
|
25
|
+
|
|
7
26
|
## [0.9.4] - 2026-03-13
|
|
8
27
|
|
|
9
28
|
### Changed
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Markawesome
|
|
4
|
+
# Replaces fenced code blocks with opaque placeholders so that Markawesome's
|
|
5
|
+
# component regexes (`:::`, `^^^`, `@@@`, etc.) cannot match syntax that
|
|
6
|
+
# appears inside example code. Callers are responsible for restoring the
|
|
7
|
+
# blocks after their transformations run.
|
|
8
|
+
#
|
|
9
|
+
# Usage:
|
|
10
|
+
# content, tokens = Markawesome::CodeBlockProtector.protect(content)
|
|
11
|
+
# content = some_transformer.transform(content)
|
|
12
|
+
# content = Markawesome::CodeBlockProtector.restore(content, tokens)
|
|
13
|
+
#
|
|
14
|
+
# The helper is stateless: each call allocates its own token map, so it is
|
|
15
|
+
# safe to use concurrently or nested. The token format is a stable HTML
|
|
16
|
+
# comment so that it survives markdown conversion intact.
|
|
17
|
+
module CodeBlockProtector
|
|
18
|
+
CODE_BLOCK_PATTERN = /```([a-zA-Z0-9.+#_-]+)?(\n.*?)```/m
|
|
19
|
+
PLACEHOLDER_PREFIX = '<!--MARKAWESOME_PROTECTED_CODE_BLOCK_'
|
|
20
|
+
PLACEHOLDER_SUFFIX = '-->'
|
|
21
|
+
|
|
22
|
+
module_function
|
|
23
|
+
|
|
24
|
+
# Replace every fenced code block with a placeholder.
|
|
25
|
+
# @param content [String]
|
|
26
|
+
# @return [Array(String, Hash)] Protected content and placeholder→block map.
|
|
27
|
+
def protect(content)
|
|
28
|
+
tokens = {}
|
|
29
|
+
counter = 0
|
|
30
|
+
|
|
31
|
+
protected_content = content.gsub(CODE_BLOCK_PATTERN) do |match|
|
|
32
|
+
placeholder = "#{PLACEHOLDER_PREFIX}#{counter}#{PLACEHOLDER_SUFFIX}"
|
|
33
|
+
tokens[placeholder] = match
|
|
34
|
+
counter += 1
|
|
35
|
+
placeholder
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
[protected_content, tokens]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Restore placeholders created by {protect}.
|
|
42
|
+
# @param content [String]
|
|
43
|
+
# @param tokens [Hash]
|
|
44
|
+
# @return [String]
|
|
45
|
+
def restore(content, tokens)
|
|
46
|
+
return content if tokens.nil? || tokens.empty?
|
|
47
|
+
|
|
48
|
+
tokens.each do |placeholder, original|
|
|
49
|
+
content = content.gsub(placeholder, original)
|
|
50
|
+
end
|
|
51
|
+
content
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'transformers'
|
|
4
|
+
require_relative 'code_block_protector'
|
|
5
|
+
|
|
6
|
+
module Markawesome
|
|
7
|
+
# Renders Markawesome-flavored markdown into "clean" plain markdown by
|
|
8
|
+
# degrading each Web Awesome component to its closest GFM equivalent.
|
|
9
|
+
# Used to serve per-page `.md` endpoints and to generate llms.txt content
|
|
10
|
+
# that LLM consumers can read without having to understand `<wa-*>` tags.
|
|
11
|
+
#
|
|
12
|
+
# Mirrors Markawesome::Transformer.process, but dispatches to each
|
|
13
|
+
# transformer's `render_as_markdown` method instead of `transform`.
|
|
14
|
+
class PlainMarkdownRenderer
|
|
15
|
+
# Per-component overrides registered by host applications. Values are
|
|
16
|
+
# procs with signature `proc { |content, options| ... }` that replace
|
|
17
|
+
# the default rendering for that component.
|
|
18
|
+
@overrides = {}
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
attr_reader :overrides
|
|
22
|
+
|
|
23
|
+
# Register a per-component override. Consumers can call this from a
|
|
24
|
+
# plugin during boot to override the default rendering for a single
|
|
25
|
+
# component without forking the gem.
|
|
26
|
+
#
|
|
27
|
+
# @param component [Symbol] one of :callout, :badge, :button, :card,
|
|
28
|
+
# :carousel, :comparison, :copy_button, :details, :dialog, :icon,
|
|
29
|
+
# :image_dialog, :layout, :popover, :tabs, :tag.
|
|
30
|
+
# @yield [content, options] Proc that receives the full source content
|
|
31
|
+
# and the renderer options; returns the content with that component
|
|
32
|
+
# syntax replaced.
|
|
33
|
+
def register_override(component, &block)
|
|
34
|
+
raise ArgumentError, 'block required' unless block_given?
|
|
35
|
+
|
|
36
|
+
@overrides[component.to_sym] = block
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Clear all registered overrides (useful in tests).
|
|
40
|
+
def reset_overrides!
|
|
41
|
+
@overrides = {}
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
PIPELINE = %i[
|
|
46
|
+
layout
|
|
47
|
+
popover
|
|
48
|
+
badge
|
|
49
|
+
button
|
|
50
|
+
callout
|
|
51
|
+
card
|
|
52
|
+
carousel
|
|
53
|
+
comparison
|
|
54
|
+
copy_button
|
|
55
|
+
details
|
|
56
|
+
image_dialog
|
|
57
|
+
dialog
|
|
58
|
+
icon
|
|
59
|
+
tag
|
|
60
|
+
tabs
|
|
61
|
+
].freeze
|
|
62
|
+
|
|
63
|
+
TRANSFORMER_MAP = {
|
|
64
|
+
layout: LayoutTransformer,
|
|
65
|
+
popover: PopoverTransformer,
|
|
66
|
+
badge: BadgeTransformer,
|
|
67
|
+
button: ButtonTransformer,
|
|
68
|
+
callout: CalloutTransformer,
|
|
69
|
+
card: CardTransformer,
|
|
70
|
+
carousel: CarouselTransformer,
|
|
71
|
+
comparison: ComparisonTransformer,
|
|
72
|
+
copy_button: CopyButtonTransformer,
|
|
73
|
+
details: DetailsTransformer,
|
|
74
|
+
image_dialog: ImageDialogTransformer,
|
|
75
|
+
dialog: DialogTransformer,
|
|
76
|
+
icon: IconTransformer,
|
|
77
|
+
tag: TagTransformer,
|
|
78
|
+
tabs: TabsTransformer
|
|
79
|
+
}.freeze
|
|
80
|
+
|
|
81
|
+
def self.process(content, options = {})
|
|
82
|
+
content, tokens = CodeBlockProtector.protect(content)
|
|
83
|
+
|
|
84
|
+
PIPELINE.each do |component|
|
|
85
|
+
if (override = overrides[component])
|
|
86
|
+
content = override.call(content, options)
|
|
87
|
+
next
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
transformer = TRANSFORMER_MAP.fetch(component)
|
|
91
|
+
content = if component == :image_dialog
|
|
92
|
+
if options[:image_dialog]
|
|
93
|
+
config = options[:image_dialog].is_a?(Hash) ? options[:image_dialog] : {}
|
|
94
|
+
transformer.render_as_markdown(content, config)
|
|
95
|
+
else
|
|
96
|
+
content
|
|
97
|
+
end
|
|
98
|
+
else
|
|
99
|
+
transformer.render_as_markdown(content, options)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
content = strip_kramdown_attributes(content)
|
|
104
|
+
CodeBlockProtector.restore(content, tokens)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Strip Kramdown attribute syntax like `{:.class}`, `{:#id}`, `{: .class}`,
|
|
108
|
+
# `{: #id .class}`, etc. These are Kramdown-specific and not valid GFM.
|
|
109
|
+
def self.strip_kramdown_attributes(content)
|
|
110
|
+
content.gsub(/\s*\{:\s*[^}]*\}/, '')
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
require 'kramdown'
|
|
4
4
|
require_relative 'transformers'
|
|
5
|
+
require_relative 'code_block_protector'
|
|
5
6
|
|
|
6
7
|
module Markawesome
|
|
7
8
|
# Main transformer that orchestrates all component transformers
|
|
8
9
|
class Transformer
|
|
9
10
|
def self.process(content, options = {})
|
|
11
|
+
content, tokens = CodeBlockProtector.protect(content)
|
|
12
|
+
|
|
10
13
|
content = LayoutTransformer.transform(content)
|
|
11
14
|
content = PopoverTransformer.transform(content)
|
|
12
15
|
content = BadgeTransformer.transform(content)
|
|
@@ -27,7 +30,9 @@ module Markawesome
|
|
|
27
30
|
content = DialogTransformer.transform(content)
|
|
28
31
|
content = IconTransformer.transform(content)
|
|
29
32
|
content = TagTransformer.transform(content)
|
|
30
|
-
TabsTransformer.transform(content)
|
|
33
|
+
content = TabsTransformer.transform(content)
|
|
34
|
+
|
|
35
|
+
CodeBlockProtector.restore(content, tokens)
|
|
31
36
|
end
|
|
32
37
|
end
|
|
33
38
|
end
|
|
@@ -41,6 +41,19 @@ module Markawesome
|
|
|
41
41
|
apply_multiple_patterns(content, patterns)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
def self.render_as_markdown(content, _options = {})
|
|
45
|
+
primary_regex = /^!!!(.*?)\n(.*?)\n!!!/m
|
|
46
|
+
alternative_regex = /^:::wa-badge\s*(.*?)\n(.*?)\n:::/m
|
|
47
|
+
|
|
48
|
+
transform_proc = proc do |_params_string, badge_content|
|
|
49
|
+
text = badge_content.to_s.strip
|
|
50
|
+
text.empty? ? '' : "**#{text}**"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
|
|
54
|
+
apply_multiple_patterns(content, patterns)
|
|
55
|
+
end
|
|
56
|
+
|
|
44
57
|
class << self
|
|
45
58
|
private
|
|
46
59
|
|
|
@@ -55,6 +55,23 @@ module Markawesome
|
|
|
55
55
|
apply_multiple_patterns(content, patterns)
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
+
def self.render_as_markdown(content, _options = {})
|
|
59
|
+
primary_regex = /^%%%([^\n]*)\n(.*?)\n%%%/m
|
|
60
|
+
alternative_regex = /^:::wa-button\s*([^\n]*)\n(.*?)\n:::/m
|
|
61
|
+
|
|
62
|
+
transform_proc = proc do |_params_string, button_content|
|
|
63
|
+
text = button_content.to_s.strip
|
|
64
|
+
if (link_match = text.match(/^\[([^\]]+)\]\(([^)]+)\)$/))
|
|
65
|
+
"[#{link_match[1]}](#{link_match[2]})"
|
|
66
|
+
else
|
|
67
|
+
text.empty? ? '' : "**#{text}**"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
|
|
72
|
+
apply_multiple_patterns(content, patterns)
|
|
73
|
+
end
|
|
74
|
+
|
|
58
75
|
class << self
|
|
59
76
|
private
|
|
60
77
|
|
|
@@ -51,6 +51,31 @@ module Markawesome
|
|
|
51
51
|
apply_multiple_patterns(content, patterns)
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
+
GFM_ALERT_MAP = {
|
|
55
|
+
'info' => 'NOTE',
|
|
56
|
+
'brand' => 'NOTE',
|
|
57
|
+
'success' => 'TIP',
|
|
58
|
+
'neutral' => 'IMPORTANT',
|
|
59
|
+
'warning' => 'WARNING',
|
|
60
|
+
'danger' => 'CAUTION'
|
|
61
|
+
}.freeze
|
|
62
|
+
|
|
63
|
+
def self.render_as_markdown(content, _options = {})
|
|
64
|
+
variant_pattern = VARIANTS.join('|')
|
|
65
|
+
primary_regex = /^:::(#{variant_pattern})([^\n]*)\n(.*?)\n:::/m
|
|
66
|
+
alternative_regex = /^:::wa-callout\s+(#{variant_pattern})([^\n]*)\n(.*?)\n:::/m
|
|
67
|
+
|
|
68
|
+
transform_proc = proc do |variant, _extra_params, inner_content|
|
|
69
|
+
alert = GFM_ALERT_MAP.fetch(variant, 'NOTE')
|
|
70
|
+
body = inner_content.to_s.strip
|
|
71
|
+
quoted = body.empty? ? '' : body.split("\n").map { |l| l.empty? ? '>' : "> #{l}" }.join("\n")
|
|
72
|
+
body.empty? ? "> [!#{alert}]" : "> [!#{alert}]\n#{quoted}"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
|
|
76
|
+
apply_multiple_patterns(content, patterns)
|
|
77
|
+
end
|
|
78
|
+
|
|
54
79
|
class << self
|
|
55
80
|
private
|
|
56
81
|
|
|
@@ -37,9 +37,35 @@ module Markawesome
|
|
|
37
37
|
apply_multiple_patterns(content, patterns)
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
def self.render_as_markdown(content, _options = {})
|
|
41
|
+
primary_regex = /^===([^\n]*)\n(.*?)\n===/m
|
|
42
|
+
alternative_regex = /^:::wa-card\s*([^\n]*)\n(.*?)\n:::/m
|
|
43
|
+
|
|
44
|
+
transform_proc = proc do |_params_string, card_content|
|
|
45
|
+
parts = parse_card_content(card_content.to_s.strip)
|
|
46
|
+
render_card_markdown(parts)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
|
|
50
|
+
apply_multiple_patterns(content, patterns)
|
|
51
|
+
end
|
|
52
|
+
|
|
40
53
|
class << self
|
|
41
54
|
private
|
|
42
55
|
|
|
56
|
+
def render_card_markdown(parts)
|
|
57
|
+
blocks = []
|
|
58
|
+
if parts[:media]
|
|
59
|
+
blocks << "![#{parts[:media][:alt]}](#{parts[:media][:src]})"
|
|
60
|
+
end
|
|
61
|
+
blocks << "### #{parts[:header]}" if parts[:header]
|
|
62
|
+
blocks << parts[:content] if parts[:content] && !parts[:content].empty?
|
|
63
|
+
if parts[:footer]
|
|
64
|
+
blocks << "[#{parts[:footer][:text]}](#{parts[:footer][:href]})"
|
|
65
|
+
end
|
|
66
|
+
blocks.join("\n\n")
|
|
67
|
+
end
|
|
68
|
+
|
|
43
69
|
def parse_card_content(content)
|
|
44
70
|
parts = {
|
|
45
71
|
media: nil,
|
|
@@ -44,6 +44,19 @@ module Markawesome
|
|
|
44
44
|
apply_multiple_patterns(content, patterns)
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
+
def self.render_as_markdown(content, _options = {})
|
|
48
|
+
primary_regex = /^~{6}([^\n]*)\n((?:~~~\n(?:.*?\n)?~~~\n?)+)~{6}/m
|
|
49
|
+
alternative_regex = /^:::wa-carousel\s*([^\n]*)\n((?:~~~\n(?:.*?\n)?~~~\n?)+):::/m
|
|
50
|
+
|
|
51
|
+
transform_proc = proc do |_params, slides_block, _third|
|
|
52
|
+
slides = extract_slides(slides_block)
|
|
53
|
+
slides.reject(&:empty?).join("\n\n")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
|
|
57
|
+
apply_multiple_patterns(content, patterns)
|
|
58
|
+
end
|
|
59
|
+
|
|
47
60
|
class << self
|
|
48
61
|
private
|
|
49
62
|
|
|
@@ -38,9 +38,27 @@ module Markawesome
|
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
+
def self.render_as_markdown(content, _options = {})
|
|
42
|
+
content = content.gsub(/^\|\|\|(\d+)?\n(.*?)\n\|\|\|/m) do |match|
|
|
43
|
+
images = extract_images(::Regexp.last_match(2))
|
|
44
|
+
images.length == 2 ? render_comparison_markdown(images) : match
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
content.gsub(/^:::wa-comparison\s*(\d+)?\n(.*?)\n:::/m) do |match|
|
|
48
|
+
images = extract_images(::Regexp.last_match(2))
|
|
49
|
+
images.length == 2 ? render_comparison_markdown(images) : match
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
41
53
|
class << self
|
|
42
54
|
private
|
|
43
55
|
|
|
56
|
+
def render_comparison_markdown(images)
|
|
57
|
+
before_alt, before_src = images[0]
|
|
58
|
+
after_alt, after_src = images[1]
|
|
59
|
+
"**Before:** \n\n**After:** "
|
|
60
|
+
end
|
|
61
|
+
|
|
44
62
|
def build_comparison_html(content, position = nil)
|
|
45
63
|
images = extract_images(content)
|
|
46
64
|
|
|
@@ -66,6 +66,18 @@ module Markawesome
|
|
|
66
66
|
apply_multiple_patterns(content, patterns)
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
def self.render_as_markdown(content, _options = {})
|
|
70
|
+
primary_regex = /^<<<(.*?)\n(.*?)\n<<</m
|
|
71
|
+
alternative_regex = /^:::wa-copy-button\s*(.*?)\n(.*?)\n:::/m
|
|
72
|
+
|
|
73
|
+
transform_proc = proc do |_params_string, copy_content|
|
|
74
|
+
copy_content.to_s.strip
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
|
|
78
|
+
apply_multiple_patterns(content, patterns)
|
|
79
|
+
end
|
|
80
|
+
|
|
69
81
|
class << self
|
|
70
82
|
private
|
|
71
83
|
|
|
@@ -66,6 +66,20 @@ module Markawesome
|
|
|
66
66
|
apply_multiple_patterns(content, patterns)
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
def self.render_as_markdown(content, _options = {})
|
|
70
|
+
primary_regex = /^\^\^\^?(.*?)\n(.*?)\n^>>>\n(.*?)\n^\^\^\^?/m
|
|
71
|
+
alternative_regex = /^:::wa-details\s*(.*?)\n(.*?)\n^>>>\n(.*?)\n:::/m
|
|
72
|
+
|
|
73
|
+
transform_proc = proc do |_params_string, summary_content, details_content|
|
|
74
|
+
summary = summary_content.to_s.strip
|
|
75
|
+
details = details_content.to_s.strip
|
|
76
|
+
"<details>\n<summary>#{summary}</summary>\n\n#{details}\n</details>"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
|
|
80
|
+
apply_multiple_patterns(content, patterns)
|
|
81
|
+
end
|
|
82
|
+
|
|
69
83
|
class << self
|
|
70
84
|
private
|
|
71
85
|
|
|
@@ -52,6 +52,25 @@ module Markawesome
|
|
|
52
52
|
apply_multiple_patterns(content, patterns)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
def self.render_as_markdown(content, _options = {})
|
|
56
|
+
primary_regex = /^\?\?\?([^\n]*)$\n(.*?)\n^>>>$\n(.*?)\n^\?\?\?$/m
|
|
57
|
+
alternative_regex = /^:::wa-dialog([^\n]*)$\n(.*?)\n^>>>$\n(.*?)\n^:::$/m
|
|
58
|
+
|
|
59
|
+
transform_proc = proc do |_params_string, button_text, dialog_content|
|
|
60
|
+
trigger = button_text.to_s.strip
|
|
61
|
+
body = dialog_content.to_s.strip
|
|
62
|
+
# If dialog body already starts with a heading, use it verbatim.
|
|
63
|
+
if body.match?(/^#\s+/)
|
|
64
|
+
"_#{trigger}:_\n\n#{body}"
|
|
65
|
+
else
|
|
66
|
+
"_#{trigger}:_\n\n#{body}"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
|
|
71
|
+
apply_multiple_patterns(content, patterns)
|
|
72
|
+
end
|
|
73
|
+
|
|
55
74
|
class << self
|
|
56
75
|
private
|
|
57
76
|
|
|
@@ -34,6 +34,16 @@ module Markawesome
|
|
|
34
34
|
restore_code_blocks(result, code_blocks)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
def self.render_as_markdown(content, _options = {})
|
|
38
|
+
protected_content, code_blocks = protect_code_blocks(content)
|
|
39
|
+
|
|
40
|
+
# Drop primary-syntax icons entirely.
|
|
41
|
+
result = protected_content.gsub(/\$\$\$([a-zA-Z0-9\-_]+)(?![a-zA-Z0-9\-_]|\s+name\b)/, '')
|
|
42
|
+
result = result.gsub(/:::wa-icon\s+([a-zA-Z0-9\-_]+)\s*\n:::/m, '')
|
|
43
|
+
|
|
44
|
+
restore_code_blocks(result, code_blocks)
|
|
45
|
+
end
|
|
46
|
+
|
|
37
47
|
class << self
|
|
38
48
|
private
|
|
39
49
|
|
|
@@ -40,6 +40,12 @@ module Markawesome
|
|
|
40
40
|
restore_fenced_code_blocks(result, fenced_code_blocks)
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
+
# For plain-markdown output image-dialog wrapping is dropped: the raw
|
|
44
|
+
# markdown image syntax is already what we want.
|
|
45
|
+
def self.render_as_markdown(content, _config = {})
|
|
46
|
+
content
|
|
47
|
+
end
|
|
48
|
+
|
|
43
49
|
class << self
|
|
44
50
|
private
|
|
45
51
|
|
|
@@ -48,6 +48,18 @@ module Markawesome
|
|
|
48
48
|
apply_multiple_patterns(content, patterns)
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
+
def self.render_as_markdown(content, _options = {})
|
|
52
|
+
primary_regex = /^::::(grid|stack|cluster|split|flank|frame)[ \t]*([^\n]*)\n(.*?)\n::::/m
|
|
53
|
+
alternative_regex = /^::::wa-(grid|stack|cluster|split|flank|frame)[ \t]*([^\n]*)\n(.*?)\n::::/m
|
|
54
|
+
|
|
55
|
+
transform_proc = proc do |_type, _params_string, inner_content|
|
|
56
|
+
inner_content.to_s
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
|
|
60
|
+
apply_multiple_patterns(content, patterns)
|
|
61
|
+
end
|
|
62
|
+
|
|
51
63
|
class << self
|
|
52
64
|
private
|
|
53
65
|
|
|
@@ -71,6 +71,32 @@ module Markawesome
|
|
|
71
71
|
apply_multiple_patterns(content, patterns)
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
+
def self.render_as_markdown(content, _options = {})
|
|
75
|
+
inline_regex = /&&&[ \t]*([^\r\n]*?)[ \t]*>>>[ \t]*([^\r\n]+?)[ \t]*&&&/
|
|
76
|
+
primary_regex = /^&&&([^\n]*)$\n(.*?)\n^>>>$\n(.*?)\n^&&&$/m
|
|
77
|
+
alternative_regex = /^:::wa-popover([^\n]*)$\n(.*?)\n^>>>$\n(.*?)\n^:::$/m
|
|
78
|
+
|
|
79
|
+
inline_transform = {
|
|
80
|
+
regex: inline_regex,
|
|
81
|
+
block: proc do |_match, matchdata|
|
|
82
|
+
combined = matchdata[1]
|
|
83
|
+
popover_content = matchdata[2].strip
|
|
84
|
+
_params, trigger_text = parse_inline_trigger_and_params(combined)
|
|
85
|
+
"**#{trigger_text}** (#{popover_content})"
|
|
86
|
+
end
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
block_transform_proc = proc do |_params_string, trigger_text, popover_content|
|
|
90
|
+
"**#{trigger_text.to_s.strip}**\n\n#{popover_content.to_s.strip}"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
patterns = [
|
|
94
|
+
inline_transform,
|
|
95
|
+
*dual_syntax_patterns(primary_regex, alternative_regex, block_transform_proc)
|
|
96
|
+
]
|
|
97
|
+
apply_multiple_patterns(content, patterns)
|
|
98
|
+
end
|
|
99
|
+
|
|
74
100
|
class << self
|
|
75
101
|
private
|
|
76
102
|
|
|
@@ -167,7 +193,7 @@ module Markawesome
|
|
|
167
193
|
'color: inherit; text-decoration: underline; ' \
|
|
168
194
|
'text-decoration-style: dotted; ' \
|
|
169
195
|
'cursor: pointer; font: inherit;'
|
|
170
|
-
"<button id='#{popover_id}' class='ma-popover-trigger' style='#{link_style_attr}'>#{trigger_content}</button>"
|
|
196
|
+
"<button type='button' id='#{popover_id}' class='ma-popover-trigger' style='#{link_style_attr}'>#{trigger_content}</button>"
|
|
171
197
|
else
|
|
172
198
|
"<wa-button id='#{popover_id}' variant='text'>#{trigger_content}</wa-button>"
|
|
173
199
|
end
|
|
@@ -59,6 +59,21 @@ module Markawesome
|
|
|
59
59
|
apply_multiple_patterns(content, patterns)
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
+
def self.render_as_markdown(content, _options = {})
|
|
63
|
+
primary_regex = /^\+{6}([^\n]*)\n((\+\+\+ [^\n]+\n.*?\n\+\+\+\n?)+)\+{6}/m
|
|
64
|
+
alternative_regex = /^:::wa-tab-group\s*([^\n]*)\n((\+\+\+ [^\n]+\n.*?\n\+\+\+\n?)+):::/m
|
|
65
|
+
|
|
66
|
+
transform_proc = proc do |_params_string, tabs_block, _third|
|
|
67
|
+
tab_contents = tabs_block.scan(/^\+\+\+ ([^\n]+)\n(.*?)\n\+\+\+/m)
|
|
68
|
+
tab_contents.map do |title, panel_content|
|
|
69
|
+
"### #{title.strip}\n\n#{panel_content.strip}"
|
|
70
|
+
end.join("\n\n")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
|
|
74
|
+
apply_multiple_patterns(content, patterns)
|
|
75
|
+
end
|
|
76
|
+
|
|
62
77
|
class << self
|
|
63
78
|
private
|
|
64
79
|
|
|
@@ -84,6 +84,37 @@ module Markawesome
|
|
|
84
84
|
apply_multiple_patterns(content, patterns)
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
+
def self.render_as_markdown(content, _options = {})
|
|
88
|
+
primary_regex = /^@@@([^\r\n]*?)\r?\n(.*?)\r?\n@@@/m
|
|
89
|
+
alternative_regex = /^:::wa-tag\s*([^\r\n]*?)\r?\n(.*?)\r?\n:::/m
|
|
90
|
+
inline_regex = /@@@\h*([^@\r\n]+?)\h*@@@/
|
|
91
|
+
|
|
92
|
+
block_transform_proc = proc do |_params, tag_content|
|
|
93
|
+
text = tag_content.to_s.strip
|
|
94
|
+
text.empty? ? '' : "**#{text}**"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
inline_transform = {
|
|
98
|
+
regex: inline_regex,
|
|
99
|
+
block: proc do |_match, matchdata|
|
|
100
|
+
full_content = matchdata[1].to_s.strip
|
|
101
|
+
# Strip attribute tokens (variant, appearance, size, pill, with-remove, icon:...)
|
|
102
|
+
content_tokens = full_content.split(/\s+/).reject do |token|
|
|
103
|
+
COMPONENT_ATTRIBUTES.any? { |_attr, values| values.include?(token) } ||
|
|
104
|
+
token.start_with?('icon:')
|
|
105
|
+
end
|
|
106
|
+
rendered = content_tokens.any? ? content_tokens.join(' ') : full_content
|
|
107
|
+
rendered.empty? ? '' : "**#{rendered}**"
|
|
108
|
+
end
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
patterns = [
|
|
112
|
+
inline_transform,
|
|
113
|
+
*dual_syntax_patterns(primary_regex, alternative_regex, block_transform_proc)
|
|
114
|
+
]
|
|
115
|
+
apply_multiple_patterns(content, patterns)
|
|
116
|
+
end
|
|
117
|
+
|
|
87
118
|
class << self
|
|
88
119
|
private
|
|
89
120
|
|
data/lib/markawesome/version.rb
CHANGED
data/lib/markawesome.rb
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'markawesome/version'
|
|
4
4
|
require_relative 'markawesome/icon_slot_parser'
|
|
5
|
+
require_relative 'markawesome/code_block_protector'
|
|
5
6
|
require_relative 'markawesome/transformer'
|
|
7
|
+
require_relative 'markawesome/plain_markdown_renderer'
|
|
6
8
|
|
|
7
9
|
# Main module for Markawesome - framework-agnostic Markdown to Web Awesome component transformer
|
|
8
10
|
module Markawesome
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: markawesome
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.10.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Janne Waren
|
|
@@ -92,7 +92,9 @@ files:
|
|
|
92
92
|
- README.md
|
|
93
93
|
- lib/markawesome.rb
|
|
94
94
|
- lib/markawesome/attribute_parser.rb
|
|
95
|
+
- lib/markawesome/code_block_protector.rb
|
|
95
96
|
- lib/markawesome/icon_slot_parser.rb
|
|
97
|
+
- lib/markawesome/plain_markdown_renderer.rb
|
|
96
98
|
- lib/markawesome/transformer.rb
|
|
97
99
|
- lib/markawesome/transformers.rb
|
|
98
100
|
- lib/markawesome/transformers/badge_transformer.rb
|