545 lines
18 KiB
Text
545 lines
18 KiB
Text
|
|
#!/usr/bin/env nu
|
||
|
|
# Markdown processing module with frontmatter support
|
||
|
|
# Supports multiple processors with Rust tools as default
|
||
|
|
|
||
|
|
# Main Markdown processing function
|
||
|
|
export def process_markdown [markdown_file: string, config: record, dev: bool, verbose: bool] {
|
||
|
|
let markdown_config = if "markdown" in ($config | columns) { $config.markdown } else { { enabled: false } }
|
||
|
|
|
||
|
|
if not $markdown_config.enabled {
|
||
|
|
if $verbose { print "📝 Markdown processing disabled, skipping..." }
|
||
|
|
return {
|
||
|
|
html: "",
|
||
|
|
metadata: {},
|
||
|
|
size: 0,
|
||
|
|
success: false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if not ($markdown_file | path exists) {
|
||
|
|
if $verbose { print $"❌ Markdown file not found: ($markdown_file)" }
|
||
|
|
return {
|
||
|
|
html: "",
|
||
|
|
metadata: {},
|
||
|
|
size: 0,
|
||
|
|
success: false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if $verbose { print "📝 Processing Markdown file..." }
|
||
|
|
|
||
|
|
# Read and parse Markdown file with frontmatter
|
||
|
|
let parsed_content = (parse_markdown_with_frontmatter $markdown_file $markdown_config $verbose)
|
||
|
|
|
||
|
|
if not $parsed_content.success {
|
||
|
|
return {
|
||
|
|
html: "",
|
||
|
|
metadata: {},
|
||
|
|
size: 0,
|
||
|
|
success: false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Process Markdown to HTML
|
||
|
|
let html_result = (markdown_to_html $parsed_content.content $markdown_config $verbose)
|
||
|
|
|
||
|
|
if not $html_result.success {
|
||
|
|
return {
|
||
|
|
html: "",
|
||
|
|
metadata: $parsed_content.metadata,
|
||
|
|
size: 0,
|
||
|
|
success: false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Apply HTML template if specified
|
||
|
|
let final_html = (apply_markdown_template $html_result.html $parsed_content.metadata $config $verbose)
|
||
|
|
|
||
|
|
{
|
||
|
|
html: $final_html,
|
||
|
|
metadata: $parsed_content.metadata,
|
||
|
|
size: ($final_html | str length),
|
||
|
|
success: true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Parse Markdown file with frontmatter (YAML or TOML)
|
||
|
|
def parse_markdown_with_frontmatter [file_path: string, markdown_config: record, verbose: bool] {
|
||
|
|
let content = (open $file_path)
|
||
|
|
let frontmatter_format = if "frontmatter_format" in ($markdown_config | columns) {
|
||
|
|
$markdown_config.frontmatter_format
|
||
|
|
} else {
|
||
|
|
"yaml"
|
||
|
|
}
|
||
|
|
|
||
|
|
mut metadata = {}
|
||
|
|
mut markdown_content = $content
|
||
|
|
|
||
|
|
# Check for frontmatter delimiters
|
||
|
|
if ($content | str starts-with "---") {
|
||
|
|
# YAML frontmatter
|
||
|
|
let parts = ($content | str replace "---" "FRONTMATTER_DELIMITER" | split row "FRONTMATTER_DELIMITER")
|
||
|
|
|
||
|
|
if ($parts | length) >= 3 {
|
||
|
|
let frontmatter_raw = ($parts | get 1 | str trim)
|
||
|
|
$markdown_content = ($parts | skip 2 | str join "FRONTMATTER_DELIMITER" | str trim)
|
||
|
|
|
||
|
|
if ($frontmatter_raw | str length) > 0 {
|
||
|
|
$metadata = (parse_frontmatter $frontmatter_raw "yaml" $verbose)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} else if ($content | str starts-with "+++") {
|
||
|
|
# TOML frontmatter
|
||
|
|
let parts = ($content | str replace "+++" "FRONTMATTER_DELIMITER" | split row "FRONTMATTER_DELIMITER")
|
||
|
|
|
||
|
|
if ($parts | length) >= 3 {
|
||
|
|
let frontmatter_raw = ($parts | get 1 | str trim)
|
||
|
|
$markdown_content = ($parts | skip 2 | str join "FRONTMATTER_DELIMITER" | str trim)
|
||
|
|
|
||
|
|
if ($frontmatter_raw | str length) > 0 {
|
||
|
|
$metadata = (parse_frontmatter $frontmatter_raw "toml" $verbose)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if $verbose and (($metadata | columns | length) > 0) {
|
||
|
|
print $" 📋 Parsed frontmatter: ($metadata | columns | str join ', ')"
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
content: $markdown_content,
|
||
|
|
metadata: $metadata,
|
||
|
|
success: true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Parse frontmatter content (YAML or TOML)
|
||
|
|
def parse_frontmatter [content: string, format: string, verbose: bool] {
|
||
|
|
try {
|
||
|
|
match $format {
|
||
|
|
"yaml" => {
|
||
|
|
# For now, we'll use a simple YAML parser
|
||
|
|
# In a real implementation, we'd use a proper YAML library
|
||
|
|
parse_simple_yaml $content $verbose
|
||
|
|
}
|
||
|
|
"toml" => {
|
||
|
|
# Parse TOML frontmatter
|
||
|
|
$content | from toml
|
||
|
|
}
|
||
|
|
_ => {
|
||
|
|
if $verbose { print $" ⚠️ Unknown frontmatter format: ($format)" }
|
||
|
|
{}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} catch { |e|
|
||
|
|
if $verbose { print $" ⚠️ Failed to parse frontmatter: ($e.msg)" }
|
||
|
|
{}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Simple YAML parser for basic frontmatter
|
||
|
|
def parse_simple_yaml [content: string, verbose: bool] {
|
||
|
|
mut result = {}
|
||
|
|
|
||
|
|
let lines = ($content | lines | where { |line| ($line | str trim | str length) > 0 and not ($line | str starts-with "#") })
|
||
|
|
|
||
|
|
for line in $lines {
|
||
|
|
if ($line | str contains ":") {
|
||
|
|
let parts = ($line | split row ":" | take 2)
|
||
|
|
if ($parts | length) == 2 {
|
||
|
|
let key = ($parts | get 0 | str trim)
|
||
|
|
let value_raw = ($parts | get 1 | str trim)
|
||
|
|
|
||
|
|
# Parse different value types
|
||
|
|
let value = if ($value_raw | str starts-with '"') and ($value_raw | str ends-with '"') {
|
||
|
|
# String value
|
||
|
|
$value_raw | str replace '"' '' | str replace '"' ''
|
||
|
|
} else if ($value_raw | str starts-with '[') and ($value_raw | str ends-with ']') {
|
||
|
|
# Array value (simple)
|
||
|
|
$value_raw | str replace '[' '' | str replace ']' '' | split row ',' | each { |item| $item | str trim | str replace '"' '' }
|
||
|
|
} else if $value_raw in ["true", "false"] {
|
||
|
|
# Boolean value
|
||
|
|
$value_raw == "true"
|
||
|
|
} else {
|
||
|
|
# Try to parse as number, fallback to string
|
||
|
|
try {
|
||
|
|
$value_raw | into int
|
||
|
|
} catch {
|
||
|
|
try {
|
||
|
|
$value_raw | into float
|
||
|
|
} catch {
|
||
|
|
$value_raw
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$result = ($result | insert $key $value)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$result
|
||
|
|
}
|
||
|
|
|
||
|
|
# Convert Markdown to HTML using configured processor
|
||
|
|
def markdown_to_html [markdown_content: string, markdown_config: record, verbose: bool] {
|
||
|
|
let processor = if "processor" in ($markdown_config | columns) {
|
||
|
|
$markdown_config.processor
|
||
|
|
} else {
|
||
|
|
"pulldown-cmark" # Rust default
|
||
|
|
}
|
||
|
|
|
||
|
|
if $verbose { print $" 🔧 Using Markdown processor: ($processor)" }
|
||
|
|
|
||
|
|
match $processor {
|
||
|
|
"pulldown-cmark" => { rust_pulldown_cmark $markdown_content $markdown_config $verbose }
|
||
|
|
"comrak" => { rust_comrak $markdown_content $markdown_config $verbose }
|
||
|
|
"pandoc" => { external_pandoc $markdown_content $markdown_config $verbose }
|
||
|
|
"marked" => { external_marked $markdown_content $markdown_config $verbose }
|
||
|
|
"markdown-it" => { external_markdown_it $markdown_content $markdown_config $verbose }
|
||
|
|
_ => {
|
||
|
|
if $verbose { print $" ⚠️ Unknown processor ($processor), falling back to pulldown-cmark" }
|
||
|
|
rust_pulldown_cmark $markdown_content $markdown_config $verbose
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Process Markdown using Rust pulldown-cmark (default)
|
||
|
|
def rust_pulldown_cmark [content: string, config: record, verbose: bool] {
|
||
|
|
# Check if pulldown-cmark is available as a CLI tool
|
||
|
|
let has_pulldown_cmark = (which pulldown-cmark | length) > 0
|
||
|
|
|
||
|
|
if $has_pulldown_cmark {
|
||
|
|
try {
|
||
|
|
# Create temp file for input
|
||
|
|
let temp_input = $"/tmp/markdown_input_(date now | format date '%s').md"
|
||
|
|
$content | save $temp_input
|
||
|
|
|
||
|
|
# Process with pulldown-cmark
|
||
|
|
let html_output = (run-external "pulldown-cmark" $temp_input)
|
||
|
|
|
||
|
|
# Clean up
|
||
|
|
rm $temp_input
|
||
|
|
|
||
|
|
{
|
||
|
|
html: $html_output,
|
||
|
|
success: true
|
||
|
|
}
|
||
|
|
} catch { |e|
|
||
|
|
if $verbose { print $" ❌ pulldown-cmark failed: ($e.msg)" }
|
||
|
|
# Fallback to built-in simple processor
|
||
|
|
simple_markdown_processor $content $config $verbose
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if $verbose { print " 💡 pulldown-cmark not found, using built-in processor" }
|
||
|
|
simple_markdown_processor $content $config $verbose
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Process Markdown using Rust comrak
|
||
|
|
def rust_comrak [content: string, config: record, verbose: bool] {
|
||
|
|
let has_comrak = (which comrak | length) > 0
|
||
|
|
|
||
|
|
if $has_comrak {
|
||
|
|
try {
|
||
|
|
# Create temp file for input
|
||
|
|
let temp_input = $"/tmp/markdown_input_(date now | format date '%s').md"
|
||
|
|
$content | save $temp_input
|
||
|
|
|
||
|
|
# Process with comrak (GitHub-flavored Markdown)
|
||
|
|
let args = ["--gfm", "--unsafe", $temp_input]
|
||
|
|
let html_output = (run-external "comrak" ...$args)
|
||
|
|
|
||
|
|
# Clean up
|
||
|
|
rm $temp_input
|
||
|
|
|
||
|
|
{
|
||
|
|
html: $html_output,
|
||
|
|
success: true
|
||
|
|
}
|
||
|
|
} catch { |e|
|
||
|
|
if $verbose { print $" ❌ comrak failed: ($e.msg)" }
|
||
|
|
# Fallback to built-in processor
|
||
|
|
simple_markdown_processor $content $config $verbose
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if $verbose { print " 💡 comrak not found, falling back to pulldown-cmark" }
|
||
|
|
rust_pulldown_cmark $content $config $verbose
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Process Markdown using external pandoc
|
||
|
|
def external_pandoc [content: string, config: record, verbose: bool] {
|
||
|
|
let has_pandoc = (which pandoc | length) > 0
|
||
|
|
|
||
|
|
if $has_pandoc {
|
||
|
|
try {
|
||
|
|
# Create temp file for input
|
||
|
|
let temp_input = $"/tmp/markdown_input_(date now | format date '%s').md"
|
||
|
|
$content | save $temp_input
|
||
|
|
|
||
|
|
# Process with pandoc
|
||
|
|
let args = ["-f", "markdown", "-t", "html", $temp_input]
|
||
|
|
let html_output = (run-external "pandoc" ...$args)
|
||
|
|
|
||
|
|
# Clean up
|
||
|
|
rm $temp_input
|
||
|
|
|
||
|
|
{
|
||
|
|
html: $html_output,
|
||
|
|
success: true
|
||
|
|
}
|
||
|
|
} catch { |e|
|
||
|
|
if $verbose { print $" ❌ pandoc failed: ($e.msg)" }
|
||
|
|
# Fallback to Rust processor
|
||
|
|
rust_pulldown_cmark $content $config $verbose
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if $verbose { print " 💡 pandoc not found, falling back to pulldown-cmark" }
|
||
|
|
rust_pulldown_cmark $content $config $verbose
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Process Markdown using external marked (Node.js)
|
||
|
|
def external_marked [content: string, config: record, verbose: bool] {
|
||
|
|
let has_marked = (which marked | length) > 0
|
||
|
|
|
||
|
|
if $has_marked {
|
||
|
|
try {
|
||
|
|
# Create temp file for input
|
||
|
|
let temp_input = $"/tmp/markdown_input_(date now | format date '%s').md"
|
||
|
|
$content | save $temp_input
|
||
|
|
|
||
|
|
# Process with marked
|
||
|
|
let args = [$temp_input]
|
||
|
|
let html_output = (run-external "marked" ...$args)
|
||
|
|
|
||
|
|
# Clean up
|
||
|
|
rm $temp_input
|
||
|
|
|
||
|
|
{
|
||
|
|
html: $html_output,
|
||
|
|
success: true
|
||
|
|
}
|
||
|
|
} catch { |e|
|
||
|
|
if $verbose { print $" ❌ marked failed: ($e.msg)" }
|
||
|
|
# Fallback to Rust processor
|
||
|
|
rust_pulldown_cmark $content $config $verbose
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if $verbose { print " 💡 marked not found, falling back to pulldown-cmark" }
|
||
|
|
rust_pulldown_cmark $content $config $verbose
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Process Markdown using external markdown-it (Node.js)
|
||
|
|
def external_markdown_it [content: string, config: record, verbose: bool] {
|
||
|
|
let has_markdown_it = (which markdown-it | length) > 0
|
||
|
|
|
||
|
|
if $has_markdown_it {
|
||
|
|
try {
|
||
|
|
# Create temp file for input
|
||
|
|
let temp_input = $"/tmp/markdown_input_(date now | format date '%s').md"
|
||
|
|
$content | save $temp_input
|
||
|
|
|
||
|
|
# Process with markdown-it
|
||
|
|
let args = [$temp_input]
|
||
|
|
let html_output = (run-external "markdown-it" ...$args)
|
||
|
|
|
||
|
|
# Clean up
|
||
|
|
rm $temp_input
|
||
|
|
|
||
|
|
{
|
||
|
|
html: $html_output,
|
||
|
|
success: true
|
||
|
|
}
|
||
|
|
} catch { |e|
|
||
|
|
if $verbose { print $" ❌ markdown-it failed: ($e.msg)" }
|
||
|
|
# Fallback to Rust processor
|
||
|
|
rust_pulldown_cmark $content $config $verbose
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if $verbose { print " 💡 markdown-it not found, falling back to pulldown-cmark" }
|
||
|
|
rust_pulldown_cmark $content $config $verbose
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Simple built-in Markdown processor (fallback)
|
||
|
|
def simple_markdown_processor [content: string, config: record, verbose: bool] {
|
||
|
|
if $verbose { print " 🔧 Using built-in Markdown processor" }
|
||
|
|
|
||
|
|
mut html = $content
|
||
|
|
|
||
|
|
# Headers
|
||
|
|
$html = ($html | str replace -ar '^# (.+)$' '<h1>$1</h1>')
|
||
|
|
$html = ($html | str replace -ar '^## (.+)$' '<h2>$1</h2>')
|
||
|
|
$html = ($html | str replace -ar '^### (.+)$' '<h3>$1</h3>')
|
||
|
|
$html = ($html | str replace -ar '^#### (.+)$' '<h4>$1</h4>')
|
||
|
|
|
||
|
|
# Bold and italic
|
||
|
|
$html = ($html | str replace -ar '\*\*([^*]+)\*\*' '<strong>$1</strong>')
|
||
|
|
$html = ($html | str replace -ar '\*([^*]+)\*' '<em>$1</em>')
|
||
|
|
|
||
|
|
# Code blocks
|
||
|
|
$html = ($html | str replace -ar '```([a-zA-Z0-9]*)\n(.*?)\n```' '<pre><code class="language-$1">$2</code></pre>')
|
||
|
|
$html = ($html | str replace -ar '`([^`]+)`' '<code>$1</code>')
|
||
|
|
|
||
|
|
# Links
|
||
|
|
$html = ($html | str replace -ar '\[([^\]]+)\]\(([^)]+)\)' '<a href="$2">$1</a>')
|
||
|
|
|
||
|
|
# Paragraphs (simple)
|
||
|
|
let lines = ($html | lines)
|
||
|
|
let processed_lines = ($lines | each { |line|
|
||
|
|
if ($line | str trim | str length) == 0 {
|
||
|
|
""
|
||
|
|
} else if ($line | str starts-with "<") {
|
||
|
|
$line
|
||
|
|
} else {
|
||
|
|
$"<p>($line)</p>"
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
$html = ($processed_lines | str join "\n")
|
||
|
|
|
||
|
|
{
|
||
|
|
html: $html,
|
||
|
|
success: true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Apply HTML template to Markdown content
|
||
|
|
def apply_markdown_template [html_content: string, metadata: record, config: record, verbose: bool] {
|
||
|
|
let markdown_config = if "markdown" in ($config | columns) { $config.markdown } else { {} }
|
||
|
|
let template_name = if "template" in ($metadata | columns) {
|
||
|
|
$metadata.template
|
||
|
|
} else if "template" in ($markdown_config | columns) {
|
||
|
|
$markdown_config.template
|
||
|
|
} else {
|
||
|
|
"article"
|
||
|
|
}
|
||
|
|
|
||
|
|
if $verbose { print $" 🎨 Applying template: ($template_name)" }
|
||
|
|
|
||
|
|
# Load template
|
||
|
|
let template_result = (load_markdown_template $template_name $config $verbose)
|
||
|
|
|
||
|
|
if not $template_result.success {
|
||
|
|
if $verbose { print " ⚠️ Template loading failed, using content as-is" }
|
||
|
|
return $html_content
|
||
|
|
}
|
||
|
|
|
||
|
|
# Replace template variables
|
||
|
|
let final_html = (render_template $template_result.content $html_content $metadata $config)
|
||
|
|
|
||
|
|
$final_html
|
||
|
|
}
|
||
|
|
|
||
|
|
# Load HTML template for Markdown content
|
||
|
|
def load_markdown_template [template_name: string, config: record, verbose: bool] {
|
||
|
|
# Find framework root
|
||
|
|
let current_dir = $env.PWD
|
||
|
|
let framework_templates = ($current_dir | path join "framework" "templates" "markdown")
|
||
|
|
|
||
|
|
let template_path = ($framework_templates | path join $"($template_name).html")
|
||
|
|
|
||
|
|
if ($template_path | path exists) {
|
||
|
|
let content = (open $template_path)
|
||
|
|
{
|
||
|
|
content: $content,
|
||
|
|
success: true
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
# Try custom template path if specified
|
||
|
|
let markdown_config = if "markdown" in ($config | columns) { $config.markdown } else { {} }
|
||
|
|
let custom_template = if "custom_template" in ($markdown_config | columns) {
|
||
|
|
$markdown_config.custom_template
|
||
|
|
} else { "" }
|
||
|
|
|
||
|
|
if ($custom_template | str length) > 0 and ($custom_template | path exists) {
|
||
|
|
let content = (open $custom_template)
|
||
|
|
{
|
||
|
|
content: $content,
|
||
|
|
success: true
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if $verbose { print $" ❌ Template not found: ($template_path)" }
|
||
|
|
{
|
||
|
|
content: "",
|
||
|
|
success: false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Render template with variables
|
||
|
|
def render_template [template: string, content: string, metadata: record, config: record] {
|
||
|
|
mut rendered = $template
|
||
|
|
|
||
|
|
# Replace content placeholder
|
||
|
|
$rendered = ($rendered | str replace "{{CONTENT}}" $content)
|
||
|
|
|
||
|
|
# Replace metadata variables
|
||
|
|
for key in ($metadata | columns) {
|
||
|
|
let value = $metadata | get $key
|
||
|
|
let placeholder = $"{{($key | str upcase)}}"
|
||
|
|
$rendered = ($rendered | str replace $placeholder ($value | into string))
|
||
|
|
}
|
||
|
|
|
||
|
|
# Replace config variables
|
||
|
|
let page_config = if "page" in ($config | columns) { $config.page } else { {} }
|
||
|
|
for key in ($page_config | columns) {
|
||
|
|
let value = $page_config | get $key
|
||
|
|
let placeholder = $"{{PAGE_($key | str upcase)}}"
|
||
|
|
$rendered = ($rendered | str replace $placeholder ($value | into string))
|
||
|
|
}
|
||
|
|
|
||
|
|
# Default fallbacks
|
||
|
|
$rendered = ($rendered | str replace -ar '{{[^}]+}}' '') # Remove unmatched placeholders
|
||
|
|
|
||
|
|
$rendered
|
||
|
|
}
|
||
|
|
|
||
|
|
# Detect if a directory contains Markdown source
|
||
|
|
export def has_markdown_source [src_dir: string, markdown_config?: record] {
|
||
|
|
let config = if ($markdown_config | is-empty) { {} } else { $markdown_config }
|
||
|
|
let source_file = if "source_file" in ($config | columns) {
|
||
|
|
$config.source_file
|
||
|
|
} else {
|
||
|
|
"content.md"
|
||
|
|
}
|
||
|
|
|
||
|
|
let markdown_path = ($src_dir | path join $source_file)
|
||
|
|
($markdown_path | path exists)
|
||
|
|
}
|
||
|
|
|
||
|
|
# Get Markdown source file path
|
||
|
|
export def get_markdown_source_path [src_dir: string, markdown_config?: record] {
|
||
|
|
let config = if ($markdown_config | is-empty) { {} } else { $markdown_config }
|
||
|
|
let source_file = if "source_file" in ($config | columns) {
|
||
|
|
$config.source_file
|
||
|
|
} else {
|
||
|
|
"content.md"
|
||
|
|
}
|
||
|
|
|
||
|
|
($src_dir | path join $source_file)
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate Markdown processor availability
|
||
|
|
export def check_markdown_processors [] {
|
||
|
|
let processors = [
|
||
|
|
{ name: "pulldown-cmark", command: "pulldown-cmark", language: "Rust" },
|
||
|
|
{ name: "comrak", command: "comrak", language: "Rust" },
|
||
|
|
{ name: "pandoc", command: "pandoc", language: "Haskell" },
|
||
|
|
{ name: "marked", command: "marked", language: "Node.js" },
|
||
|
|
{ name: "markdown-it", command: "markdown-it", language: "Node.js" }
|
||
|
|
]
|
||
|
|
|
||
|
|
$processors | each { |proc|
|
||
|
|
{
|
||
|
|
name: $proc.name,
|
||
|
|
available: ((which $proc.command | length) > 0),
|
||
|
|
language: $proc.language,
|
||
|
|
command: $proc.command
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|