@heshammesalam/heshjs 0.2.0 → 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/README.md +17 -12
- package/cli.js +31 -0
- package/dist/architecture/diagnostics.d.ts +12 -0
- package/dist/architecture/diagnostics.js +8 -0
- package/dist/architecture/diagnostics.js.map +1 -0
- package/dist/architecture/html.d.ts +18 -0
- package/dist/architecture/html.js +150 -0
- package/dist/architecture/html.js.map +1 -0
- package/dist/architecture/index.d.ts +42 -0
- package/dist/architecture/index.js +428 -0
- package/dist/architecture/index.js.map +1 -0
- package/dist/compiler/index.js +2 -0
- package/dist/compiler/index.js.map +1 -1
- package/dist/destinations/index.d.ts +63 -0
- package/dist/destinations/index.js +186 -0
- package/dist/destinations/index.js.map +1 -0
- package/dist/dom/index.d.ts +2 -0
- package/dist/dom/index.js +5 -1
- package/dist/dom/index.js.map +1 -1
- package/dist/domains/index.d.ts +24 -0
- package/dist/domains/index.js +110 -0
- package/dist/domains/index.js.map +1 -0
- package/dist/heshjs/index.d.ts +2 -0
- package/dist/heshjs/index.js +1 -0
- package/dist/heshjs/index.js.map +1 -1
- package/dist/hmvc/index.d.ts +2 -0
- package/dist/hmvc/index.js +11 -0
- package/dist/hmvc/index.js.map +1 -1
- package/dist/parser/index.d.ts +15 -1
- package/dist/parser/index.js +73 -3
- package/dist/parser/index.js.map +1 -1
- package/dist/presentation/index.d.ts +12 -0
- package/dist/presentation/index.js +39 -0
- package/dist/presentation/index.js.map +1 -0
- package/dist/units/index.d.ts +13 -0
- package/dist/units/index.js +16 -0
- package/dist/units/index.js.map +1 -0
- package/dist/vite/index.d.ts +4 -1
- package/dist/vite/index.js +36 -2
- package/dist/vite/index.js.map +1 -1
- package/docs/contracts.md +67 -0
- package/docs/domain-graph.md +205 -0
- package/docs/grammar.md +4 -0
- package/docs/units.md +71 -0
- package/package.json +10 -4
- package/scaffold/assets/hesh-icon.png +0 -0
- package/scaffold/create.js +78 -0
- package/scaffold/template.js +188 -0
- package/src/architecture/diagnostics.ts +11 -0
- package/src/architecture/html.ts +101 -0
- package/src/architecture/index.ts +291 -0
- package/src/compiler/index.ts +1 -0
- package/src/destinations/index.ts +147 -0
- package/src/dom/index.ts +6 -1
- package/src/domains/index.ts +97 -0
- package/src/heshjs/index.ts +2 -0
- package/src/hmvc/index.ts +7 -0
- package/src/parser/index.ts +55 -4
- package/src/presentation/index.ts +33 -0
- package/src/units/index.ts +23 -0
- package/src/vite/index.ts +24 -2
package/README.md
CHANGED
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
# HeshJS
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
Requires Node.js 22.12 or later.
|
|
3
|
+
Version 0.5.0 unifies the creator, runtime, compiler and architecture tools in **one npm package**.
|
|
4
|
+
HTML is the default for every screen, including the persistent shell and nested parts.
|
|
7
5
|
|
|
8
6
|
```sh
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
npm install
|
|
12
|
-
npm run dev
|
|
7
|
+
npx @heshammesalam/heshjs@latest create
|
|
8
|
+
# or: npx @heshammesalam/heshjs@latest create my-project --ts
|
|
13
9
|
```
|
|
14
10
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
The wizard asks for your folder and JavaScript/TypeScript (JavaScript by default).
|
|
12
|
+
Then run cd YOUR_FOLDER, npm install, npm run dev.
|
|
13
|
+
Use npm run check, npm run graph and npm run build.
|
|
14
|
+
|
|
15
|
+
Hesh Units preserve hierarchical MVC lifetimes with Hesh-specific names:
|
|
16
|
+
state.js/ts for state, actions.js/ts for behavior, screen.html for views,
|
|
17
|
+
unit.hesh for Domain Graph contracts, and parts/ for nested units. Business units
|
|
18
|
+
live under src/hesh-units; foundation/shell owns the persistent HTML shell.
|
|
19
|
+
The supplied Hesh logo and favicon are bundled. See docs/contracts.md for HTML directives.
|
|
20
|
+
See docs/units.md for the complete structure and the `/units` API.
|
|
21
|
+
The legacy create-heshjs package is superseded; use the npx command above.
|
|
22
|
+
|
|
23
|
+
Requires Node.js 22.12 or later.
|
|
19
24
|
|
|
20
25
|
```hesh
|
|
21
26
|
export default view Counter {
|
package/cli.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const args = process.argv.slice(2);
|
|
3
|
+
const command = args.shift();
|
|
4
|
+
if (command === '--help' || command === '-h' || !command) {
|
|
5
|
+
console.log('Usage: hesh create [directory] [--js | --ts]\n hesh check|graph [project-root] [--entry app.hesh] [--tsconfig tsconfig.json] [--write]\nAll commands are included in @heshammesalam/heshjs.');
|
|
6
|
+
process.exit(command ? 0 : 1);
|
|
7
|
+
}
|
|
8
|
+
if (command === 'create') {
|
|
9
|
+
try { const { createProject } = await import('./scaffold/create.js'); await createProject(args); }
|
|
10
|
+
catch (error) { console.error(error.message); process.exitCode = error.exitCode ?? 1; }
|
|
11
|
+
} else if (!['check', 'graph'].includes(command)) { console.error(`Unknown command ${command}`); process.exitCode = 1; }
|
|
12
|
+
else {
|
|
13
|
+
const options = { root: process.cwd() }; let write = false;
|
|
14
|
+
if (args[0] && !args[0].startsWith('--')) options.root = args.shift();
|
|
15
|
+
while (args.length) {
|
|
16
|
+
const flag = args.shift();
|
|
17
|
+
if (flag === '--write') { write = true; continue; }
|
|
18
|
+
if (!['--entry', '--tsconfig'].includes(flag) || !args[0] || args[0].startsWith('--')) { console.error(`Invalid option ${flag}`); process.exit(1); }
|
|
19
|
+
options[flag.slice(2)] = args.shift();
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const { checkProject, writeProject, formatDiagnostic } = await import('./dist/architecture/index.js');
|
|
23
|
+
const result = checkProject(options);
|
|
24
|
+
for (const item of result.diagnostics) console.error(formatDiagnostic(item));
|
|
25
|
+
if (result.diagnostics.some(item => item.severity === 'error')) process.exitCode = 1;
|
|
26
|
+
else {
|
|
27
|
+
if (write) writeProject(result);
|
|
28
|
+
console.log(command === 'graph' ? JSON.stringify(result.graph, null, 2) : `Architecture valid: ${result.graph.domains.length} domains, ${result.graph.destinations.length} destinations${write ? '; generated JS/declarations written' : ''}.`);
|
|
29
|
+
}
|
|
30
|
+
} catch (error) { console.error(error instanceof Error ? error.message : String(error)); process.exitCode = 1; }
|
|
31
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface ArchitectureDiagnostic {
|
|
2
|
+
code: string;
|
|
3
|
+
severity: 'error' | 'warning';
|
|
4
|
+
message: string;
|
|
5
|
+
file: string;
|
|
6
|
+
offset: number;
|
|
7
|
+
line: number;
|
|
8
|
+
column: number;
|
|
9
|
+
suggestion: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function diagnostic(code: string, message: string, file: string, source: string, offset: number, suggestion: string, severity?: 'error' | 'warning'): ArchitectureDiagnostic;
|
|
12
|
+
export declare function formatDiagnostic(item: ArchitectureDiagnostic): string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function diagnostic(code, message, file, source, offset, suggestion, severity = 'error') {
|
|
2
|
+
const lines = source.slice(0, offset).split('\n');
|
|
3
|
+
return { code, message, file, offset, line: lines.length, column: lines.at(-1).length + 1, suggestion, severity };
|
|
4
|
+
}
|
|
5
|
+
export function formatDiagnostic(item) {
|
|
6
|
+
return `${item.file}:${item.line}:${item.column} ${item.code} ${item.severity}: ${item.message}\n ${item.suggestion}`;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/architecture/diagnostics.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,OAAe,EAAE,IAAY,EAAE,MAAc,EAAE,MAAc,EAAE,UAAkB,EAAE,WAAgC,OAAO;IACjK,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,MAAM,GAAG,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;AACrH,CAAC;AACD,MAAM,UAAU,gBAAgB,CAAC,IAA4B;IAC3D,OAAO,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,OAAO,OAAO,IAAI,CAAC,UAAU,EAAE,CAAC;AACzH,CAAC","sourcesContent":["export interface ArchitectureDiagnostic {\n code: string; severity: 'error' | 'warning'; message: string;\n file: string; offset: number; line: number; column: number; suggestion: string;\n}\nexport function diagnostic(code: string, message: string, file: string, source: string, offset: number, suggestion: string, severity: 'error' | 'warning' = 'error'): ArchitectureDiagnostic {\n const lines = source.slice(0, offset).split('\\n');\n return { code, message, file, offset, line: lines.length, column: lines.at(-1)!.length + 1, suggestion, severity };\n}\nexport function formatDiagnostic(item: ArchitectureDiagnostic): string {\n return `${item.file}:${item.line}:${item.column} ${item.code} ${item.severity}: ${item.message}\\n ${item.suggestion}`;\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ArchitectureDiagnostic } from './diagnostics.js';
|
|
2
|
+
export interface HTMLContract {
|
|
3
|
+
filename: string;
|
|
4
|
+
bindings: string[];
|
|
5
|
+
actions: string[];
|
|
6
|
+
parts?: string[];
|
|
7
|
+
allowOutlet?: boolean;
|
|
8
|
+
destinations: Record<string, Record<string, string>>;
|
|
9
|
+
validateBinding?: (path: string, offset: number, expected?: string, writable?: boolean) => void;
|
|
10
|
+
}
|
|
11
|
+
export interface HTMLResult {
|
|
12
|
+
code: string;
|
|
13
|
+
diagnostics: ArchitectureDiagnostic[];
|
|
14
|
+
usedBindings: string[];
|
|
15
|
+
usedActions: string[];
|
|
16
|
+
destinations: string[];
|
|
17
|
+
}
|
|
18
|
+
export declare function compileHTML(source: string, contract: HTMLContract): HTMLResult;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { parseFragment } from 'parse5';
|
|
2
|
+
import { diagnostic } from './diagnostics.js';
|
|
3
|
+
export function compileHTML(source, contract) {
|
|
4
|
+
const diagnostics = [], usedBindings = new Set(), usedActions = new Set();
|
|
5
|
+
const report = (code, message, at, suggestion, severity = 'error') => diagnostics.push(diagnostic(code, message, contract.filename, source, at, suggestion, severity));
|
|
6
|
+
const fragment = parseFragment(source, { sourceCodeLocationInfo: true, onParseError: error => report('HESH-HTML-001', error.code, error.startOffset, 'Correct the HTML syntax.') });
|
|
7
|
+
const lines = ["import * as p from '@heshammesalam/heshjs/presentation';", 'export default function render(parent, state, destinations) {'];
|
|
8
|
+
let serial = 0;
|
|
9
|
+
const linked = new Set();
|
|
10
|
+
const path = (value, offset, expected, writable = false) => {
|
|
11
|
+
const pieces = value.trim().split('.');
|
|
12
|
+
if (pieces.some(piece => !/^[$_\p{ID_Start}][$_\u200c\u200d\p{ID_Continue}]*$/u.test(piece) || ['constructor', '__proto__', 'prototype'].includes(piece)))
|
|
13
|
+
report('HESH-BIND-001', `Invalid binding path ${value}`, offset, 'Use a declared dotted data path, not an expression.');
|
|
14
|
+
if (!contract.bindings.includes(pieces[0]))
|
|
15
|
+
report('HESH-BIND-002', `Missing data binding ${pieces[0]}`, offset, 'Declare the binding and return it from the presentation factory.');
|
|
16
|
+
usedBindings.add(pieces[0]);
|
|
17
|
+
contract.validateBinding?.(value.trim(), offset, expected, writable);
|
|
18
|
+
return `p.readBinding(state.bindings, ${JSON.stringify(value.trim())})`;
|
|
19
|
+
};
|
|
20
|
+
const interpolation = (value, offset) => {
|
|
21
|
+
const parts = [];
|
|
22
|
+
let literal = '', cursor = 0;
|
|
23
|
+
const emit = () => { if (literal) {
|
|
24
|
+
parts.push(JSON.stringify(literal));
|
|
25
|
+
literal = '';
|
|
26
|
+
} };
|
|
27
|
+
while (cursor < value.length) {
|
|
28
|
+
if (value[cursor] === '\\' && ['{', '}'].includes(value[cursor + 1] ?? '')) {
|
|
29
|
+
literal += value[cursor + 1];
|
|
30
|
+
cursor += 2;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (value[cursor] !== '{') {
|
|
34
|
+
literal += value[cursor++];
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
emit();
|
|
38
|
+
const start = ++cursor, end = value.indexOf('}', start);
|
|
39
|
+
if (end < 0) {
|
|
40
|
+
report('HESH-BIND-001', 'Unterminated interpolation', offset + start - 1, 'Close the binding with }.');
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
parts.push(`String(${path(value.slice(start, end), offset + start)} ?? '')`);
|
|
44
|
+
cursor = end + 1;
|
|
45
|
+
}
|
|
46
|
+
emit();
|
|
47
|
+
return parts.join(' + ') || "''";
|
|
48
|
+
};
|
|
49
|
+
const visit = (node, parent) => {
|
|
50
|
+
const at = node.sourceCodeLocation?.startOffset ?? 0;
|
|
51
|
+
if (node.nodeName === '#text') {
|
|
52
|
+
lines.push(`p.text(${parent}, () => ${interpolation(node.value, at)});`);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (!('tagName' in node))
|
|
56
|
+
return;
|
|
57
|
+
if (node.namespaceURI !== 'http://www.w3.org/1999/xhtml' || ['script', 'iframe', 'object', 'embed', 'base', 'meta', 'link', 'style', 'template'].includes(node.tagName)) {
|
|
58
|
+
report('HESH-HTML-002', `Unsupported active/foreign template element <${node.tagName}>`, at, 'Use semantic HTML and declared CSS/JS modules.');
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const id = `node${serial++}`;
|
|
62
|
+
lines.push(`const ${id} = p.element(${parent}, ${JSON.stringify(node.tagName)});`);
|
|
63
|
+
const attributes = Object.fromEntries(node.attrs.map(attr => [attr.name, attr.value]));
|
|
64
|
+
const attrAt = (name) => node.sourceCodeLocation?.attrs?.[name]?.startOffset ?? at;
|
|
65
|
+
for (const attr of node.attrs) {
|
|
66
|
+
if (attr.name.startsWith('h-'))
|
|
67
|
+
continue;
|
|
68
|
+
if (/^on/i.test(attr.name) || ['srcdoc', 'innerhtml', 'outerhtml'].includes(attr.name)) {
|
|
69
|
+
report('HESH-HTML-003', `Unsafe attribute ${attr.name}`, attrAt(attr.name), 'Use h-action and safe DOM bindings.');
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const wholeBinding = attr.value.startsWith('{') && attr.value.endsWith('}') && !attr.value.slice(1, -1).includes('{') && !attr.value.slice(1, -1).includes('}');
|
|
73
|
+
lines.push(`p.attribute(${id}, ${JSON.stringify(attr.name)}, () => ${wholeBinding ? path(attr.value.slice(1, -1), attrAt(attr.name) + 1) : interpolation(attr.value, attrAt(attr.name))});`);
|
|
74
|
+
}
|
|
75
|
+
for (const name of Object.keys(attributes))
|
|
76
|
+
if (name.startsWith('h-') && !['h-action', 'h-bind', 'h-value', 'h-destination', 'h-part', 'h-outlet'].includes(name) && !name.startsWith('h-input-'))
|
|
77
|
+
report('HESH-HTML-004', `Unsupported directive ${name}`, attrAt(name), 'Use supported directives; keyed lists/scoped templates are a later milestone.');
|
|
78
|
+
const content = ['h-bind', 'h-part', 'h-outlet'].filter(name => attributes[name] !== undefined);
|
|
79
|
+
if (content.length > 1 || (content.length && node.childNodes.length))
|
|
80
|
+
report('HESH-HTML-005', 'Content directives require an empty container and cannot be combined', at, 'Choose one content directive and remove children.');
|
|
81
|
+
if (attributes['h-part'] !== undefined || attributes['h-outlet'] !== undefined) {
|
|
82
|
+
if (['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'].includes(node.tagName))
|
|
83
|
+
report('HESH-HTML-005', 'Parts and outlets require a container element', at, 'Use div, main, section or another container.');
|
|
84
|
+
if (attributes['h-part'] !== undefined) {
|
|
85
|
+
const name = attributes['h-part'];
|
|
86
|
+
if (!contract.parts?.includes(name))
|
|
87
|
+
report('HESH-PART-001', `Undeclared Hesh part ${name}`, at, 'Declare parts and return a Hesh Unit from parts.NAME.');
|
|
88
|
+
lines.push(`p.mountPart(${id}, state, ${JSON.stringify(name)});`);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
if (!contract.allowOutlet || attributes['h-outlet'] !== '')
|
|
92
|
+
report('HESH-PART-002', 'h-outlet is only available on standalone shell screens', at, 'Use an empty h-outlet on the persistent shell.');
|
|
93
|
+
lines.push(`p.unitOutlet(${id});`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else if (attributes['h-bind'] !== undefined) {
|
|
97
|
+
if (node.childNodes.length)
|
|
98
|
+
report('HESH-BIND-003', 'h-bind cannot also contain children', at, 'Remove the children or use text interpolation.');
|
|
99
|
+
lines.push(`p.text(${id}, () => ${path(attributes['h-bind'], attrAt('h-bind'))});`);
|
|
100
|
+
}
|
|
101
|
+
else
|
|
102
|
+
node.childNodes.forEach(child => visit(child, id));
|
|
103
|
+
if (attributes['h-action'] !== undefined) {
|
|
104
|
+
const name = attributes['h-action'];
|
|
105
|
+
usedActions.add(name);
|
|
106
|
+
if (!contract.actions.includes(name))
|
|
107
|
+
report('HESH-ACTION-001', `Missing action ${name}`, attrAt('h-action'), 'Declare and implement the action.');
|
|
108
|
+
lines.push(`p.bindAction(${id}, state, ${JSON.stringify(name)});`);
|
|
109
|
+
}
|
|
110
|
+
if (attributes['h-value'] !== undefined) {
|
|
111
|
+
const name = attributes['h-value'];
|
|
112
|
+
if (!['input', 'textarea', 'select'].includes(node.tagName) || name.includes('.') || ['checkbox', 'radio', 'file'].includes(attributes.type ?? '') || attributes.multiple !== undefined)
|
|
113
|
+
report('HESH-BIND-004', 'h-value requires a single-value text control and root writable signal', attrAt('h-value'), 'Use a text input/textarea/single select and a declared signal.');
|
|
114
|
+
path(name, attrAt('h-value'), undefined, true);
|
|
115
|
+
lines.push(`p.bindValue(${id}, state.bindings, ${JSON.stringify(name)});`);
|
|
116
|
+
}
|
|
117
|
+
const destination = attributes['h-destination'];
|
|
118
|
+
const inputs = Object.keys(attributes).filter(name => name.startsWith('h-input-'));
|
|
119
|
+
if (destination !== undefined) {
|
|
120
|
+
linked.add(destination);
|
|
121
|
+
const schema = contract.destinations[destination];
|
|
122
|
+
if (!schema)
|
|
123
|
+
report('HESH-NAV-001', `Unknown destination ${destination}`, attrAt('h-destination'), 'Declare this destination in the application.');
|
|
124
|
+
if (node.tagName !== 'a' || attributes.href !== undefined)
|
|
125
|
+
report('HESH-NAV-002', 'h-destination requires an anchor without an explicit href', at, 'Use <a h-destination="Name" ...>.');
|
|
126
|
+
for (const key of Object.keys(schema ?? {}))
|
|
127
|
+
if (attributes[`h-input-${key.toLowerCase()}`] === undefined)
|
|
128
|
+
report('HESH-NAV-003', `Missing destination input ${key}`, at, `Add h-input-${key} bound to a declared value.`);
|
|
129
|
+
const entries = inputs.map(attr => {
|
|
130
|
+
const key = Object.keys(schema ?? {}).find(key => key.toLowerCase() === attr.slice(8)) ?? attr.slice(8);
|
|
131
|
+
if (!schema || !Object.hasOwn(schema, key))
|
|
132
|
+
report('HESH-NAV-003', `Unknown destination input ${key}`, attrAt(attr), 'Use only inputs declared by the destination.');
|
|
133
|
+
return `${JSON.stringify(key)}: ${path(attributes[attr], attrAt(attr), schema?.[key])}`;
|
|
134
|
+
});
|
|
135
|
+
lines.push(`p.attribute(${id}, 'href', () => destinations[${JSON.stringify(destination)}].href({${entries.join(',')}}));`);
|
|
136
|
+
}
|
|
137
|
+
else if (inputs.length)
|
|
138
|
+
report('HESH-NAV-003', 'h-input-* requires h-destination', at, 'Declare the destination on this anchor.');
|
|
139
|
+
};
|
|
140
|
+
fragment.childNodes.forEach(node => visit(node, 'parent'));
|
|
141
|
+
lines.push('}');
|
|
142
|
+
for (const name of contract.bindings)
|
|
143
|
+
if (!usedBindings.has(name))
|
|
144
|
+
report('HESH-BIND-005', `Unused binding ${name}`, 0, 'Remove the declaration if it is not needed by this template.', 'warning');
|
|
145
|
+
for (const name of contract.actions)
|
|
146
|
+
if (!usedActions.has(name))
|
|
147
|
+
report('HESH-ACTION-002', `Unused action ${name}`, 0, 'Remove the declaration if it is not needed by this template.', 'warning');
|
|
148
|
+
return { code: lines.join('\n'), diagnostics, usedBindings: [...usedBindings], usedActions: [...usedActions], destinations: [...linked] };
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/architecture/html.ts"],"names":[],"mappings":"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","sourcesContent":["import { parseFragment, type DefaultTreeAdapterMap } from 'parse5';\nimport { diagnostic, type ArchitectureDiagnostic } from './diagnostics.js';\nexport interface HTMLContract {\n filename: string; bindings: string[]; actions: string[];\n parts?: string[]; allowOutlet?: boolean;\n destinations: Record<string, Record<string, string>>;\n validateBinding?: (path: string, offset: number, expected?: string, writable?: boolean) => void;\n}\nexport interface HTMLResult { code: string; diagnostics: ArchitectureDiagnostic[]; usedBindings: string[]; usedActions: string[]; destinations: string[] }\nexport function compileHTML(source: string, contract: HTMLContract): HTMLResult {\n const diagnostics: ArchitectureDiagnostic[] = [], usedBindings = new Set<string>(), usedActions = new Set<string>();\n const report = (code: string, message: string, at: number, suggestion: string, severity: 'error' | 'warning' = 'error') => diagnostics.push(diagnostic(code, message, contract.filename, source, at, suggestion, severity));\n const fragment = parseFragment(source, { sourceCodeLocationInfo: true, onParseError: error => report('HESH-HTML-001', error.code, error.startOffset, 'Correct the HTML syntax.') });\n const lines = [\"import * as p from '@heshammesalam/heshjs/presentation';\", 'export default function render(parent, state, destinations) {'];\n let serial = 0;\n const linked = new Set<string>();\n const path = (value: string, offset: number, expected?: string, writable = false): string => {\n const pieces = value.trim().split('.');\n if (pieces.some(piece => !/^[$_\\p{ID_Start}][$_\\u200c\\u200d\\p{ID_Continue}]*$/u.test(piece) || ['constructor', '__proto__', 'prototype'].includes(piece))) report('HESH-BIND-001', `Invalid binding path ${value}`, offset, 'Use a declared dotted data path, not an expression.');\n if (!contract.bindings.includes(pieces[0]!)) report('HESH-BIND-002', `Missing data binding ${pieces[0]}`, offset, 'Declare the binding and return it from the presentation factory.');\n usedBindings.add(pieces[0]!); contract.validateBinding?.(value.trim(), offset, expected, writable);\n return `p.readBinding(state.bindings, ${JSON.stringify(value.trim())})`;\n };\n const interpolation = (value: string, offset: number): string => {\n const parts: string[] = []; let literal = '', cursor = 0;\n const emit = () => { if (literal) { parts.push(JSON.stringify(literal)); literal = ''; } };\n while (cursor < value.length) {\n if (value[cursor] === '\\\\' && ['{', '}'].includes(value[cursor + 1] ?? '')) { literal += value[cursor + 1]; cursor += 2; continue; }\n if (value[cursor] !== '{') { literal += value[cursor++]; continue; }\n emit(); const start = ++cursor, end = value.indexOf('}', start);\n if (end < 0) { report('HESH-BIND-001', 'Unterminated interpolation', offset + start - 1, 'Close the binding with }.'); break; }\n parts.push(`String(${path(value.slice(start, end), offset + start)} ?? '')`); cursor = end + 1;\n }\n emit(); return parts.join(' + ') || \"''\";\n };\n const visit = (node: DefaultTreeAdapterMap['childNode'], parent: string): void => {\n const at = node.sourceCodeLocation?.startOffset ?? 0;\n if (node.nodeName === '#text') { lines.push(`p.text(${parent}, () => ${interpolation((node as DefaultTreeAdapterMap['textNode']).value, at)});`); return; }\n if (!('tagName' in node)) return;\n if (node.namespaceURI !== 'http://www.w3.org/1999/xhtml' || ['script', 'iframe', 'object', 'embed', 'base', 'meta', 'link', 'style', 'template'].includes(node.tagName)) {\n report('HESH-HTML-002', `Unsupported active/foreign template element <${node.tagName}>`, at, 'Use semantic HTML and declared CSS/JS modules.'); return;\n }\n const id = `node${serial++}`;\n lines.push(`const ${id} = p.element(${parent}, ${JSON.stringify(node.tagName)});`);\n const attributes = Object.fromEntries(node.attrs.map(attr => [attr.name, attr.value]));\n const attrAt = (name: string) => node.sourceCodeLocation?.attrs?.[name]?.startOffset ?? at;\n for (const attr of node.attrs) {\n if (attr.name.startsWith('h-')) continue;\n if (/^on/i.test(attr.name) || ['srcdoc', 'innerhtml', 'outerhtml'].includes(attr.name)) { report('HESH-HTML-003', `Unsafe attribute ${attr.name}`, attrAt(attr.name), 'Use h-action and safe DOM bindings.'); continue; }\n const wholeBinding = attr.value.startsWith('{') && attr.value.endsWith('}') && !attr.value.slice(1, -1).includes('{') && !attr.value.slice(1, -1).includes('}');\n lines.push(`p.attribute(${id}, ${JSON.stringify(attr.name)}, () => ${wholeBinding ? path(attr.value.slice(1, -1), attrAt(attr.name) + 1) : interpolation(attr.value, attrAt(attr.name))});`);\n }\n for (const name of Object.keys(attributes)) if (name.startsWith('h-') && !['h-action', 'h-bind', 'h-value', 'h-destination', 'h-part', 'h-outlet'].includes(name) && !name.startsWith('h-input-')) report('HESH-HTML-004', `Unsupported directive ${name}`, attrAt(name), 'Use supported directives; keyed lists/scoped templates are a later milestone.');\n const content = ['h-bind', 'h-part', 'h-outlet'].filter(name => attributes[name] !== undefined);\n if (content.length > 1 || (content.length && node.childNodes.length)) report('HESH-HTML-005', 'Content directives require an empty container and cannot be combined', at, 'Choose one content directive and remove children.');\n if (attributes['h-part'] !== undefined || attributes['h-outlet'] !== undefined) {\n if (['area','base','br','col','embed','hr','img','input','link','meta','param','source','track','wbr'].includes(node.tagName)) report('HESH-HTML-005', 'Parts and outlets require a container element', at, 'Use div, main, section or another container.');\n if (attributes['h-part'] !== undefined) {\n const name = attributes['h-part'];\n if (!contract.parts?.includes(name)) report('HESH-PART-001', `Undeclared Hesh part ${name}`, at, 'Declare parts and return a Hesh Unit from parts.NAME.');\n lines.push(`p.mountPart(${id}, state, ${JSON.stringify(name)});`);\n } else {\n if (!contract.allowOutlet || attributes['h-outlet'] !== '') report('HESH-PART-002', 'h-outlet is only available on standalone shell screens', at, 'Use an empty h-outlet on the persistent shell.');\n lines.push(`p.unitOutlet(${id});`);\n }\n } else if (attributes['h-bind'] !== undefined) {\n if (node.childNodes.length) report('HESH-BIND-003', 'h-bind cannot also contain children', at, 'Remove the children or use text interpolation.');\n lines.push(`p.text(${id}, () => ${path(attributes['h-bind'], attrAt('h-bind'))});`);\n } else node.childNodes.forEach(child => visit(child, id));\n if (attributes['h-action'] !== undefined) {\n const name = attributes['h-action']; usedActions.add(name);\n if (!contract.actions.includes(name)) report('HESH-ACTION-001', `Missing action ${name}`, attrAt('h-action'), 'Declare and implement the action.');\n lines.push(`p.bindAction(${id}, state, ${JSON.stringify(name)});`);\n }\n if (attributes['h-value'] !== undefined) {\n const name = attributes['h-value'];\n if (!['input', 'textarea', 'select'].includes(node.tagName) || name.includes('.') || ['checkbox', 'radio', 'file'].includes(attributes.type ?? '') || attributes.multiple !== undefined) report('HESH-BIND-004', 'h-value requires a single-value text control and root writable signal', attrAt('h-value'), 'Use a text input/textarea/single select and a declared signal.');\n path(name, attrAt('h-value'), undefined, true);\n lines.push(`p.bindValue(${id}, state.bindings, ${JSON.stringify(name)});`);\n }\n const destination = attributes['h-destination'];\n const inputs = Object.keys(attributes).filter(name => name.startsWith('h-input-'));\n if (destination !== undefined) {\n linked.add(destination);\n const schema = contract.destinations[destination];\n if (!schema) report('HESH-NAV-001', `Unknown destination ${destination}`, attrAt('h-destination'), 'Declare this destination in the application.');\n if (node.tagName !== 'a' || attributes.href !== undefined) report('HESH-NAV-002', 'h-destination requires an anchor without an explicit href', at, 'Use <a h-destination=\"Name\" ...>.');\n for (const key of Object.keys(schema ?? {})) if (attributes[`h-input-${key.toLowerCase()}`] === undefined) report('HESH-NAV-003', `Missing destination input ${key}`, at, `Add h-input-${key} bound to a declared value.`);\n const entries = inputs.map(attr => {\n const key = Object.keys(schema ?? {}).find(key => key.toLowerCase() === attr.slice(8)) ?? attr.slice(8);\n if (!schema || !Object.hasOwn(schema, key)) report('HESH-NAV-003', `Unknown destination input ${key}`, attrAt(attr), 'Use only inputs declared by the destination.');\n return `${JSON.stringify(key)}: ${path(attributes[attr]!, attrAt(attr), schema?.[key])}`;\n });\n lines.push(`p.attribute(${id}, 'href', () => destinations[${JSON.stringify(destination)}].href({${entries.join(',')}}));`);\n } else if (inputs.length) report('HESH-NAV-003', 'h-input-* requires h-destination', at, 'Declare the destination on this anchor.');\n };\n fragment.childNodes.forEach(node => visit(node, 'parent')); lines.push('}');\n for (const name of contract.bindings) if (!usedBindings.has(name)) report('HESH-BIND-005', `Unused binding ${name}`, 0, 'Remove the declaration if it is not needed by this template.', 'warning');\n for (const name of contract.actions) if (!usedActions.has(name)) report('HESH-ACTION-002', `Unused action ${name}`, 0, 'Remove the declaration if it is not needed by this template.', 'warning');\n return { code: lines.join('\\n'), diagnostics, usedBindings: [...usedBindings], usedActions: [...usedActions], destinations: [...linked] };\n}\n"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { compileHTML } from './html.js';
|
|
2
|
+
import { formatDiagnostic, type ArchitectureDiagnostic } from './diagnostics.js';
|
|
3
|
+
export { compileHTML, formatDiagnostic };
|
|
4
|
+
export type { ArchitectureDiagnostic };
|
|
5
|
+
export interface ProjectOptions {
|
|
6
|
+
root: string;
|
|
7
|
+
entry?: string;
|
|
8
|
+
tsconfig?: string;
|
|
9
|
+
outDir?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ProjectResult {
|
|
12
|
+
diagnostics: ArchitectureDiagnostic[];
|
|
13
|
+
files: string[];
|
|
14
|
+
outputs: Record<string, string>;
|
|
15
|
+
graph: {
|
|
16
|
+
domains: {
|
|
17
|
+
name: string;
|
|
18
|
+
exposes: string[];
|
|
19
|
+
consumes: string[];
|
|
20
|
+
}[];
|
|
21
|
+
destinations: {
|
|
22
|
+
name: string;
|
|
23
|
+
url: string;
|
|
24
|
+
input: Record<string, string>;
|
|
25
|
+
owner: string;
|
|
26
|
+
}[];
|
|
27
|
+
links: {
|
|
28
|
+
from: string;
|
|
29
|
+
to: string;
|
|
30
|
+
}[];
|
|
31
|
+
};
|
|
32
|
+
statistics: {
|
|
33
|
+
parsed: number;
|
|
34
|
+
reused: number;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export declare function createArchitectureCompiler(): {
|
|
38
|
+
clear(): void;
|
|
39
|
+
check(options: ProjectOptions): ProjectResult;
|
|
40
|
+
};
|
|
41
|
+
export declare function checkProject(options: ProjectOptions): ProjectResult;
|
|
42
|
+
export declare function writeProject(result: ProjectResult): void;
|