coralite 0.11.0 → 0.11.2
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 +11 -9
- package/bin/coralite.js +11 -19
- package/changelog.md +45 -4
- package/lib/collection.js +10 -10
- package/lib/coralite.js +52 -28
- package/lib/html.js +1 -1
- package/lib/parse.js +8 -8
- package/lib/type-helper.js +0 -2
- package/lib/utils.js +2 -2
- package/package.json +2 -2
- package/plugins/define-component.js +5 -5
- package/.woodpecker/publish.yml +0 -48
- package/.woodpecker/test-e2e.yml +0 -48
- package/.woodpecker/test-script.yml +0 -58
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
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
|
<p style="text-align:center;">
|
|
6
|
-
<img src="
|
|
6
|
+
<img src="https://codeberg.org/tjdavid/coralite/media/branch/main/docs/images/logo.png" alt="Coralite logo" style="max-width: 100%; width: auto;filter: drop-shadow(rgba(0,0,0,0.2) 0px 0px 0.75rem)">
|
|
7
7
|
</p>
|
|
8
8
|
|
|
9
9
|
- Getting started
|
|
@@ -49,14 +49,14 @@ Replace `[options]` with the desired flags and arguments.
|
|
|
49
49
|
|
|
50
50
|
To generate a website using Coralite, you must provide three essential options:
|
|
51
51
|
|
|
52
|
-
- **-t or --templates**: The path to your templates directory containing reusable UI elements (e.g., `-
|
|
53
|
-
- **-p or --pages**: The path to your pages directory where static HTML files reside (e.g., `-p
|
|
54
|
-
- **--output or -o**: The output directory for the generated site (e.g., `--output
|
|
52
|
+
- **-t or --templates**: The path to your templates directory containing reusable UI elements (e.g., `-t src/templates`).
|
|
53
|
+
- **-p or --pages**: The path to your pages directory where static HTML files reside (e.g., `-p src/pages`).
|
|
54
|
+
- **--output or -o**: The output directory for the generated site (e.g., `--output dist`).
|
|
55
55
|
|
|
56
56
|
Here's an example of how these options might look:
|
|
57
57
|
|
|
58
58
|
```bash
|
|
59
|
-
coralite --templates
|
|
59
|
+
coralite --templates path/to/templates --pages path/to/pages --output dist
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
## Optional Options
|
|
@@ -66,20 +66,22 @@ coralite --templates ./path/to/templates --pages ./path/to/pages --output ./dist
|
|
|
66
66
|
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:
|
|
67
67
|
|
|
68
68
|
```bash
|
|
69
|
-
coralite --templates
|
|
69
|
+
coralite --templates path/to/templates --pages path/to/pages --output dist --dry-run
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
## Troubleshooting
|
|
73
73
|
|
|
74
74
|
|
|
75
|
-
Coralite uses **ECMAScript Modules** which requires to run Node.js with the **`--experimental-vm-modules`** option enabled.
|
|
75
|
+
Coralite uses **ECMAScript Modules** and **Import meta resolve** which requires to run Node.js with the **`--experimental-vm-modules`** and **`--experimental-import-meta-resolve`** option enabled.
|
|
76
76
|
|
|
77
77
|
```bash
|
|
78
|
-
node --experimental-vm-modules node_modules/coralite/bin/coralite.js [options]
|
|
78
|
+
node --experimental-vm-modules --experimental-import-meta-resolve node_modules/coralite/bin/coralite.js [options]
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
+
If you require your templates to import
|
|
82
|
+
|
|
81
83
|
or using NODE_OPTIONS
|
|
82
84
|
|
|
83
85
|
```bash
|
|
84
|
-
NODE_OPTIONS
|
|
86
|
+
NODE_OPTIONS="--experimental-vm-modules --experimental-import-meta-resolve" coralite [options]
|
|
85
87
|
```
|
package/bin/coralite.js
CHANGED
|
@@ -2,12 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import { getPkg, Coralite } from '#lib'
|
|
4
4
|
import { Command } from 'commander'
|
|
5
|
-
import { join } from 'node:path'
|
|
6
|
-
import { existsSync, mkdirSync, writeFileSync } from 'node:fs'
|
|
7
5
|
import kleur from 'kleur'
|
|
8
6
|
import { loadConfig } from '../lib/loader.js'
|
|
9
7
|
|
|
10
|
-
//
|
|
8
|
+
// remove all Node warnings before doing anything else
|
|
11
9
|
process.removeAllListeners('warning')
|
|
12
10
|
|
|
13
11
|
const pkg = await getPkg()
|
|
@@ -41,6 +39,7 @@ const coraliteOptions = {
|
|
|
41
39
|
plugins: []
|
|
42
40
|
}
|
|
43
41
|
|
|
42
|
+
// process ignore-attribute key=value pairs
|
|
44
43
|
for (let i = 0; i < options.ignoreAttribute.length; i++) {
|
|
45
44
|
const pair = options.ignoreAttribute[i].split('=')
|
|
46
45
|
|
|
@@ -54,19 +53,23 @@ for (let i = 0; i < options.ignoreAttribute.length; i++) {
|
|
|
54
53
|
})
|
|
55
54
|
}
|
|
56
55
|
|
|
56
|
+
// merge plugins from config file into coraliteOptions
|
|
57
57
|
if (config && config.plugins) {
|
|
58
58
|
coraliteOptions.plugins = coraliteOptions.plugins.concat(config.plugins)
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
// initializes Coralite with the provided options and compiles documents
|
|
61
62
|
const coralite = new Coralite(coraliteOptions)
|
|
62
|
-
|
|
63
|
+
// compiles all pages using Coralite
|
|
64
|
+
const documents = await coralite.compile()
|
|
63
65
|
|
|
64
66
|
if (options.dryRun) {
|
|
67
|
+
// print document details without saving files
|
|
65
68
|
const PAD = ' '
|
|
66
69
|
const border = '─'.repeat(Math.min(process.stdout.columns, 36) / 2)
|
|
67
70
|
|
|
68
|
-
for (let i = 0; i <
|
|
69
|
-
const document =
|
|
71
|
+
for (let i = 0; i < documents.length; i++) {
|
|
72
|
+
const document = documents[i]
|
|
70
73
|
|
|
71
74
|
process.stdout.write('\n' + PAD + kleur.green('Document is ready!\n\n'))
|
|
72
75
|
process.stdout.write(PAD + `${kleur.bold('- Path:')} ${document.item.path.pathname}\n`)
|
|
@@ -76,17 +79,6 @@ if (options.dryRun) {
|
|
|
76
79
|
process.stdout.write('\n\n' + border + kleur.inverse(' Content end ') + border + '\n')
|
|
77
80
|
}
|
|
78
81
|
} else {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const dir = join(output, document.item.path.dirname)
|
|
82
|
-
|
|
83
|
-
if (!existsSync(dir)) {
|
|
84
|
-
// create directory
|
|
85
|
-
mkdirSync(dir, {
|
|
86
|
-
recursive: true
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
writeFileSync(join(output, document.item.path.pathname), document.html)
|
|
91
|
-
}
|
|
82
|
+
// save the generated documents to output directory
|
|
83
|
+
await coralite.save(documents, output)
|
|
92
84
|
}
|
package/changelog.md
CHANGED
|
@@ -1,11 +1,52 @@
|
|
|
1
1
|
# 🎁 Complete Release History
|
|
2
2
|
|
|
3
|
+
## Release: `v0.11.2`
|
|
4
|
+
|
|
5
|
+
### Changes from `v0.11.1` to `v0.11.2`
|
|
6
|
+
|
|
7
|
+
- b9d8c37 (HEAD -> main, tag: v0.11.2) chore: bump version - ([Thomas David](https://codeberg.org/tjdavid))
|
|
8
|
+
- e427d7d (origin/main) style: update comment formatting consistency - ([Thomas David](https://codeberg.org/tjdavid))
|
|
9
|
+
- 707c462 types: add ts-ignore for script.namespace.default - ([Thomas David](https://codeberg.org/tjdavid))
|
|
10
|
+
- 3e4df9a fix: correctly skip directive nodes in replaceToken function - ([Thomas David](https://codeberg.org/tjdavid))
|
|
11
|
+
- bed8aa6 docs: update parameter names and type annotations - ([Thomas David](https://codeberg.org/tjdavid))
|
|
12
|
+
- c065e9a fix: Improve error messages for template directory and module export issues - ([Thomas David](https://codeberg.org/tjdavid))
|
|
13
|
+
- a76bc28 feat: add save method to export processed documents as HTML files - ([Thomas David](https://codeberg.org/tjdavid))
|
|
14
|
+
- cc65461 refactor: use coralite.save instead of manual file operations - ([Thomas David](https://codeberg.org/tjdavid))
|
|
15
|
+
- 48f180f docs: add inline comments - ([Thomas David](https://codeberg.org/tjdavid))
|
|
16
|
+
|
|
17
|
+
### Metadata
|
|
18
|
+
```
|
|
19
|
+
This version -------- v0.11.2
|
|
20
|
+
Previous version ---- v0.11.1
|
|
21
|
+
Total commits ------- 9
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Release: `v0.11.1`
|
|
25
|
+
|
|
26
|
+
### Changes from `v0.11.0` to `v0.11.1`
|
|
27
|
+
|
|
28
|
+
- c0ab58b (tag: v0.11.1) docs: add experimental-import-meta-resolve flag to Node.js runtime options - ([Thomas David](https://codeberg.org/tjdavid))
|
|
29
|
+
- 5675297 chore: bump version - ([Thomas David](https://codeberg.org/tjdavid))
|
|
30
|
+
- 9ca30e8 build: update minimum required Node.js version - ([Thomas David](https://codeberg.org/tjdavid))
|
|
31
|
+
- 7b40a42 fix: script identifier path - ([Thomas David](https://codeberg.org/tjdavid))
|
|
32
|
+
- a9300f7 docs: update example commands in readme.md - ([Thomas David](https://codeberg.org/tjdavid))
|
|
33
|
+
- b128309 npmignore codeberg ci - ([Thomas David](https://codeberg.org/tjdavid))
|
|
34
|
+
- 398737d docs: use absolute path for logo - ([Thomas David](https://codeberg.org/tjdavid))
|
|
35
|
+
- 68eb2c7 docs: update readme image to logo.png - ([Thomas David](https://codeberg.org/tjdavid))
|
|
36
|
+
|
|
37
|
+
### Metadata
|
|
38
|
+
```
|
|
39
|
+
This version -------- v0.11.1
|
|
40
|
+
Previous version ---- v0.11.0
|
|
41
|
+
Total commits ------- 8
|
|
42
|
+
```
|
|
43
|
+
|
|
3
44
|
## Release: `v0.11.0`
|
|
4
45
|
|
|
5
46
|
### Changes from `v0.10.0` to `v0.11.0`
|
|
6
47
|
|
|
7
|
-
- 56f6474 (
|
|
8
|
-
- 29b2c6a
|
|
48
|
+
- 56f6474 (tag: v0.11.0) chore: bump version to 0.11.0 - ([Thomas David](https://codeberg.org/tjdavid))
|
|
49
|
+
- 29b2c6a chore: Remove unused test-unit script - ([Thomas David](https://codeberg.org/tjdavid))
|
|
9
50
|
- 38a7c85 test: add test for cast names from local JSON file - ([Thomas David](https://codeberg.org/tjdavid))
|
|
10
51
|
- 7605e09 docs: update ignoreByAttribute config format to use objects - ([Thomas David](https://codeberg.org/tjdavid))
|
|
11
52
|
- 8e13c2d types: update ignoreByAttribute to use object structure - ([Thomas David](https://codeberg.org/tjdavid))
|
|
@@ -1138,6 +1179,6 @@ Total commits ------- 86
|
|
|
1138
1179
|
|
|
1139
1180
|
## Summary
|
|
1140
1181
|
```
|
|
1141
|
-
Total releases ------
|
|
1142
|
-
Total commits -------
|
|
1182
|
+
Total releases ------ 27
|
|
1183
|
+
Total commits ------- 474
|
|
1143
1184
|
```
|
package/lib/collection.js
CHANGED
|
@@ -72,7 +72,7 @@ CoraliteCollection.prototype.setItem = function (value) {
|
|
|
72
72
|
const documentValue = value
|
|
73
73
|
|
|
74
74
|
if (!originalValue) {
|
|
75
|
-
//
|
|
75
|
+
// handle pre-set hook if defined
|
|
76
76
|
if (typeof this._onSet === 'function') {
|
|
77
77
|
const result = this._onSet(value)
|
|
78
78
|
|
|
@@ -82,21 +82,21 @@ CoraliteCollection.prototype.setItem = function (value) {
|
|
|
82
82
|
documentValue.type = result.type
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
//
|
|
85
|
+
// update collection using ID from hook result if available
|
|
86
86
|
if (typeof result.id === 'string' && result.id) {
|
|
87
87
|
this.collection[result.id] = documentValue
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
//
|
|
91
|
+
// always update the collection with current pathname
|
|
92
92
|
this.collection[pathname] = documentValue
|
|
93
93
|
|
|
94
|
-
//
|
|
94
|
+
// initialize directory list if it doesn't exist
|
|
95
95
|
if (!this.listByPath[dirname]) {
|
|
96
96
|
this.listByPath[dirname] = []
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
//
|
|
99
|
+
// add to both directory-specific and general lists
|
|
100
100
|
this.listByPath[dirname].push(documentValue)
|
|
101
101
|
this.list.push(documentValue)
|
|
102
102
|
} else {
|
|
@@ -122,12 +122,12 @@ CoraliteCollection.prototype.deleteItem = function (value) {
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
if (typeof value !== 'string' && value.path) {
|
|
125
|
-
//
|
|
125
|
+
// if the input is an HTMLData object, extract its pathname and directory name
|
|
126
126
|
pathname = value.path.pathname
|
|
127
127
|
dirname = value.path.dirname
|
|
128
128
|
valuesByPath = this.listByPath[dirname]
|
|
129
129
|
} else if (pathname && typeof pathname == 'string') {
|
|
130
|
-
//
|
|
130
|
+
// if the input is a string, use it as the pathname and determine the directory name
|
|
131
131
|
dirname = path.dirname(pathname)
|
|
132
132
|
valuesByPath = this.listByPath[dirname]
|
|
133
133
|
} else {
|
|
@@ -141,10 +141,10 @@ CoraliteCollection.prototype.deleteItem = function (value) {
|
|
|
141
141
|
const originalValue = this.collection[pathname]
|
|
142
142
|
|
|
143
143
|
if (originalValue) {
|
|
144
|
-
//
|
|
144
|
+
// remove the document from the collection
|
|
145
145
|
delete this.collection[pathname]
|
|
146
146
|
|
|
147
|
-
//
|
|
147
|
+
// find and remove the document from the list and by-path grouping
|
|
148
148
|
const listIndex = this.list.indexOf(originalValue)
|
|
149
149
|
const pathIndex = valuesByPath.indexOf(originalValue)
|
|
150
150
|
|
|
@@ -164,7 +164,7 @@ CoraliteCollection.prototype.updateItem = function (value) {
|
|
|
164
164
|
const originalValue = this.collection[value.path.pathname]
|
|
165
165
|
|
|
166
166
|
if (!originalValue) {
|
|
167
|
-
//
|
|
167
|
+
// if the document does not exist, add it using the set method
|
|
168
168
|
this.setItem(value)
|
|
169
169
|
} else {
|
|
170
170
|
if (typeof this._onUpdate === 'function') {
|
package/lib/coralite.js
CHANGED
|
@@ -5,6 +5,7 @@ import { resolve, join } from 'node:path'
|
|
|
5
5
|
import { createContext, SourceTextModule } from 'node:vm'
|
|
6
6
|
import { defineComponent } from '#plugins'
|
|
7
7
|
import { existsSync } from 'node:fs'
|
|
8
|
+
import { mkdir, writeFile } from 'node:fs/promises'
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* @import {
|
|
@@ -22,6 +23,7 @@ import { existsSync } from 'node:fs'
|
|
|
22
23
|
* CoralitePluginInstance,
|
|
23
24
|
* CoraliteCollectionEventSet,
|
|
24
25
|
* IgnoreByAttribute} from '#types'
|
|
26
|
+
* @import CoraliteCollection from './collection.js'
|
|
25
27
|
* @import {Module} from 'node:vm'
|
|
26
28
|
*/
|
|
27
29
|
|
|
@@ -50,9 +52,7 @@ export function Coralite ({
|
|
|
50
52
|
templates,
|
|
51
53
|
pages
|
|
52
54
|
}
|
|
53
|
-
|
|
54
55
|
this.values = {}
|
|
55
|
-
|
|
56
56
|
this.templates = getHtmlFiles({
|
|
57
57
|
path: templates,
|
|
58
58
|
recursive: true,
|
|
@@ -149,6 +149,7 @@ export function Coralite ({
|
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
/** @type {CoraliteCollection} */
|
|
152
153
|
this.pages = getHtmlFiles({
|
|
153
154
|
path: pages,
|
|
154
155
|
recursive: true,
|
|
@@ -265,14 +266,10 @@ export function Coralite ({
|
|
|
265
266
|
* and returns rendered results with performance metrics.
|
|
266
267
|
*
|
|
267
268
|
* @param {string | string[]} [path] - Path to a single page or array of page paths relative to the pages directory. If omitted, compiles all pages.
|
|
268
|
-
* @return {Promise<Array<CoraliteResult>>}
|
|
269
|
-
* - item: The compiled document object
|
|
270
|
-
* - html: Rendered HTML string
|
|
271
|
-
* - duration: Total render time in milliseconds (if performance measurement is enabled)
|
|
269
|
+
* @return {Promise<Array<CoraliteResult>>}
|
|
272
270
|
*/
|
|
273
271
|
Coralite.prototype.compile = async function (path) {
|
|
274
272
|
const startTime = performance.now()
|
|
275
|
-
|
|
276
273
|
this._currentRenderQueue = this.pages.list.slice()
|
|
277
274
|
|
|
278
275
|
if (Array.isArray(path)) {
|
|
@@ -377,6 +374,35 @@ Coralite.prototype.compile = async function (path) {
|
|
|
377
374
|
return results
|
|
378
375
|
}
|
|
379
376
|
|
|
377
|
+
/**
|
|
378
|
+
* Saves processed documents as HTML files to the specified output directory.
|
|
379
|
+
* @param {Array<CoraliteResult>} documents - Array of document objects containing metadata and HTML content
|
|
380
|
+
* @param {string} output - Base directory path where generated HTML files will be saved
|
|
381
|
+
*/
|
|
382
|
+
Coralite.prototype.save = async function (documents, output) {
|
|
383
|
+
try {
|
|
384
|
+
// create a list of promises for writing each document's HTML file
|
|
385
|
+
const writePromises = documents.map(async (document) => {
|
|
386
|
+
const dir = join(output, document.item.path.dirname)
|
|
387
|
+
const filename = join(dir, document.item.path.filename)
|
|
388
|
+
|
|
389
|
+
// ensure the directory exists
|
|
390
|
+
await mkdir(dir, { recursive: true })
|
|
391
|
+
|
|
392
|
+
// write the HTML content to the file
|
|
393
|
+
await writeFile(filename, document.html)
|
|
394
|
+
|
|
395
|
+
return filename
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
// wait for all files to be written
|
|
399
|
+
const outputFiles = await Promise.all(writePromises)
|
|
400
|
+
return outputFiles
|
|
401
|
+
} catch (error) {
|
|
402
|
+
throw error
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
380
406
|
/**
|
|
381
407
|
* Renders the provided node or array of nodes using the render function.
|
|
382
408
|
* This method serves as an internal utility to handle the rendering process.
|
|
@@ -396,22 +422,22 @@ Coralite.prototype._render = function (root) {
|
|
|
396
422
|
* @returns {string[]} An array of page paths linked to the custom element template.
|
|
397
423
|
*/
|
|
398
424
|
Coralite.prototype.getPagePathsUsingCustomElement = function (path) {
|
|
399
|
-
//
|
|
425
|
+
// normalize path by removing the templates directory prefix
|
|
400
426
|
if (path.startsWith(this.path.templates)) {
|
|
401
427
|
path = path.substring(this.path.templates.length + 1)
|
|
402
428
|
}
|
|
403
429
|
|
|
404
|
-
//
|
|
430
|
+
// retrieve the template item from the templates collection
|
|
405
431
|
const item = this.templates.getItem(path)
|
|
406
432
|
const pages = []
|
|
407
433
|
|
|
408
|
-
//
|
|
434
|
+
// if template exists, collect associated page paths
|
|
409
435
|
if (item) {
|
|
410
436
|
const id = this._childCustomElements[item.result.id] || item.result.id
|
|
411
437
|
const pageCustomElements = this._pageCustomElements[id]
|
|
412
438
|
|
|
413
439
|
if (pageCustomElements) {
|
|
414
|
-
//
|
|
440
|
+
// iterate over custom element paths linked to this template
|
|
415
441
|
pageCustomElements.forEach(path => {
|
|
416
442
|
pages.push(path)
|
|
417
443
|
})
|
|
@@ -454,10 +480,10 @@ Coralite.prototype.addRenderQueue = function (value) {
|
|
|
454
480
|
*
|
|
455
481
|
* @example
|
|
456
482
|
* ```
|
|
457
|
-
* //
|
|
483
|
+
* // example usage:
|
|
458
484
|
* const component = await createComponent({
|
|
459
485
|
* id: 'my-component',
|
|
460
|
-
*
|
|
486
|
+
* tokens: {
|
|
461
487
|
* 'some-value': 'value-for-template'
|
|
462
488
|
* },
|
|
463
489
|
* components: {
|
|
@@ -490,7 +516,7 @@ Coralite.prototype.createComponent = async function ({
|
|
|
490
516
|
values = Object.assign(values, element.attribs)
|
|
491
517
|
}
|
|
492
518
|
|
|
493
|
-
//
|
|
519
|
+
// convert object keys to camel case format for consistent naming conventions
|
|
494
520
|
values = cleanKeys(values)
|
|
495
521
|
}
|
|
496
522
|
|
|
@@ -734,6 +760,7 @@ Coralite.prototype._evaluate = async function ({
|
|
|
734
760
|
contextId
|
|
735
761
|
}) {
|
|
736
762
|
this._currentSourceContextId = contextId
|
|
763
|
+
|
|
737
764
|
const context = {
|
|
738
765
|
...this._sourceContext,
|
|
739
766
|
document,
|
|
@@ -744,7 +771,7 @@ Coralite.prototype._evaluate = async function ({
|
|
|
744
771
|
}
|
|
745
772
|
|
|
746
773
|
this._sourceContextInstances[contextId] = context
|
|
747
|
-
//
|
|
774
|
+
// create a new context object with the provided context and global objects
|
|
748
775
|
const contextifiedObject = createContext({
|
|
749
776
|
console: globalThis.console,
|
|
750
777
|
crypto: globalThis.crypto,
|
|
@@ -753,22 +780,22 @@ Coralite.prototype._evaluate = async function ({
|
|
|
753
780
|
const template = this.templates.getItem(module.id)
|
|
754
781
|
let parentPath = template.path.dirname
|
|
755
782
|
|
|
756
|
-
//
|
|
783
|
+
// resolve the parent path of the template
|
|
757
784
|
if (!existsSync(parentPath)) {
|
|
758
785
|
parentPath = resolve(join(this.path.templates, template.path.dirname))
|
|
759
786
|
|
|
760
787
|
if (!existsSync(parentPath)) {
|
|
761
|
-
throw new Error('
|
|
788
|
+
throw new Error('Template directory not found: ' + parentPath)
|
|
762
789
|
}
|
|
763
790
|
}
|
|
764
791
|
|
|
765
|
-
//
|
|
792
|
+
// create a new source text module with the provided script content, configuration options, and context
|
|
766
793
|
const script = new SourceTextModule(module.script, {
|
|
767
794
|
initializeImportMeta (meta) {
|
|
768
795
|
meta.url = process.cwd()
|
|
769
796
|
},
|
|
770
797
|
lineOffset: module.lineOffset,
|
|
771
|
-
identifier: parentPath,
|
|
798
|
+
identifier: join(parentPath, template.path.filename),
|
|
772
799
|
context: contextifiedObject
|
|
773
800
|
})
|
|
774
801
|
|
|
@@ -776,20 +803,17 @@ Coralite.prototype._evaluate = async function ({
|
|
|
776
803
|
|
|
777
804
|
await script.link(linker)
|
|
778
805
|
|
|
779
|
-
//
|
|
806
|
+
// evaluate the module to execute its content
|
|
780
807
|
await script.evaluate()
|
|
781
808
|
|
|
782
809
|
// @ts-ignore
|
|
783
810
|
if (script.namespace.default) {
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
} catch (err) {
|
|
787
|
-
throw err
|
|
788
|
-
}
|
|
811
|
+
// @ts-ignore
|
|
812
|
+
return await script.namespace.default
|
|
789
813
|
}
|
|
790
814
|
|
|
791
|
-
//
|
|
792
|
-
throw new Error(
|
|
815
|
+
// throw an error if no default export was found
|
|
816
|
+
throw new Error(`Module "${module.id}" has no default export`)
|
|
793
817
|
}
|
|
794
818
|
|
|
795
819
|
/**
|
|
@@ -871,7 +895,7 @@ function replaceToken ({
|
|
|
871
895
|
for (let i = 0; i < value.length; i++) {
|
|
872
896
|
const child = value[i]
|
|
873
897
|
|
|
874
|
-
if (typeof child !== 'string') {
|
|
898
|
+
if (typeof child !== 'string' && child.type !== 'directive') {
|
|
875
899
|
// update child parent
|
|
876
900
|
child.parent = node.parent
|
|
877
901
|
children.push(child)
|
package/lib/html.js
CHANGED
|
@@ -22,7 +22,7 @@ import CoraliteCollection from './collection.js'
|
|
|
22
22
|
* @returns {CoraliteCollection} Array of HTML file data including parent path, name, and content
|
|
23
23
|
*
|
|
24
24
|
* @example
|
|
25
|
-
* //
|
|
25
|
+
* // example usage:
|
|
26
26
|
* const htmlFiles = await getHtmlFiles({
|
|
27
27
|
* path: 'src',
|
|
28
28
|
* recursive: true,
|
package/lib/parse.js
CHANGED
|
@@ -136,7 +136,7 @@ export function parseHTML (string, ignoreByAttribute) {
|
|
|
136
136
|
/** @type {CoraliteModuleValues} */
|
|
137
137
|
const meta = {}
|
|
138
138
|
const prefix = '$'
|
|
139
|
-
//
|
|
139
|
+
// process metadata and populate values for rendering
|
|
140
140
|
for (const key in metadata) {
|
|
141
141
|
if (Object.prototype.hasOwnProperty.call(metadata, key)) {
|
|
142
142
|
const data = metadata[key]
|
|
@@ -144,7 +144,7 @@ export function parseHTML (string, ignoreByAttribute) {
|
|
|
144
144
|
|
|
145
145
|
if (Array.isArray(data)) {
|
|
146
146
|
let prefixName
|
|
147
|
-
//
|
|
147
|
+
// handle multiple metadata items as list
|
|
148
148
|
for (let i = 0; i < data.length; i++) {
|
|
149
149
|
const item = data[i]
|
|
150
150
|
let name = prefix + item.name
|
|
@@ -188,13 +188,13 @@ export function parseHTML (string, ignoreByAttribute) {
|
|
|
188
188
|
*
|
|
189
189
|
* @example
|
|
190
190
|
* ```
|
|
191
|
-
* //
|
|
191
|
+
* // example usage:
|
|
192
192
|
* const html = `<template id="home">
|
|
193
193
|
* <slot name="default">Hello</slot>
|
|
194
194
|
* </template>`;
|
|
195
195
|
* const module = parseModule(html, { ignoreByAttribute: [] });
|
|
196
196
|
*
|
|
197
|
-
* //
|
|
197
|
+
* // module object structure will be:
|
|
198
198
|
* //{
|
|
199
199
|
* // id: 'home',
|
|
200
200
|
* // template: { ... },
|
|
@@ -408,10 +408,10 @@ function addMetadata (meta, name, content) {
|
|
|
408
408
|
let entry = meta[name]
|
|
409
409
|
|
|
410
410
|
if (!entry) {
|
|
411
|
-
//
|
|
411
|
+
// if the metadata key does not exist, initialize it with the provided content.
|
|
412
412
|
meta[name] = content
|
|
413
413
|
} else {
|
|
414
|
-
//
|
|
414
|
+
// if the existing value is not an array, convert it into an array containing a single object
|
|
415
415
|
// with the name and content. This allows for handling multiple values under the same metadata key.
|
|
416
416
|
if (!Array.isArray(entry)) {
|
|
417
417
|
meta[name] = [{
|
|
@@ -420,8 +420,8 @@ function addMetadata (meta, name, content) {
|
|
|
420
420
|
}]
|
|
421
421
|
entry = meta[name]
|
|
422
422
|
}
|
|
423
|
-
//
|
|
424
|
-
//
|
|
423
|
+
// add the new content to the array as a new object, preserving existing entries.
|
|
424
|
+
// this is useful for adding multiple values (e.g., Open Graph metadata) under the same key.
|
|
425
425
|
entry.push({
|
|
426
426
|
name,
|
|
427
427
|
content
|
package/lib/type-helper.js
CHANGED
|
@@ -42,8 +42,6 @@ function isCoralitePageItem (obj) {
|
|
|
42
42
|
return isObject(obj) && obj.hasOwnProperty('path') && typeof obj.content === 'string'
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
// Export the functions (if using modules) - important for reusability
|
|
47
45
|
export {
|
|
48
46
|
isCoralitePageItem,
|
|
49
47
|
isCoraliteElement,
|
package/lib/utils.js
CHANGED
|
@@ -6,7 +6,7 @@ import { readFile } from 'node:fs/promises'
|
|
|
6
6
|
* @returns {string} - The camelCase version of the string
|
|
7
7
|
*/
|
|
8
8
|
function kebabToCamel (str) {
|
|
9
|
-
//
|
|
9
|
+
// replace each dash followed by a letter with the uppercase version of the letter
|
|
10
10
|
return str.replace(/[-|:]([a-z])/g, function (match, letter) {
|
|
11
11
|
return letter.toUpperCase()
|
|
12
12
|
})
|
|
@@ -23,7 +23,7 @@ export function cleanKeys (object) {
|
|
|
23
23
|
|
|
24
24
|
for (const key in object) {
|
|
25
25
|
if (Object.prototype.hasOwnProperty.call(object, key)) {
|
|
26
|
-
//
|
|
26
|
+
// convert the kebab-case key to camelCase and assign the value to the new object
|
|
27
27
|
result[kebabToCamel(key)] = object[key]
|
|
28
28
|
}
|
|
29
29
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coralite",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.2",
|
|
4
4
|
"description": "HTML modules static site generator",
|
|
5
5
|
"main": "./lib/coralite.js",
|
|
6
6
|
"type": "module",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"sirv-cli": "^3.0.0"
|
|
73
73
|
},
|
|
74
74
|
"engines": {
|
|
75
|
-
"node": ">=18"
|
|
75
|
+
"node": ">=18.19.0"
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
78
|
"commander": "^13.0.0",
|
|
@@ -58,7 +58,7 @@ export const defineComponent = createPlugin({
|
|
|
58
58
|
} else {
|
|
59
59
|
for (let i = 0; i < result.customElements.length; i++) {
|
|
60
60
|
const customElement = result.customElements[i]
|
|
61
|
-
//
|
|
61
|
+
// create a component instance from the custom element and its attributes
|
|
62
62
|
const component = await this.createComponent({
|
|
63
63
|
id: customElement.name,
|
|
64
64
|
values,
|
|
@@ -93,7 +93,7 @@ export const defineComponent = createPlugin({
|
|
|
93
93
|
if (result.root.children.length) {
|
|
94
94
|
for (let i = 0; i < result.customElements.length; i++) {
|
|
95
95
|
const customElement = result.customElements[i]
|
|
96
|
-
//
|
|
96
|
+
// create a component instance from the custom element and its attributes
|
|
97
97
|
const component = await this.createComponent({
|
|
98
98
|
id: customElement.name,
|
|
99
99
|
values,
|
|
@@ -194,14 +194,14 @@ export const defineComponent = createPlugin({
|
|
|
194
194
|
* @param {CoraliteElement} element - The target element to replace the tokens with.
|
|
195
195
|
*/
|
|
196
196
|
async function replaceCustomElementWithTemplate (coraliteElement, element) {
|
|
197
|
-
//
|
|
197
|
+
// update parent references for new children to maintain the correct structure in the document
|
|
198
198
|
for (let i = 0; i < element.children.length; i++) {
|
|
199
199
|
element.children[i].parent = coraliteElement.parent
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
//
|
|
202
|
+
// determine the index of the original custom element within its parent's child list
|
|
203
203
|
const index = coraliteElement.parent.children.indexOf(coraliteElement, coraliteElement.parentChildIndex)
|
|
204
204
|
|
|
205
|
-
//
|
|
205
|
+
// replace the custom element with its template children in the document structure
|
|
206
206
|
coraliteElement.parent.children.splice(index, 1, ...element.children)
|
|
207
207
|
}
|
package/.woodpecker/publish.yml
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
name: Publish
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
release:
|
|
5
|
-
types: [created]
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
test:
|
|
9
|
-
runs-on: ubuntu-latest
|
|
10
|
-
steps:
|
|
11
|
-
- name: Checkout
|
|
12
|
-
uses: actions/checkout@v4
|
|
13
|
-
|
|
14
|
-
- uses: pnpm/action-setup@v4
|
|
15
|
-
name: Install pnpm
|
|
16
|
-
with:
|
|
17
|
-
version: 9
|
|
18
|
-
run_install: false
|
|
19
|
-
|
|
20
|
-
- name: Install Node.js
|
|
21
|
-
uses: actions/setup-node@v4
|
|
22
|
-
with:
|
|
23
|
-
node-version: 22
|
|
24
|
-
cache: "pnpm"
|
|
25
|
-
|
|
26
|
-
- name: Install dependencies
|
|
27
|
-
run: pnpm install
|
|
28
|
-
|
|
29
|
-
- name: Lint
|
|
30
|
-
run: pnpm run lint
|
|
31
|
-
|
|
32
|
-
- name: Test
|
|
33
|
-
run: pnpm run test-e2e
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
publish-npm:
|
|
37
|
-
needs: test
|
|
38
|
-
runs-on: ubuntu-latest
|
|
39
|
-
steps:
|
|
40
|
-
- uses: actions/checkout@v4
|
|
41
|
-
- uses: actions/setup-node@v4
|
|
42
|
-
with:
|
|
43
|
-
node-version: 22
|
|
44
|
-
registry-url: https://registry.npmjs.org/
|
|
45
|
-
- run: npm publish
|
|
46
|
-
env:
|
|
47
|
-
NODE_AUTH_TOKEN: ${{secrets.npm_token}}
|
|
48
|
-
|
package/.woodpecker/test-e2e.yml
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
name: Test e2e
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
- push
|
|
5
|
-
- pull_request
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
test:
|
|
9
|
-
timeout-minutes: 60
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
|
|
12
|
-
steps:
|
|
13
|
-
- name: Checkout
|
|
14
|
-
uses: actions/checkout@v4
|
|
15
|
-
|
|
16
|
-
- uses: pnpm/action-setup@v4
|
|
17
|
-
name: Install pnpm
|
|
18
|
-
with:
|
|
19
|
-
version: 9
|
|
20
|
-
run_install: false
|
|
21
|
-
|
|
22
|
-
- name: Install Node.js
|
|
23
|
-
uses: actions/setup-node@v4
|
|
24
|
-
with:
|
|
25
|
-
node-version: 22
|
|
26
|
-
cache: "pnpm"
|
|
27
|
-
|
|
28
|
-
- name: Install dependencies
|
|
29
|
-
run: pnpm install
|
|
30
|
-
|
|
31
|
-
- name: Add symlink
|
|
32
|
-
run: pnpm link
|
|
33
|
-
|
|
34
|
-
- name: Build HTML from templates
|
|
35
|
-
run: pnpm run html
|
|
36
|
-
|
|
37
|
-
- name: Install Playwright Browser
|
|
38
|
-
run: pnpm exec playwright install firefox --with-deps
|
|
39
|
-
|
|
40
|
-
- name: Run Playwright tests
|
|
41
|
-
run: pnpm exec playwright test
|
|
42
|
-
|
|
43
|
-
- uses: actions/upload-artifact@v4
|
|
44
|
-
if: ${{ !cancelled() }}
|
|
45
|
-
with:
|
|
46
|
-
name: playwright-report
|
|
47
|
-
path: playwright-report/
|
|
48
|
-
retention-days: 30
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
name: Test script
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
- push
|
|
5
|
-
- pull_request
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
linux:
|
|
9
|
-
runs-on: ubuntu-latest
|
|
10
|
-
|
|
11
|
-
steps:
|
|
12
|
-
- name: Checkout
|
|
13
|
-
uses: actions/checkout@v4
|
|
14
|
-
|
|
15
|
-
- uses: pnpm/action-setup@v4
|
|
16
|
-
name: Install pnpm
|
|
17
|
-
with:
|
|
18
|
-
version: 9
|
|
19
|
-
run_install: false
|
|
20
|
-
|
|
21
|
-
- name: Install Node.js
|
|
22
|
-
uses: actions/setup-node@v4
|
|
23
|
-
with:
|
|
24
|
-
node-version: 22
|
|
25
|
-
cache: "pnpm"
|
|
26
|
-
|
|
27
|
-
- name: Install dependencies
|
|
28
|
-
run: pnpm install
|
|
29
|
-
|
|
30
|
-
- name: Build HTML from templates
|
|
31
|
-
run: pnpm run html
|
|
32
|
-
macos:
|
|
33
|
-
runs-on: macos-15
|
|
34
|
-
|
|
35
|
-
steps:
|
|
36
|
-
- name: Checkout
|
|
37
|
-
uses: actions/checkout@v4
|
|
38
|
-
|
|
39
|
-
- uses: pnpm/action-setup@v4
|
|
40
|
-
name: Install pnpm
|
|
41
|
-
with:
|
|
42
|
-
version: 9
|
|
43
|
-
run_install: false
|
|
44
|
-
|
|
45
|
-
- name: Install Node.js
|
|
46
|
-
uses: actions/setup-node@v4
|
|
47
|
-
with:
|
|
48
|
-
node-version: 22
|
|
49
|
-
cache: "pnpm"
|
|
50
|
-
|
|
51
|
-
- name: Install dependencies
|
|
52
|
-
run: pnpm install
|
|
53
|
-
|
|
54
|
-
- name: Add symlink
|
|
55
|
-
run: pnpm link
|
|
56
|
-
|
|
57
|
-
- name: Build HTML from templates
|
|
58
|
-
run: pnpm run html
|