@progalaxyelabs/htms-cli 0.4.1 → 0.5.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/htms.js +4 -1
- package/dist/router.ts +77 -0
- package/dist/templates.ts +69 -0
- package/package.json +3 -3
- package/src/compiler.js +22 -3
- package/wasm/htms_compiler.wasm +0 -0
package/bin/htms.js
CHANGED
|
@@ -23,9 +23,12 @@ program
|
|
|
23
23
|
// Compile command
|
|
24
24
|
program
|
|
25
25
|
.command('compile')
|
|
26
|
-
.description('Compile .htms file to TypeScript')
|
|
26
|
+
.description('Compile .htms file to TypeScript or HTML')
|
|
27
27
|
.argument('<input>', 'Input .htms file')
|
|
28
28
|
.option('-o, --output <dir>', 'Output directory', 'dist')
|
|
29
|
+
.option('-f, --format <format>', 'Output format: typescript or html', 'typescript')
|
|
30
|
+
.option('-t, --template <file>', 'HTML template file to inject into (only for html format)')
|
|
31
|
+
.option('-s, --split-templates', 'Split templates into separate files for lazy loading (only for html format)')
|
|
29
32
|
.option('-w, --watch', 'Watch for changes')
|
|
30
33
|
.option('-q, --quiet', 'Suppress output')
|
|
31
34
|
.action(async (input, options) => {
|
package/dist/router.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Generated by HTMS Compiler
|
|
2
|
+
// Do not edit manually
|
|
3
|
+
|
|
4
|
+
interface RouterConfig {
|
|
5
|
+
mode: 'hash' | 'history';
|
|
6
|
+
routes: Record<string, () => void>;
|
|
7
|
+
notFound: () => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
class Router {
|
|
11
|
+
constructor(config: RouterConfig) {
|
|
12
|
+
const handleRoute = () => {
|
|
13
|
+
const hash = window.location.hash.slice(1) || '/';
|
|
14
|
+
const handler = config.routes[hash];
|
|
15
|
+
if (handler) {
|
|
16
|
+
handler();
|
|
17
|
+
} else {
|
|
18
|
+
config.notFound();
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
window.addEventListener('hashchange', handleRoute);
|
|
22
|
+
handleRoute();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
import { HomePage } from './templates';
|
|
27
|
+
|
|
28
|
+
// Application context
|
|
29
|
+
let context: Record<string, unknown> = {};
|
|
30
|
+
let currentPage: string = '';
|
|
31
|
+
const appContainer = document.getElementById('app');
|
|
32
|
+
|
|
33
|
+
export function getContext(): Record<string, unknown> {
|
|
34
|
+
return context;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function setContext(data: Record<string, unknown>): void {
|
|
38
|
+
context = data;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function rerender(): void {
|
|
42
|
+
if (currentPage && appContainer) {
|
|
43
|
+
const renderer = routes[currentPage];
|
|
44
|
+
if (renderer) {
|
|
45
|
+
appContainer.innerHTML = '';
|
|
46
|
+
appContainer.appendChild(renderer(context));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Route definitions
|
|
52
|
+
const routes: Record<string, (ctx: Record<string, unknown>) => HTMLElement> = {
|
|
53
|
+
'/': HomePage,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
function renderPage(route: string): void {
|
|
57
|
+
currentPage = route;
|
|
58
|
+
const renderer = routes[route];
|
|
59
|
+
if (renderer && appContainer) {
|
|
60
|
+
appContainer.innerHTML = '';
|
|
61
|
+
appContainer.appendChild(renderer(context));
|
|
62
|
+
} else if (appContainer) {
|
|
63
|
+
const el = document.createElement('h1');
|
|
64
|
+
el.textContent = '404 - Page Not Found';
|
|
65
|
+
appContainer.innerHTML = '';
|
|
66
|
+
appContainer.appendChild(el);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Create router
|
|
71
|
+
export const router = new Router({
|
|
72
|
+
mode: 'hash',
|
|
73
|
+
routes: {
|
|
74
|
+
'/': () => renderPage('/'),
|
|
75
|
+
},
|
|
76
|
+
notFound: () => renderPage('__404__'),
|
|
77
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Generated by HTMS Compiler
|
|
2
|
+
// Do not edit manually
|
|
3
|
+
|
|
4
|
+
export type Context = Record<string, unknown>;
|
|
5
|
+
|
|
6
|
+
export function TodoItem(ctx: Context): HTMLElement {
|
|
7
|
+
const el0 = document.createElement('div');
|
|
8
|
+
el0.className = 'todo-item';
|
|
9
|
+
const el1 = document.createElement('input');
|
|
10
|
+
el1.type = 'checkbox';
|
|
11
|
+
el0.appendChild(el1);
|
|
12
|
+
const el2 = document.createElement('span');
|
|
13
|
+
el2.className = 'todo-title';
|
|
14
|
+
const el3 = document.createTextNode('Todo title');
|
|
15
|
+
el2.appendChild(el3);
|
|
16
|
+
el0.appendChild(el2);
|
|
17
|
+
const el4 = document.createElement('span');
|
|
18
|
+
el4.className = 'todo-date';
|
|
19
|
+
const el5 = document.createTextNode('Date');
|
|
20
|
+
el4.appendChild(el5);
|
|
21
|
+
el0.appendChild(el4);
|
|
22
|
+
const el6 = document.createElement('button');
|
|
23
|
+
el6.className = 'delete-btn';
|
|
24
|
+
const el7 = document.createTextNode('×');
|
|
25
|
+
el6.appendChild(el7);
|
|
26
|
+
el0.appendChild(el6);
|
|
27
|
+
return el0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function EmptyState(ctx: Context): HTMLElement {
|
|
31
|
+
const el0 = document.createElement('p');
|
|
32
|
+
el0.className = 'empty';
|
|
33
|
+
const el1 = document.createTextNode('No todos yet. Add one above!');
|
|
34
|
+
el0.appendChild(el1);
|
|
35
|
+
return el0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function HomePage(ctx: Context): HTMLElement {
|
|
39
|
+
const el0 = document.createElement('main');
|
|
40
|
+
el0.className = 'container';
|
|
41
|
+
const el1 = document.createElement('h1');
|
|
42
|
+
const el2 = document.createTextNode('My Todos');
|
|
43
|
+
el1.appendChild(el2);
|
|
44
|
+
el0.appendChild(el1);
|
|
45
|
+
const el3 = document.createElement('p');
|
|
46
|
+
el3.className = 'subtitle';
|
|
47
|
+
const el4 = document.createTextNode('Simple todo app with localStorage');
|
|
48
|
+
el3.appendChild(el4);
|
|
49
|
+
el0.appendChild(el3);
|
|
50
|
+
const el5 = document.createElement('div');
|
|
51
|
+
el5.className = 'add-todo';
|
|
52
|
+
const el6 = document.createElement('input');
|
|
53
|
+
el6.type = 'text';
|
|
54
|
+
el6.id = 'todoInput';
|
|
55
|
+
el6.placeholder = 'What needs to be done?';
|
|
56
|
+
el5.appendChild(el6);
|
|
57
|
+
const el7 = document.createElement('button');
|
|
58
|
+
el7.id = 'addBtn';
|
|
59
|
+
const el8 = document.createTextNode('Add Todo');
|
|
60
|
+
el7.appendChild(el8);
|
|
61
|
+
el5.appendChild(el7);
|
|
62
|
+
el0.appendChild(el5);
|
|
63
|
+
const el9 = document.createElement('div');
|
|
64
|
+
el9.id = 'todoList';
|
|
65
|
+
el9.className = 'todo-list';
|
|
66
|
+
el0.appendChild(el9);
|
|
67
|
+
return el0;
|
|
68
|
+
}
|
|
69
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@progalaxyelabs/htms-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "CLI for HTMS compiler",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
"compiler",
|
|
20
20
|
"cli"
|
|
21
21
|
],
|
|
22
|
-
"author": "ProGalaxy
|
|
22
|
+
"author": "ProGalaxy eLabs <info@progalaxyelabs.com>",
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@progalaxyelabs/htms-compiler": "^0.
|
|
25
|
+
"@progalaxyelabs/htms-compiler": "^0.5.0",
|
|
26
26
|
"chokidar": "^3.5.0",
|
|
27
27
|
"commander": "^11.0.0",
|
|
28
28
|
"picocolors": "^1.0.0"
|
package/src/compiler.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { compile_wasm, init } from '@progalaxyelabs/htms-compiler';
|
|
1
|
+
import { compile_wasm, compile_with_options_wasm, init } from '@progalaxyelabs/htms-compiler';
|
|
2
2
|
import { readFile, writeFile, mkdir } from 'fs/promises';
|
|
3
3
|
import { dirname, join, basename } from 'path';
|
|
4
4
|
import { printDiagnostics } from './format-errors.js';
|
|
@@ -14,7 +14,7 @@ async function ensureWasmInit() {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* Compile HTMS file to TypeScript
|
|
17
|
+
* Compile HTMS file to TypeScript or HTML
|
|
18
18
|
* @param {string} inputPath - Path to .htms file
|
|
19
19
|
* @param {string} outputDir - Output directory for generated files
|
|
20
20
|
* @param {object} options - Compilation options
|
|
@@ -26,8 +26,27 @@ export async function compileFile(inputPath, outputDir, options = {}) {
|
|
|
26
26
|
// Read source file
|
|
27
27
|
const source = await readFile(inputPath, 'utf-8');
|
|
28
28
|
|
|
29
|
+
// Read template file if provided
|
|
30
|
+
let templateHtml = undefined;
|
|
31
|
+
if (options.template) {
|
|
32
|
+
templateHtml = await readFile(options.template, 'utf-8');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Get source filename for HTML output (e.g., "app.htms" -> "app.html")
|
|
36
|
+
const sourceFilename = basename(inputPath, '.htms') + '.html';
|
|
37
|
+
|
|
38
|
+
// Prepare compile options
|
|
39
|
+
const compileOptions = {
|
|
40
|
+
output_format: options.format || 'typescript',
|
|
41
|
+
generate_router: true,
|
|
42
|
+
generate_events: true,
|
|
43
|
+
template_html: templateHtml,
|
|
44
|
+
source_filename: sourceFilename,
|
|
45
|
+
split_templates: options.splitTemplates || false,
|
|
46
|
+
};
|
|
47
|
+
|
|
29
48
|
// Compile using WASM
|
|
30
|
-
const result =
|
|
49
|
+
const result = compile_with_options_wasm(source, compileOptions);
|
|
31
50
|
|
|
32
51
|
// Print diagnostics
|
|
33
52
|
if (result.diagnostics && result.diagnostics.length > 0) {
|
|
Binary file
|