chocola 2.0.0-next.11 → 2.0.0-next.12

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/package.json CHANGED
@@ -1,57 +1,56 @@
1
- {
2
- "name": "chocola",
3
- "version": "2.0.0-next.11",
4
- "description": "The sweetest way to build the web",
5
- "keywords": [
6
- "web",
7
- "app",
8
- "pipeline",
9
- "framework",
10
- "gui",
11
- "components",
12
- "ui"
13
- ],
14
- "homepage": "https://chocolaframework.web.app/",
15
- "bugs": {
16
- "url": "https://github.com/chocolajs/chocola/issues"
17
- },
18
- "repository": {
19
- "type": "git",
20
- "url": "git+https://github.com/chocolajs/chocola.git"
21
- },
22
- "license": "MIT",
23
- "author": "SadGabi",
24
- "type": "module",
25
- "main": "index.js",
26
- "funding": {
27
- "type": "github",
28
- "url": "https://github.com/sponsors/chocolajs"
29
- },
30
- "scripts": {
31
- "test": "node --test \"tests/**/*.test.js\"",
32
- "bench": "node bench/index.js",
33
- "bench:csv": "node bench/index.js --csv"
34
- },
35
- "exports": {
36
- "./compiler": "./compiler/index.js",
37
- "./dev": "./dev/index.js",
38
- "./server": "./server/index.js"
39
- },
40
- "bin": {
41
- "chocola": "./bin/chocola.js",
42
- "chjs": "./bin/chocola.js"
43
- },
44
- "files": [
45
- "bin/",
46
- "compiler/",
47
- "dev/",
48
- "server/",
49
- "runtime/",
50
- "parser/",
51
- "utils.js"
52
- ],
53
- "dependencies": {
54
- "acorn": "^8.18.0",
55
- "linkedom": "^0.18.13"
56
- }
57
- }
1
+ {
2
+ "name": "chocola",
3
+ "version": "2.0.0-next.12",
4
+ "description": "The sweetest way to build the web",
5
+ "keywords": [
6
+ "web",
7
+ "app",
8
+ "pipeline",
9
+ "framework",
10
+ "gui",
11
+ "components",
12
+ "ui"
13
+ ],
14
+ "homepage": "https://chocolaframework.web.app/",
15
+ "bugs": {
16
+ "url": "https://github.com/chocolajs/chocola/issues"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/chocolajs/chocola.git"
21
+ },
22
+ "license": "MIT",
23
+ "author": "SadGabi",
24
+ "type": "module",
25
+ "main": "compiler/index.js",
26
+ "funding": {
27
+ "type": "github",
28
+ "url": "https://github.com/sponsors/chocolajs"
29
+ },
30
+ "scripts": {
31
+ "test": "node --test \"tests/**/*.test.js\"",
32
+ "bench": "node bench/index.js",
33
+ "bench:csv": "node bench/index.js --csv"
34
+ },
35
+ "exports": {
36
+ ".": {
37
+ "import": "./compiler/index.js",
38
+ "require": "./compiler/index.js"
39
+ },
40
+ "./compiler": "./compiler/index.js",
41
+ "./compiler/*": "./compiler/*",
42
+ "./runtime": "./runtime/index.js",
43
+ "./parser": "./parser/index.js",
44
+ "./parser/*": "./parser/*"
45
+ },
46
+ "files": [
47
+ "compiler/",
48
+ "parser/",
49
+ "runtime/",
50
+ "utils.js"
51
+ ],
52
+ "dependencies": {
53
+ "acorn": "^8.18.0",
54
+ "linkedom": "^0.18.13"
55
+ }
56
+ }
package/utils.js CHANGED
@@ -1,122 +1,39 @@
1
- import { promises as fs } from "fs";
2
- import path from "path";
3
- import chalk from "./compiler/chalk.js";
4
- import { throwError } from "./compiler/utils.js";
5
-
6
- const warnedMissing = new Set();
7
- const warnedBlockBundle = new Set();
8
- const warnedBlockDev = new Set();
9
- const warnedBlockServer = new Set();
10
-
11
- const configWarningBuffers = new Map();
12
-
13
- export function queueConfigWarning(rootDir, ...args) {
14
- if (!configWarningBuffers.has(rootDir)) configWarningBuffers.set(rootDir, []);
15
- configWarningBuffers.get(rootDir).push(args);
16
- }
17
-
18
- export function flushConfigWarnings(rootDir) {
19
- // if rootDir provided, flush only that dir; if not, flush all (fallback)
20
- if (rootDir) {
21
- const buf = configWarningBuffers.get(rootDir);
22
- if (!buf || !buf.length) return;
23
- const toFlush = [...buf];
24
- buf.length = 0;
25
- for (const args of toFlush) {
26
- console.warn(...args);
27
- }
28
- return;
29
- }
30
- for (const [dir, buf] of configWarningBuffers) {
31
- if (!buf.length) continue;
32
- const toFlush = [...buf];
33
- buf.length = 0;
34
- for (const args of toFlush) {
35
- console.warn(...args);
36
- }
37
- }
38
- }
39
-
40
- export async function getConfig(__rootdir, { silent } = {}) {
41
- try {
42
- const raw = await fs.readFile(path.join(__rootdir, "chocola.config.json"), "utf-8");
43
- const config = JSON.parse(raw);
44
-
45
- // Hierarchical block-level warnings: if file exists but block missing, warn per missing block
46
- const hasBundle = (config.bundle !== undefined && config.bundle !== null) || (config.build !== undefined && config.build !== null);
47
- const hasDev = config.dev !== undefined && config.dev !== null;
48
- const hasServer = config.server !== undefined && config.server !== null;
49
-
50
- if (!silent) {
51
- if (!hasBundle && !warnedBlockBundle.has(__rootdir)) {
52
- warnedBlockBundle.add(__rootdir);
53
- queueConfigWarning(__rootdir, chalk.bold.yellow("WARNING!"), "bundle config not defined in chocola.config.json file: using default bundle configuration.");
54
- }
55
- if (!hasDev && !warnedBlockDev.has(__rootdir)) {
56
- warnedBlockDev.add(__rootdir);
57
- queueConfigWarning(__rootdir, chalk.bold.yellow("WARNING!"), "dev config not defined in chocola.config.json file: using default dev configuration.");
58
- }
59
- if (!hasServer && !warnedBlockServer.has(__rootdir)) {
60
- warnedBlockServer.add(__rootdir);
61
- queueConfigWarning(__rootdir, chalk.bold.yellow("WARNING!"), "server config not defined in chocola.config.json file: using default server configuration.");
62
- }
63
- }
64
-
65
- return config;
66
- } catch(err) {
67
- if (err && err.code === "ENOENT") {
68
- if (!silent && !warnedMissing.has(__rootdir)) {
69
- warnedMissing.add(__rootdir);
70
- queueConfigWarning(__rootdir, chalk.bold.yellow("WARNING!"), "chocola.config.json not found: using default configuration.");
71
- }
72
- const empty = {};
73
- Object.defineProperty(empty, "__chocolaMissingConfigFile", { value: true, enumerable: false, writable: false });
74
- return empty;
75
- }
76
- throwError("An error occurred while fetching the Chocola config file:\n" + err);
77
- }
78
- }
79
-
80
- export function isMissingConfigFile(cfg) {
81
- return !!(cfg && cfg.__chocolaMissingConfigFile);
82
- }
83
-
84
- const LBRACE_PH = "_%%CHOCOLA-LBRACE%%_";
85
- const RBRACE_PH = "_%%CHOCOLA-RBRACE%%_";
86
- const PROTECTED_REGEX = /_%%CHOCOLA-(?:AMP|LT|GT)\d+%%_/g;
87
-
88
- let protectSeq = 0;
89
-
90
- export function protectCurlyBraces(html) {
91
- return html
92
- .replace(/&(?:lbrace|#123|#x7B);/gi, LBRACE_PH)
93
- .replace(/&(?:rcub|#125|#x7D);/gi, RBRACE_PH)
94
- .split(/(<script\b[^>]*>[\s\S]*?<\/script>|<style\b[^>]*>[\s\S]*?<\/style>)/gi)
95
- .map((part, i) => i % 2 === 0
96
- ? part.replace(/\{([^{}]*)\}/g, (m, inner) =>
97
- `{${inner
98
- .replace(/&/g, () => `_%%CHOCOLA-AMP${protectSeq++}%%_`)
99
- .replace(/</g, () => `_%%CHOCOLA-LT${protectSeq++}%%_`)
100
- .replace(/>/g, () => `_%%CHOCOLA-GT${protectSeq++}%%_`)}}`)
101
- : part)
102
- .join("");
103
- }
104
-
105
- export function restoreCurlyBraces(html) {
106
- return html
107
- .replace(/_%%CHOCOLA-LBRACE%%_/g, "{")
108
- .replace(/_%%CHOCOLA-RBRACE%%_/g, "}")
109
- .replace(PROTECTED_REGEX, char => {
110
- if (char.includes("AMP")) return "&";
111
- if (char.includes("LT")) return "<";
112
- return ">";
113
- });
114
- }
115
-
116
- export function restoreTemplateChars(str) {
117
- return str.replace(PROTECTED_REGEX, char => {
118
- if (char.includes("AMP")) return "&";
119
- if (char.includes("LT")) return "<";
120
- return ">";
121
- });
122
- }
1
+ const LBRACE_PH = "_%%CHOCOLA-LBRACE%%_";
2
+ const RBRACE_PH = "_%%CHOCOLA-RBRACE%%_";
3
+ const PROTECTED_REGEX = /_%%CHOCOLA-(?:AMP|LT|GT)\d+%%_/g;
4
+
5
+ let protectSeq = 0;
6
+
7
+ export function protectCurlyBraces(html) {
8
+ return html
9
+ .replace(/&(?:lbrace|#123|#x7B);/gi, LBRACE_PH)
10
+ .replace(/&(?:rcub|#125|#x7D);/gi, RBRACE_PH)
11
+ .split(/(<script\b[^>]*>[\s\S]*?<\/script>|<style\b[^>]*>[\s\S]*?<\/style>)/gi)
12
+ .map((part, i) => i % 2 === 0
13
+ ? part.replace(/\{([^{}]*)\}/g, (m, inner) =>
14
+ `{${inner
15
+ .replace(/&/g, () => `_%%CHOCOLA-AMP${protectSeq++}%%_`)
16
+ .replace(/</g, () => `_%%CHOCOLA-LT${protectSeq++}%%_`)
17
+ .replace(/>/g, () => `_%%CHOCOLA-GT${protectSeq++}%%_`)}}`)
18
+ : part)
19
+ .join("");
20
+ }
21
+
22
+ export function restoreCurlyBraces(html) {
23
+ return html
24
+ .replace(/_%%CHOCOLA-LBRACE%%_/g, "{")
25
+ .replace(/_%%CHOCOLA-RBRACE%%_/g, "}")
26
+ .replace(PROTECTED_REGEX, char => {
27
+ if (char.includes("AMP")) return "&";
28
+ if (char.includes("LT")) return "<";
29
+ return ">";
30
+ });
31
+ }
32
+
33
+ export function restoreTemplateChars(str) {
34
+ return str.replace(PROTECTED_REGEX, char => {
35
+ if (char.includes("AMP")) return "&";
36
+ if (char.includes("LT")) return "<";
37
+ return ">";
38
+ });
39
+ }
package/bin/chocola.js DELETED
@@ -1,227 +0,0 @@
1
- #!/usr/bin/env node
2
- import path from "path";
3
- import { fileURLToPath, pathToFileURL } from "url";
4
- import { createRequire } from "module";
5
- import { readFile } from "fs/promises";
6
- import { getConfig, isMissingConfigFile } from "../utils.js";
7
- import { loadConfig } from "../compiler/config.js";
8
-
9
- import chalk from "../compiler/chalk.js";
10
-
11
- const __filename = fileURLToPath(import.meta.url);
12
- const __dirname = path.dirname(__filename);
13
- const isPlain = process.env.NO_COLOR === "1" || process.argv.includes("--plain");
14
- const c = isPlain ? {
15
- hex: () => (s) => s, bold: (s) => s, green: (s) => s, yellow: (s) => s, red: (s) => s, underline: (s) => s,
16
- } : chalk;
17
-
18
- export default __dirname;
19
-
20
- export async function resolveConfig(rootDir, cliOverrides, configPathOpt) {
21
- const customPath = configPathOpt ? path.resolve(rootDir, configPathOpt) : null;
22
- const fullConfig = customPath
23
- ? await readFile(customPath, "utf-8").then(r => JSON.parse(r))
24
- : await getConfig(rootDir, { silent: true });
25
- const isMissing = customPath ? false : isMissingConfigFile(fullConfig);
26
- const base = await loadConfig(rootDir, { silent: true, customPath });
27
- if (cliOverrides.outDir) base.outDir = path.resolve(rootDir, cliOverrides.outDir);
28
- if (cliOverrides.srcDir) base.srcDir = path.resolve(rootDir, cliOverrides.srcDir);
29
- if (cliOverrides.libDir) base.libDir = path.resolve(rootDir, cliOverrides.libDir);
30
- if (cliOverrides.emptyOutDir != null) base.emptyOutDir = cliOverrides.emptyOutDir;
31
- const effectiveDev = { hostname: "localhost", port: 3000, ...(!isMissing && fullConfig.dev || {}), ...cliOverrides.dev };
32
- const effectiveServer = { hostname: "localhost", port: 8080, middleware: null, ...(!isMissing && fullConfig.server || {}), ...cliOverrides.server };
33
- if (!cliOverrides.server?.port && process.env.PORT) {
34
- const envPort = parseInt(process.env.PORT, 10);
35
- if (Number.isFinite(envPort)) effectiveServer.port = envPort;
36
- }
37
- if (!cliOverrides.server?.hostname && !fullConfig.server?.hostname && !fullConfig.server?.host && process.env.PORT) {
38
- effectiveServer.hostname = "0.0.0.0";
39
- }
40
- return { fullConfig, base, effectiveDev, effectiveServer, isMissing };
41
- }
42
-
43
- function parsePort(val) {
44
- const n = parseInt(val, 10);
45
- if (Number.isNaN(n) || n < 1 || n > 65535) {
46
- throw new Error(`Invalid port: ${val}. Must be between 1 and 65535.`);
47
- }
48
- return n;
49
- }
50
-
51
- function kebabToCamel(str) {
52
- return str.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
53
- }
54
-
55
- export function parseArgs(argv) {
56
- const args = argv.slice(2).filter(a => a !== "--plain");
57
- const cmd = args[0];
58
- if (!cmd || cmd === "--help" || cmd === "-h") return { cmd: "help", rest: [] };
59
- if (cmd === "--version" || cmd === "-v") return { cmd: "version", rest: [] };
60
- const positional = [];
61
- const flags = {};
62
- let configPath = null;
63
- let i = 1;
64
- while (i < args.length) {
65
- const arg = args[i];
66
- if (arg === "--config" || arg === "-c") {
67
- configPath = args[++i];
68
- } else if (arg.startsWith("--")) {
69
- const key = kebabToCamel(arg.slice(2));
70
- if (i + 1 < args.length && !args[i + 1].startsWith("--")) {
71
- flags[key] = args[++i];
72
- } else {
73
- flags[key] = true;
74
- }
75
- } else {
76
- positional.push(arg);
77
- }
78
- i++;
79
- }
80
- return { cmd, root: positional[0] || undefined, flags, configPath, rest: args };
81
- }
82
-
83
- async function getLocalModules(rootDir) {
84
- try {
85
- const req = createRequire(pathToFileURL(path.join(rootDir, "package.json")).href);
86
- const localPkgPath = req.resolve("chocola/package.json");
87
- const localRoot = path.dirname(localPkgPath);
88
- const cliDir = path.dirname(path.dirname(__filename));
89
- if (localRoot === cliDir) return null;
90
- const mod = await import(pathToFileURL(path.join(localRoot, "compiler/index.js")).href);
91
- return { rootDir: localRoot, mod };
92
- } catch { return null; }
93
- }
94
-
95
- async function banner() {
96
- if (!isPlain) {
97
- const { logBanner } = await import("../compiler/index.js");
98
- logBanner();
99
- }
100
- }
101
-
102
- export async function main() {
103
- const { cmd, root, flags, configPath } = parseArgs(process.argv);
104
-
105
- if (cmd === "help") {
106
- await banner();
107
- console.log(c.bold("Usage: ") + "chocola <command> [root] [options]");
108
- console.log("");
109
- console.log("Commands:");
110
- console.log(" build Build for production");
111
- console.log(" dev Start dev server with hot-reload");
112
- console.log(" serve Start SSR production server");
113
- console.log("");
114
- console.log("Options:");
115
- console.log(" -c, --config <path> Path to config file");
116
- console.log(" --help, -h Show help");
117
- console.log(" --version, -v Show version");
118
- console.log(" --plain, NO_COLOR=1 Disable color output");
119
- console.log("");
120
- console.log("build options:");
121
- console.log(" --srcDir <dir> Source directory (default: src)");
122
- console.log(" --outDir <dir> Output directory (default: dist)");
123
- console.log(" --libDir <dir> Components subdir (default: lib)");
124
- console.log(" --no-emptyOutDir Do not clean outDir before build");
125
- console.log("");
126
- console.log("dev options:");
127
- console.log(" --host <hostname> Hostname (default: localhost)");
128
- console.log(" --port <number> Port (default: 3000)");
129
- console.log(" --open Open browser after start");
130
- console.log("");
131
- console.log("serve options:");
132
- console.log(" --host <hostname> Hostname (default: localhost)");
133
- console.log(" --port <number> Port (default: 8080)");
134
- console.log(" --middleware <path> Path to middleware file");
135
- return;
136
- }
137
- if (cmd === "version") {
138
- const pkg = await readFile(path.join(__dirname, "../package.json"), "utf-8");
139
- console.log(JSON.parse(pkg).version);
140
- return;
141
- }
142
-
143
- if (!["build", "dev", "serve"].includes(cmd)) {
144
- console.error(c.red(`Unknown command: ${cmd}. Use "chocola --help" for usage.`));
145
- process.exit(2);
146
- }
147
-
148
- const rootDir = path.resolve(root || process.cwd());
149
-
150
- try {
151
- if (configPath) {
152
- await readFile(path.resolve(rootDir, configPath), "utf-8");
153
- }
154
- const rawPort = flags.port ? parsePort(flags.port) : undefined;
155
- const effectiveHost = flags.host || flags.hostname;
156
-
157
- const { base, effectiveDev, effectiveServer } = await resolveConfig(rootDir, {
158
- outDir: flags.outDir,
159
- srcDir: flags.srcDir,
160
- libDir: flags.libDir,
161
- emptyOutDir: flags.emptyOutDir === false ? false : (flags.noEmptyOutDir === true ? false : undefined),
162
- dev: { port: rawPort, hostname: effectiveHost },
163
- server: { port: rawPort, hostname: effectiveHost },
164
- }, configPath);
165
-
166
- let serverInstance = null;
167
- let devServer = null;
168
- const cleanup = () => {
169
- if (devServer) { try { devServer.close(); } catch {} }
170
- if (serverInstance) { try { serverInstance.close(); } catch {} }
171
- process.exit(0);
172
- };
173
- process.on("SIGINT", cleanup);
174
- process.on("SIGTERM", cleanup);
175
-
176
- switch (cmd) {
177
- case "build": {
178
- const local = await getLocalModules(rootDir);
179
- const compile = local ? local.mod.default : (await import("../compiler/index.js")).default;
180
- await compile(rootDir, { overrides: base });
181
- process.exit(0);
182
- }
183
- case "dev": {
184
- const local = await getLocalModules(rootDir);
185
- const devMod = local
186
- ? await import(pathToFileURL(path.join(local.rootDir, "dev/index.js")).href)
187
- : await import("../dev/index.js");
188
- const serve = devMod.serve || devMod.default;
189
- serverInstance = await serve(rootDir, {
190
- port: rawPort || effectiveDev.port,
191
- hostname: effectiveHost || effectiveDev.hostname,
192
- open: flags.open || false,
193
- silent: true,
194
- });
195
- devServer = serverInstance;
196
- break;
197
- }
198
- case "serve": {
199
- const local = await getLocalModules(rootDir);
200
- const serverMod = local
201
- ? await import(pathToFileURL(path.join(local.rootDir, "server/index.js")).href)
202
- : await import("../server/index.js");
203
- const serve = serverMod.serve || serverMod.default?.serve;
204
- serverInstance = await serve(rootDir, {
205
- port: rawPort || effectiveServer.port,
206
- hostname: effectiveHost || effectiveServer.hostname,
207
- middleware: flags.middleware || null,
208
- silent: true,
209
- });
210
- }
211
- }
212
- } catch (err) {
213
- if (err.code === "ENOENT" && configPath) {
214
- console.error(c.red(`Config file not found: ${path.resolve(rootDir, configPath)}`));
215
- process.exit(1);
216
- }
217
- console.error(c.red(err.message || err));
218
- process.exit(1);
219
- }
220
- }
221
-
222
- if (process.argv[1] === __filename) {
223
- main().catch(err => {
224
- console.error(err.message || err);
225
- process.exit(1);
226
- });
227
- }