feat: add merge_all_wren utility, strutil demo, and 7 new API manual pages

Add WrenFileReader class in apps/merge_all_wren.wren for recursive .wren file discovery and content printing. Introduce example/strutil_demo.wren demonstrating case conversion, hex encoding, SHA256 hashing, string repetition, padding, HTML/JSON escaping, and URL encoding/decoding. Create manual/api pages for argparse, dataset, html, markdown, uuid, wdantic, and web modules. Update manual/api/index.html sidebar and module count from 21 to 28, adding links and cards for the new modules.
This commit is contained in:
2026-01-25 01:47:47 +00:00
parent 5a4054ec66
commit 74ef5cbc11
74 changed files with 7749 additions and 292 deletions
+24
View File
@@ -0,0 +1,24 @@
// retoor <retoor@molodetz.nl>
import "dataset" for Dataset
var ds = Dataset.memory()
var users = ds["users"]
var active = users.insert({"name": "Alice", "active": true, "admin": false})
System.print(active["active"]) // expect: true
System.print(active["admin"]) // expect: false
var inactive = users.insert({"name": "Bob", "active": false, "admin": true})
System.print(inactive["active"]) // expect: false
System.print(inactive["admin"]) // expect: true
var found = users.findOne({"name": "Alice"})
System.print(found["active"]) // expect: 1
System.print(found["admin"]) // expect: 0
var activeUsers = users.find({"active": true})
System.print(activeUsers.count) // expect: 1
System.print(activeUsers[0]["name"]) // expect: Alice
ds.close()
+23
View File
@@ -0,0 +1,23 @@
// retoor <retoor@molodetz.nl>
import "dataset" for Dataset
var ds = Dataset.memory()
var events = ds["events"]
var event = events.insert({
"name": "Conference",
"created_at": "2024-01-15T10:00:00"
})
System.print(event["created_at"]) // expect: 2024-01-15T10:00:00
System.print(event["name"]) // expect: Conference
var found = events.findOne({"name": "Conference"})
System.print(found["created_at"]) // expect: 2024-01-15T10:00:00
var auto = events.insert({"name": "Meeting"})
System.print(auto["created_at"] != null) // expect: true
System.print(auto["created_at"] != "2024-01-15T10:00:00") // expect: true
ds.close()
+24
View File
@@ -0,0 +1,24 @@
// retoor <retoor@molodetz.nl>
import "dataset" for Dataset
var ds = Dataset.memory()
var users = ds["users"]
var user = users.insert({
"uid": "my-custom-id-123",
"name": "Alice"
})
System.print(user["uid"]) // expect: my-custom-id-123
System.print(user["name"]) // expect: Alice
var found = users.findOne({"uid": "my-custom-id-123"})
System.print(found != null) // expect: true
System.print(found["name"]) // expect: Alice
users.update({"uid": "my-custom-id-123", "name": "Alice Smith"})
var updated = users.findOne({"uid": "my-custom-id-123"})
System.print(updated["name"]) // expect: Alice Smith
ds.close()
+38
View File
@@ -0,0 +1,38 @@
// retoor <retoor@molodetz.nl>
import "dataset" for Dataset
var ds = Dataset.memory()
var users = ds["users"]
var emptyAll = users.all()
System.print(emptyAll.count) // expect: 0
System.print(users.count()) // expect: 0
var user = users.insert({"name": "Alice", "score": 100})
var notFound = users.findOne({"name": "Nobody"})
System.print(notFound == null) // expect: true
var emptyFind = users.find({"name": "Nobody"})
System.print(emptyFind.count) // expect: 0
System.print(emptyFind is List) // expect: true
var uid = user["uid"]
var changes1 = users.update({"uid": uid, "score": 200})
System.print(changes1) // expect: 1
var changes2 = users.update({"uid": uid, "score": 300, "level": 5})
System.print(changes2) // expect: 1
var updated = users.findOne({"uid": uid})
System.print(updated["score"]) // expect: 300
System.print(updated["level"]) // expect: 5
var fakeChanges = users.update({"uid": "nonexistent-uid", "score": 999})
System.print(fakeChanges) // expect: 0
System.print(users.delete("nonexistent-uid")) // expect: false
ds.close()
+33
View File
@@ -0,0 +1,33 @@
// retoor <retoor@molodetz.nl>
import "dataset" for Dataset
import "io" for File
var dbPath = "/tmp/test_dataset.db"
if (File.exists(dbPath)) {
File.delete(dbPath)
}
var ds = Dataset.open(dbPath)
var users = ds["users"]
var user = users.insert({"name": "Alice", "score": 100})
System.print(user["name"]) // expect: Alice
System.print(users.count()) // expect: 1
ds.close()
System.print(File.exists(dbPath)) // expect: true
var ds2 = Dataset.open(dbPath)
var users2 = ds2["users"]
System.print(users2.count()) // expect: 1
var found = users2.findOne({"name": "Alice"})
System.print(found["score"]) // expect: 100
ds2.close()
File.delete(dbPath)
System.print(File.exists(dbPath)) // expect: false
+29
View File
@@ -0,0 +1,29 @@
// retoor <retoor@molodetz.nl>
import "dataset" for Dataset
var ds = Dataset.memory()
var users = ds["users"]
var user = users.insert({"name": "Alice"})
var uid = user["uid"]
System.print(users.count()) // expect: 1
users.delete(uid)
System.print(users.count()) // expect: 0
var softDeleted = ds.db.query("SELECT * FROM users WHERE uid = ?", [uid])
System.print(softDeleted.count) // expect: 1
System.print(softDeleted[0]["deleted_at"] != null) // expect: true
var user2 = users.insert({"name": "Bob"})
var uid2 = user2["uid"]
System.print(users.hardDelete(uid2)) // expect: true
var hardDeleted = ds.db.query("SELECT * FROM users WHERE uid = ?", [uid2])
System.print(hardDeleted.count) // expect: 0
System.print(users.hardDelete("nonexistent")) // expect: false
ds.close()
+39
View File
@@ -0,0 +1,39 @@
// retoor <retoor@molodetz.nl>
import "dataset" for Dataset
var ds = Dataset.memory()
var posts = ds["posts"]
var post = posts.insert({
"title": "Hello",
"tags": ["wren", "programming"],
"metadata": {"views": 100, "featured": true}
})
System.print(post["title"]) // expect: Hello
System.print(post["tags"] is List) // expect: true
System.print(post["tags"].count) // expect: 2
System.print(post["tags"][0]) // expect: wren
System.print(post["metadata"] is Map) // expect: true
System.print(post["metadata"]["views"]) // expect: 100
System.print(post["metadata"]["featured"]) // expect: true
var retrieved = posts.findOne({"title": "Hello"})
System.print(retrieved["tags"] is List) // expect: true
System.print(retrieved["tags"][1]) // expect: programming
System.print(retrieved["metadata"]["views"]) // expect: 100
var nested = posts.insert({
"title": "Nested",
"data": {
"level1": {
"level2": ["a", "b", "c"]
}
}
})
var fetched = posts.findOne({"title": "Nested"})
System.print(fetched["data"]["level1"]["level2"][0]) // expect: a
ds.close()
+33
View File
@@ -0,0 +1,33 @@
// retoor <retoor@molodetz.nl>
import "dataset" for Dataset
var ds = Dataset.memory()
var users = ds["users"]
var posts = ds["posts"]
var comments = ds["comments"]
var user = users.insert({"name": "Alice"})
var userUid = user["uid"]
var post = posts.insert({"title": "Hello", "author_uid": userUid})
var postUid = post["uid"]
comments.insert({"text": "Nice!", "post_uid": postUid, "author_uid": userUid})
comments.insert({"text": "Great!", "post_uid": postUid, "author_uid": userUid})
System.print(users.count()) // expect: 1
System.print(posts.count()) // expect: 1
System.print(comments.count()) // expect: 2
var tables = ds.tables
System.print(tables.count) // expect: 3
System.print(tables.contains("users")) // expect: true
System.print(tables.contains("posts")) // expect: true
System.print(tables.contains("comments")) // expect: true
var postComments = comments.find({"post_uid": postUid})
System.print(postComments.count) // expect: 2
ds.close()
+22
View File
@@ -0,0 +1,22 @@
// retoor <retoor@molodetz.nl>
import "dataset" for Dataset
var ds = Dataset.memory()
var users = ds["users"]
users.insert({"name": "Alice", "email": "alice@example.com"})
users.insert({"name": "Bob", "email": null})
users.insert({"name": "Charlie"})
var withEmail = users.find({"email__null": false})
System.print(withEmail.count) // expect: 1
System.print(withEmail[0]["name"]) // expect: Alice
var withoutEmail = users.find({"email__null": true})
System.print(withoutEmail.count) // expect: 2
var all = users.all()
System.print(all.count) // expect: 3
ds.close()
+27
View File
@@ -0,0 +1,27 @@
// retoor <retoor@molodetz.nl>
import "dataset" for Dataset
var ds = Dataset.memory()
var products = ds["products"]
var p1 = products.insert({"name": "Widget", "price": 19.99, "quantity": 100})
System.print(p1["price"]) // expect: 19.99
System.print(p1["quantity"]) // expect: 100
var p2 = products.insert({"name": "Gadget", "price": 0.5, "quantity": 0})
System.print(p2["price"]) // expect: 0.5
System.print(p2["quantity"]) // expect: 0
var found = products.findOne({"name": "Widget"})
System.print(found["price"]) // expect: 19.99
System.print(found["quantity"]) // expect: 100
var cheap = products.find({"price__lt": 1})
System.print(cheap.count) // expect: 1
System.print(cheap[0]["name"]) // expect: Gadget
var expensive = products.find({"price__gte": 10})
System.print(expensive.count) // expect: 1
ds.close()
+36
View File
@@ -0,0 +1,36 @@
// retoor <retoor@molodetz.nl>
import "dataset" for Dataset
var ds = Dataset.memory()
var products = ds["products"]
products.insert({"name": "Apple", "price": 10, "stock": 100})
products.insert({"name": "Banana", "price": 5, "stock": 50})
products.insert({"name": "Cherry", "price": 20, "stock": 0})
products.insert({"name": "Date", "price": 15, "stock": 25})
var gte = products.find({"price__gte": 15})
System.print(gte.count) // expect: 2
var lte = products.find({"price__lte": 10})
System.print(lte.count) // expect: 2
var ne = products.find({"name__ne": "Apple"})
System.print(ne.count) // expect: 3
var like = products.find({"name__like": "A\%"})
System.print(like.count) // expect: 1
System.print(like[0]["name"]) // expect: Apple
var inList = products.find({"name__in": ["Apple", "Banana"]})
System.print(inList.count) // expect: 2
var zeroStock = products.find({"stock": 0})
System.print(zeroStock.count) // expect: 1
System.print(zeroStock[0]["name"]) // expect: Cherry
var combined = products.find({"price__gte": 10, "stock__gt": 0})
System.print(combined.count) // expect: 2
ds.close()
+16
View File
@@ -0,0 +1,16 @@
// retoor <retoor@molodetz.nl>
import "dataset" for Dataset
var ds = Dataset.memory()
var users = ds["users"]
System.print(users.name) // expect: users
var products = ds["products"]
System.print(products.name) // expect: products
var orders = ds["my_orders"]
System.print(orders.name) // expect: my_orders
ds.close()
+20
View File
@@ -0,0 +1,20 @@
// retoor <retoor@molodetz.nl>
import "dataset" for Dataset
var ds = Dataset.memory()
System.print(ds.tables.count) // expect: 0
ds["users"].insert({"name": "Alice"})
System.print(ds.tables.count) // expect: 1
System.print(ds.tables.contains("users")) // expect: true
ds["products"].insert({"name": "Widget"})
System.print(ds.tables.count) // expect: 2
System.print(ds.tables.contains("products")) // expect: true
ds["orders"].insert({"total": 100})
System.print(ds.tables.count) // expect: 3
ds.close()
+22
View File
@@ -0,0 +1,22 @@
// retoor <retoor@molodetz.nl>
import "markdown" for Markdown
var multiLine = Markdown.toHtml("```\nline 1\nline 2\nline 3\n```")
System.print(multiLine.contains("line 1")) // expect: true
System.print(multiLine.contains("line 2")) // expect: true
System.print(multiLine.contains("line 3")) // expect: true
System.print(multiLine.contains("<pre><code>")) // expect: true
var multiQuote = Markdown.toHtml("> line 1\n> line 2")
System.print(multiQuote.contains("<blockquote>")) // expect: true
System.print(multiQuote.contains("line 1")) // expect: true
System.print(multiQuote.contains("line 2")) // expect: true
var withLang = Markdown.toHtml("```wren\nSystem.print(\"hello\")\n```")
System.print(withLang.contains("<pre><code>")) // expect: true
System.print(withLang.contains("System.print")) // expect: true
var emptyBlock = Markdown.toHtml("```\n\n```")
System.print(emptyBlock.contains("<pre><code>")) // expect: true
System.print(emptyBlock.contains("</code></pre>")) // expect: true
+24
View File
@@ -0,0 +1,24 @@
// retoor <retoor@molodetz.nl>
import "markdown" for Markdown
System.print(Markdown.toHtml("__bold underscore__")) // expect: <p><strong>bold underscore</strong></p>
var mixed = Markdown.toHtml("This is **bold** and *italic* text")
System.print(mixed.contains("<strong>bold</strong>")) // expect: true
System.print(mixed.contains("<em>italic</em>")) // expect: true
var code = Markdown.toHtml("Use `print()` function")
System.print(code.contains("<code>print()</code>")) // expect: true
var multi = Markdown.toHtml("**bold** and `code` and *italic*")
System.print(multi.contains("<strong>bold</strong>")) // expect: true
System.print(multi.contains("<code>code</code>")) // expect: true
System.print(multi.contains("<em>italic</em>")) // expect: true
var unclosed = Markdown.toHtml("This has *unclosed italic")
System.print(unclosed.contains("<p>")) // expect: true
var empty = Markdown.toHtml("**bold****more**")
System.print(empty.contains("<strong>bold</strong>")) // expect: true
System.print(empty.contains("<strong>more</strong>")) // expect: true
+49
View File
@@ -0,0 +1,49 @@
// retoor <retoor@molodetz.nl>
import "markdown" for Markdown
System.print(Markdown.fromHtml("<h1>Title</h1>")) // expect: # Title
System.print(Markdown.fromHtml("<h2>Subtitle</h2>")) // expect: ## Subtitle
System.print(Markdown.fromHtml("<h3>Section</h3>")) // expect: ### Section
System.print(Markdown.fromHtml("<h4>Subsection</h4>")) // expect: #### Subsection
System.print(Markdown.fromHtml("<h5>Minor</h5>")) // expect: ##### Minor
System.print(Markdown.fromHtml("<h6>Smallest</h6>")) // expect: ###### Smallest
System.print(Markdown.fromHtml("<strong>bold</strong>")) // expect: **bold**
System.print(Markdown.fromHtml("<b>bold</b>")) // expect: **bold**
System.print(Markdown.fromHtml("<em>italic</em>")) // expect: *italic*
System.print(Markdown.fromHtml("<i>italic</i>")) // expect: *italic*
System.print(Markdown.fromHtml("<code>code</code>")) // expect: `code`
System.print(Markdown.fromHtml("<del>deleted</del>")) // expect: ~~deleted~~
System.print(Markdown.fromHtml("<s>strike</s>")) // expect: ~~strike~~
System.print(Markdown.fromHtml("<a href=\"https://example.com\">Example</a>")) // expect: [Example](https://example.com)
System.print(Markdown.fromHtml("<img src=\"image.png\" alt=\"My Image\">")) // expect: ![My Image](image.png)
var ul = Markdown.fromHtml("<ul><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>")
System.print(ul.contains("- Item 1")) // expect: true
System.print(ul.contains("- Item 2")) // expect: true
System.print(ul.contains("- Item 3")) // expect: true
var ol = Markdown.fromHtml("<ol><li>First</li><li>Second</li><li>Third</li></ol>")
System.print(ol.contains("1. First")) // expect: true
System.print(ol.contains("2. Second")) // expect: true
System.print(ol.contains("3. Third")) // expect: true
var bq = Markdown.fromHtml("<blockquote>Quote text</blockquote>")
System.print(bq.contains("> Quote text")) // expect: true
System.print(Markdown.fromHtml("<hr>").contains("---")) // expect: true
System.print(Markdown.fromHtml("<hr/>").contains("---")) // expect: true
var p = Markdown.fromHtml("<p>First paragraph</p><p>Second paragraph</p>")
System.print(p.contains("First paragraph")) // expect: true
System.print(p.contains("Second paragraph")) // expect: true
var br = Markdown.fromHtml("Line one<br>Line two")
System.print(br.contains("Line one")) // expect: true
System.print(br.contains("Line two")) // expect: true
+78
View File
@@ -0,0 +1,78 @@
// retoor <retoor@molodetz.nl>
import "markdown" for Markdown
var nested = Markdown.fromHtml("<p><strong>Bold <em>and italic</em> text</strong></p>")
System.print(nested.contains("**Bold *and italic* text**")) // expect: true
var mixed = Markdown.fromHtml("<p>Normal <strong>bold</strong> and <em>italic</em> and <code>code</code></p>")
System.print(mixed.contains("Normal **bold** and *italic* and `code`")) // expect: true
var codeBlock = Markdown.fromHtml("<pre><code>function test() {\n return true;\n}</code></pre>")
System.print(codeBlock.contains("```")) // expect: true
System.print(codeBlock.contains("function test()")) // expect: true
var script = Markdown.fromHtml("<p>Hello</p><script>alert('xss');</script><p>World</p>")
System.print(script.contains("Hello")) // expect: true
System.print(script.contains("World")) // expect: true
System.print(script.contains("alert")) // expect: false
System.print(script.contains("script")) // expect: false
var style = Markdown.fromHtml("<p>Content</p><style>.red { color: red; }</style>")
System.print(style.contains("Content")) // expect: true
System.print(style.contains("color")) // expect: false
var entities = Markdown.fromHtml("<p>5 &gt; 3 &amp;&amp; 3 &lt; 5</p>")
System.print(entities.contains(">")) // expect: true
System.print(entities.contains("<")) // expect: true
System.print(entities.contains("&")) // expect: true
var doc = """
<html>
<head><title>Test</title></head>
<body>
<h1>Main Title</h1>
<p>Introduction paragraph with <strong>bold</strong> text.</p>
<h2>Section One</h2>
<ul>
<li>Item A</li>
<li>Item B</li>
</ul>
<blockquote>A wise quote</blockquote>
<hr>
<p>Footer content</p>
</body>
</html>
"""
var result = Markdown.fromHtml(doc)
System.print(result.contains("# Main Title")) // expect: true
System.print(result.contains("**bold**")) // expect: true
System.print(result.contains("## Section One")) // expect: true
System.print(result.contains("- Item A")) // expect: true
System.print(result.contains("> A wise quote")) // expect: true
System.print(result.contains("---")) // expect: true
var linkNested = Markdown.fromHtml("<a href=\"/page\"><strong>Bold Link</strong></a>")
System.print(linkNested.contains("[**Bold Link**](/page)")) // expect: true
var container = Markdown.fromHtml("<div><section><article>Content</article></section></div>")
System.print(container.contains("Content")) // expect: true
System.print(container.contains("<div>")) // expect: false
System.print(container.contains("<section>")) // expect: false
System.print(Markdown.fromHtml("<img src=\"a.png\" alt=\"test\"/>").contains("![test](a.png)")) // expect: true
System.print(Markdown.fromHtml("<br/>").trim() == "") // expect: true
System.print(Markdown.fromHtml("<p></p>").trim() == "") // expect: true
System.print(Markdown.fromHtml("<strong></strong>").trim() == "****") // expect: true
var ws = Markdown.fromHtml("<p> spaced content </p>")
System.print(ws.contains("spaced content")) // expect: true
var multi = Markdown.fromHtml("<p>Para 1</p><p>Para 2</p><p>Para 3</p>")
var lines = multi.split("\n")
var nonEmpty = 0
for (line in lines) {
if (line.trim().count > 0) nonEmpty = nonEmpty + 1
}
System.print(nonEmpty >= 3) // expect: true
+11
View File
@@ -0,0 +1,11 @@
// retoor <retoor@molodetz.nl>
import "markdown" for Markdown
System.print(Markdown.toHtml("---").contains("<hr>")) // expect: true
System.print(Markdown.toHtml("***").contains("<hr>")) // expect: true
System.print(Markdown.toHtml("___").contains("<hr>")) // expect: true
System.print(Markdown.toHtml("-----").contains("<hr>")) // expect: true
System.print(Markdown.toHtml("*****").contains("<hr>")) // expect: true
System.print(Markdown.toHtml("_____").contains("<hr>")) // expect: true
+21
View File
@@ -0,0 +1,21 @@
// retoor <retoor@molodetz.nl>
import "markdown" for Markdown
var multi = Markdown.toHtml("[First](http://a.com) and [Second](http://b.com)")
System.print(multi.contains("<a href=\"http://a.com\">First</a>")) // expect: true
System.print(multi.contains("<a href=\"http://b.com\">Second</a>")) // expect: true
var withPath = Markdown.toHtml("[Docs](/docs/api/index.html)")
System.print(withPath.contains("<a href=\"/docs/api/index.html\">Docs</a>")) // expect: true
var imgAlt = Markdown.toHtml("![A cat](cat.jpg)")
System.print(imgAlt.contains("<img src=\"cat.jpg\" alt=\"A cat\">")) // expect: true
var imgUrl = Markdown.toHtml("![Logo](https://example.com/logo.png)")
System.print(imgUrl.contains("<img src=\"https://example.com/logo.png\" alt=\"Logo\">")) // expect: true
var textAround = Markdown.toHtml("Click [here](url) now")
System.print(textAround.contains("Click ")) // expect: true
System.print(textAround.contains("<a href=\"url\">here</a>")) // expect: true
System.print(textAround.contains(" now")) // expect: true
+22
View File
@@ -0,0 +1,22 @@
// retoor <retoor@molodetz.nl>
import "markdown" for Markdown
var star = Markdown.toHtml("* item a\n* item b")
System.print(star.contains("<ul>")) // expect: true
System.print(star.contains("<li>item a</li>")) // expect: true
System.print(star.contains("<li>item b</li>")) // expect: true
var plus = Markdown.toHtml("+ item x\n+ item y")
System.print(plus.contains("<ul>")) // expect: true
System.print(plus.contains("<li>item x</li>")) // expect: true
System.print(plus.contains("<li>item y</li>")) // expect: true
var multiDigit = Markdown.toHtml("10. tenth\n11. eleventh")
System.print(multiDigit.contains("<ol>")) // expect: true
System.print(multiDigit.contains("<li>tenth</li>")) // expect: true
System.print(multiDigit.contains("<li>eleventh</li>")) // expect: true
var formatted = Markdown.toHtml("- **bold item**\n- *italic item*")
System.print(formatted.contains("<li><strong>bold item</strong></li>")) // expect: true
System.print(formatted.contains("<li><em>italic item</em></li>")) // expect: true
+40
View File
@@ -0,0 +1,40 @@
// retoor <retoor@molodetz.nl>
import "markdown" for Markdown
var doc = "# Title
This is a paragraph with **bold** text.
- Item 1
- Item 2
Another paragraph.
> A quote
---
## Subtitle
1. First
2. Second"
var html = Markdown.toHtml(doc)
System.print(html.contains("<h1>Title</h1>")) // expect: true
System.print(html.contains("<strong>bold</strong>")) // expect: true
System.print(html.contains("<ul>")) // expect: true
System.print(html.contains("<li>Item 1</li>")) // expect: true
System.print(html.contains("<blockquote>")) // expect: true
System.print(html.contains("<hr>")) // expect: true
System.print(html.contains("<h2>Subtitle</h2>")) // expect: true
System.print(html.contains("<ol>")) // expect: true
System.print(html.contains("<li>First</li>")) // expect: true
var linkInList = Markdown.toHtml("- [Link](http://example.com)")
System.print(linkInList.contains("<li>")) // expect: true
System.print(linkInList.contains("<a href=\"http://example.com\">Link</a>")) // expect: true
var codeInHeading = Markdown.toHtml("# Using `print()`")
System.print(codeInHeading.contains("<h1>")) // expect: true
System.print(codeInHeading.contains("<code>print()</code>")) // expect: true
+17
View File
@@ -0,0 +1,17 @@
// retoor <retoor@molodetz.nl>
import "markdown" for Markdown
var p = Markdown.toHtml("This is a paragraph.")
System.print(p) // expect: <p>This is a paragraph.</p>
var multi = Markdown.toHtml("First paragraph.\n\nSecond paragraph.")
System.print(multi.contains("<p>First paragraph.</p>")) // expect: true
System.print(multi.contains("<p>Second paragraph.</p>")) // expect: true
var afterHeading = Markdown.toHtml("# Title\n\nSome text here.")
System.print(afterHeading.contains("<h1>Title</h1>")) // expect: true
System.print(afterHeading.contains("<p>Some text here.</p>")) // expect: true
var empty = Markdown.toHtml("")
System.print(empty) // expect:
+21
View File
@@ -0,0 +1,21 @@
// retoor <retoor@molodetz.nl>
import "markdown" for Markdown
var unsafe = Markdown.toHtml("<script>alert('xss')</script>")
System.print(unsafe.contains("<script>")) // expect: true
var safe = Markdown.toHtml("<script>alert('xss')</script>", {"safeMode": true})
System.print(safe.contains("<script>")) // expect: false
System.print(safe.contains("&lt;script&gt;")) // expect: true
var safeCode = Markdown.toHtml("```\n<div>test</div>\n```", {"safeMode": true})
System.print(safeCode.contains("<div>")) // expect: false
System.print(safeCode.contains("&lt;div&gt;")) // expect: true
var safeInline = Markdown.toHtml("Text with <b>html</b> inside", {"safeMode": true})
System.print(safeInline.contains("<b>")) // expect: false
System.print(safeInline.contains("&lt;b&gt;")) // expect: true
var ampersand = Markdown.toHtml("A & B", {"safeMode": true})
System.print(ampersand.contains("&amp;")) // expect: true
+13
View File
@@ -0,0 +1,13 @@
// retoor <retoor@molodetz.nl>
import "pathlib" for Path
var p1 = Path.new("/home/user")
System.print(p1.isAbsolute) // expect: true
System.print(p1.root) // expect: /
System.print(p1.anchor) // expect: /
var p2 = Path.new("relative/path")
System.print(p2.isAbsolute) // expect: false
System.print(p2.root) // expect:
System.print(p2.anchor) // expect:
+15
View File
@@ -0,0 +1,15 @@
// retoor <retoor@molodetz.nl>
import "pathlib" for Path
var p1 = Path.new("/home/user/file.txt")
System.print(p1.toString) // expect: /home/user/file.txt
var p2 = Path.new("")
System.print(p2.toString) // expect:
var p3 = Path.new(p1)
System.print(p3.toString) // expect: /home/user/file.txt
var p4 = Path.new("/home") / "user" / "file.txt"
System.print(p4.toString) // expect: /home/user/file.txt
+27
View File
@@ -0,0 +1,27 @@
// retoor <retoor@molodetz.nl>
import "pathlib" for Path
var p1 = Path.new("/home/user/file.tar.gz")
System.print(p1.name) // expect: file.tar.gz
System.print(p1.stem) // expect: file.tar
System.print(p1.suffix) // expect: .gz
System.print(p1.suffixes) // expect: [.tar, .gz]
var p2 = Path.new("/home/user/file.txt")
System.print(p2.name) // expect: file.txt
System.print(p2.stem) // expect: file
System.print(p2.suffix) // expect: .txt
System.print(p2.suffixes) // expect: [.txt]
var p3 = Path.new("/home/user/noext")
System.print(p3.name) // expect: noext
System.print(p3.stem) // expect: noext
System.print(p3.suffix) // expect:
System.print(p3.suffixes) // expect: []
var p4 = Path.new("/home/user/.hidden")
System.print(p4.name) // expect: .hidden
System.print(p4.stem) // expect: .hidden
System.print(p4.suffix) // expect:
System.print(p4.suffixes) // expect: []
+21
View File
@@ -0,0 +1,21 @@
// retoor <retoor@molodetz.nl>
import "pathlib" for Path
var p1 = Path.new("/home/user/file.txt")
System.print(p1.parent) // expect: /home/user
System.print(p1.parent.parent) // expect: /home
System.print(p1.parent.parent.parent) // expect: /
var p2 = Path.new("/home/user/file.txt")
var parents = p2.parents
System.print(parents.count) // expect: 3
System.print(parents[0]) // expect: /home/user
System.print(parents[1]) // expect: /home
System.print(parents[2]) // expect: /
var p3 = Path.new("relative/path")
System.print(p3.parent) // expect: relative
var p4 = Path.new("file.txt")
System.print(p4.parent) // expect: .
+18
View File
@@ -0,0 +1,18 @@
// retoor <retoor@molodetz.nl>
import "pathlib" for Path
var p1 = Path.new("/home/user/file.txt")
System.print(p1.parts) // expect: [/, home, user, file.txt]
var p2 = Path.new("relative/path/file.txt")
System.print(p2.parts) // expect: [relative, path, file.txt]
var p3 = Path.new("")
System.print(p3.parts) // expect: []
var p4 = Path.new("/")
System.print(p4.parts) // expect: [/]
var p5 = Path.new("file.txt")
System.print(p5.parts) // expect: [file.txt]
+44
View File
@@ -0,0 +1,44 @@
// retoor <retoor@molodetz.nl>
import "strutil" for Str
System.print(Str.toLower("HELLO World")) // expect: hello world
System.print(Str.toLower("abc123")) // expect: abc123
System.print(Str.toLower("")) // expect:
System.print(Str.toUpper("hello World")) // expect: HELLO WORLD
System.print(Str.toUpper("ABC123")) // expect: ABC123
System.print(Str.toUpper("")) // expect:
System.print(Str.hexEncode("ABC")) // expect: 414243
System.print(Str.hexEncode("\x00\xFF")) // expect: 00ff
System.print(Str.hexEncode("")) // expect:
System.print(Str.hexDecode("414243")) // expect: ABC
System.print(Str.hexDecode("")) // expect:
System.print(Str.repeat("ab", 3)) // expect: ababab
System.print(Str.repeat("x", 5)) // expect: xxxxx
System.print(Str.repeat("", 10)) // expect:
System.print(Str.padLeft("hi", 5, " ")) // expect: hi
System.print(Str.padLeft("hello", 3, " ")) // expect: hello
System.print(Str.padLeft("x", 4, "0")) // expect: 000x
System.print("[" + Str.padRight("hi", 5, " ") + "]") // expect: [hi ]
System.print(Str.padRight("hello", 3, " ")) // expect: hello
System.print(Str.padRight("x", 4, "0")) // expect: x000
System.print(Str.escapeHtml("<div class=\"test\">A & B</div>")) // expect: &lt;div class=&quot;test&quot;&gt;A &amp; B&lt;/div&gt;
System.print(Str.escapeHtml("hello")) // expect: hello
System.print(Str.escapeHtml("it's")) // expect: it&#39;s
System.print(Str.escapeJson("hello")) // expect: "hello"
System.print(Str.escapeJson("a\"b")) // expect: "a\"b"
System.print(Str.escapeJson("line1\nline2")) // expect: "line1\nline2"
System.print(Str.urlEncode("hello world")) // expect: hello+world
System.print(Str.urlEncode("test")) // expect: test
System.print(Str.urlDecode("hello+world")) // expect: hello world
System.print(Str.urlDecode("test")) // expect: test
+27
View File
@@ -0,0 +1,27 @@
// retoor <retoor@molodetz.nl>
import "web" for Client
var parsed1 = Client.parseUrl_("http://example.com/path")
System.print(parsed1["scheme"]) // expect: http
System.print(parsed1["host"]) // expect: example.com
System.print(parsed1["port"]) // expect: 80
System.print(parsed1["path"]) // expect: /path
var parsed2 = Client.parseUrl_("https://example.com/path")
System.print(parsed2["scheme"]) // expect: https
System.print(parsed2["port"]) // expect: 443
var parsed3 = Client.parseUrl_("http://example.com:8080/api/v1")
System.print(parsed3["host"]) // expect: example.com
System.print(parsed3["port"]) // expect: 8080
System.print(parsed3["path"]) // expect: /api/v1
var parsed4 = Client.parseUrl_("https://api.example.com")
System.print(parsed4["host"]) // expect: api.example.com
System.print(parsed4["path"]) // expect: /
var parsed5 = Client.parseUrl_("http://localhost:3000/")
System.print(parsed5["host"]) // expect: localhost
System.print(parsed5["port"]) // expect: 3000
System.print(parsed5["path"]) // expect: /
+36
View File
@@ -0,0 +1,36 @@
// retoor <retoor@molodetz.nl>
import "web" for Request
var headers = {
"Content-Type": "application/json",
"Accept": "text/html",
"Cookie": "session=abc123; user=alice"
}
var req = Request.new_("POST", "/api/users", {"page": "1", "limit": "10"}, headers, "{\"name\":\"Alice\"}", {"id": "42"}, null)
System.print(req.method) // expect: POST
System.print(req.path) // expect: /api/users
System.print(req.query["page"]) // expect: 1
System.print(req.query["limit"]) // expect: 10
System.print(req.params["id"]) // expect: 42
System.print(req.body) // expect: {"name":"Alice"}
System.print(req.header("Content-Type")) // expect: application/json
System.print(req.header("content-type")) // expect: application/json
System.print(req.header("ACCEPT")) // expect: text/html
System.print(req.header("X-Missing") == null) // expect: true
var json = req.json
System.print(json["name"]) // expect: Alice
var cookies = req.cookies
System.print(cookies["session"]) // expect: abc123
System.print(cookies["user"]) // expect: alice
var formBody = "username=bob&password=secret"
var formReq = Request.new_("POST", "/login", {}, {"Content-Type": "application/x-www-form-urlencoded"}, formBody, {}, null)
var form = formReq.form
System.print(form["username"]) // expect: bob
System.print(form["password"]) // expect: secret
+39
View File
@@ -0,0 +1,39 @@
// retoor <retoor@molodetz.nl>
import "web" for Response
var r1 = Response.redirect("/dashboard", 301)
System.print(r1.status) // expect: 301
System.print(r1.headers["Location"]) // expect: /dashboard
var r2 = Response.new()
r2.status = 404
r2.body = "Not Found"
System.print(r2.status) // expect: 404
System.print(r2.body) // expect: Not Found
var r3 = Response.new()
r3.header("X-Custom", "value1")
r3.header("X-Another", "value2")
System.print(r3.headers["X-Custom"]) // expect: value1
System.print(r3.headers["X-Another"]) // expect: value2
var r4 = Response.new()
r4.cookie("session", "abc123")
r4.body = "test"
var built = r4.build()
System.print(built.contains("Set-Cookie: session=abc123")) // expect: true
var r5 = Response.new()
r5.cookie("auth", "token", {"path": "/", "httpOnly": true, "maxAge": 3600})
r5.body = "test"
var built2 = r5.build()
System.print(built2.contains("Path=/")) // expect: true
System.print(built2.contains("HttpOnly")) // expect: true
System.print(built2.contains("Max-Age=3600")) // expect: true
var r6 = Response.text("Hello World")
var httpResponse = r6.build()
System.print(httpResponse.contains("HTTP/1.1 200 OK")) // expect: true
System.print(httpResponse.contains("Content-Length:")) // expect: true
System.print(httpResponse.contains("Hello World")) // expect: true
+42
View File
@@ -0,0 +1,42 @@
// retoor <retoor@molodetz.nl>
import "web" for Router
var router = Router.new()
router.get("/api/v1/*", Fn.new { |r| "wildcard" })
router.put("/users/:id", Fn.new { |r| "put user" })
router.delete("/users/:id", Fn.new { |r| "delete user" })
router.patch("/users/:id", Fn.new { |r| "patch user" })
router.post("/users", Fn.new { |r| "create user" })
var m1 = router.match("GET", "/api/v1/anything")
System.print(m1 != null) // expect: true
var m2 = router.match("GET", "/api/v1/nested/path")
System.print(m2 != null) // expect: true
var m3 = router.match("PUT", "/users/456")
System.print(m3 != null) // expect: true
System.print(m3["params"]["id"]) // expect: 456
var m4 = router.match("DELETE", "/users/789")
System.print(m4 != null) // expect: true
System.print(m4["params"]["id"]) // expect: 789
var m5 = router.match("PATCH", "/users/101")
System.print(m5 != null) // expect: true
var m6 = router.match("POST", "/users")
System.print(m6 != null) // expect: true
var m7 = router.match("OPTIONS", "/users")
System.print(m7 == null) // expect: true
var router2 = Router.new()
router2.get("/posts/:postId/comments/:commentId", Fn.new { |r| "comment" })
var m8 = router2.match("GET", "/posts/10/comments/20")
System.print(m8 != null) // expect: true
System.print(m8["params"]["postId"]) // expect: 10
System.print(m8["params"]["commentId"]) // expect: 20
+34
View File
@@ -0,0 +1,34 @@
// retoor <retoor@molodetz.nl>
import "web" for Session, SessionStore
var store = SessionStore.new()
var session = store.create()
session["name"] = "Alice"
session["age"] = 30
session["active"] = true
System.print(session["name"]) // expect: Alice
System.print(session["age"]) // expect: 30
System.print(session["active"]) // expect: true
System.print(session["nonexistent"] == null) // expect: true
System.print(session.isModified) // expect: true
session.remove("age")
System.print(session["age"] == null) // expect: true
store.save(session)
var data = session.data
System.print(data.containsKey("name")) // expect: true
System.print(data.containsKey("age")) // expect: false
System.print(data["active"]) // expect: true
var session2 = store.create()
var session3 = store.create()
System.print(session.id != session2.id) // expect: true
System.print(session2.id != session3.id) // expect: true
System.print(session.id.count) // expect: 36
System.print(session2.id.count) // expect: 36
+58
View File
@@ -0,0 +1,58 @@
// retoor <retoor@molodetz.nl>
import "web" for View, Response, Request
class TestView is View {
construct new() {}
get(request) {
return Response.json({"method": "GET"})
}
post(request) {
return Response.json({"method": "POST"})
}
put(request) {
return Response.json({"method": "PUT"})
}
delete(request) {
return Response.json({"method": "DELETE"})
}
}
class GetOnlyView is View {
construct new() {}
get(request) {
return Response.text("GET only")
}
}
var mockGet = Request.new_("GET", "/test", {}, {}, "", {}, null)
var mockPost = Request.new_("POST", "/test", {}, {}, "", {}, null)
var mockPut = Request.new_("PUT", "/test", {}, {}, "", {}, null)
var mockDelete = Request.new_("DELETE", "/test", {}, {}, "", {}, null)
var mockPatch = Request.new_("PATCH", "/test", {}, {}, "", {}, null)
var view = TestView.new()
var r1 = view.dispatch(mockGet)
System.print(r1.body.contains("GET")) // expect: true
var r2 = view.dispatch(mockPost)
System.print(r2.body.contains("POST")) // expect: true
var r3 = view.dispatch(mockPut)
System.print(r3.body.contains("PUT")) // expect: true
var r4 = view.dispatch(mockDelete)
System.print(r4.body.contains("DELETE")) // expect: true
var getOnlyView = GetOnlyView.new()
var r5 = getOnlyView.dispatch(mockGet)
System.print(r5.body) // expect: GET only
var r6 = getOnlyView.dispatch(mockPost)
System.print(r6.status) // expect: 405