boxwood 0.74.0 → 0.75.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +111 -0
  3. package/benchmark/fixtures/basic/boxwood.js +3 -0
  4. package/benchmark/fixtures/basic/data.json +1 -0
  5. package/benchmark/fixtures/basic/handlebars.hbs +1 -0
  6. package/benchmark/fixtures/basic/lodash.ejs +1 -0
  7. package/benchmark/fixtures/basic/mustache.mst +1 -0
  8. package/benchmark/fixtures/basic/underscore.ejs +1 -0
  9. package/benchmark/fixtures/basic/vanilla.js +3 -0
  10. package/benchmark/fixtures/div/boxwood.js +5 -0
  11. package/benchmark/fixtures/div/data.json +1 -0
  12. package/benchmark/fixtures/div/handlebars.hbs +1 -0
  13. package/benchmark/fixtures/div/lodash.ejs +1 -0
  14. package/benchmark/fixtures/div/mustache.mst +1 -0
  15. package/benchmark/fixtures/div/underscore.ejs +1 -0
  16. package/benchmark/fixtures/div/vanilla.js +4 -0
  17. package/benchmark/fixtures/escape/boxwood.js +3 -0
  18. package/benchmark/fixtures/escape/data.json +3 -0
  19. package/benchmark/fixtures/escape/handlebars.hbs +1 -0
  20. package/benchmark/fixtures/escape/lodash.ejs +1 -0
  21. package/benchmark/fixtures/escape/mustache.mst +1 -0
  22. package/benchmark/fixtures/escape/underscore.ejs +1 -0
  23. package/benchmark/fixtures/escape/vanilla.js +5 -0
  24. package/benchmark/fixtures/friends/boxwood.js +56 -0
  25. package/benchmark/fixtures/friends/data.json +30 -0
  26. package/benchmark/fixtures/friends/handlebars.hbs +45 -0
  27. package/benchmark/fixtures/friends/lodash.ejs +48 -0
  28. package/benchmark/fixtures/friends/mustache.mst +45 -0
  29. package/benchmark/fixtures/friends/underscore.ejs +48 -0
  30. package/benchmark/fixtures/friends/vanilla.js +36 -0
  31. package/benchmark/fixtures/if/boxwood.js +21 -0
  32. package/benchmark/fixtures/if/data.json +12 -0
  33. package/benchmark/fixtures/if/handlebars.hbs +13 -0
  34. package/benchmark/fixtures/if/lodash.ejs +12 -0
  35. package/benchmark/fixtures/if/mustache.mst +13 -0
  36. package/benchmark/fixtures/if/underscore.ejs +12 -0
  37. package/benchmark/fixtures/if/vanilla.js +14 -0
  38. package/benchmark/fixtures/projects/boxwood.js +20 -0
  39. package/benchmark/fixtures/projects/data.json +26 -0
  40. package/benchmark/fixtures/projects/handlebars.hbs +15 -0
  41. package/benchmark/fixtures/projects/lodash.ejs +17 -0
  42. package/benchmark/fixtures/projects/mustache.mst +16 -0
  43. package/benchmark/fixtures/projects/underscore.ejs +17 -0
  44. package/benchmark/fixtures/projects/vanilla.js +21 -0
  45. package/benchmark/fixtures/search/boxwood.js +18 -0
  46. package/benchmark/fixtures/search/data.json +35 -0
  47. package/benchmark/fixtures/search/handlebars.hbs +18 -0
  48. package/benchmark/fixtures/search/lodash.ejs +22 -0
  49. package/benchmark/fixtures/search/mustache.mst +18 -0
  50. package/benchmark/fixtures/search/underscore.ejs +22 -0
  51. package/benchmark/fixtures/search/vanilla.js +26 -0
  52. package/benchmark/fixtures/todos/boxwood.js +9 -0
  53. package/benchmark/fixtures/todos/data.json +9 -0
  54. package/benchmark/fixtures/todos/handlebars.hbs +7 -0
  55. package/benchmark/fixtures/todos/lodash.ejs +7 -0
  56. package/benchmark/fixtures/todos/mustache.mst +7 -0
  57. package/benchmark/fixtures/todos/underscore.ejs +7 -0
  58. package/benchmark/fixtures/todos/vanilla.js +12 -0
  59. package/benchmark/index.js +112 -0
  60. package/index.js +19 -8
  61. package/package.json +9 -11
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2018 - 2022 buxlabs
3
+ Copyright (c) 2018 - 2024 buxlabs
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -5,9 +5,28 @@
5
5
 
6
6
  > Server side templating engine written in JavaScript
7
7
 
8
+ [boxwood](https://github.com/buxlabs/boxwood) was created to achieve the following design goals:
9
+
10
+ 1. templates can be split into components
11
+ 2. css is hashed per component
12
+ 3. css is automatically minified
13
+ 4. critical css is inlined
14
+ 5. templates can import other dependencies
15
+ 6. inline images or svgs
16
+ 7. i18n support
17
+ 8. server side
18
+ 9. good for seo
19
+ 10. small (1 file, 700 LOC~)
20
+ 11. easy to start, familiar syntax
21
+ 12. easy to test
22
+
23
+ The template starts with a standard js file, which builds a tree of nodes, that get rendered to html.
24
+
8
25
  ## Table of Contents
9
26
 
10
27
  - [Install](#install)
28
+ - [Usage](#usage)
29
+ - [Syntax](#syntax)
11
30
  - [Maintainers](#maintainers)
12
31
  - [Contributing](#contributing)
13
32
  - [License](#license)
@@ -16,6 +35,98 @@
16
35
 
17
36
  `npm install boxwood`
18
37
 
38
+ ## Usage
39
+
40
+ ```js
41
+ const { compile } = require("boxwood")
42
+ const { join } = require("path")
43
+ // ...
44
+ const path = join(__dirname, "index.js")
45
+ const { template } = await compile(path)
46
+ // ...
47
+ const html = template({ foo: "bar" })
48
+ console.log(html)
49
+ ```
50
+
51
+ ## Syntax
52
+
53
+ ```js
54
+ // example/index.js
55
+ const layout = require("./layout")
56
+ const banner = require("./banner")
57
+
58
+ module.exports = () => {
59
+ return layout([
60
+ banner({
61
+ title: "Hello, world!",
62
+ description: "Lorem ipsum dolor sit amet",
63
+ }),
64
+ ])
65
+ }
66
+ ```
67
+
68
+ ```js
69
+ // example/layout/index.js
70
+
71
+ const { component, css, html, head, body } = require("boxwood")
72
+ const head = require("./head")
73
+
74
+ const styles = css.load(__dirname)
75
+
76
+ module.exports = component(
77
+ (children) => {
78
+ return html([head(), body({ className: styles.layout }, children)])
79
+ },
80
+ { styles }
81
+ )
82
+ ```
83
+
84
+ ```js
85
+ // example/head/index.js
86
+ const { head, title } = require("boxwood")
87
+
88
+ module.exports = () => {
89
+ return head([title("example")])
90
+ }
91
+ ```
92
+
93
+ ```js
94
+ // example/banner/index.js
95
+ const { component, css, h1, p, section } = require("boxwood")
96
+
97
+ const styles = css.load(__dirname)
98
+
99
+ module.exports = component(
100
+ ({ title, description }) => {
101
+ return section({ className: styles.banner }, [
102
+ h1(title),
103
+ description && p(description),
104
+ ])
105
+ },
106
+ { styles }
107
+ )
108
+ ```
109
+
110
+ ```js
111
+ // example/banner/index.test.js
112
+ const test = require("node:test")
113
+ const assert = require("node:assert")
114
+ const { compile } = require("boxwood")
115
+
116
+ test("banner renders a title", () => {
117
+ const { template } = await compile(__dirname)
118
+ const html = template({ title: 'foo' })
119
+ assert(html.includes('<h1>foo</h1>'))
120
+ })
121
+
122
+ test('banner renders an optional description', () => {
123
+ const { template } = await compile(__dirname)
124
+ const html = template({ title: 'foo', description: 'bar' })
125
+ assert(html.includes('<h1>foo</h1>'))
126
+ assert(html.includes('<p>bar</p>'))
127
+ })
128
+ ```
129
+
19
130
  ## Maintainers
20
131
 
21
132
  [@emilos](https://github.com/emilos)
@@ -0,0 +1,3 @@
1
+ module.exports = function () {
2
+ return 'foo'
3
+ }
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1 @@
1
+ foo
@@ -0,0 +1 @@
1
+ foo
@@ -0,0 +1 @@
1
+ foo
@@ -0,0 +1 @@
1
+ foo
@@ -0,0 +1,3 @@
1
+ module.exports = function () {
2
+ return 'foo'
3
+ }
@@ -0,0 +1,5 @@
1
+ const { div } = require("../../..")
2
+
3
+ module.exports = function () {
4
+ return div("foo")
5
+ }
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1 @@
1
+ <div>foo</div>
@@ -0,0 +1 @@
1
+ <div>foo</div>
@@ -0,0 +1 @@
1
+ <div>foo</div>
@@ -0,0 +1 @@
1
+ <div>foo</div>
@@ -0,0 +1,4 @@
1
+
2
+ module.exports = function () {
3
+ return '<div>foo</div>'
4
+ }
@@ -0,0 +1,3 @@
1
+ module.exports = function ({ foo }) {
2
+ return foo
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "foo": "<img>"
3
+ }
@@ -0,0 +1 @@
1
+ {{foo}}
@@ -0,0 +1 @@
1
+ <%- foo %>
@@ -0,0 +1 @@
1
+ {{foo}}
@@ -0,0 +1 @@
1
+ <%- foo %>
@@ -0,0 +1,5 @@
1
+ const { escape } = require("../../..")
2
+
3
+ module.exports = function ({ foo }) {
4
+ return escape(foo)
5
+ }
@@ -0,0 +1,56 @@
1
+ const {
2
+ fragment,
3
+ doctype,
4
+ html,
5
+ head,
6
+ body,
7
+ meta,
8
+ img,
9
+ title,
10
+ div,
11
+ ul,
12
+ li,
13
+ a,
14
+ } = require("../../..")
15
+
16
+ module.exports = function ({ friends }) {
17
+ return fragment([
18
+ doctype(),
19
+ html({ lang: "en" }, [
20
+ head([meta({ charset: "UTF-8" }), title("Friends")]),
21
+ body([
22
+ div(
23
+ { class: "friends" },
24
+ friends.map((friend) => {
25
+ return div({ class: "friend" }, [
26
+ ul([
27
+ li(`Name: ${friend.name}`),
28
+ li(`Balance: ${friend.balance}`),
29
+ li(`Age: ${friend.age}`),
30
+ li(`Address: ${friend.address}`),
31
+ li(["Image: ", img({ src: friend.picture })]),
32
+ li(`Company: ${friend.company}`),
33
+ li([
34
+ "Email: ",
35
+ a({ href: `mailto:${friend.email}` }, friend.email),
36
+ ]),
37
+ li(`About: ${friend.about}`),
38
+ friend.tags.length &&
39
+ li(["Tags: ", ul(friend.tags.map((tag) => li(tag)))]),
40
+ friend.friends.length &&
41
+ li([
42
+ "Friends: ",
43
+ ul(
44
+ friend.friends.map((friend) =>
45
+ li(`${friend.name} (${friend.id})`)
46
+ )
47
+ ),
48
+ ]),
49
+ ]),
50
+ ])
51
+ })
52
+ ),
53
+ ]),
54
+ ]),
55
+ ])
56
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "friends": [
3
+ {
4
+ "name": "Jan Kowalski",
5
+ "id": 1,
6
+ "balance": "100 PLN",
7
+ "age": 50,
8
+ "address": "Warszawa",
9
+ "picture": "jankowalski.png",
10
+ "email": "jan@kowalski.pl",
11
+ "about": "I like fishing",
12
+ "company": "PKO",
13
+ "tags": ["fisherman"],
14
+ "friends": [
15
+ {
16
+ "name": "Piotr Nowak",
17
+ "id": 2,
18
+ "balance": "80 PLN",
19
+ "age": 40,
20
+ "address": "Kraków",
21
+ "picture": "piotrnowak.png",
22
+ "email": "piotr@nowak.pl",
23
+ "about": "I like cooking",
24
+ "company": "ING",
25
+ "tags": ["chef"]
26
+ }
27
+ ]
28
+ }
29
+ ]
30
+ }
@@ -0,0 +1,45 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Friends</title>
6
+ </head>
7
+ <body>
8
+ <div class="friends">
9
+ {{#each friends}}
10
+ <div class="friend">
11
+ <ul>
12
+ <li>Name: {{this.name}}</li>
13
+ <li>Balance: {{this.balance}}</li>
14
+ <li>Age: {{this.age}}</li>
15
+ <li>Address: {{this.address}}</li>
16
+ <li>Image: <img src="{{this.picture}}"></li>
17
+ <li>Company: {{this.company}}</li>
18
+ <li>Email: <a href="mailto:{{this.email}}">{{this.email}}</a></li>
19
+ <li>About: {{this.about}}</li>
20
+ {{#if tags.length}}
21
+ <li>
22
+ Tags:
23
+ <ul>
24
+ {{#each tags}}
25
+ <li>{{this}}</li>
26
+ {{/each}}
27
+ </ul>
28
+ </li>
29
+ {{/if}}
30
+ {{#if friends.length}}
31
+ <li>
32
+ Friends:
33
+ <ul>
34
+ {{#each friends}}
35
+ <li>{{this.name}} ({{this.id}})</li>
36
+ {{/each}}
37
+ </ul>
38
+ </li>
39
+ {{/if}}
40
+ </ul>
41
+ </div>
42
+ {{/each}}
43
+ </div>
44
+ </body>
45
+ </html>
@@ -0,0 +1,48 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Friends</title>
6
+ </head>
7
+ <body>
8
+ <div class="friends">
9
+ <% for (var i = 0, ilen = friends.length; i < ilen; i += 1) { %>
10
+ <% var friend = friends[i]; %>
11
+ <div class="friend">
12
+ <ul>
13
+ <li>Name: <%- friend.name %></li>
14
+ <li>Balance: <%- friend.balance %></li>
15
+ <li>Age: <%- friend.age %></li>
16
+ <li>Address: <%- friend.address %></li>
17
+ <li>Image: <img src="<%- friend.picture %>"></li>
18
+ <li>Company: <%- friend.company %></li>
19
+ <li>Email: <a href="mailto:<%- friend.email %>"><%- friend.email %></a></li>
20
+ <li>About: <%- friend.about %></li>
21
+ <% if (friend.tags.length) { %>
22
+ <li>
23
+ Tags:
24
+ <ul>
25
+ <% for (var j = 0, jlen = friend.tags.length; j < jlen; j += 1) { %>
26
+ <% var tag = friend.tags[i]; %>
27
+ <li><%- tag %></li>
28
+ <% } %>
29
+ </ul>
30
+ </li>
31
+ <% } %>
32
+ <% if (friend.friends.length) { %>
33
+ <li>
34
+ Friends:
35
+ <ul>
36
+ <% for (var k = 0, klen = friend.friends.length; k < klen; k += 1) { %>
37
+ <% var fr = friend.friends[i] %>
38
+ <li><%- fr.name %> (<%- fr.id %>)</li>
39
+ <% } %>
40
+ </ul>
41
+ </li>
42
+ <% } %>
43
+ </ul>
44
+ </div>
45
+ <% } %>
46
+ </div>
47
+ </body>
48
+ </html>
@@ -0,0 +1,45 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Friends</title>
6
+ </head>
7
+ <body>
8
+ <div class="friends">
9
+ {{#friends}}
10
+ <div class="friend">
11
+ <ul>
12
+ <li>Name: {{name}}</li>
13
+ <li>Balance: {{balance}}</li>
14
+ <li>Age: {{age}}</li>
15
+ <li>Address: {{address}}</li>
16
+ <li>Image: <img src="{{picture}}"></li>
17
+ <li>Company: {{company}}</li>
18
+ <li>Email: <a href="mailto:{{email}}">{{email}}</a></li>
19
+ <li>About: {{about}}</li>
20
+ {{#tags.length}}
21
+ <li>
22
+ Tags:
23
+ <ul>
24
+ {{#tags}}
25
+ <li>{{.}}</li>
26
+ {{/tags}}
27
+ </ul>
28
+ </li>
29
+ {{/tags.length}}
30
+ {{#friends.length}}
31
+ <li>
32
+ Friends:
33
+ <ul>
34
+ {{#friends}}
35
+ <li>{{name}} ({{id}})</li>
36
+ {{/friends}}
37
+ </ul>
38
+ </li>
39
+ {{/friends.length}}
40
+ </ul>
41
+ </div>
42
+ {{/friends}}
43
+ </div>
44
+ </body>
45
+ </html>
@@ -0,0 +1,48 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Friends</title>
6
+ </head>
7
+ <body>
8
+ <div class="friends">
9
+ <% for (var i = 0, ilen = friends.length; i < ilen; i += 1) { %>
10
+ <% var friend = friends[i]; %>
11
+ <div class="friend">
12
+ <ul>
13
+ <li>Name: <%- friend.name %></li>
14
+ <li>Balance: <%- friend.balance %></li>
15
+ <li>Age: <%- friend.age %></li>
16
+ <li>Address: <%- friend.address %></li>
17
+ <li>Image: <img src="<%- friend.picture %>"></li>
18
+ <li>Company: <%- friend.company %></li>
19
+ <li>Email: <a href="mailto:<%- friend.email %>"><%- friend.email %></a></li>
20
+ <li>About: <%- friend.about %></li>
21
+ <% if (friend.tags.length) { %>
22
+ <li>
23
+ Tags:
24
+ <ul>
25
+ <% for (var j = 0, jlen = friend.tags.length; j < jlen; j += 1) { %>
26
+ <% var tag = friend.tags[i]; %>
27
+ <li><%- tag %></li>
28
+ <% } %>
29
+ </ul>
30
+ </li>
31
+ <% } %>
32
+ <% if (friend.friends.length) { %>
33
+ <li>
34
+ Friends:
35
+ <ul>
36
+ <% for (var k = 0, klen = friend.friends.length; k < klen; k += 1) { %>
37
+ <% var fr = friend.friends[i] %>
38
+ <li><%- fr.name %> (<%- fr.id %>)</li>
39
+ <% } %>
40
+ </ul>
41
+ </li>
42
+ <% } %>
43
+ </ul>
44
+ </div>
45
+ <% } %>
46
+ </div>
47
+ </body>
48
+ </html>
@@ -0,0 +1,36 @@
1
+ module.exports = function ({ friends }) {
2
+ let template = '<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Friends</title></head><body><div class="friends">'
3
+ for (let i = 0, ilen = friends.length; i < ilen; i++) {
4
+ const friend = friends[i]
5
+ template += '<div class="friend">'
6
+ template += '<ul>'
7
+ template += '<li>Name: ' + friend.name + '</li>'
8
+ template += '<li>Balance: ' + friend.balance + '</li>'
9
+ template += '<li>Age: ' + friend.age + '</li>'
10
+ template += '<li>Address: ' + friend.address + '</li>'
11
+ template += '<li>Image: <img src="' + friend.picture + '"></li>'
12
+ template += '<li>Company: ' + friend.company + '</li>'
13
+ template += '<li>Email: <a href="mailto:' + friend.email + '">' + friend.email + '</a></li>'
14
+ template += '<li>About: ' + friend.about + '</li>'
15
+ if (friend.tags.length) {
16
+ template += '<li>Tags: <ul>'
17
+ for (let j = 0, jlen = friend.tags.length; j < jlen; j++) {
18
+ const tag = friend.tags[j]
19
+ template += '<li>' + tag + '</li>'
20
+ }
21
+ template += '</ul></li>'
22
+ }
23
+ if (friend.friends.length) {
24
+ template += '<li>Friends: <ul>'
25
+ for (let j = 0, jlen = friend.friends.length; j < jlen; j++) {
26
+ const person = friend.friends[j]
27
+ template += '<li>' + person.name + ' (' + person.id + ')</li>'
28
+ }
29
+ template += '</ul></li>'
30
+ }
31
+ template += '</ul>'
32
+ template += '</div>'
33
+ }
34
+ template += '</div></body></html>'
35
+ return template
36
+ }
@@ -0,0 +1,21 @@
1
+ const { fragment, div, span } = require("../../..")
2
+
3
+ function description(account) {
4
+ if (account.status === "closed") {
5
+ return "Your account has been closed!"
6
+ }
7
+ if (account.status === "suspended") {
8
+ return "Your account has been temporarily suspended"
9
+ }
10
+ return (
11
+ "Bank balance: " +
12
+ span(
13
+ { class: account.balance >= 0 ? "positive" : "negative" },
14
+ account.balance
15
+ )
16
+ )
17
+ }
18
+
19
+ module.exports = function ({ accounts }) {
20
+ return fragment(accounts.map((account) => div(description(account))))
21
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "accounts": [
3
+ {
4
+ "closed": true,
5
+ "suspended": false,
6
+ "active": false,
7
+ "status": "closed",
8
+ "balance": 100,
9
+ "balanceClass": "positive"
10
+ }
11
+ ]
12
+ }
@@ -0,0 +1,13 @@
1
+ {{#each accounts}}
2
+ <div>
3
+ {{#if this.closed}}
4
+ Your account has been closed!
5
+ {{/if}}
6
+ {{#if this.suspended}}
7
+ Your account has been temporarily suspended
8
+ {{/if}}
9
+ {{#if this.active}}
10
+ Bank balance: <span class="{{ account.balanceClass }}">{{this.balance}}</span>
11
+ {{/if}}
12
+ </div>
13
+ {{/each}}
@@ -0,0 +1,12 @@
1
+ <% for (var i = 0, ilen = accounts.length; i < ilen; i += 1) { %>
2
+ <% var account = accounts[i]; %>
3
+ <div>
4
+ <% if (account.status === "closed") { %>
5
+ Your account has been closed!
6
+ <% } else if (account.status === "suspended") { %>
7
+ Your account has been temporarily suspended
8
+ <% } else { %>
9
+ Bank balance: <span class="<%- account.balance >= 0 ? 'positive' : 'negative' %>"><%- account.balance %></span>
10
+ <% } %>
11
+ </div>
12
+ <% } %>
@@ -0,0 +1,13 @@
1
+ {{#accounts}}
2
+ <div>
3
+ {{#closed}}
4
+ Your account has been closed!
5
+ {{/closed}}
6
+ {{#suspended}}
7
+ Your account has been temporarily suspended
8
+ {{/suspended}}
9
+ {{#active}}
10
+ Bank balance: <span class="{{balanceClass}}">{{balance}}</span>
11
+ {{/active}}
12
+ </div>
13
+ {{/accounts}}
@@ -0,0 +1,12 @@
1
+ <% for (var i = 0, ilen = accounts.length; i < ilen; i += 1) { %>
2
+ <% var account = accounts[i]; %>
3
+ <div>
4
+ <% if (account.status === "closed") { %>
5
+ Your account has been closed!
6
+ <% } else if (account.status === "suspended") { %>
7
+ Your account has been temporarily suspended
8
+ <% } else { %>
9
+ Bank balance: <span class="<%- account.balance >= 0 ? 'positive' : 'negative' %>"><%- account.balance %></span>
10
+ <% } %>
11
+ </div>
12
+ <% } %>
@@ -0,0 +1,14 @@
1
+ function description (account) {
2
+ if (account.status === 'closed') { return 'Your account has been closed!' }
3
+ if (account.status === 'suspended') { return 'Your account has been temporarily suspended' }
4
+ return 'Bank balance: ' + '<span class="' + account.balance >= 0 ? 'positive' : 'negative' + '">' + account.balance + '</span>'
5
+ }
6
+
7
+ module.exports = function ({ accounts }) {
8
+ let template = ''
9
+ for (let i = 0, ilen = accounts.length; i < ilen; i++) {
10
+ const account = accounts[i]
11
+ template += '<div>' + description(account) + '</div>'
12
+ }
13
+ return template
14
+ }
@@ -0,0 +1,20 @@
1
+ const { doctype, tag, html, head, body, p, a } = require("../../..")
2
+
3
+ module.exports = ({ title, projects, text }) => {
4
+ return [
5
+ doctype(),
6
+ html([
7
+ head([tag("title", title)]),
8
+ body([
9
+ p(text),
10
+ ...projects.map((project) => {
11
+ return [
12
+ a({ href: project.url }, project.name),
13
+ p(project.description),
14
+ ]
15
+ }),
16
+ projects.length === 0 && "No projects",
17
+ ]),
18
+ ]),
19
+ ]
20
+ }