website-htmx-rustelo-code/scripts/content/new-post.nu

132 lines
4.8 KiB
Text
Raw Normal View History

2026-07-10 03:44:13 +01:00
#!/usr/bin/env nu
# Blog Post Creator / Editor
#
# Orchestrates the typedialog-web nickel-roundtrip workflow for creating
# or editing post metadata (.ncl files).
#
# Modes:
# new — load form defaults → typedialog-web → write to target .ncl
# edit -- load existing .ncl → typedialog-web → overwrite in place
# agent — write prescribed values directly to .ncl (no browser, no TUI)
#
# Usage:
# nu new-post.nu --type blog --lang en --category devops --slug my-post
# nu new-post.nu --edit site/content/blog/en/devops/my-post.ncl
# nu new-post.nu --type blog --lang en --slug my-post --agent values.json
def main [
--type: string = "blog" # Content type
--lang: string = "en" # Language directory
--category: string = "" # Category slug (matches parent dir)
--slug: string = "" # Post slug (becomes filename stem)
--edit: string = "" # Path to existing .ncl to edit (skips new)
--agent: string = "" # JSON file with prescribed field values (agent mode)
--form: string = "" # Override form template path
--content-dir: string = "" # Override SITE_CONTENT_PATH
--dry-run # Print resolved paths without opening typedialog
--verbose
] {
let content_root = resolve_env "SITE_CONTENT_PATH" $content_dir "site/content"
let form_base = if $form != "" { $form } else {
$"rustelo/forms/content/($type)/post.ncl"
}
if not ($form_base | path exists) {
error make { msg: $"Form template not found: ($form_base)" }
}
# Determine mode
let mode = if $edit != "" { "edit" } else if $agent != "" { "agent" } else { "new" }
# Resolve working .ncl path
let ncl_path = if $mode == "edit" {
$edit
} else {
if $slug == "" { error make { msg: "--slug is required for new posts" } }
if $category != "" {
$"($content_root)/($type)/($lang)/($category)/($slug).ncl"
} else {
$"($content_root)/($type)/($lang)/($slug).ncl"
}
}
if $verbose or $dry_run {
print $" mode : ($mode)"
print $" form : ($form_base)"
print $" output : ($ncl_path)"
}
if $dry_run { return }
# Prepare working copy for typedialog
let work_ncl = if $mode == "edit" {
$ncl_path
} else {
# Copy form template to a temp file — typedialog edits it in place
let tmp = $"/tmp/new-post-(random chars).ncl"
cp ($form_base | path expand) $tmp
$tmp
}
match $mode {
"new" | "edit" => {
print $"(ansi cyan)Opening typedialog form(ansi reset) — ($work_ncl)"
let result = do {
typedialog-web nickel-roundtrip ($work_ncl | path expand)
} | complete
if $result.exit_code != 0 {
error make { msg: $"typedialog failed: ($result.stderr)" }
}
if $mode == "new" {
mkdir ($ncl_path | path dirname)
cp $work_ncl $ncl_path
rm $work_ncl
print $"(ansi green)Created(ansi reset) → ($ncl_path)"
} else {
print $"(ansi green)Updated(ansi reset) → ($ncl_path)"
}
}
"agent" => {
# Agent mode: merge prescribed JSON values into the form template
if not ($agent | path exists) {
error make { msg: $"Agent values file not found: ($agent)" }
}
let values = open $agent
let base = open ($form_base | path expand)
# Render filled .ncl by patching fields in the base form
mut ncl_lines = $base | lines
for entry in ($values | items { |k, v| { key: $k, val: $v } }) {
let pat = $" ($entry.key) ="
let replacement = $" ($entry.key) = ($entry.val | to nuon),"
$ncl_lines = $ncl_lines | each { |l|
if ($l | str starts-with $pat) { $replacement } else { $l }
}
}
mkdir ($ncl_path | path dirname)
$ncl_lines | str join "\n" | save --force $ncl_path
print $"(ansi green)Agent wrote(ansi reset) → ($ncl_path)"
}
_ => { error make { msg: $"Unknown mode: ($mode)" } }
}
# Validate the result
print " validating .ncl..."
let validate = do { nickel-export ($ncl_path | path expand) } | complete
if $validate.exit_code != 0 {
print $"(ansi yellow)WARNING(ansi reset) .ncl validation failed — check fields before publishing"
print $validate.stderr
} else {
print $" (ansi green)✓(ansi reset) valid"
}
}
def resolve_env [var_name: string, cli_arg: string, fallback: string] {
if $cli_arg != "" { return $cli_arg }
try { $env | get $var_name } catch { $fallback }
}