coralite 0.6.2 → 0.6.4
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 +17 -16
- package/bin/coralite.js +4 -1
- package/change-logs.md +96 -0
- package/lib/coralite.js +11 -4
- package/lib/html-module.js +35 -8
- package/lib/parse.js +113 -40
- package/package.json +3 -2
- package/scripts/change-log.sh +6 -0
- package/types/index.js +5 -0
package/README.md
CHANGED
|
@@ -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,96 @@
|
|
|
1
|
+
# 🎁 Release notes (`v0.6.4`)
|
|
2
|
+
|
|
3
|
+
## Changes
|
|
4
|
+
- 41771d5 (HEAD -> main, tag: v0.6.4, origin/main) chore: version bump - (*Thomas David*)
|
|
5
|
+
- ea2ef46 test: cover values param - (*Thomas David*)
|
|
6
|
+
- 60e70d3 feat: add props argument to tokens and slots functions - (*Thomas David*)
|
|
7
|
+
- 1ed074a chore: version bump - (*Thomas David*)
|
|
8
|
+
- 9d710c0 ci: fix publish needs ref - (*Thomas David*)
|
|
9
|
+
|
|
10
|
+
## Metadata
|
|
11
|
+
```
|
|
12
|
+
This version -------- v0.6.4
|
|
13
|
+
Previous version ---- v0.6.3
|
|
14
|
+
Total commits ------- 5
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
# 🎁 Release notes (`v0.6.3`)
|
|
18
|
+
|
|
19
|
+
## Changes
|
|
20
|
+
- 6fe640d (HEAD -> main, tag: v0.6.3, origin/main) test: cover ignore by attribute - (*[Thomas David](https://github.com/tjdav)*)
|
|
21
|
+
- a47ff8f types: add IgnoreByAttribute type - (*[Thomas David](https://github.com/tjdav)*)
|
|
22
|
+
- 8547c37 feat: ignore element by attributes inside meta and component parsers - (*[Thomas David](https://github.com/tjdav)*)
|
|
23
|
+
- f61ae88 docs: update ignore-attribute example with quotes - (*[Thomas David](https://github.com/tjdav)*)
|
|
24
|
+
- d4a277d docs: create consistent path names in example - (*[Thomas David](https://github.com/tjdav)*)
|
|
25
|
+
- 566463f docs: remove requirements section - (*[Thomas David](https://github.com/tjdav)*)
|
|
26
|
+
- 2493ab3 style: import type new line - (*[Thomas David](https://github.com/tjdav)*)
|
|
27
|
+
- 2e44174 ci: test before publish - (*[Thomas David](https://github.com/tjdav)*)
|
|
28
|
+
- c1d5ce7 fix: add template id to script module error - (*[Thomas David](https://github.com/tjdav)*)
|
|
29
|
+
- 4fabac1 ci: include self to test script - (*[Thomas David](https://github.com/tjdav)*)
|
|
30
|
+
- efd34d0 fix: add --experimental-vm-modules to shebang - (*[Thomas David](https://github.com/tjdav)*)
|
|
31
|
+
- 7da5d98 refactor: add type check before splicing children. - (*[Thomas David](https://github.com/tjdav)*)
|
|
32
|
+
- 2e39027 fix: catch bad options for aggregate function - (*[Thomas David](https://github.com/tjdav)*)
|
|
33
|
+
|
|
34
|
+
## Metadata
|
|
35
|
+
```
|
|
36
|
+
This version -------- v0.6.3
|
|
37
|
+
Previous version ---- v0.6.2
|
|
38
|
+
Total commits ------- 13
|
|
39
|
+
```
|
|
40
|
+
# 🎁 Release notes (`v0.6.2`)
|
|
41
|
+
|
|
42
|
+
## Changes
|
|
43
|
+
- be6c54c (HEAD -> main, tag: v0.6.2, origin/main) fix: update lock - (*[Thomas David](https://github.com/tjdav)*)
|
|
44
|
+
- 15d9b4e chore: version bump - (*[Thomas David](https://github.com/tjdav)*)
|
|
45
|
+
- fac695e fix: node v18 requires globalThis reference for crypto - (*[Thomas David](https://github.com/tjdav)*)
|
|
46
|
+
- d7c551e doc: format doc links - (*[Thomas David](https://github.com/tjdav)*)
|
|
47
|
+
|
|
48
|
+
## Metadata
|
|
49
|
+
```
|
|
50
|
+
This version -------- v0.6.2
|
|
51
|
+
Previous version ---- v0.6.1
|
|
52
|
+
Total commits ------- 4
|
|
53
|
+
```
|
|
54
|
+
# 🎁 Release notes (`v0.6.1`)
|
|
55
|
+
|
|
56
|
+
## Changes
|
|
57
|
+
- bcc1637 (HEAD -> main, tag: v0.6.1, origin/main) chore: version bump - (*[Thomas David](https://github.com/tjdav)*)
|
|
58
|
+
- 95cfdba docs: add doc links - (*[Thomas David](https://github.com/tjdav)*)
|
|
59
|
+
- 101a305 fix: render computedSlot nodes - (*[Thomas David](https://github.com/tjdav)*)
|
|
60
|
+
- 11a35d8 feat: dynamically import modules - (*[Thomas David](https://github.com/tjdav)*)
|
|
61
|
+
- e1364b9 docs: add CoraliteResult type - (*[Thomas David](https://github.com/tjdav)*)
|
|
62
|
+
- 11c6405 docs: add @example to coralite - (*[Thomas David](https://github.com/tjdav)*)
|
|
63
|
+
- a050263 docs: basic technical documentation - (*[Thomas David](https://github.com/tjdav)*)
|
|
64
|
+
- 83fdddd docs: update dry run option - (*[Thomas David](https://github.com/tjdav)*)
|
|
65
|
+
|
|
66
|
+
## Metadata
|
|
67
|
+
```
|
|
68
|
+
This version -------- v0.6.1
|
|
69
|
+
Previous version ---- v0.6.0
|
|
70
|
+
Total commits ------- 8
|
|
71
|
+
```
|
|
72
|
+
# 🎁 Release notes (`v0.6.0`)
|
|
73
|
+
|
|
74
|
+
## Changes
|
|
75
|
+
- 22d75e2 (HEAD -> main, tag: v0.6.0, origin/main) chore: version bump - (*[Thomas David](https://github.com/tjdav)*)
|
|
76
|
+
- c5cc7cc lint: ignore playwright-report - (*[Thomas David](https://github.com/tjdav)*)
|
|
77
|
+
- fdb3697 docs: add dry run option - (*[Thomas David](https://github.com/tjdav)*)
|
|
78
|
+
- 891db2e feat: export coralite utils - (*[Thomas David](https://github.com/tjdav)*)
|
|
79
|
+
- 9265681 test: cover ignore attribute - (*[Thomas David](https://github.com/tjdav)*)
|
|
80
|
+
- 5d44661 fix: allow missing component to compile - (*[Thomas David](https://github.com/tjdav)*)
|
|
81
|
+
- f3d6e65 docs: add remove prop to CoraliteElement - (*[Thomas David](https://github.com/tjdav)*)
|
|
82
|
+
- 229fef5 feat: new option to ignore element by attribute name value pair - (*[Thomas David](https://github.com/tjdav)*)
|
|
83
|
+
- c78dde1 chore: include kleur dep - (*[Thomas David](https://github.com/tjdav)*)
|
|
84
|
+
- b10bbe8 feat: update cli to use coralite module - (*[Thomas David](https://github.com/tjdav)*)
|
|
85
|
+
- 48fe816 docs: make defineComponent param tokens and slots optional - (*[Thomas David](https://github.com/tjdav)*)
|
|
86
|
+
- 02a5e8f feat: move coralite to a module - (*[Thomas David](https://github.com/tjdav)*)
|
|
87
|
+
- d336090 feat: get package.json util function - (*[Thomas David](https://github.com/tjdav)*)
|
|
88
|
+
- e210844 feat: add document used in error message - (*[Thomas David](https://github.com/tjdav)*)
|
|
89
|
+
- 1556a3b chore: version bump - (*[Thomas David](https://github.com/tjdav)*)
|
|
90
|
+
|
|
91
|
+
## Metadata
|
|
92
|
+
```
|
|
93
|
+
This version -------- v0.6.0
|
|
94
|
+
Previous version ---- v0.5.1
|
|
95
|
+
Total commits ------- 15
|
|
96
|
+
```
|
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
|
/**
|
|
@@ -18,7 +19,13 @@ import render from 'dom-serializer'
|
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* @callback DefineComponentSlot
|
|
21
|
-
* @param {CoraliteAnyNode[]} nodes
|
|
22
|
+
* @param {CoraliteAnyNode[]} nodes - The nodes to be rendered in the component's slots
|
|
23
|
+
* @param {Object.<string, string>} values - Attribute values
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @callback DefineComponentToken
|
|
28
|
+
* @param {Object.<string, string>} values - Attribute values
|
|
22
29
|
*/
|
|
23
30
|
|
|
24
31
|
/**
|
|
@@ -31,7 +38,7 @@ export const tokens = {}
|
|
|
31
38
|
*
|
|
32
39
|
* @param {Object} options
|
|
33
40
|
* @param {string} [options.id] - Optional component id, if not defined, the id will be extracted from the first top level element with the id attribute
|
|
34
|
-
* @param {Object.<string, (string |
|
|
41
|
+
* @param {Object.<string, (string | DefineComponentToken)>} [options.tokens] - Token names and values are either strings or functions representing the corresponding tokens' content or behavior.
|
|
35
42
|
* @param {Object.<string, DefineComponentSlot>} [options.slots] - Middleware for slot content
|
|
36
43
|
* @returns {Promise<Object.<string, string>>}
|
|
37
44
|
*/
|
|
@@ -98,7 +105,7 @@ export async function coralite ({
|
|
|
98
105
|
// create templates
|
|
99
106
|
for (let i = 0; i < htmlTemplates.length; i++) {
|
|
100
107
|
const html = htmlTemplates[i]
|
|
101
|
-
const coraliteModule = parseModule(html.content)
|
|
108
|
+
const coraliteModule = parseModule(html.content, ignoreByAttribute)
|
|
102
109
|
|
|
103
110
|
coraliteModules[coraliteModule.id] = coraliteModule
|
|
104
111
|
}
|
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
|
@@ -19,7 +19,8 @@ import { invalidCustomTags, validTags } from './tags.js'
|
|
|
19
19
|
* CoraliteDocumentRoot,
|
|
20
20
|
* CoraliteContentNode,
|
|
21
21
|
* CoraliteModuleValues,
|
|
22
|
-
* CoraliteAggregateTemplate
|
|
22
|
+
* CoraliteAggregateTemplate,
|
|
23
|
+
* IgnoreByAttribute
|
|
23
24
|
* } from '#types'
|
|
24
25
|
*/
|
|
25
26
|
|
|
@@ -32,7 +33,7 @@ const customElementTagTokenRegExp = /^[^-].*[-._a-z0-9\u00B7\u00C0-\u00D6\u00D8-
|
|
|
32
33
|
*
|
|
33
34
|
* @param {HTMLData} html - The HTML data containing the content to parse
|
|
34
35
|
* @param {CoralitePath} path - The path object containing the file path information
|
|
35
|
-
* @param {
|
|
36
|
+
* @param {IgnoreByAttribute} [ignoreByAttribute] - Ignore element with attribute name value pair
|
|
36
37
|
* @returns {CoraliteDocument} An object representing the parsed document structure
|
|
37
38
|
*
|
|
38
39
|
* @example
|
|
@@ -76,17 +77,13 @@ export function parseHTMLDocument (html, path, ignoreByAttribute) {
|
|
|
76
77
|
},
|
|
77
78
|
onopentag (originalName, attributes) {
|
|
78
79
|
const parent = stack[stack.length - 1]
|
|
79
|
-
const element = createElement(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
element.remove = true
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
80
|
+
const element = createElement({
|
|
81
|
+
name: originalName,
|
|
82
|
+
attributes,
|
|
83
|
+
customElements,
|
|
84
|
+
parent,
|
|
85
|
+
ignoreByAttribute
|
|
86
|
+
})
|
|
90
87
|
|
|
91
88
|
// push element to stack as it may have children
|
|
92
89
|
stack.push(element)
|
|
@@ -99,10 +96,8 @@ export function parseHTMLDocument (html, path, ignoreByAttribute) {
|
|
|
99
96
|
onclosetag () {
|
|
100
97
|
const element = stack[stack.length - 1]
|
|
101
98
|
|
|
102
|
-
|
|
103
|
-
if (element.remove) {
|
|
99
|
+
if (element.type === 'tag' && element.remove) {
|
|
104
100
|
// remove element from tree
|
|
105
|
-
// @ts-ignore
|
|
106
101
|
element.parent.children.pop()
|
|
107
102
|
}
|
|
108
103
|
|
|
@@ -149,7 +144,8 @@ export function parseHTMLDocument (html, path, ignoreByAttribute) {
|
|
|
149
144
|
parentPath: html.parentPath,
|
|
150
145
|
root,
|
|
151
146
|
customElements,
|
|
152
|
-
path
|
|
147
|
+
path,
|
|
148
|
+
ignoreByAttribute
|
|
153
149
|
}
|
|
154
150
|
}
|
|
155
151
|
|
|
@@ -157,6 +153,7 @@ export function parseHTMLDocument (html, path, ignoreByAttribute) {
|
|
|
157
153
|
* Parses HTML string containing meta tags and extracts associated metadata.
|
|
158
154
|
*
|
|
159
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)
|
|
160
157
|
* @returns {Object.<string, CoraliteToken[]>}
|
|
161
158
|
*
|
|
162
159
|
* @example
|
|
@@ -171,7 +168,7 @@ export function parseHTMLDocument (html, path, ignoreByAttribute) {
|
|
|
171
168
|
* //}
|
|
172
169
|
* ```
|
|
173
170
|
*/
|
|
174
|
-
export function parseHTMLMeta (string) {
|
|
171
|
+
export function parseHTMLMeta (string, ignoreByAttribute) {
|
|
175
172
|
// stack to keep track of current element hierarchy
|
|
176
173
|
const stack = []
|
|
177
174
|
/** @type {Object.<string, CoraliteToken[]>} */
|
|
@@ -182,6 +179,15 @@ export function parseHTMLMeta (string) {
|
|
|
182
179
|
onopentag (name, attributes) {
|
|
183
180
|
if (name === 'meta') {
|
|
184
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
|
+
|
|
185
191
|
if (attributes.property) {
|
|
186
192
|
addMetadata(meta, attributes.property, attributes.content)
|
|
187
193
|
}
|
|
@@ -218,6 +224,7 @@ export function parseHTMLMeta (string) {
|
|
|
218
224
|
* Parses HTML string containing meta tags or generates Coralite module structure from markup.
|
|
219
225
|
*
|
|
220
226
|
* @param {string} string - HTML content containing meta tags or module markup
|
|
227
|
+
* @param {IgnoreByAttribute} ignoreByAttribute
|
|
221
228
|
* @returns {CoraliteModule} - Parsed module information, including template, script, tokens, and slot configurations
|
|
222
229
|
*
|
|
223
230
|
* @example
|
|
@@ -245,7 +252,7 @@ export function parseHTMLMeta (string) {
|
|
|
245
252
|
* //}
|
|
246
253
|
* ```
|
|
247
254
|
*/
|
|
248
|
-
export function parseModule (string) {
|
|
255
|
+
export function parseModule (string, ignoreByAttribute) {
|
|
249
256
|
// root element reference
|
|
250
257
|
/** @type {CoraliteDocumentRoot} */
|
|
251
258
|
const root = {
|
|
@@ -269,7 +276,13 @@ export function parseModule (string) {
|
|
|
269
276
|
const parser = new Parser({
|
|
270
277
|
onopentag (originalName, attributes) {
|
|
271
278
|
const parent = stack[stack.length -1]
|
|
272
|
-
const element = createElement(
|
|
279
|
+
const element = createElement({
|
|
280
|
+
name: originalName,
|
|
281
|
+
attributes,
|
|
282
|
+
customElements,
|
|
283
|
+
parent,
|
|
284
|
+
ignoreByAttribute
|
|
285
|
+
})
|
|
273
286
|
const attributeNames = Object.keys(attributes)
|
|
274
287
|
|
|
275
288
|
// push element to stack as it may have children
|
|
@@ -352,6 +365,13 @@ export function parseModule (string) {
|
|
|
352
365
|
}
|
|
353
366
|
},
|
|
354
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
|
+
|
|
355
375
|
// remove current element from stack as we're done with its children
|
|
356
376
|
stack.pop()
|
|
357
377
|
},
|
|
@@ -388,7 +408,7 @@ export function parseModule (string) {
|
|
|
388
408
|
|
|
389
409
|
} else if (node.name == 'script') {
|
|
390
410
|
if (node.attribs.type !== 'module') {
|
|
391
|
-
throw new Error('
|
|
411
|
+
throw new Error('Template "'+ templateId + '" script tag must contain the `type="module"` attribute')
|
|
392
412
|
}
|
|
393
413
|
const scriptString = node.children[0]
|
|
394
414
|
|
|
@@ -457,10 +477,13 @@ export async function createComponent ({
|
|
|
457
477
|
return console.warn('Could not find component "' + id +'" used in document "' + document.parentPath + '/' + document.name + '"')
|
|
458
478
|
}
|
|
459
479
|
|
|
480
|
+
// clone the component to avoid mutations during replacement process.
|
|
460
481
|
component = structuredClone(component)
|
|
482
|
+
|
|
461
483
|
const template = component.template
|
|
462
484
|
const computedTokens = []
|
|
463
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).
|
|
464
487
|
for (let i = 0; i < component.tokens.attributes.length; i++) {
|
|
465
488
|
const item = component.tokens.attributes[i]
|
|
466
489
|
|
|
@@ -480,7 +503,7 @@ export async function createComponent ({
|
|
|
480
503
|
|
|
481
504
|
continue
|
|
482
505
|
} else {
|
|
483
|
-
console.
|
|
506
|
+
console.log('Token "' + token.name +'" was empty used on "' + component.id + '"')
|
|
484
507
|
value = ''
|
|
485
508
|
}
|
|
486
509
|
}
|
|
@@ -524,7 +547,13 @@ export async function createComponent ({
|
|
|
524
547
|
|
|
525
548
|
// merge values from component script
|
|
526
549
|
if (component.script) {
|
|
527
|
-
const computedValues = await parseScript(
|
|
550
|
+
const computedValues = await parseScript({
|
|
551
|
+
component,
|
|
552
|
+
values,
|
|
553
|
+
element,
|
|
554
|
+
components,
|
|
555
|
+
document
|
|
556
|
+
})
|
|
528
557
|
|
|
529
558
|
values = Object.assign(values, computedValues)
|
|
530
559
|
|
|
@@ -588,7 +617,9 @@ export async function createComponent ({
|
|
|
588
617
|
}
|
|
589
618
|
|
|
590
619
|
// replace custom element with component
|
|
591
|
-
|
|
620
|
+
if (typeof component === 'object') {
|
|
621
|
+
children.splice(childIndex, 1, ...component.children)
|
|
622
|
+
}
|
|
592
623
|
}
|
|
593
624
|
|
|
594
625
|
const slots = component.slotElements[id]
|
|
@@ -639,14 +670,21 @@ export async function createComponent ({
|
|
|
639
670
|
/**
|
|
640
671
|
* Parses a Coralite module script and compiles it into JavaScript.
|
|
641
672
|
*
|
|
642
|
-
* @param {
|
|
643
|
-
* @param {
|
|
644
|
-
* @param {
|
|
645
|
-
* @param {
|
|
646
|
-
* @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
|
|
647
679
|
* @returns {Promise<Object.<string,(string|(CoraliteElement|CoraliteTextNode)[])>>}
|
|
648
680
|
*/
|
|
649
|
-
export async function parseScript (
|
|
681
|
+
export async function parseScript ({
|
|
682
|
+
component,
|
|
683
|
+
values,
|
|
684
|
+
element,
|
|
685
|
+
components,
|
|
686
|
+
document
|
|
687
|
+
}) {
|
|
650
688
|
const contextifiedObject = vm.createContext({
|
|
651
689
|
crypto: globalThis.crypto,
|
|
652
690
|
coralite: {
|
|
@@ -659,7 +697,7 @@ export async function parseScript (component, values, element, components, docum
|
|
|
659
697
|
*/
|
|
660
698
|
async defineComponent (options) {
|
|
661
699
|
/** @type {Object.<string, string>} */
|
|
662
|
-
const
|
|
700
|
+
const tokens = {}
|
|
663
701
|
|
|
664
702
|
if (options.tokens) {
|
|
665
703
|
for (const key in options.tokens) {
|
|
@@ -667,7 +705,7 @@ export async function parseScript (component, values, element, components, docum
|
|
|
667
705
|
const token = options.tokens[key]
|
|
668
706
|
|
|
669
707
|
if (typeof token === 'function') {
|
|
670
|
-
|
|
708
|
+
tokens[key] = await token(values)
|
|
671
709
|
}
|
|
672
710
|
}
|
|
673
711
|
}
|
|
@@ -695,7 +733,7 @@ export async function parseScript (component, values, element, components, docum
|
|
|
695
733
|
}
|
|
696
734
|
|
|
697
735
|
// compute slot nodes
|
|
698
|
-
const result = computedSlot(slotContent) || slotContent
|
|
736
|
+
const result = computedSlot(slotContent, values) || slotContent
|
|
699
737
|
|
|
700
738
|
// append new slot nodes
|
|
701
739
|
for (let index = 0; index < result.length; index++) {
|
|
@@ -713,7 +751,7 @@ export async function parseScript (component, values, element, components, docum
|
|
|
713
751
|
}
|
|
714
752
|
}
|
|
715
753
|
|
|
716
|
-
return
|
|
754
|
+
return tokens
|
|
717
755
|
},
|
|
718
756
|
/**
|
|
719
757
|
* @overload
|
|
@@ -733,7 +771,7 @@ export async function parseScript (component, values, element, components, docum
|
|
|
733
771
|
|
|
734
772
|
if (typeof options.template === 'string') {
|
|
735
773
|
templateId = options.template
|
|
736
|
-
} else {
|
|
774
|
+
} else if (typeof options.template === 'object') {
|
|
737
775
|
templateId = options.template.item
|
|
738
776
|
}
|
|
739
777
|
|
|
@@ -842,12 +880,20 @@ function addMetadata (meta, name, content) {
|
|
|
842
880
|
}
|
|
843
881
|
|
|
844
882
|
/**
|
|
845
|
-
* @param {
|
|
846
|
-
* @param {
|
|
847
|
-
* @param {
|
|
848
|
-
* @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
|
|
849
889
|
*/
|
|
850
|
-
function createElement (
|
|
890
|
+
function createElement ({
|
|
891
|
+
name,
|
|
892
|
+
attributes,
|
|
893
|
+
customElements,
|
|
894
|
+
parent,
|
|
895
|
+
ignoreByAttribute
|
|
896
|
+
}) {
|
|
851
897
|
const sanitisedName = name.toLowerCase()
|
|
852
898
|
|
|
853
899
|
/** @type {CoraliteElement} */
|
|
@@ -860,6 +906,14 @@ function createElement (name, attributes, customElements, parent) {
|
|
|
860
906
|
parentChildIndex: parent.children.length
|
|
861
907
|
}
|
|
862
908
|
|
|
909
|
+
if (ignoreByAttribute) {
|
|
910
|
+
const ignore = findAttributesToIgnore(ignoreByAttribute, attributes)
|
|
911
|
+
|
|
912
|
+
if (ignore) {
|
|
913
|
+
element.remove = true
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
|
|
863
917
|
if (!validTags[sanitisedName]) {
|
|
864
918
|
if (invalidCustomTags[sanitisedName]) {
|
|
865
919
|
throw new Error('Element name is reserved: "'+ sanitisedName +'"')
|
|
@@ -901,3 +955,22 @@ function createTextNode (data, parent) {
|
|
|
901
955
|
|
|
902
956
|
return textNode
|
|
903
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.4",
|
|
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,7 @@
|
|
|
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:",
|
|
59
60
|
"highlight.js": "^11.11.1",
|
|
60
61
|
"kleur": "^4.1.5",
|
|
61
62
|
"sirv-cli": "^3.0.0"
|
|
@@ -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
|
+
*/
|