#! /usr/bin/env tclsh
# Copyright (c) 2021 D. Bohdan.
# License: MIT.
namespace eval tclmark {
variable interp
variable renders 0
variable version 0.1.0
namespace eval cmd {
namespace path [namespace parent]
}
}
proc tclmark::render {content {variables {}}} {
variable interp
variable renders
incr renders
set interp tclmark-$renders
try {
interp create -safe $interp
foreach command [info commands cmd::*] {
$interp alias \
[namespace tail $command] \
$command \
}
interp hide $interp subst
flatten [msubst $content]
} finally {
catch {
interp delete $interp
}
}
}
proc tclmark::msubst content {
variable interp
set r [interp invokehidden \
$interp \
subst -nobackslashes -novariables $content \
]
if {$r eq $content} {
return [list text $content]
}
return $r
}
proc tclmark::flatten tree {
if {[llength $tree] != 2} {
error [list not two elements: $tree]
}
lassign $tree tag data
switch -- $tag {
html {
lindex $data
}
text {
entities $data
}
tree {
join [lmap el $data {
flatten $el
}] {}
}
default {
error [list unknown tag: $tag]
}
}
}
proc tclmark::entities text {
string map {
& &
< <
> >
\" "
' '
} $text
}
proc tclmark::tree args {
list tree $args
}
proc tclmark::cmd::b content {
tree {html <b>} [msubst $content] {html </b>}
}
proc tclmark::cmd::i content {
tree {html <i>} [msubst $content] {html </i>}
}
proc tclmark::run-tests {} {
set stats [dict create total 0 passed 0 failed 0]
proc test {name script arrow expected} {
upvar stats stats
dict incr stats total
catch $script result
set matched [switch -- $arrow {
-> { expr {$result eq $expected} }
->* { string match $expected $result }
->$ { regexp -- $expected $result }
default {
return -code error \
-errorcode {JIMLIB TEST BAD-ARROW} \
[list unknown arrow: $arrow]
}
}]
if {!$matched} {
set error {}
append error "\n>>>>> $name failed: [list $script]\n"
append error " got: [list $result]\n"
append error " expected: [list $expected]"
if {$arrow ne {->}} {
append error "\n match: $arrow"
}
dict incr stats failed
puts stderr $error
return
}
dict incr stats passed
}
test basic-1 {
tclmark::render Test
} -> Test
test basic-2 {
tclmark::render {[b Test]}
} -> <b>Test</b>
test basic-3 {
tclmark::render {[i {Hello, world!}]}
} -> {<i>Hello, world!</i>}
test basic-4 {
tclmark::render {[b [i Test]]}
} -> <b><i>Test</i></b>
test basic-5 {
tclmark::render {[b {[i Test]}]}
} -> <b><i>Test</i></b>
test basic-6 {
tclmark::render {[}
} -> \[
test html-1 {
tclmark::render {<b><i>Test</i></b>}
} -> {<b><i>Test</i></b>}
test html-2 {
tclmark::render {[b <script>alert('Hello!')</script>]}
} -> {<b><script>alert('Hello!')</script></b>}
test list-1 {
tclmark::render {[list first second third]}
} -> {<ol><li>first</li><li>second</li><li>third</li></ol>}
puts stderr $stats
return [expr {[dict get $stats failed] > 0}]
}
# If this is the main script...
if {[info exists argv0] && ([file tail [info script]] eq [file tail $argv0])} {
exit [tclmark::run-tests]
}
package provide tclmark 0