coralite 0.6.1 → 0.6.3
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 +20 -19
- package/bin/coralite.js +4 -1
- package/change-logs.md +80 -0
- package/lib/coralite.js +3 -2
- package/lib/html-module.js +35 -8
- package/lib/parse.js +111 -37
- package/package.json +4 -2
- package/scripts/change-log.sh +6 -0
- package/types/index.js +5 -0
package/README.md
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
coralite is a static site generator library built around the emerging [HTML modules proposal](https://github.com/WICG/webcomponents/blob/gh-pages/proposals/html-modules-explainer.md).
|
|
4
4
|
|
|
5
5
|
- Getting started
|
|
6
|
-
[Basic templating](./docs/basic-templating.md)
|
|
6
|
+
- [Basic templating](./docs/basic-templating.md)
|
|
7
7
|
- Reference
|
|
8
|
-
[Coralite CLI](./docs/coralite-cli.md)
|
|
9
|
-
[Coralite](./docs/coralite.md)
|
|
8
|
+
- [Coralite CLI](./docs/coralite-cli.md)
|
|
9
|
+
- [Coralite](./docs/coralite.md)
|
|
10
10
|
|
|
11
11
|
## Installation
|
|
12
12
|
|
|
@@ -30,20 +30,6 @@ yarn add -D coralite
|
|
|
30
30
|
pnpm add -D coralite
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
## Requirements
|
|
34
|
-
|
|
35
|
-
Coralite uses **ECMAScript Modules** which requires to run Node.js with the **`--experimental-vm-modules`** option enabled.
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
node --experimental-vm-modules node_modules/coralite/bin/coralite.js [options]
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
or using NODE_OPTIONS
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
NODE_OPTIONS=--experimental-vm-modules coralite [options]
|
|
45
|
-
```
|
|
46
|
-
|
|
47
33
|
## Basic Syntax
|
|
48
34
|
|
|
49
35
|
Coralite is executed using the following command:
|
|
@@ -65,7 +51,7 @@ To generate a website using Coralite, you must provide three essential options:
|
|
|
65
51
|
Here's an example of how these options might look:
|
|
66
52
|
|
|
67
53
|
```bash
|
|
68
|
-
coralite --templates ./
|
|
54
|
+
coralite --templates ./path/to/templates --pages ./path/to/pages --output ./dist
|
|
69
55
|
```
|
|
70
56
|
|
|
71
57
|
## Optional Options
|
|
@@ -75,5 +61,20 @@ coralite --templates ./src/templates --pages ./src/pages --output ./dist
|
|
|
75
61
|
Run the CLI in dry-run mode to preview the actions that would be performed without actually generating the website. This is useful for debugging or when you want to check potential issues before committing changes:
|
|
76
62
|
|
|
77
63
|
```bash
|
|
78
|
-
coralite --templates ./
|
|
64
|
+
coralite --templates ./path/to/templates --pages ./path/to/pages --output ./dist --dry-run
|
|
79
65
|
```
|
|
66
|
+
|
|
67
|
+
## Troubleshooting
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
Coralite uses **ECMAScript Modules** which requires to run Node.js with the **`--experimental-vm-modules`** option enabled.
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
node --experimental-vm-modules node_modules/coralite/bin/coralite.js [options]
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
or using NODE_OPTIONS
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
NODE_OPTIONS=--experimental-vm-modules coralite [options]
|
|
80
|
+
```
|
package/bin/coralite.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node --experimental-vm-modules
|
|
2
2
|
|
|
3
3
|
import { getSubDirectory, getPkg, coralite } from '#lib'
|
|
4
4
|
import { Command } from 'commander'
|
|
@@ -6,6 +6,9 @@ import { join } from 'node:path'
|
|
|
6
6
|
import { existsSync, mkdirSync, writeFileSync } from 'node:fs'
|
|
7
7
|
import kleur from 'kleur'
|
|
8
8
|
|
|
9
|
+
// Remove all Node warnings before doing anything else
|
|
10
|
+
process.removeAllListeners('warning')
|
|
11
|
+
|
|
9
12
|
const pkg = await getPkg()
|
|
10
13
|
const program = new Command()
|
|
11
14
|
|
package/change-logs.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# 🎁 Release notes (`v0.6.3`)
|
|
2
|
+
|
|
3
|
+
## Changes
|
|
4
|
+
- 6fe640d (HEAD -> main, tag: v0.6.3, origin/main) test: cover ignore by attribute - (*[Thomas David](https://github.com/tjdav)*)
|
|
5
|
+
- a47ff8f types: add IgnoreByAttribute type - (*[Thomas David](https://github.com/tjdav)*)
|
|
6
|
+
- 8547c37 feat: ignore element by attributes inside meta and component parsers - (*[Thomas David](https://github.com/tjdav)*)
|
|
7
|
+
- f61ae88 docs: update ignore-attribute example with quotes - (*[Thomas David](https://github.com/tjdav)*)
|
|
8
|
+
- d4a277d docs: create consistent path names in example - (*[Thomas David](https://github.com/tjdav)*)
|
|
9
|
+
- 566463f docs: remove requirements section - (*[Thomas David](https://github.com/tjdav)*)
|
|
10
|
+
- 2493ab3 style: import type new line - (*[Thomas David](https://github.com/tjdav)*)
|
|
11
|
+
- 2e44174 ci: test before publish - (*[Thomas David](https://github.com/tjdav)*)
|
|
12
|
+
- c1d5ce7 fix: add template id to script module error - (*[Thomas David](https://github.com/tjdav)*)
|
|
13
|
+
- 4fabac1 ci: include self to test script - (*[Thomas David](https://github.com/tjdav)*)
|
|
14
|
+
- efd34d0 fix: add --experimental-vm-modules to shebang - (*[Thomas David](https://github.com/tjdav)*)
|
|
15
|
+
- 7da5d98 refactor: add type check before splicing children. - (*[Thomas David](https://github.com/tjdav)*)
|
|
16
|
+
- 2e39027 fix: catch bad options for aggregate function - (*[Thomas David](https://github.com/tjdav)*)
|
|
17
|
+
|
|
18
|
+
## Metadata
|
|
19
|
+
```
|
|
20
|
+
This version -------- v0.6.3
|
|
21
|
+
Previous version ---- v0.6.2
|
|
22
|
+
Total commits ------- 13
|
|
23
|
+
```
|
|
24
|
+
# 🎁 Release notes (`v0.6.2`)
|
|
25
|
+
|
|
26
|
+
## Changes
|
|
27
|
+
- be6c54c (HEAD -> main, tag: v0.6.2, origin/main) fix: update lock - (*[Thomas David](https://github.com/tjdav)*)
|
|
28
|
+
- 15d9b4e chore: version bump - (*[Thomas David](https://github.com/tjdav)*)
|
|
29
|
+
- fac695e fix: node v18 requires globalThis reference for crypto - (*[Thomas David](https://github.com/tjdav)*)
|
|
30
|
+
- d7c551e doc: format doc links - (*[Thomas David](https://github.com/tjdav)*)
|
|
31
|
+
|
|
32
|
+
## Metadata
|
|
33
|
+
```
|
|
34
|
+
This version -------- v0.6.2
|
|
35
|
+
Previous version ---- v0.6.1
|
|
36
|
+
Total commits ------- 4
|
|
37
|
+
```
|
|
38
|
+
# 🎁 Release notes (`v0.6.1`)
|
|
39
|
+
|
|
40
|
+
## Changes
|
|
41
|
+
- bcc1637 (HEAD -> main, tag: v0.6.1, origin/main) chore: version bump - (*[Thomas David](https://github.com/tjdav)*)
|
|
42
|
+
- 95cfdba docs: add doc links - (*[Thomas David](https://github.com/tjdav)*)
|
|
43
|
+
- 101a305 fix: render computedSlot nodes - (*[Thomas David](https://github.com/tjdav)*)
|
|
44
|
+
- 11a35d8 feat: dynamically import modules - (*[Thomas David](https://github.com/tjdav)*)
|
|
45
|
+
- e1364b9 docs: add CoraliteResult type - (*[Thomas David](https://github.com/tjdav)*)
|
|
46
|
+
- 11c6405 docs: add @example to coralite - (*[Thomas David](https://github.com/tjdav)*)
|
|
47
|
+
- a050263 docs: basic technical documentation - (*[Thomas David](https://github.com/tjdav)*)
|
|
48
|
+
- 83fdddd docs: update dry run option - (*[Thomas David](https://github.com/tjdav)*)
|
|
49
|
+
|
|
50
|
+
## Metadata
|
|
51
|
+
```
|
|
52
|
+
This version -------- v0.6.1
|
|
53
|
+
Previous version ---- v0.6.0
|
|
54
|
+
Total commits ------- 8
|
|
55
|
+
```
|
|
56
|
+
# 🎁 Release notes (`v0.6.0`)
|
|
57
|
+
|
|
58
|
+
## Changes
|
|
59
|
+
- 22d75e2 (HEAD -> main, tag: v0.6.0, origin/main) chore: version bump - (*[Thomas David](https://github.com/tjdav)*)
|
|
60
|
+
- c5cc7cc lint: ignore playwright-report - (*[Thomas David](https://github.com/tjdav)*)
|
|
61
|
+
- fdb3697 docs: add dry run option - (*[Thomas David](https://github.com/tjdav)*)
|
|
62
|
+
- 891db2e feat: export coralite utils - (*[Thomas David](https://github.com/tjdav)*)
|
|
63
|
+
- 9265681 test: cover ignore attribute - (*[Thomas David](https://github.com/tjdav)*)
|
|
64
|
+
- 5d44661 fix: allow missing component to compile - (*[Thomas David](https://github.com/tjdav)*)
|
|
65
|
+
- f3d6e65 docs: add remove prop to CoraliteElement - (*[Thomas David](https://github.com/tjdav)*)
|
|
66
|
+
- 229fef5 feat: new option to ignore element by attribute name value pair - (*[Thomas David](https://github.com/tjdav)*)
|
|
67
|
+
- c78dde1 chore: include kleur dep - (*[Thomas David](https://github.com/tjdav)*)
|
|
68
|
+
- b10bbe8 feat: update cli to use coralite module - (*[Thomas David](https://github.com/tjdav)*)
|
|
69
|
+
- 48fe816 docs: make defineComponent param tokens and slots optional - (*[Thomas David](https://github.com/tjdav)*)
|
|
70
|
+
- 02a5e8f feat: move coralite to a module - (*[Thomas David](https://github.com/tjdav)*)
|
|
71
|
+
- d336090 feat: get package.json util function - (*[Thomas David](https://github.com/tjdav)*)
|
|
72
|
+
- e210844 feat: add document used in error message - (*[Thomas David](https://github.com/tjdav)*)
|
|
73
|
+
- 1556a3b chore: version bump - (*[Thomas David](https://github.com/tjdav)*)
|
|
74
|
+
|
|
75
|
+
## Metadata
|
|
76
|
+
```
|
|
77
|
+
This version -------- v0.6.0
|
|
78
|
+
Previous version ---- v0.5.1
|
|
79
|
+
Total commits ------- 15
|
|
80
|
+
```
|
package/lib/coralite.js
CHANGED
|
@@ -8,7 +8,8 @@ import render from 'dom-serializer'
|
|
|
8
8
|
* CoraliteAggregateTemplate,
|
|
9
9
|
* CoraliteAnyNode,
|
|
10
10
|
* CoraliteModule,
|
|
11
|
-
* CoraliteResult
|
|
11
|
+
* CoraliteResult
|
|
12
|
+
* } from '#types'
|
|
12
13
|
*/
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -98,7 +99,7 @@ export async function coralite ({
|
|
|
98
99
|
// create templates
|
|
99
100
|
for (let i = 0; i < htmlTemplates.length; i++) {
|
|
100
101
|
const html = htmlTemplates[i]
|
|
101
|
-
const coraliteModule = parseModule(html.content)
|
|
102
|
+
const coraliteModule = parseModule(html.content, ignoreByAttribute)
|
|
102
103
|
|
|
103
104
|
coraliteModules[coraliteModule.id] = coraliteModule
|
|
104
105
|
}
|
package/lib/html-module.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { join } from 'node:path'
|
|
2
2
|
import getHTML from './get-html.js'
|
|
3
3
|
import { createComponent, parseHTMLMeta } from './parse.js'
|
|
4
|
+
import { existsSync } from 'node:fs'
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
|
-
* @import { CoraliteTokenOptions, CoraliteModule, CoraliteDocument, CoraliteModuleValues } from '#types'
|
|
7
|
+
* @import { CoraliteTokenOptions, CoraliteModule, CoraliteDocument, CoraliteModuleValues, CoraliteAggregateTemplate } from '#types'
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -11,8 +12,7 @@ import { createComponent, parseHTMLMeta } from './parse.js'
|
|
|
11
12
|
*
|
|
12
13
|
* @param {Object} options - Configuration object for the aggregation process
|
|
13
14
|
* @param {string} options.path - The path to aggregate, relative to pages directory
|
|
14
|
-
* @param {
|
|
15
|
-
* @param {string} options.template.item - Unique identifier for the component used for each document
|
|
15
|
+
* @param {CoraliteAggregateTemplate | string} options.template - Templates used to display the result
|
|
16
16
|
* @param {boolean} [options.recursive] - Whether to recursively search subdirectories
|
|
17
17
|
* @param {CoraliteTokenOptions} [options.tokens] - Token configuration options
|
|
18
18
|
* @param {CoraliteModuleValues} values - Default token values
|
|
@@ -25,15 +25,39 @@ import { createComponent, parseHTMLMeta } from './parse.js'
|
|
|
25
25
|
* aggregate({
|
|
26
26
|
* path: 'button',
|
|
27
27
|
* recursive: true,
|
|
28
|
-
* template:
|
|
28
|
+
* template: 'my-component'
|
|
29
29
|
* }, {
|
|
30
30
|
* className: 'btn'
|
|
31
31
|
* }, components, document);
|
|
32
32
|
* ```
|
|
33
33
|
*/
|
|
34
34
|
export async function aggregate (options, values, components, document) {
|
|
35
|
+
if (!document.path.pages) {
|
|
36
|
+
throw new Error('Document page path was undefined')
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const path = join(document.path.pages, options.path)
|
|
40
|
+
|
|
41
|
+
if (!existsSync(path)) {
|
|
42
|
+
/** @TODO Refer to documentation */
|
|
43
|
+
throw new Error('Aggregate path does not exist: "' + path + '"')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let componentId
|
|
47
|
+
|
|
48
|
+
if (typeof options.template === 'string') {
|
|
49
|
+
componentId = options.template
|
|
50
|
+
} else if (typeof options.template === 'object') {
|
|
51
|
+
componentId = options.template.item
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (!componentId) {
|
|
55
|
+
/** @TODO Refer to documentation */
|
|
56
|
+
throw new Error('Aggregate template was undefined')
|
|
57
|
+
}
|
|
58
|
+
|
|
35
59
|
const pages = await getHTML({
|
|
36
|
-
path
|
|
60
|
+
path,
|
|
37
61
|
recursive: options.recursive,
|
|
38
62
|
exclude: [document.name]
|
|
39
63
|
})
|
|
@@ -42,7 +66,7 @@ export async function aggregate (options, values, components, document) {
|
|
|
42
66
|
|
|
43
67
|
for (let i = 0; i < pages.length; i++) {
|
|
44
68
|
const page = pages[i]
|
|
45
|
-
const meta = parseHTMLMeta(page.content)
|
|
69
|
+
const meta = parseHTMLMeta(page.content, document.ignoreByAttribute)
|
|
46
70
|
const pageValues = Object.assign({}, values)
|
|
47
71
|
|
|
48
72
|
for (const key in meta) {
|
|
@@ -63,13 +87,16 @@ export async function aggregate (options, values, components, document) {
|
|
|
63
87
|
}
|
|
64
88
|
|
|
65
89
|
const component = await createComponent({
|
|
66
|
-
id:
|
|
90
|
+
id: componentId,
|
|
67
91
|
values: pageValues,
|
|
68
92
|
components,
|
|
69
93
|
document
|
|
70
94
|
})
|
|
71
95
|
|
|
72
|
-
|
|
96
|
+
if (typeof component === 'object') {
|
|
97
|
+
// concat rendered components
|
|
98
|
+
result = result.concat(component.children)
|
|
99
|
+
}
|
|
73
100
|
}
|
|
74
101
|
|
|
75
102
|
return result
|
package/lib/parse.js
CHANGED
|
@@ -3,6 +3,7 @@ import { aggregate } from './html-module.js'
|
|
|
3
3
|
import vm from 'node:vm'
|
|
4
4
|
import { invalidCustomTags, validTags } from './tags.js'
|
|
5
5
|
|
|
6
|
+
|
|
6
7
|
/**
|
|
7
8
|
* @import {Module} from 'node:vm'
|
|
8
9
|
* @import {
|
|
@@ -18,7 +19,8 @@ import { invalidCustomTags, validTags } from './tags.js'
|
|
|
18
19
|
* CoraliteDocumentRoot,
|
|
19
20
|
* CoraliteContentNode,
|
|
20
21
|
* CoraliteModuleValues,
|
|
21
|
-
* CoraliteAggregateTemplate
|
|
22
|
+
* CoraliteAggregateTemplate,
|
|
23
|
+
* IgnoreByAttribute
|
|
22
24
|
* } from '#types'
|
|
23
25
|
*/
|
|
24
26
|
|
|
@@ -31,7 +33,7 @@ const customElementTagTokenRegExp = /^[^-].*[-._a-z0-9\u00B7\u00C0-\u00D6\u00D8-
|
|
|
31
33
|
*
|
|
32
34
|
* @param {HTMLData} html - The HTML data containing the content to parse
|
|
33
35
|
* @param {CoralitePath} path - The path object containing the file path information
|
|
34
|
-
* @param {
|
|
36
|
+
* @param {IgnoreByAttribute} [ignoreByAttribute] - Ignore element with attribute name value pair
|
|
35
37
|
* @returns {CoraliteDocument} An object representing the parsed document structure
|
|
36
38
|
*
|
|
37
39
|
* @example
|
|
@@ -75,17 +77,13 @@ export function parseHTMLDocument (html, path, ignoreByAttribute) {
|
|
|
75
77
|
},
|
|
76
78
|
onopentag (originalName, attributes) {
|
|
77
79
|
const parent = stack[stack.length - 1]
|
|
78
|
-
const element = createElement(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
element.remove = true
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
80
|
+
const element = createElement({
|
|
81
|
+
name: originalName,
|
|
82
|
+
attributes,
|
|
83
|
+
customElements,
|
|
84
|
+
parent,
|
|
85
|
+
ignoreByAttribute
|
|
86
|
+
})
|
|
89
87
|
|
|
90
88
|
// push element to stack as it may have children
|
|
91
89
|
stack.push(element)
|
|
@@ -98,10 +96,8 @@ export function parseHTMLDocument (html, path, ignoreByAttribute) {
|
|
|
98
96
|
onclosetag () {
|
|
99
97
|
const element = stack[stack.length - 1]
|
|
100
98
|
|
|
101
|
-
|
|
102
|
-
if (element.remove) {
|
|
99
|
+
if (element.type === 'tag' && element.remove) {
|
|
103
100
|
// remove element from tree
|
|
104
|
-
// @ts-ignore
|
|
105
101
|
element.parent.children.pop()
|
|
106
102
|
}
|
|
107
103
|
|
|
@@ -148,7 +144,8 @@ export function parseHTMLDocument (html, path, ignoreByAttribute) {
|
|
|
148
144
|
parentPath: html.parentPath,
|
|
149
145
|
root,
|
|
150
146
|
customElements,
|
|
151
|
-
path
|
|
147
|
+
path,
|
|
148
|
+
ignoreByAttribute
|
|
152
149
|
}
|
|
153
150
|
}
|
|
154
151
|
|
|
@@ -156,6 +153,7 @@ export function parseHTMLDocument (html, path, ignoreByAttribute) {
|
|
|
156
153
|
* Parses HTML string containing meta tags and extracts associated metadata.
|
|
157
154
|
*
|
|
158
155
|
* @param {string} string - HTML content containing meta tags
|
|
156
|
+
* @param {IgnoreByAttribute} ignoreByAttribute - IgnoreByAttribute option (optional) - If provided and true then the HTML tags will be ignored by this attribute name(s)
|
|
159
157
|
* @returns {Object.<string, CoraliteToken[]>}
|
|
160
158
|
*
|
|
161
159
|
* @example
|
|
@@ -170,7 +168,7 @@ export function parseHTMLDocument (html, path, ignoreByAttribute) {
|
|
|
170
168
|
* //}
|
|
171
169
|
* ```
|
|
172
170
|
*/
|
|
173
|
-
export function parseHTMLMeta (string) {
|
|
171
|
+
export function parseHTMLMeta (string, ignoreByAttribute) {
|
|
174
172
|
// stack to keep track of current element hierarchy
|
|
175
173
|
const stack = []
|
|
176
174
|
/** @type {Object.<string, CoraliteToken[]>} */
|
|
@@ -181,6 +179,15 @@ export function parseHTMLMeta (string) {
|
|
|
181
179
|
onopentag (name, attributes) {
|
|
182
180
|
if (name === 'meta') {
|
|
183
181
|
if (attributes.content) {
|
|
182
|
+
if (ignoreByAttribute) {
|
|
183
|
+
// ignore meta tags by attribute name
|
|
184
|
+
const ignore = findAttributesToIgnore(ignoreByAttribute, attributes)
|
|
185
|
+
|
|
186
|
+
if (ignore) {
|
|
187
|
+
return
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
184
191
|
if (attributes.property) {
|
|
185
192
|
addMetadata(meta, attributes.property, attributes.content)
|
|
186
193
|
}
|
|
@@ -217,6 +224,7 @@ export function parseHTMLMeta (string) {
|
|
|
217
224
|
* Parses HTML string containing meta tags or generates Coralite module structure from markup.
|
|
218
225
|
*
|
|
219
226
|
* @param {string} string - HTML content containing meta tags or module markup
|
|
227
|
+
* @param {IgnoreByAttribute} ignoreByAttribute
|
|
220
228
|
* @returns {CoraliteModule} - Parsed module information, including template, script, tokens, and slot configurations
|
|
221
229
|
*
|
|
222
230
|
* @example
|
|
@@ -244,7 +252,7 @@ export function parseHTMLMeta (string) {
|
|
|
244
252
|
* //}
|
|
245
253
|
* ```
|
|
246
254
|
*/
|
|
247
|
-
export function parseModule (string) {
|
|
255
|
+
export function parseModule (string, ignoreByAttribute) {
|
|
248
256
|
// root element reference
|
|
249
257
|
/** @type {CoraliteDocumentRoot} */
|
|
250
258
|
const root = {
|
|
@@ -268,7 +276,13 @@ export function parseModule (string) {
|
|
|
268
276
|
const parser = new Parser({
|
|
269
277
|
onopentag (originalName, attributes) {
|
|
270
278
|
const parent = stack[stack.length -1]
|
|
271
|
-
const element = createElement(
|
|
279
|
+
const element = createElement({
|
|
280
|
+
name: originalName,
|
|
281
|
+
attributes,
|
|
282
|
+
customElements,
|
|
283
|
+
parent,
|
|
284
|
+
ignoreByAttribute
|
|
285
|
+
})
|
|
272
286
|
const attributeNames = Object.keys(attributes)
|
|
273
287
|
|
|
274
288
|
// push element to stack as it may have children
|
|
@@ -351,6 +365,13 @@ export function parseModule (string) {
|
|
|
351
365
|
}
|
|
352
366
|
},
|
|
353
367
|
onclosetag () {
|
|
368
|
+
const element = stack[stack.length - 1]
|
|
369
|
+
|
|
370
|
+
if (element.type === 'tag' && element.remove) {
|
|
371
|
+
// remove element from tree
|
|
372
|
+
element.parent.children.pop()
|
|
373
|
+
}
|
|
374
|
+
|
|
354
375
|
// remove current element from stack as we're done with its children
|
|
355
376
|
stack.pop()
|
|
356
377
|
},
|
|
@@ -387,7 +408,7 @@ export function parseModule (string) {
|
|
|
387
408
|
|
|
388
409
|
} else if (node.name == 'script') {
|
|
389
410
|
if (node.attribs.type !== 'module') {
|
|
390
|
-
throw new Error('
|
|
411
|
+
throw new Error('Template "'+ templateId + '" script tag must contain the `type="module"` attribute')
|
|
391
412
|
}
|
|
392
413
|
const scriptString = node.children[0]
|
|
393
414
|
|
|
@@ -456,10 +477,13 @@ export async function createComponent ({
|
|
|
456
477
|
return console.warn('Could not find component "' + id +'" used in document "' + document.parentPath + '/' + document.name + '"')
|
|
457
478
|
}
|
|
458
479
|
|
|
480
|
+
// clone the component to avoid mutations during replacement process.
|
|
459
481
|
component = structuredClone(component)
|
|
482
|
+
|
|
460
483
|
const template = component.template
|
|
461
484
|
const computedTokens = []
|
|
462
485
|
|
|
486
|
+
// replace tokens in the template with their values from `values` object and store them into computedTokens array for later use if needed (e.g., to be injected back).
|
|
463
487
|
for (let i = 0; i < component.tokens.attributes.length; i++) {
|
|
464
488
|
const item = component.tokens.attributes[i]
|
|
465
489
|
|
|
@@ -479,7 +503,7 @@ export async function createComponent ({
|
|
|
479
503
|
|
|
480
504
|
continue
|
|
481
505
|
} else {
|
|
482
|
-
console.
|
|
506
|
+
console.log('Token "' + token.name +'" was empty used on "' + component.id + '"')
|
|
483
507
|
value = ''
|
|
484
508
|
}
|
|
485
509
|
}
|
|
@@ -523,7 +547,13 @@ export async function createComponent ({
|
|
|
523
547
|
|
|
524
548
|
// merge values from component script
|
|
525
549
|
if (component.script) {
|
|
526
|
-
const computedValues = await parseScript(
|
|
550
|
+
const computedValues = await parseScript({
|
|
551
|
+
component,
|
|
552
|
+
values,
|
|
553
|
+
element,
|
|
554
|
+
components,
|
|
555
|
+
document
|
|
556
|
+
})
|
|
527
557
|
|
|
528
558
|
values = Object.assign(values, computedValues)
|
|
529
559
|
|
|
@@ -587,7 +617,9 @@ export async function createComponent ({
|
|
|
587
617
|
}
|
|
588
618
|
|
|
589
619
|
// replace custom element with component
|
|
590
|
-
|
|
620
|
+
if (typeof component === 'object') {
|
|
621
|
+
children.splice(childIndex, 1, ...component.children)
|
|
622
|
+
}
|
|
591
623
|
}
|
|
592
624
|
|
|
593
625
|
const slots = component.slotElements[id]
|
|
@@ -638,16 +670,23 @@ export async function createComponent ({
|
|
|
638
670
|
/**
|
|
639
671
|
* Parses a Coralite module script and compiles it into JavaScript.
|
|
640
672
|
*
|
|
641
|
-
* @param {
|
|
642
|
-
* @param {
|
|
643
|
-
* @param {
|
|
644
|
-
* @param {
|
|
645
|
-
* @param {
|
|
673
|
+
* @param {Object} data
|
|
674
|
+
* @param {CoraliteModule} data.component - The Coralite module to parse
|
|
675
|
+
* @param {CoraliteModuleValues} data.values - Replacement tokens for the component
|
|
676
|
+
* @param {CoraliteElement} data.element - Element
|
|
677
|
+
* @param {Object.<string, CoraliteModule>} data.components - Mapping of other components that might be referenced
|
|
678
|
+
* @param {CoraliteDocument} data.document - The current document being processed
|
|
646
679
|
* @returns {Promise<Object.<string,(string|(CoraliteElement|CoraliteTextNode)[])>>}
|
|
647
680
|
*/
|
|
648
|
-
export async function parseScript (
|
|
681
|
+
export async function parseScript ({
|
|
682
|
+
component,
|
|
683
|
+
values,
|
|
684
|
+
element,
|
|
685
|
+
components,
|
|
686
|
+
document
|
|
687
|
+
}) {
|
|
649
688
|
const contextifiedObject = vm.createContext({
|
|
650
|
-
crypto,
|
|
689
|
+
crypto: globalThis.crypto,
|
|
651
690
|
coralite: {
|
|
652
691
|
tokens: values,
|
|
653
692
|
/**
|
|
@@ -732,7 +771,7 @@ export async function parseScript (component, values, element, components, docum
|
|
|
732
771
|
|
|
733
772
|
if (typeof options.template === 'string') {
|
|
734
773
|
templateId = options.template
|
|
735
|
-
} else {
|
|
774
|
+
} else if (typeof options.template === 'object') {
|
|
736
775
|
templateId = options.template.item
|
|
737
776
|
}
|
|
738
777
|
|
|
@@ -841,12 +880,20 @@ function addMetadata (meta, name, content) {
|
|
|
841
880
|
}
|
|
842
881
|
|
|
843
882
|
/**
|
|
844
|
-
* @param {
|
|
845
|
-
* @param {
|
|
846
|
-
* @param {
|
|
847
|
-
* @param {CoraliteElement
|
|
883
|
+
* @param {Object} data
|
|
884
|
+
* @param {string} data.name
|
|
885
|
+
* @param {Object.<string, string>} data.attributes
|
|
886
|
+
* @param {CoraliteElement[]} data.customElements
|
|
887
|
+
* @param {CoraliteElement | CoraliteDocumentRoot} data.parent
|
|
888
|
+
* @param {IgnoreByAttribute} data.ignoreByAttribute
|
|
848
889
|
*/
|
|
849
|
-
function createElement (
|
|
890
|
+
function createElement ({
|
|
891
|
+
name,
|
|
892
|
+
attributes,
|
|
893
|
+
customElements,
|
|
894
|
+
parent,
|
|
895
|
+
ignoreByAttribute
|
|
896
|
+
}) {
|
|
850
897
|
const sanitisedName = name.toLowerCase()
|
|
851
898
|
|
|
852
899
|
/** @type {CoraliteElement} */
|
|
@@ -859,6 +906,14 @@ function createElement (name, attributes, customElements, parent) {
|
|
|
859
906
|
parentChildIndex: parent.children.length
|
|
860
907
|
}
|
|
861
908
|
|
|
909
|
+
if (ignoreByAttribute) {
|
|
910
|
+
const ignore = findAttributesToIgnore(ignoreByAttribute, attributes)
|
|
911
|
+
|
|
912
|
+
if (ignore) {
|
|
913
|
+
element.remove = true
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
|
|
862
917
|
if (!validTags[sanitisedName]) {
|
|
863
918
|
if (invalidCustomTags[sanitisedName]) {
|
|
864
919
|
throw new Error('Element name is reserved: "'+ sanitisedName +'"')
|
|
@@ -900,3 +955,22 @@ function createTextNode (data, parent) {
|
|
|
900
955
|
|
|
901
956
|
return textNode
|
|
902
957
|
}
|
|
958
|
+
|
|
959
|
+
/**
|
|
960
|
+
* Find attributes to be ignored by the parser.
|
|
961
|
+
*
|
|
962
|
+
* @param {Array<Array<string, string>>} ignore - An array of attribute pairs to be ignored by the parser
|
|
963
|
+
* @param {Object<string, string>} attributes - The HTML attribute object to be parsed by the parser
|
|
964
|
+
* @returns {boolean}
|
|
965
|
+
*/
|
|
966
|
+
function findAttributesToIgnore (ignore, attributes) {
|
|
967
|
+
for (let i = 0; i < ignore.length; i++) {
|
|
968
|
+
const [key, value] = ignore[i]
|
|
969
|
+
|
|
970
|
+
if (attributes[key] && attributes[key].includes(value)) {
|
|
971
|
+
return true
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
return false
|
|
976
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coralite",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"description": "HTML modules static site generator",
|
|
5
5
|
"main": "./lib/coralite.js",
|
|
6
6
|
"type": "module",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"test-e2e": "playwright test",
|
|
32
32
|
"test-e2e-report": "playwright show-report",
|
|
33
33
|
"test-e2e-ui": "playwright test --ui",
|
|
34
|
-
"html": "
|
|
34
|
+
"html": "coralite -t tests/fixtures/templates -p tests/fixtures/pages -o dist -i 'data-dev=true'",
|
|
35
35
|
"server": "sirv dist --dev --port 3000"
|
|
36
36
|
},
|
|
37
37
|
"bin": "bin/coralite.js",
|
|
@@ -56,6 +56,8 @@
|
|
|
56
56
|
"@stylistic/eslint-plugin-js": "^2.12.1",
|
|
57
57
|
"@stylistic/eslint-plugin-plus": "^2.12.1",
|
|
58
58
|
"@types/node": "^22.10.5",
|
|
59
|
+
"coralite": "link:",
|
|
60
|
+
"highlight.js": "^11.11.1",
|
|
59
61
|
"kleur": "^4.1.5",
|
|
60
62
|
"sirv-cli": "^3.0.0"
|
|
61
63
|
},
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#! /bin/bash
|
|
2
|
+
|
|
3
|
+
export VERSION=$(git tag --sort=-committerdate | head -1)
|
|
4
|
+
export PREVIOUS_VERSION=$(git tag --sort=-committerdate | head -2 | awk '{split($0, tags, "\n")} END {print tags[1]}')
|
|
5
|
+
export CHANGES=$(git log --pretty="- %h%d %s - (*%an*)" $VERSION...$PREVIOUS_VERSION)
|
|
6
|
+
printf "# 🎁 Release notes (\`$VERSION\`)\n\n## Changes\n$CHANGES\n\n## Metadata\n\`\`\`\nThis version -------- $VERSION\nPrevious version ---- $PREVIOUS_VERSION\nTotal commits ------- $(echo "$CHANGES" | wc -l)\n\`\`\`\n" > change-logs.md
|
package/types/index.js
CHANGED
|
@@ -123,6 +123,7 @@
|
|
|
123
123
|
* @property {CoraliteDocumentRoot} root - Array of elements and text nodes in the document
|
|
124
124
|
* @property {CoraliteElement[]} customElements - Custom elements defined in the document
|
|
125
125
|
* @property {CoralitePath} path - Document's file path
|
|
126
|
+
* @property {IgnoreByAttribute} ignoreByAttribute - An array of attribute names and values to ignore by element type.
|
|
126
127
|
*/
|
|
127
128
|
|
|
128
129
|
/**
|
|
@@ -136,3 +137,7 @@
|
|
|
136
137
|
* @property {string} html - Raw HTML content of the render process as a string
|
|
137
138
|
* @property {number} duration - The duration of the render process in milliseconds
|
|
138
139
|
*/
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* @typedef {Array<Array<string, string>>} IgnoreByAttribute - An array of attribute names and values to ignore by element type.
|
|
143
|
+
*/
|