chocola 2.0.0-next.4 → 2.0.0-next.5
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 +12 -8
- package/compiler/chalk.js +32 -0
- package/compiler/component-processor.js +667 -553
- package/compiler/dom-processor.js +5 -3
- package/compiler/index.js +77 -79
- package/compiler/pipeline.js +40 -13
- package/compiler/utils.js +11 -13
- package/dev/index.js +1 -1
- package/package.json +4 -9
|
@@ -39,9 +39,7 @@ export function extractContextFromElement(element) {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export async function serializeDOM(dom) {
|
|
42
|
-
|
|
43
|
-
const finalHtml = restoreCurlyBraces(dom.serialize());
|
|
44
|
-
return beautify.html(finalHtml, { indent_size: 2 });
|
|
42
|
+
return restoreCurlyBraces(dom.serialize());
|
|
45
43
|
}
|
|
46
44
|
|
|
47
45
|
export async function writeHTMLOutput(html, outDirPath) {
|
|
@@ -66,6 +64,10 @@ export function appendStylesheetLink(doc, filename) {
|
|
|
66
64
|
doc.head.appendChild(linkEl);
|
|
67
65
|
}
|
|
68
66
|
|
|
67
|
+
export function getScriptElements(doc) {
|
|
68
|
+
return Array.from(doc.querySelectorAll("script[src]"));
|
|
69
|
+
}
|
|
70
|
+
|
|
69
71
|
export function appendRuntimeScript(doc, filename) {
|
|
70
72
|
const runtimeScriptEl = doc.createElement("script");
|
|
71
73
|
runtimeScriptEl.type = "module";
|
package/compiler/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { promises as fs } from "fs";
|
|
2
|
-
import chalk from "chalk";
|
|
2
|
+
import chalk from "./chalk.js";
|
|
3
3
|
import { loadConfig, resolvePaths } from "./config.js";
|
|
4
4
|
import {
|
|
5
5
|
createDOM,
|
|
6
6
|
validateAppContainer,
|
|
7
7
|
getAppElements,
|
|
8
8
|
getAssetLinks,
|
|
9
|
+
getScriptElements,
|
|
9
10
|
appendRuntimeScript,
|
|
10
11
|
appendStylesheetLink,
|
|
11
12
|
serializeDOM,
|
|
@@ -14,12 +15,13 @@ import {
|
|
|
14
15
|
} from "./dom-processor.js";
|
|
15
16
|
import { processAllComponents } from "./component-processor.js";
|
|
16
17
|
import { generateRuntimeScript } from "./runtime-generator.js";
|
|
17
|
-
import { genRandomId, throwError, compileExpression } from "./utils.js";
|
|
18
|
+
import { genRandomId, throwError, compileExpression, hasDelIfAttr, getDelIfAttr, removeDelIfAttr } from "./utils.js";
|
|
18
19
|
import {
|
|
19
20
|
copyStaticDir,
|
|
20
21
|
getComponents,
|
|
21
22
|
getSrcIndex,
|
|
22
23
|
processIcons,
|
|
24
|
+
processScript,
|
|
23
25
|
processStylesheet,
|
|
24
26
|
} from "./pipeline.js";
|
|
25
27
|
|
|
@@ -91,6 +93,7 @@ async function loadAndDisplayComponents(srcComponentsPath) {
|
|
|
91
93
|
|
|
92
94
|
async function processAssets(doc, rootDir, srcDir, outDirPath) {
|
|
93
95
|
const { stylesheets, icons } = getAssetLinks(doc);
|
|
96
|
+
const scripts = getScriptElements(doc);
|
|
94
97
|
const fileIds = [];
|
|
95
98
|
let cssContents = [];
|
|
96
99
|
|
|
@@ -102,9 +105,81 @@ async function processAssets(doc, rootDir, srcDir, outDirPath) {
|
|
|
102
105
|
for (const link of icons) {
|
|
103
106
|
await processIcons(link, rootDir, srcDir, outDirPath);
|
|
104
107
|
}
|
|
108
|
+
|
|
109
|
+
for (const script of scripts) {
|
|
110
|
+
await processScript(doc, script, rootDir, srcDir, outDirPath, fileIds);
|
|
111
|
+
}
|
|
105
112
|
return cssContents
|
|
106
113
|
}
|
|
107
114
|
|
|
115
|
+
function processPageConditionals(parent) {
|
|
116
|
+
const children = [...parent.children];
|
|
117
|
+
let chainActive = false;
|
|
118
|
+
let chainRendered = false;
|
|
119
|
+
|
|
120
|
+
for (const child of children) {
|
|
121
|
+
const hasIf = child.hasAttribute("if");
|
|
122
|
+
const hasDelIf = hasDelIfAttr(child);
|
|
123
|
+
const hasElif = child.hasAttribute("elif");
|
|
124
|
+
const hasElse = child.hasAttribute("else");
|
|
125
|
+
|
|
126
|
+
if (hasElif || hasElse) {
|
|
127
|
+
if (!chainActive) continue;
|
|
128
|
+
if (chainRendered) { child.remove(); continue; }
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (hasIf) {
|
|
132
|
+
const raw = child.getAttribute("if");
|
|
133
|
+
const expr = raw.startsWith("{") ? raw.slice(1, -1) : raw;
|
|
134
|
+
const fn = compileExpression(expr, false);
|
|
135
|
+
const result = fn();
|
|
136
|
+
chainActive = true;
|
|
137
|
+
if (result) {
|
|
138
|
+
chainRendered = true;
|
|
139
|
+
} else {
|
|
140
|
+
child.remove();
|
|
141
|
+
chainRendered = false;
|
|
142
|
+
}
|
|
143
|
+
child.removeAttribute("if");
|
|
144
|
+
} else if (hasDelIf) {
|
|
145
|
+
const raw = getDelIfAttr(child);
|
|
146
|
+
const expr = raw.startsWith("{") ? raw.slice(1, -1) : raw;
|
|
147
|
+
const fn = compileExpression(expr, false);
|
|
148
|
+
const result = fn();
|
|
149
|
+
chainActive = true;
|
|
150
|
+
if (result) {
|
|
151
|
+
chainRendered = true;
|
|
152
|
+
} else {
|
|
153
|
+
child.remove();
|
|
154
|
+
chainRendered = false;
|
|
155
|
+
}
|
|
156
|
+
removeDelIfAttr(child);
|
|
157
|
+
} else if (hasElif) {
|
|
158
|
+
const raw = child.getAttribute("elif");
|
|
159
|
+
const expr = raw.startsWith("{") ? raw.slice(1, -1) : raw;
|
|
160
|
+
const fn = compileExpression(expr, false);
|
|
161
|
+
const result = fn();
|
|
162
|
+
if (result) {
|
|
163
|
+
chainRendered = true;
|
|
164
|
+
} else {
|
|
165
|
+
child.remove();
|
|
166
|
+
}
|
|
167
|
+
child.removeAttribute("elif");
|
|
168
|
+
} else if (hasElse) {
|
|
169
|
+
chainRendered = true;
|
|
170
|
+
chainActive = false;
|
|
171
|
+
child.removeAttribute("else");
|
|
172
|
+
} else {
|
|
173
|
+
chainActive = false;
|
|
174
|
+
chainRendered = false;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (child.parentNode) {
|
|
178
|
+
processPageConditionals(child);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
108
183
|
export default async function compile(rootDir, buildConfig) {
|
|
109
184
|
const isHotReload = buildConfig?.isHotReload || null;
|
|
110
185
|
!isHotReload && logBanner();
|
|
@@ -129,83 +204,6 @@ export default async function compile(rootDir, buildConfig) {
|
|
|
129
204
|
const doc = dom.window.document;
|
|
130
205
|
const appContainer = validateAppContainer(doc);
|
|
131
206
|
|
|
132
|
-
function hasDelIfAttr(el) {
|
|
133
|
-
return el.hasAttribute("del:if");
|
|
134
|
-
}
|
|
135
|
-
function getDelIfAttr(el) {
|
|
136
|
-
return el.getAttribute("del:if");
|
|
137
|
-
}
|
|
138
|
-
function removeDelIfAttr(el) {
|
|
139
|
-
el.removeAttribute("del:if");
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function processPageConditionals(parent) {
|
|
143
|
-
const children = [...parent.children];
|
|
144
|
-
let chainActive = false;
|
|
145
|
-
let chainRendered = false;
|
|
146
|
-
|
|
147
|
-
for (const child of children) {
|
|
148
|
-
const hasIf = child.hasAttribute("if");
|
|
149
|
-
const hasDelIf = hasDelIfAttr(child);
|
|
150
|
-
const hasElif = child.hasAttribute("elif");
|
|
151
|
-
const hasElse = child.hasAttribute("else");
|
|
152
|
-
|
|
153
|
-
if (hasElif || hasElse) {
|
|
154
|
-
if (!chainActive) continue;
|
|
155
|
-
if (chainRendered) { child.remove(); continue; }
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (hasIf) {
|
|
159
|
-
const raw = child.getAttribute("if");
|
|
160
|
-
const expr = raw.startsWith("{") ? raw.slice(1, -1) : raw;
|
|
161
|
-
const fn = compileExpression(expr, false);
|
|
162
|
-
const result = fn();
|
|
163
|
-
chainActive = true;
|
|
164
|
-
if (result) {
|
|
165
|
-
chainRendered = true;
|
|
166
|
-
} else {
|
|
167
|
-
child.remove();
|
|
168
|
-
chainRendered = false;
|
|
169
|
-
}
|
|
170
|
-
child.removeAttribute("if");
|
|
171
|
-
} else if (hasDelIf) {
|
|
172
|
-
const raw = getDelIfAttr(child);
|
|
173
|
-
const expr = raw.startsWith("{") ? raw.slice(1, -1) : raw;
|
|
174
|
-
const fn = compileExpression(expr, false);
|
|
175
|
-
const result = fn();
|
|
176
|
-
chainActive = true;
|
|
177
|
-
if (result) {
|
|
178
|
-
chainRendered = true;
|
|
179
|
-
} else {
|
|
180
|
-
child.remove();
|
|
181
|
-
chainRendered = false;
|
|
182
|
-
}
|
|
183
|
-
removeDelIfAttr(child);
|
|
184
|
-
} else if (hasElif) {
|
|
185
|
-
const raw = child.getAttribute("elif");
|
|
186
|
-
const expr = raw.startsWith("{") ? raw.slice(1, -1) : raw;
|
|
187
|
-
const fn = compileExpression(expr, false);
|
|
188
|
-
const result = fn();
|
|
189
|
-
if (result) {
|
|
190
|
-
chainRendered = true;
|
|
191
|
-
} else {
|
|
192
|
-
child.remove();
|
|
193
|
-
}
|
|
194
|
-
child.removeAttribute("elif");
|
|
195
|
-
} else if (hasElse) {
|
|
196
|
-
chainRendered = true;
|
|
197
|
-
chainActive = false;
|
|
198
|
-
child.removeAttribute("else");
|
|
199
|
-
} else {
|
|
200
|
-
chainActive = false;
|
|
201
|
-
chainRendered = false;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (child.parentNode) {
|
|
205
|
-
processPageConditionals(child);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
207
|
processPageConditionals(appContainer);
|
|
210
208
|
|
|
211
209
|
const appElements = getAppElements(appContainer);
|
package/compiler/pipeline.js
CHANGED
|
@@ -15,22 +15,23 @@ export async function getComponents(libDir) {
|
|
|
15
15
|
throw Error(`The specified components folder ${libDir} could not be found.`);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
const reads = components
|
|
19
|
+
.filter(comp => comp.endsWith(".html"))
|
|
20
|
+
.map(async (comp) => {
|
|
21
|
+
try {
|
|
22
|
+
const compPath = path.join(libDir, comp);
|
|
23
|
+
const instance = await fs.readFile(compPath, "utf-8");
|
|
20
24
|
|
|
21
|
-
|
|
25
|
+
if (instance === "" || instance.trim().length === 0) emptyComps.push(comp);
|
|
22
26
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
loadedComponents.set(comp.toLowerCase(), instance);
|
|
28
|
+
componentsLib.push(comp);
|
|
29
|
+
} catch (err) {
|
|
30
|
+
throwError(`Failed to load component "${comp}": ${err.message || err}`);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
26
33
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
loadedComponents.set(comp.toLowerCase(), instance);
|
|
30
|
-
} catch (err) {
|
|
31
|
-
throwError(`Failed to load component "${comp}": ${err.message || err}`);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
+
await Promise.all(reads);
|
|
34
35
|
|
|
35
36
|
return { componentsLib, loadedComponents, emptyComps };
|
|
36
37
|
} catch (err) {
|
|
@@ -83,6 +84,32 @@ export async function processIcons(link, rootDir, srcDir, outDirPath) {
|
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
86
|
|
|
87
|
+
export async function processScript(doc, script, rootDir, srcDir, outDirPath, fileIds) {
|
|
88
|
+
try {
|
|
89
|
+
const src = script.getAttribute("src");
|
|
90
|
+
if (src.startsWith("http://") || src.startsWith("https://")) return;
|
|
91
|
+
const scriptPath = path.join(rootDir, srcDir, src);
|
|
92
|
+
const content = await fs.readFile(scriptPath, { encoding: "utf8" });
|
|
93
|
+
const jsFileName = "js-" + genRandomId(fileIds, 6) + ".js";
|
|
94
|
+
await fs.writeFile(path.join(outDirPath, jsFileName), content);
|
|
95
|
+
|
|
96
|
+
const newScript = doc.createElement("script");
|
|
97
|
+
for (const attr of script.attributes) {
|
|
98
|
+
if (attr.name === "src") {
|
|
99
|
+
newScript.setAttribute("src", "./" + jsFileName);
|
|
100
|
+
} else {
|
|
101
|
+
newScript.setAttribute(attr.name, attr.value);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (script.textContent.trim()) {
|
|
105
|
+
newScript.textContent = script.textContent;
|
|
106
|
+
}
|
|
107
|
+
script.parentNode.replaceChild(newScript, script);
|
|
108
|
+
} catch (err) {
|
|
109
|
+
throwError(`Failed to process script: ${err}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
86
113
|
export async function copyStaticDir(srcPath, outDirPath) {
|
|
87
114
|
const staticSrc = path.join(srcPath, "static");
|
|
88
115
|
const staticDest = path.join(outDirPath, "static");
|
package/compiler/utils.js
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
|
-
import
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { pathToFileURL } from "url";
|
|
4
|
-
import chalk from "chalk";
|
|
1
|
+
import chalk from "./chalk.js";
|
|
5
2
|
|
|
6
3
|
export function throwError(err) {
|
|
7
4
|
console.log(chalk.red.bold("Error!"), "A fatal error has occurred:\n");
|
|
8
5
|
throw new Error(err);
|
|
9
6
|
}
|
|
10
7
|
|
|
8
|
+
export function hasDelIfAttr(el) {
|
|
9
|
+
return el.hasAttribute("del:if");
|
|
10
|
+
}
|
|
11
|
+
export function getDelIfAttr(el) {
|
|
12
|
+
return el.getAttribute("del:if");
|
|
13
|
+
}
|
|
14
|
+
export function removeDelIfAttr(el) {
|
|
15
|
+
el.removeAttribute("del:if");
|
|
16
|
+
}
|
|
17
|
+
|
|
11
18
|
export function genRandomId(collection = null, length = 10, lettersOnly = false) {
|
|
12
19
|
let id;
|
|
13
20
|
if (lettersOnly) {
|
|
@@ -42,15 +49,6 @@ export function incrementAlfabet(letters) {
|
|
|
42
49
|
return "a" + arr.join("");
|
|
43
50
|
}
|
|
44
51
|
|
|
45
|
-
export function isWebLink(str) {
|
|
46
|
-
try {
|
|
47
|
-
const url = new URL(str);
|
|
48
|
-
return url.protocol === "http:" || url.protocol === "https:";
|
|
49
|
-
} catch (e) {
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
52
|
const LBRACE_PH = "_%%CHOCOLA-LBRACE%%_";
|
|
55
53
|
const RBRACE_PH = "_%%CHOCOLA-RBRACE%%_";
|
|
56
54
|
|
package/dev/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import http from "http";
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import path from "path";
|
|
4
|
-
import chalk from "chalk";
|
|
4
|
+
import chalk from "../compiler/chalk.js";
|
|
5
5
|
import compile from "../compiler/index.js";
|
|
6
6
|
import { loadConfig, resolvePaths } from "../compiler/config.js";
|
|
7
7
|
import { getChocolaConfig } from "../utils.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chocola",
|
|
3
|
-
"version": "2.0.0-next.
|
|
3
|
+
"version": "2.0.0-next.5",
|
|
4
4
|
"description": "The sweetest way to build the web",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"web",
|
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
],
|
|
14
14
|
"homepage": "https://chocolaframework.web.app/",
|
|
15
15
|
"bugs": {
|
|
16
|
-
"url": "https://github.com/
|
|
16
|
+
"url": "https://github.com/chocolajs/chocola/issues"
|
|
17
17
|
},
|
|
18
18
|
"repository": {
|
|
19
19
|
"type": "git",
|
|
20
|
-
"url": "git+https://github.com/
|
|
20
|
+
"url": "git+https://github.com/chocolajs/chocola.git"
|
|
21
21
|
},
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"author": "SadGabi",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"main": "index.js",
|
|
26
26
|
"funding": {
|
|
27
27
|
"type": "github",
|
|
28
|
-
"url": "https://github.com/sponsors/
|
|
28
|
+
"url": "https://github.com/sponsors/chocolajs"
|
|
29
29
|
},
|
|
30
30
|
"scripts": {
|
|
31
31
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
@@ -35,11 +35,6 @@
|
|
|
35
35
|
"./dev": "./dev/index.js"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"chalk": "^5.6.2",
|
|
39
|
-
"js-beautify": "^1.15.4",
|
|
40
38
|
"jsdom": "^27.4.0"
|
|
41
|
-
},
|
|
42
|
-
"devDependencies": {
|
|
43
|
-
"js-beautify": "^1.15.4"
|
|
44
39
|
}
|
|
45
40
|
}
|