coralite 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/coralite.js +1 -1
- package/changelog.md +60 -6
- package/lib/coralite.js +101 -41
- package/lib/get-html.js +32 -4
- package/lib/html-module.js +286 -43
- package/lib/index.js +2 -3
- package/lib/parse.js +159 -107
- package/lib/utils.js +56 -0
- package/package.json +1 -1
- package/types/index.js +34 -16
- package/lib/path-utils.js +0 -26
package/bin/coralite.js
CHANGED
package/changelog.md
CHANGED
|
@@ -1,12 +1,66 @@
|
|
|
1
|
+
# 🎁 Release notes (`v0.8.0`)
|
|
2
|
+
|
|
3
|
+
## Changes
|
|
4
|
+
- 25c4669 (HEAD -> main, tag: v0.8.0, origin/main) feat(aggregate): add pagination support - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
5
|
+
- 1268e3c fix(aggregate): handle non-array metadata values correctly - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
6
|
+
- 42c3ae0 fix(aggregate): handle string and non-array limit values correctly - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
7
|
+
- 0538a80 fix(aggregate): Handle offset parsing robustly for numeric conversion - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
8
|
+
- 4d2fe56 feat(aggregate): Add metadata-based page filtering using options.filter - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
9
|
+
- 176c7f3 feat(lib/html-module): add support for custom sort function in aggregate - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
10
|
+
- 3acfb99 feat(lib/html-module): add pagination support with token validation - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
11
|
+
- 41b0e10 refactor(lib): integrate htmlparser2 and dom-serializer for improved HTML parsing - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
12
|
+
- 0c7fb5e refactor(html-module): update aggregate to use component element children and return Aggregation object - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
13
|
+
- 6bb83d3 refactor: restructure document rendering logic and add HTMLData type support - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
14
|
+
- 8d4b43c refactor: move coralite rendering logic to new renderDocument function - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
15
|
+
- c81786e types: add pagination configuration to CoraliteAggregate - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
16
|
+
- c8ddec4 feat(metadata): Update metadata token prefix to '$' - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
17
|
+
- ee57e18 feat: add parsePagination function for handling pagination templates - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
18
|
+
- 4471482 types: add Aggregation typedef and update imports - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
19
|
+
- 2772969 docs: Improve JSDoc clarity for parseHTMLDocument function - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
20
|
+
- 37e79db refactor: restructure html file path properties - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
21
|
+
- dab3a61 refactor: Export createTextNode function - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
22
|
+
- c538186 fix: handle custom element creation with proper tag validation - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
23
|
+
- 58d101d refactor: update addMetadata to support non-array values as array of objects - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
24
|
+
- d0fa67c docs: update parseHTMLMeta parameters and example documentation - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
25
|
+
- de8035e fix: correct path calculation in parseScript function - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
26
|
+
- b9c94ee refactor(parse): use scriptResult.values instead of computedValues when merging values - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
27
|
+
- 7b0be0c fix: correct script parsing path resolution and module identifier - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
28
|
+
- 803aa3e refactor(parse): refactor aggregate method to use helper and collect documents - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
29
|
+
- 2c77b44 fix: add warning when component is not found - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
30
|
+
- 885fd6c refactor(parseModule): remove html parameter and introduce lineOffset property - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
31
|
+
- 84c8a74 types: allow string or CoraliteToken[] as meta value types - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
32
|
+
- 0b9ce81 refactor: merge html.path into path object in parseHTMLDocument - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
33
|
+
- 1964a60 types: update JSDoc types for aggregate callbacks - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
34
|
+
- 2205c1a types: Refactor types to introduce CoraliteFilePath and improve module interface definitions - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
35
|
+
- c37fa7c docs: add CoraliteComponent import - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
36
|
+
- 281e07e refactor: rename getHTML to getHtmlFiles and add getHtmlFile function - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
37
|
+
- f91251a types: Update return type of createComponent to CoraliteComponent - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
38
|
+
- d6fab1e refactor: use cleanKeys for consistent naming conventions - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
39
|
+
- dfe3b06 docs: update aggregate comments - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
40
|
+
- 6a495f3 feat: add document data to component - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
41
|
+
- 17afeb4 feat: require experimental-import-meta-resolve for dynamic imports - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
42
|
+
- 34ccd76 feat: dynamic module linker - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
43
|
+
- 828bcaa feat: add console to script context - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
44
|
+
- 47ab7db chore: version bump - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
45
|
+
- 4c7f361 fix kleur dependencies - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
46
|
+
- 2f88f2d chore: update changelong - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
47
|
+
- aedf75f chore: version bump - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
48
|
+
|
|
49
|
+
## Metadata
|
|
50
|
+
```
|
|
51
|
+
This version -------- v0.8.0
|
|
52
|
+
Previous version ---- v0.7.0
|
|
53
|
+
Total commits ------- 44
|
|
54
|
+
```
|
|
1
55
|
# 🎁 Release notes (`v0.7.0`)
|
|
2
56
|
|
|
3
57
|
## Changes
|
|
4
|
-
- d7b183d (HEAD -> main, tag: v0.7.0, origin/main) fix: use type helper to confirm child is a node - (*Thomas David*)
|
|
5
|
-
- b574569 feat: check if slot is a node - (*Thomas David*)
|
|
6
|
-
- de05e38 feat: type helper functions - (*Thomas David*)
|
|
7
|
-
- 24f3935 test: cover nested components attributes - (*Thomas David*)
|
|
8
|
-
- 8dc8f5d fix: apply nested custom component attribute values - (*Thomas David*)
|
|
9
|
-
- 3fa3eb5 chore: version bump - (*Thomas David*)
|
|
58
|
+
- d7b183d (HEAD -> main, tag: v0.7.0, origin/main) fix: use type helper to confirm child is a node - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
59
|
+
- b574569 feat: check if slot is a node - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
60
|
+
- de05e38 feat: type helper functions - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
61
|
+
- 24f3935 test: cover nested components attributes - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
62
|
+
- 8dc8f5d fix: apply nested custom component attribute values - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
63
|
+
- 3fa3eb5 chore: version bump - (*[Thomas David](https://codeberg.org/tjdavid)*)
|
|
10
64
|
|
|
11
65
|
## Metadata
|
|
12
66
|
```
|
package/lib/coralite.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createComponent, parseHTMLDocument, parseModule,
|
|
1
|
+
import { createComponent, parseHTMLDocument, parseModule, getHtmlFiles } from '#lib'
|
|
2
2
|
import render from 'dom-serializer'
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -8,8 +8,9 @@ import render from 'dom-serializer'
|
|
|
8
8
|
* CoraliteAnyNode,
|
|
9
9
|
* CoraliteModule,
|
|
10
10
|
* CoraliteResult,
|
|
11
|
-
* CoraliteAggregate
|
|
12
|
-
*
|
|
11
|
+
* CoraliteAggregate,
|
|
12
|
+
* IgnoreByAttribute,
|
|
13
|
+
* HTMLData } from '#types'
|
|
13
14
|
*/
|
|
14
15
|
|
|
15
16
|
/**
|
|
@@ -86,69 +87,128 @@ export async function coralite ({
|
|
|
86
87
|
ignoreByAttribute
|
|
87
88
|
}) {
|
|
88
89
|
const startTime = performance.now()
|
|
89
|
-
const htmlTemplates = await
|
|
90
|
+
const htmlTemplates = await getHtmlFiles({
|
|
90
91
|
path: templates,
|
|
91
92
|
recursive: true
|
|
92
93
|
})
|
|
93
|
-
const htmlPages = await
|
|
94
|
+
const htmlPages = await getHtmlFiles({
|
|
94
95
|
path: pages,
|
|
95
96
|
recursive: true
|
|
96
97
|
})
|
|
97
98
|
|
|
98
99
|
/** @type {Object.<string, CoraliteModule>} */
|
|
99
|
-
const
|
|
100
|
-
/** @type {CoraliteResult[]} */
|
|
101
|
-
const documents = []
|
|
100
|
+
const components = {}
|
|
102
101
|
|
|
103
102
|
// create templates
|
|
104
103
|
for (let i = 0; i < htmlTemplates.length; i++) {
|
|
105
104
|
const html = htmlTemplates[i]
|
|
106
|
-
const
|
|
105
|
+
const component = parseModule(html.content, {
|
|
106
|
+
ignoreByAttribute
|
|
107
|
+
})
|
|
107
108
|
|
|
108
|
-
|
|
109
|
+
components[component.id] = {
|
|
110
|
+
...component,
|
|
111
|
+
path: html.path
|
|
112
|
+
}
|
|
109
113
|
}
|
|
110
114
|
|
|
115
|
+
/** @type {CoraliteResult[]} */
|
|
116
|
+
const documents = []
|
|
117
|
+
|
|
111
118
|
for (let i = 0; i < htmlPages.length; i++) {
|
|
112
119
|
const html = htmlPages[i]
|
|
113
|
-
|
|
120
|
+
await renderDocument({
|
|
121
|
+
html,
|
|
114
122
|
pages,
|
|
115
|
-
templates
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
123
|
+
templates,
|
|
124
|
+
ignoreByAttribute,
|
|
125
|
+
components,
|
|
126
|
+
startTime,
|
|
127
|
+
documents
|
|
128
|
+
})
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return documents
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Renders an HTML document using the provided configuration and components.
|
|
136
|
+
*
|
|
137
|
+
* @param {Object} param
|
|
138
|
+
* @param {HTMLData} param.html - The raw HTML content to render.
|
|
139
|
+
* @param {string} param.pages - Path to the root pages directory.
|
|
140
|
+
* @param {string} param.templates - Path to the root templates directory.
|
|
141
|
+
* @param {IgnoreByAttribute} param.ignoreByAttribute - An array of attribute names and values to ignore by element type.
|
|
142
|
+
* @param {Object} param.components - Components configuration used during rendering.
|
|
143
|
+
* @param {number} param.startTime - Timestamp when rendering started (for performance tracking).
|
|
144
|
+
* @param {CoraliteResult[]} [param.documents=[]] - Array of rendered documents to accumulate results.
|
|
145
|
+
* @param {boolean} [param.isHead=true] - Whether this is the head section (controls recursive rendering behavior).
|
|
146
|
+
*
|
|
147
|
+
* @returns {Promise<CoraliteResult[]>} A promise that resolves to an array of rendered document results.
|
|
148
|
+
*/
|
|
149
|
+
async function renderDocument ({
|
|
150
|
+
html,
|
|
151
|
+
pages,
|
|
152
|
+
templates,
|
|
153
|
+
ignoreByAttribute,
|
|
154
|
+
components,
|
|
155
|
+
startTime,
|
|
156
|
+
documents = [],
|
|
157
|
+
isHead = true
|
|
158
|
+
}) {
|
|
159
|
+
const document = parseHTMLDocument(html, {
|
|
160
|
+
pages,
|
|
161
|
+
templates
|
|
162
|
+
}, ignoreByAttribute)
|
|
163
|
+
|
|
164
|
+
for (let i = 0; i < document.customElements.length; i++) {
|
|
165
|
+
const customElement = document.customElements[i]
|
|
166
|
+
const component = await createComponent({
|
|
167
|
+
id: customElement.name,
|
|
168
|
+
values: customElement.attribs,
|
|
169
|
+
element: customElement,
|
|
170
|
+
components,
|
|
171
|
+
document
|
|
172
|
+
})
|
|
132
173
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
174
|
+
if (component) {
|
|
175
|
+
const element = component.element
|
|
176
|
+
for (let i = 0; i < element.children.length; i++) {
|
|
177
|
+
// update component parent
|
|
178
|
+
element.children[i].parent = customElement.parent
|
|
136
179
|
}
|
|
180
|
+
|
|
137
181
|
const index = customElement.parent.children.indexOf(customElement, customElement.parentChildIndex)
|
|
138
182
|
// replace custom element with template
|
|
139
|
-
customElement.parent.children.splice(index, 1, ...
|
|
183
|
+
customElement.parent.children.splice(index, 1, ...element.children)
|
|
184
|
+
|
|
185
|
+
if (isHead && component.documents) {
|
|
186
|
+
for (let i = 0; i < component.documents.length; i++) {
|
|
187
|
+
const html = component.documents[i]
|
|
188
|
+
await renderDocument({
|
|
189
|
+
html,
|
|
190
|
+
pages,
|
|
191
|
+
templates,
|
|
192
|
+
ignoreByAttribute,
|
|
193
|
+
components,
|
|
194
|
+
startTime,
|
|
195
|
+
documents,
|
|
196
|
+
isHead: false
|
|
197
|
+
})
|
|
198
|
+
}
|
|
199
|
+
}
|
|
140
200
|
}
|
|
201
|
+
}
|
|
141
202
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
203
|
+
// render document
|
|
204
|
+
// @ts-ignore
|
|
205
|
+
const result = render(document.root)
|
|
145
206
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
207
|
+
documents.push({
|
|
208
|
+
item: document,
|
|
209
|
+
html: result,
|
|
210
|
+
duration: performance.now() - startTime
|
|
211
|
+
})
|
|
152
212
|
|
|
153
213
|
return documents
|
|
154
214
|
}
|
package/lib/get-html.js
CHANGED
|
@@ -15,13 +15,13 @@ import { readdir, readFile } from 'node:fs/promises'
|
|
|
15
15
|
*
|
|
16
16
|
* @example
|
|
17
17
|
* // Example usage:
|
|
18
|
-
* const htmlFiles = await
|
|
18
|
+
* const htmlFiles = await getHtmlFiles({
|
|
19
19
|
* path: 'src',
|
|
20
20
|
* recursive: true,
|
|
21
21
|
* exclude: ['index.html', 'subdir/file2.html']
|
|
22
22
|
* })
|
|
23
23
|
*/
|
|
24
|
-
export
|
|
24
|
+
export function getHtmlFiles ({ path, recursive = false, exclude = [] }) {
|
|
25
25
|
return new Promise((resolve, reject) => {
|
|
26
26
|
const html = []
|
|
27
27
|
|
|
@@ -39,10 +39,17 @@ export default function getHTML ({ path, recursive = false, exclude = [] }) {
|
|
|
39
39
|
&& !exclude.includes(file.name)
|
|
40
40
|
) {
|
|
41
41
|
const parentPath = file.parentPath || file.path
|
|
42
|
+
const dirname = parentPath.replace(path, '')
|
|
43
|
+
const name = file.name
|
|
42
44
|
|
|
43
45
|
html.push({
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
path: {
|
|
47
|
+
pathname: join(dirname, name),
|
|
48
|
+
filename: name,
|
|
49
|
+
dirname,
|
|
50
|
+
page: parentPath,
|
|
51
|
+
pageName: join(parentPath, name)
|
|
52
|
+
}
|
|
46
53
|
})
|
|
47
54
|
|
|
48
55
|
promises.push(readFile(join(parentPath, file.name), { encoding: 'utf8' }))
|
|
@@ -62,3 +69,24 @@ export default function getHTML ({ path, recursive = false, exclude = [] }) {
|
|
|
62
69
|
.catch(error => reject(error))
|
|
63
70
|
})
|
|
64
71
|
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Reads an HTML file and returns its content as a string.
|
|
75
|
+
* @param {string} filename - The path to the HTML file.
|
|
76
|
+
* @returns {Promise<string>} A promise that resolves with the HTML content.
|
|
77
|
+
* @throws {Error} If the file cannot be read.
|
|
78
|
+
*/
|
|
79
|
+
export async function getHtmlFile (filename) {
|
|
80
|
+
try {
|
|
81
|
+
const extension = extname(filename).toLowerCase()
|
|
82
|
+
|
|
83
|
+
if (extension === '.html') {
|
|
84
|
+
const data = await readFile(filename, 'utf8')
|
|
85
|
+
return data
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
throw new Error('Unexpected filename extension "' + extension +'"')
|
|
89
|
+
} catch (err) {
|
|
90
|
+
throw err
|
|
91
|
+
}
|
|
92
|
+
}
|