136 lines
3.6 KiB
TypeScript
136 lines
3.6 KiB
TypeScript
import { expect, describe, test } from 'bun:test'
|
|
|
|
describe('single line function blocks', () => {
|
|
test('work with no args', () => {
|
|
expect(`trap = do x: x end; trap: true end`).toEvaluateTo(true)
|
|
})
|
|
|
|
test('work with one arg', () => {
|
|
expect(`trap = do x y: [ x (y) ] end; trap EXIT: true end`).toEvaluateTo(['EXIT', true])
|
|
})
|
|
|
|
test('work with named args', () => {
|
|
expect(`attach = do signal fn: [ signal (fn) ] end; attach signal='exit': true end`).toEvaluateTo(['exit', true])
|
|
})
|
|
|
|
|
|
test('work with dot-get', () => {
|
|
expect(`signals = [trap=do x y: [x (y)] end]; signals.trap 'EXIT': true end`).toEvaluateTo(['EXIT', true])
|
|
})
|
|
})
|
|
|
|
describe('multi line function blocks', () => {
|
|
test('work with no args', () => {
|
|
expect(`
|
|
trap = do x: x end
|
|
trap:
|
|
true
|
|
end`).toEvaluateTo(true)
|
|
})
|
|
|
|
test('work with one arg', () => {
|
|
expect(`
|
|
trap = do x y: [ x (y) ] end
|
|
trap EXIT:
|
|
true
|
|
end`).toEvaluateTo(['EXIT', true])
|
|
})
|
|
|
|
test('work with named args', () => {
|
|
expect(`
|
|
attach = do signal fn: [ signal (fn) ] end
|
|
attach signal='exit':
|
|
true
|
|
end`).toEvaluateTo(['exit', true])
|
|
})
|
|
|
|
|
|
test('work with dot-get', () => {
|
|
expect(`
|
|
signals = [trap=do x y: [x (y)] end]
|
|
signals.trap 'EXIT':
|
|
true
|
|
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(
|
|
`<p class="container">
|
|
<h1 class="bright" style="font-family: helvetica">Heya</h1>
|
|
<h2>man that is <b>wild</b>!</h2>
|
|
<p>Double the fun.</p>
|
|
</p>`, {
|
|
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(''),
|
|
})
|
|
})
|
|
}) |