From 7756306e1d247b24a58711fb6838e01f2c06dbd3 Mon Sep 17 00:00:00 2001
From: Chris Wanstrath
Date: Sat, 1 Nov 2025 22:40:25 -0700
Subject: [PATCH] insanity
---
src/compiler/tests/function-blocks.test.ts | 81 ---------------
src/compiler/tests/ribbit.test.ts | 113 +++++++++++++++++++++
2 files changed, 113 insertions(+), 81 deletions(-)
create mode 100644 src/compiler/tests/ribbit.test.ts
diff --git a/src/compiler/tests/function-blocks.test.ts b/src/compiler/tests/function-blocks.test.ts
index 056affe..41bf65d 100644
--- a/src/compiler/tests/function-blocks.test.ts
+++ b/src/compiler/tests/function-blocks.test.ts
@@ -53,84 +53,3 @@ signals.trap 'EXIT':
end`).toEvaluateTo(['EXIT', true])
})
})
-
-describe('ribbit', () => {
- test('head tag', () => {
- expect(`
- head:
- title What up
- meta charSet=UTF-8
- meta name=viewport content='width=device-width, initial-scale=1, viewport-fit=cover'
- end`).toEvaluateTo(`head`, {
- head: () => 'head'
- })
- })
-
- test('li', () => {
- expect(`
- list:
- li border-bottom='1px solid black' one
- li two
- li three
- end`).toEvaluateTo(`list`, {
- list: () => 'list'
- })
- })
-
- test('inline expressions', () => {
- const buffer: string[] = []
-
- const tagBlock = async (tagName: string, props = {}, fn: Function) => {
- const attrs = Object.entries(props).map(([key, value]) => `${key}="${value}"`)
- const space = attrs.length ? ' ' : ''
-
- buffer.push(`<${tagName}${space}${attrs.join(' ')}>`)
- await fn()
- buffer.push(`${tagName}>`)
- }
-
- const tagCall = (tagName: string, atNamed: {}, ...args: any[]) => {
- const attrs = Object.entries(atNamed).map(([key, value]) => `${key}="${value}"`)
- const space = attrs.length ? ' ' : ''
- const children = args
- .reverse()
- .map(a => a === null ? buffer.pop() : a)
- .reverse().join(' ')
- .replaceAll(' !!ribbit-nospace!! ', '')
-
- buffer.push(`<${tagName}${space}${attrs.join(' ')}>${children}${tagName}>`)
- }
-
- const tag = async (tagName: string, atNamed: {}, ...args: any[]) => {
- if (typeof args[0] === 'function')
- await tagBlock(tagName, atNamed, args[0])
- else
- tagCall(tagName, atNamed, ...args)
- }
-
- expect(`
- ribbit:
- p class=container:
- h1 class=bright style='font-family: helvetica' Heya
- h2 man that is (b wild) (nospace) !
- p Double the fun.
- end
- end`).toEvaluateTo(
- `
-
Heya
-man that is wild!
-Double the fun.
-
`, {
- ribbit: async (cb: Function) => {
- await cb()
- return buffer.join("\n")
- },
- p: (atNamed: {}, ...args: any[]) => tag('p', atNamed, ...args),
- h1: (atNamed: {}, ...args: any[]) => tag('h1', atNamed, ...args),
- h2: (atNamed: {}, ...args: any[]) => tag('h2', atNamed, ...args),
- b: (atNamed: {}, ...args: any[]) => tag('b', atNamed, ...args),
- nospace: () => '!!ribbit-nospace!!',
- join: (...args: string[]) => args.join(''),
- })
- })
-})
\ No newline at end of file
diff --git a/src/compiler/tests/ribbit.test.ts b/src/compiler/tests/ribbit.test.ts
new file mode 100644
index 0000000..0fe397a
--- /dev/null
+++ b/src/compiler/tests/ribbit.test.ts
@@ -0,0 +1,113 @@
+import { expect, describe, test, beforeEach } from 'bun:test'
+import { type Value } from 'reefvm'
+
+const buffer: string[] = []
+
+const ribbitGlobals = {
+ ribbit: async (cb: Function) => {
+ await cb()
+ return buffer.join("\n")
+ },
+ tag: (tagName: string, atDefaults = {}) => {
+ return (atNamed = {}, ...args: any[]) => tag(tagName, Object.assign({}, atDefaults, atNamed), ...args)
+ },
+ head: (atNamed: {}, ...args: any[]) => tag('head', atNamed, ...args),
+ title: (atNamed: {}, ...args: any[]) => tag('title', atNamed, ...args),
+ meta: (atNamed: {}, ...args: any[]) => tag('meta', atNamed, ...args),
+ p: (atNamed: {}, ...args: any[]) => tag('p', atNamed, ...args),
+ h1: (atNamed: {}, ...args: any[]) => tag('h1', atNamed, ...args),
+ h2: (atNamed: {}, ...args: any[]) => tag('h2', atNamed, ...args),
+ b: (atNamed: {}, ...args: any[]) => tag('b', atNamed, ...args),
+ ul: (atNamed: {}, ...args: any[]) => tag('ul', atNamed, ...args),
+ li: (atNamed: {}, ...args: any[]) => tag('li', atNamed, ...args),
+ nospace: () => NOSPACE_TOKEN,
+ echo: (...args: any[]) => console.log(...args)
+}
+
+function raw(fn: Function) { (fn as any).raw = true }
+
+const tagBlock = async (tagName: string, props = {}, fn: Function) => {
+ const attrs = Object.entries(props).map(([key, value]) => `${key}="${value}"`)
+ const space = attrs.length ? ' ' : ''
+
+ buffer.push(`<${tagName}${space}${attrs.join(' ')}>`)
+ await fn()
+ buffer.push(`${tagName}>`)
+}
+
+const tagCall = (tagName: string, atNamed = {}, ...args: any[]) => {
+ const attrs = Object.entries(atNamed).map(([key, value]) => `${key}="${value}"`)
+ const space = attrs.length ? ' ' : ''
+ const children = args
+ .reverse()
+ .map(a => a === null ? buffer.pop() : a)
+ .reverse().join(' ')
+ .replaceAll(` ${NOSPACE_TOKEN} `, '')
+
+ if (SELF_CLOSING.includes(tagName))
+ buffer.push(`<${tagName}${space}${attrs.join(' ')} />`)
+ else
+ buffer.push(`<${tagName}${space}${attrs.join(' ')}>${children}${tagName}>`)
+}
+
+const tag = async (tagName: string, atNamed = {}, ...args: any[]) => {
+ if (typeof args[0] === 'function')
+ await tagBlock(tagName, atNamed, args[0])
+ else
+ tagCall(tagName, atNamed, ...args)
+}
+
+const NOSPACE_TOKEN = '!!ribbit-nospace!!'
+const SELF_CLOSING = ["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"]
+
+describe('ribbit', () => {
+ beforeEach(() => buffer.length = 0)
+
+ test('head tag', () => {
+ expect(`
+ribbit:
+ head:
+ title What up
+ meta charset=UTF-8
+ meta name=viewport content='width=device-width, initial-scale=1, viewport-fit=cover'
+ end
+end
+ `).toEvaluateTo(`
+What up
+
+
+`, ribbitGlobals)
+ })
+
+ test('custom tags', () => {
+ expect(`
+list = tag 'ul' class=list
+ribbit:
+ list:
+ li border-bottom='1px solid black' one
+ li two
+ li three
+ end
+end`).toEvaluateTo(``, ribbitGlobals)
+ })
+
+ test('inline expressions', () => {
+ expect(`
+ ribbit:
+ p class=container:
+ h1 class=bright style='font-family: helvetica' Heya
+ h2 man that is (b wild) (nospace) !
+ p Double the fun.
+ end
+ end`).toEvaluateTo(
+ `
+
Heya
+man that is wild!
+Double the fun.
+`, ribbitGlobals)
+ })
+})
\ No newline at end of file