boxwood 0.75.0 → 0.76.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.
package/README.md
CHANGED
|
@@ -113,17 +113,17 @@ const test = require("node:test")
|
|
|
113
113
|
const assert = require("node:assert")
|
|
114
114
|
const { compile } = require("boxwood")
|
|
115
115
|
|
|
116
|
-
test("banner renders a title", () => {
|
|
116
|
+
test("banner renders a title", async () => {
|
|
117
117
|
const { template } = await compile(__dirname)
|
|
118
|
-
const html = template({ title:
|
|
119
|
-
assert(html.includes(
|
|
118
|
+
const html = template({ title: "foo" })
|
|
119
|
+
assert(html.includes("<h1>foo</h1>"))
|
|
120
120
|
})
|
|
121
121
|
|
|
122
|
-
test(
|
|
122
|
+
test("banner renders an optional description", async () => {
|
|
123
123
|
const { template } = await compile(__dirname)
|
|
124
|
-
const html = template({ title:
|
|
125
|
-
assert(html.includes(
|
|
126
|
-
assert(html.includes(
|
|
124
|
+
const html = template({ title: "foo", description: "bar" })
|
|
125
|
+
assert(html.includes("<h1>foo</h1>"))
|
|
126
|
+
assert(html.includes("<p>bar</p>"))
|
|
127
127
|
})
|
|
128
128
|
```
|
|
129
129
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const {
|
|
2
|
-
fragment,
|
|
3
2
|
doctype,
|
|
4
3
|
html,
|
|
5
4
|
head,
|
|
@@ -14,7 +13,7 @@ const {
|
|
|
14
13
|
} = require("../../..")
|
|
15
14
|
|
|
16
15
|
module.exports = function ({ friends }) {
|
|
17
|
-
return
|
|
16
|
+
return [
|
|
18
17
|
doctype(),
|
|
19
18
|
html({ lang: "en" }, [
|
|
20
19
|
head([meta({ charset: "UTF-8" }), title("Friends")]),
|
|
@@ -52,5 +51,5 @@ module.exports = function ({ friends }) {
|
|
|
52
51
|
),
|
|
53
52
|
]),
|
|
54
53
|
]),
|
|
55
|
-
]
|
|
54
|
+
]
|
|
56
55
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { div, span } = require("../../..")
|
|
2
2
|
|
|
3
3
|
function description(account) {
|
|
4
4
|
if (account.status === "closed") {
|
|
@@ -17,5 +17,5 @@ function description(account) {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
module.exports = function ({ accounts }) {
|
|
20
|
-
return
|
|
20
|
+
return accounts.map((account) => div(description(account)))
|
|
21
21
|
}
|
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { div, ul, li, p } = require("../../..")
|
|
2
2
|
|
|
3
3
|
module.exports = function ({ count, results }) {
|
|
4
4
|
return div({ class: "search" }, [
|
|
5
5
|
div({ class: "loader" }, "Loading..."),
|
|
6
6
|
div({ class: "results" }, [
|
|
7
7
|
p(`${count} results`),
|
|
8
|
-
...results.map((result) =>
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
])
|
|
15
|
-
),
|
|
8
|
+
...results.map((result) => [
|
|
9
|
+
div({ class: "title" }, result.title),
|
|
10
|
+
div({ class: "description" }, result.description),
|
|
11
|
+
result.featured && div({ class: "highlight" }, "Featured!"),
|
|
12
|
+
result.sizes.length && ul(result.sizes.map((size) => li(size))),
|
|
13
|
+
]),
|
|
16
14
|
]),
|
|
17
15
|
])
|
|
18
16
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
const { h1, h2, ul, li
|
|
1
|
+
const { h1, h2, ul, li } = require("../../..")
|
|
2
2
|
|
|
3
3
|
module.exports = function ({ title, subtitle, todos }) {
|
|
4
|
-
return
|
|
4
|
+
return [
|
|
5
5
|
h1(title),
|
|
6
6
|
h2(subtitle),
|
|
7
7
|
ul(todos.map((todo) => li(todo.description))),
|
|
8
|
-
]
|
|
8
|
+
]
|
|
9
9
|
}
|
package/index.js
CHANGED
|
@@ -2,7 +2,6 @@ const { join } = require("path")
|
|
|
2
2
|
const { readFileSync } = require("fs")
|
|
3
3
|
const csstree = require("css-tree")
|
|
4
4
|
const toHash = require("string-hash")
|
|
5
|
-
const YAML = require("yaml")
|
|
6
5
|
|
|
7
6
|
async function compile(path) {
|
|
8
7
|
const fn = require(path)
|
|
@@ -175,7 +174,7 @@ const isUnescapedTag = (name) => {
|
|
|
175
174
|
}
|
|
176
175
|
|
|
177
176
|
const render = (input, escape = true) => {
|
|
178
|
-
if (input.ignore) {
|
|
177
|
+
if (!input || input.ignore) {
|
|
179
178
|
return ""
|
|
180
179
|
}
|
|
181
180
|
if (Array.isArray(input)) {
|
|
@@ -188,10 +187,10 @@ const render = (input, escape = true) => {
|
|
|
188
187
|
return input.toString()
|
|
189
188
|
}
|
|
190
189
|
if (typeof input === "string") {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
return
|
|
190
|
+
if (escape) {
|
|
191
|
+
return escapeHTML(input)
|
|
192
|
+
}
|
|
193
|
+
return input
|
|
195
194
|
}
|
|
196
195
|
if (input.name === "raw") {
|
|
197
196
|
return render(input.children, false)
|
|
@@ -202,32 +201,14 @@ const render = (input, escape = true) => {
|
|
|
202
201
|
}
|
|
203
202
|
return `<${input.name}>`
|
|
204
203
|
}
|
|
205
|
-
if (input.attributes && input.children) {
|
|
206
|
-
return (
|
|
207
|
-
`<${input.name} ` +
|
|
208
|
-
attributes(input.attributes) +
|
|
209
|
-
">" +
|
|
210
|
-
render(input.children, isUnescapedTag(input.name)) +
|
|
211
|
-
`</${input.name}>`
|
|
212
|
-
)
|
|
213
|
-
}
|
|
214
|
-
if (input.attributes) {
|
|
215
|
-
return (
|
|
216
|
-
`<${input.name} ` + attributes(input.attributes) + `></${input.name}>`
|
|
217
|
-
)
|
|
218
|
-
}
|
|
219
|
-
if (input.children) {
|
|
220
|
-
return (
|
|
221
|
-
`<${input.name}>` +
|
|
222
|
-
render(input.children, isUnescapedTag(input.name)) +
|
|
223
|
-
`</${input.name}>`
|
|
224
|
-
)
|
|
225
|
-
}
|
|
226
|
-
return `<${input.name}></${input.name}>`
|
|
227
|
-
}
|
|
228
204
|
|
|
229
|
-
|
|
230
|
-
|
|
205
|
+
return (
|
|
206
|
+
`<${input.name}` +
|
|
207
|
+
(input.attributes ? " " + attributes(input.attributes) : "") +
|
|
208
|
+
">" +
|
|
209
|
+
render(input.children, isUnescapedTag(input.name)) +
|
|
210
|
+
`</${input.name}>`
|
|
211
|
+
)
|
|
231
212
|
}
|
|
232
213
|
|
|
233
214
|
const raw = (children) => {
|
|
@@ -504,15 +485,6 @@ function classes() {
|
|
|
504
485
|
return array.join(" ")
|
|
505
486
|
}
|
|
506
487
|
|
|
507
|
-
const yaml = {
|
|
508
|
-
load() {
|
|
509
|
-
const path = join(...arguments)
|
|
510
|
-
const file = path.endsWith(".yaml") ? path : join(path, "index.yaml")
|
|
511
|
-
const content = readFileSync(file, "utf8")
|
|
512
|
-
return YAML.parse(content)
|
|
513
|
-
},
|
|
514
|
-
}
|
|
515
|
-
|
|
516
488
|
const json = {
|
|
517
489
|
load() {
|
|
518
490
|
const path = join(...arguments)
|
|
@@ -530,23 +502,20 @@ function i18n(translations) {
|
|
|
530
502
|
|
|
531
503
|
i18n.load = function () {
|
|
532
504
|
const path = join(...arguments)
|
|
533
|
-
const data =
|
|
505
|
+
const data = json.load(path)
|
|
534
506
|
return function translate(language, key) {
|
|
535
|
-
if (!key) {
|
|
536
|
-
throw new Error(`TranslationError[${key}][${language}]: key is undefined`)
|
|
537
|
-
}
|
|
538
507
|
if (!language) {
|
|
539
|
-
throw new Error(
|
|
540
|
-
|
|
541
|
-
|
|
508
|
+
throw new Error(`TranslationError: language is undefined`)
|
|
509
|
+
}
|
|
510
|
+
if (!key) {
|
|
511
|
+
throw new Error(`TranslationError: key is undefined`)
|
|
542
512
|
}
|
|
543
|
-
|
|
544
|
-
if (!translation) {
|
|
513
|
+
if (!data[key] || !data[key][language]) {
|
|
545
514
|
throw new Error(
|
|
546
|
-
`TranslationError[${key}][${language}]
|
|
515
|
+
`TranslationError: translation [${key}][${language}] is undefined`
|
|
547
516
|
)
|
|
548
517
|
}
|
|
549
|
-
return
|
|
518
|
+
return data[key][language]
|
|
550
519
|
}
|
|
551
520
|
}
|
|
552
521
|
|
|
@@ -556,24 +525,24 @@ function component(fn, { styles, i18n, scripts } = {}) {
|
|
|
556
525
|
return fn({}, a)
|
|
557
526
|
}
|
|
558
527
|
if (i18n) {
|
|
528
|
+
if (!a || !a.language) {
|
|
529
|
+
throw new Error(
|
|
530
|
+
`TranslationError: language is undefined for component:\n${fn.toString()}`
|
|
531
|
+
)
|
|
532
|
+
}
|
|
559
533
|
const { language } = a
|
|
560
534
|
function translate(key) {
|
|
561
535
|
if (!key) {
|
|
562
536
|
throw new Error(
|
|
563
|
-
`TranslationError
|
|
537
|
+
`TranslationError: key is undefined for component:\n${fn.toString()}`
|
|
564
538
|
)
|
|
565
539
|
}
|
|
566
|
-
if (!language) {
|
|
540
|
+
if (!i18n[key] || !i18n[key][language]) {
|
|
567
541
|
throw new Error(
|
|
568
|
-
`TranslationError[${key}][${language}]
|
|
542
|
+
`TranslationError: translation [${key}][${language}] is undefined for component:\n${fn.toString()}`
|
|
569
543
|
)
|
|
570
544
|
}
|
|
571
545
|
const translation = i18n[key][language]
|
|
572
|
-
if (!translation) {
|
|
573
|
-
throw new Error(
|
|
574
|
-
`TranslationError[${key}][${language}]: translation is undefined for component:\n${fn.toString()}`
|
|
575
|
-
)
|
|
576
|
-
}
|
|
577
546
|
return translation
|
|
578
547
|
}
|
|
579
548
|
return fn({ ...a, translate }, b || [])
|
|
@@ -582,25 +551,19 @@ function component(fn, { styles, i18n, scripts } = {}) {
|
|
|
582
551
|
}
|
|
583
552
|
return function (a, b) {
|
|
584
553
|
const tree = execute(a, b)
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
return tree.concat(styles.css, scripts.js)
|
|
588
|
-
}
|
|
589
|
-
return [tree, styles.css, scripts.js]
|
|
590
|
-
}
|
|
554
|
+
let nodes = Array.isArray(tree) ? tree : [tree]
|
|
555
|
+
|
|
591
556
|
if (styles) {
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
}
|
|
595
|
-
return [tree, styles.css]
|
|
557
|
+
const data = Array.isArray(styles) ? styles : [styles]
|
|
558
|
+
nodes = nodes.concat(data.map((style) => style.css))
|
|
596
559
|
}
|
|
560
|
+
|
|
597
561
|
if (scripts) {
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
}
|
|
601
|
-
return [tree, scripts.js]
|
|
562
|
+
const data = Array.isArray(scripts) ? scripts : [scripts]
|
|
563
|
+
nodes = nodes.concat(data.map((script) => script.js))
|
|
602
564
|
}
|
|
603
|
-
|
|
565
|
+
|
|
566
|
+
return nodes
|
|
604
567
|
}
|
|
605
568
|
}
|
|
606
569
|
|
|
@@ -610,11 +573,9 @@ module.exports = {
|
|
|
610
573
|
classes,
|
|
611
574
|
doctype,
|
|
612
575
|
escape: escapeHTML,
|
|
613
|
-
fragment,
|
|
614
576
|
raw,
|
|
615
577
|
css,
|
|
616
578
|
js,
|
|
617
|
-
yaml,
|
|
618
579
|
json,
|
|
619
580
|
tag,
|
|
620
581
|
i18n,
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "boxwood",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.76.0",
|
|
4
4
|
"description": "Compile HTML templates into JS",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "node --test",
|
|
7
|
+
"test": "node --test --test-reporter=dot",
|
|
8
|
+
"test:debug": "node --test --test-reporter=spec",
|
|
8
9
|
"coverage": "c8 npm test",
|
|
9
10
|
"benchmark": "node --test benchmark/index.js",
|
|
10
11
|
"watch": "npm test -- --watch",
|
|
@@ -62,7 +63,6 @@
|
|
|
62
63
|
},
|
|
63
64
|
"dependencies": {
|
|
64
65
|
"css-tree": "^2.3.1",
|
|
65
|
-
"string-hash": "^1.1.3"
|
|
66
|
-
"yaml": "^2.4.2"
|
|
66
|
+
"string-hash": "^1.1.3"
|
|
67
67
|
}
|
|
68
68
|
}
|