chocola 2.0.0-next.2 → 2.0.0-next.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 +32 -45
- package/compiler/component-processor.js +271 -207
- package/compiler/config.js +1 -54
- package/compiler/dom-processor.js +0 -51
- package/compiler/fs.js +0 -11
- package/compiler/index.js +12 -32
- package/compiler/pipeline.js +7 -188
- package/compiler/runtime-generator.js +0 -6
- package/compiler/utils.js +0 -94
- package/package.json +1 -1
- package/utils.js +0 -5
package/compiler/utils.js
CHANGED
|
@@ -3,80 +3,11 @@ import path from "path";
|
|
|
3
3
|
import { pathToFileURL } from "url";
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* Throws a formatted error message and exits
|
|
8
|
-
* @param {string|Error} err - Error message or Error object
|
|
9
|
-
* @throws {Error}
|
|
10
|
-
*/
|
|
11
6
|
export function throwError(err) {
|
|
12
7
|
console.log(chalk.red.bold("Error!"), "A fatal error has occurred:\n");
|
|
13
8
|
throw new Error(err);
|
|
14
9
|
}
|
|
15
10
|
|
|
16
|
-
/**
|
|
17
|
-
* Loads a JavaScript module and inlines asset imports (HTML/CSS files)
|
|
18
|
-
* This allows components to import external template files as strings
|
|
19
|
-
* @param {import("fs").PathLike} filePath - Path to the JavaScript file
|
|
20
|
-
* @returns {Promise<object>} - The imported module
|
|
21
|
-
* @example
|
|
22
|
-
* // Component with asset import
|
|
23
|
-
* import template from "./button.html";
|
|
24
|
-
* export default function Button() { return { body: template }; }
|
|
25
|
-
*/
|
|
26
|
-
export async function loadWithAssets(filePath) {
|
|
27
|
-
let code;
|
|
28
|
-
try {
|
|
29
|
-
code = await fs.readFile(filePath, "utf8");
|
|
30
|
-
} catch (err) {
|
|
31
|
-
throwError(`Failed to read component file "${filePath}": ${err.message || err}`);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const importRegex = /import\s+(\w+)\s+from\s+["'](.+?\.(html|css))["'];?/g;
|
|
35
|
-
|
|
36
|
-
const replacements = [];
|
|
37
|
-
let match;
|
|
38
|
-
while ((match = importRegex.exec(code))) {
|
|
39
|
-
const varName = match[1];
|
|
40
|
-
const relPath = match[2];
|
|
41
|
-
const absPath = path.resolve(path.dirname(filePath), relPath);
|
|
42
|
-
|
|
43
|
-
let content;
|
|
44
|
-
try {
|
|
45
|
-
content = await fs.readFile(absPath, "utf8");
|
|
46
|
-
} catch (err) {
|
|
47
|
-
throwError(
|
|
48
|
-
`Failed to read imported file "${relPath}" (resolved to "${absPath}") ` +
|
|
49
|
-
`for variable "${varName}" in component "${filePath}": ${err.message || err}`
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
replacements.push({ from: match[0], to: `const ${varName} = ${JSON.stringify(content)};` });
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
for (const { from, to } of replacements) {
|
|
57
|
-
code = code.replace(from, to);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const dataUrl =
|
|
61
|
-
"data:text/javascript;base64," +
|
|
62
|
-
Buffer.from(code).toString("base64");
|
|
63
|
-
|
|
64
|
-
try {
|
|
65
|
-
const mod = await import(dataUrl);
|
|
66
|
-
return mod;
|
|
67
|
-
} catch (err) {
|
|
68
|
-
throwError(
|
|
69
|
-
`Failed to evaluate component "${filePath}": ${err.message || err}`
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Generates a random ID string
|
|
76
|
-
* @param {Array} collection - Array to track used IDs (prevents duplicates)
|
|
77
|
-
* @param {number} length - Desired length of the ID (default: 10)
|
|
78
|
-
* @returns {string} - Unique random ID
|
|
79
|
-
*/
|
|
80
11
|
export function genRandomId(collection = null, length = 10, lettersOnly = false) {
|
|
81
12
|
let id;
|
|
82
13
|
if (lettersOnly) {
|
|
@@ -93,14 +24,6 @@ export function genRandomId(collection = null, length = 10, lettersOnly = false)
|
|
|
93
24
|
}
|
|
94
25
|
}
|
|
95
26
|
|
|
96
|
-
/**
|
|
97
|
-
* Increments a letter or sequence of letters like Excel columns (a → b, z → aa)
|
|
98
|
-
* @param {string} letters - Letter(s) to increment
|
|
99
|
-
* @returns {string} - Incremented letter(s)
|
|
100
|
-
* @example
|
|
101
|
-
* incrementAlfabet("a") // "b"
|
|
102
|
-
* incrementAlfabet("z") // "aa"
|
|
103
|
-
*/
|
|
104
27
|
export function incrementAlfabet(letters) {
|
|
105
28
|
let arr = letters.split("");
|
|
106
29
|
let i = arr.length - 1;
|
|
@@ -119,11 +42,6 @@ export function incrementAlfabet(letters) {
|
|
|
119
42
|
return "a" + arr.join("");
|
|
120
43
|
}
|
|
121
44
|
|
|
122
|
-
/**
|
|
123
|
-
* Checks if a string is a valid HTTP/HTTPS URL
|
|
124
|
-
* @param {string} str - String to check
|
|
125
|
-
* @returns {boolean} - True if valid web link, false otherwise
|
|
126
|
-
*/
|
|
127
45
|
export function isWebLink(str) {
|
|
128
46
|
try {
|
|
129
47
|
const url = new URL(str);
|
|
@@ -136,24 +54,12 @@ export function isWebLink(str) {
|
|
|
136
54
|
const LBRACE_PH = "_%%CHOCOLA-LBRACE%%_";
|
|
137
55
|
const RBRACE_PH = "_%%CHOCOLA-RBRACE%%_";
|
|
138
56
|
|
|
139
|
-
/**
|
|
140
|
-
* Replaces HTML entities for curly braces with placeholders before JSDOM parsing.
|
|
141
|
-
* This prevents JSDOM from decoding them into literal braces before binding processing.
|
|
142
|
-
* @param {string} html - Raw HTML content
|
|
143
|
-
* @returns {string} - HTML with curly brace entities replaced
|
|
144
|
-
*/
|
|
145
57
|
export function protectCurlyBraces(html) {
|
|
146
58
|
return html
|
|
147
59
|
.replace(/&(?:lbrace|#123|#x7B);/gi, LBRACE_PH)
|
|
148
60
|
.replace(/&(?:rcub|#125|#x7D);/gi, RBRACE_PH);
|
|
149
61
|
}
|
|
150
62
|
|
|
151
|
-
/**
|
|
152
|
-
* Restores curly brace placeholders back to literal characters.
|
|
153
|
-
* Called after binding processing is complete and before final output.
|
|
154
|
-
* @param {string} html - Serialized HTML with placeholders
|
|
155
|
-
* @returns {string} - HTML with literal curly braces restored
|
|
156
|
-
*/
|
|
157
63
|
export function restoreCurlyBraces(html) {
|
|
158
64
|
return html
|
|
159
65
|
.replace(/_%%CHOCOLA-LBRACE%%_/g, "{")
|
package/package.json
CHANGED
package/utils.js
CHANGED
|
@@ -2,11 +2,6 @@ import { promises as fs } from "fs";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { throwError } from "./compiler/utils.js";
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* Returns `chocola.config.json` as an object.
|
|
7
|
-
* @param {import("fs").PathLike} __rootdir
|
|
8
|
-
* @returns {Object}
|
|
9
|
-
*/
|
|
10
5
|
export async function getChocolaConfig(__rootdir) {
|
|
11
6
|
try {
|
|
12
7
|
const config = await fs.readFile(path.join(__rootdir, "chocola.config.json"), "utf-8");
|