@heshammesalam/heshjs 0.2.0 → 0.3.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.
Files changed (45) hide show
  1. package/README.md +8 -2
  2. package/cli.js +26 -0
  3. package/dist/architecture/diagnostics.d.ts +12 -0
  4. package/dist/architecture/diagnostics.js +8 -0
  5. package/dist/architecture/diagnostics.js.map +1 -0
  6. package/dist/architecture/html.d.ts +16 -0
  7. package/dist/architecture/html.js +132 -0
  8. package/dist/architecture/html.js.map +1 -0
  9. package/dist/architecture/index.d.ts +42 -0
  10. package/dist/architecture/index.js +418 -0
  11. package/dist/architecture/index.js.map +1 -0
  12. package/dist/compiler/index.js +2 -0
  13. package/dist/compiler/index.js.map +1 -1
  14. package/dist/destinations/index.d.ts +63 -0
  15. package/dist/destinations/index.js +185 -0
  16. package/dist/destinations/index.js.map +1 -0
  17. package/dist/dom/index.d.ts +2 -0
  18. package/dist/dom/index.js +5 -1
  19. package/dist/dom/index.js.map +1 -1
  20. package/dist/domains/index.d.ts +24 -0
  21. package/dist/domains/index.js +110 -0
  22. package/dist/domains/index.js.map +1 -0
  23. package/dist/parser/index.d.ts +15 -1
  24. package/dist/parser/index.js +73 -3
  25. package/dist/parser/index.js.map +1 -1
  26. package/dist/presentation/index.d.ts +9 -0
  27. package/dist/presentation/index.js +38 -0
  28. package/dist/presentation/index.js.map +1 -0
  29. package/dist/vite/index.d.ts +4 -1
  30. package/dist/vite/index.js +36 -2
  31. package/dist/vite/index.js.map +1 -1
  32. package/docs/contracts.md +60 -0
  33. package/docs/domain-graph.md +205 -0
  34. package/docs/grammar.md +4 -0
  35. package/package.json +8 -3
  36. package/src/architecture/diagnostics.ts +11 -0
  37. package/src/architecture/html.ts +88 -0
  38. package/src/architecture/index.ts +283 -0
  39. package/src/compiler/index.ts +1 -0
  40. package/src/destinations/index.ts +146 -0
  41. package/src/dom/index.ts +6 -1
  42. package/src/domains/index.ts +97 -0
  43. package/src/parser/index.ts +55 -4
  44. package/src/presentation/index.ts +31 -0
  45. package/src/vite/index.ts +24 -2
package/README.md CHANGED
@@ -1,7 +1,13 @@
1
1
  # HeshJS
2
2
 
3
- An independent JavaScript/TypeScript UI framework created by Hesham. Experimental
4
- 0.2 release with History API routing and hierarchical MVC modules.
3
+ An independent JavaScript/TypeScript UI framework created by Hesham, with History
4
+ API routing and hierarchical MVC modules plus an experimental Domain Graph layer.
5
+
6
+ Version 0.3 adds opt-in .hesh domain/presentation/destination contracts,
7
+ the Node-only `/architecture` compiler and `hesh check|graph` command, `/domains`,
8
+ `/presentation` and `/destinations` runtimes. See docs/contracts.md and
9
+ docs/domain-graph.md for the precise supported slice and its limits. The default
10
+ creator remains an HMVC starter; Domain Graph is enabled explicitly in Vite.
5
11
 
6
12
  Requires Node.js 22.12 or later.
7
13
 
package/cli.js ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ import { checkProject, writeProject, formatDiagnostic } from './dist/architecture/index.js';
3
+ const args = process.argv.slice(2);
4
+ const command = args.shift();
5
+ if (command === '--help' || command === '-h' || !command) {
6
+ console.log('Usage: hesh check|graph [project-root] [--entry app.hesh] [--tsconfig tsconfig.json] [--write]');
7
+ process.exit(command ? 0 : 1);
8
+ }
9
+ if (!['check', 'graph'].includes(command)) { console.error(`Unknown command ${command}`); process.exit(1); }
10
+ const options = { root: process.cwd() }; let write = false;
11
+ if (args[0] && !args[0].startsWith('--')) options.root = args.shift();
12
+ while (args.length) {
13
+ const flag = args.shift();
14
+ if (flag === '--write') { write = true; continue; }
15
+ if (!['--entry', '--tsconfig'].includes(flag) || !args[0] || args[0].startsWith('--')) { console.error(`Invalid option ${flag}`); process.exit(1); }
16
+ options[flag.slice(2)] = args.shift();
17
+ }
18
+ try {
19
+ const result = checkProject(options);
20
+ for (const item of result.diagnostics) console.error(formatDiagnostic(item));
21
+ if (result.diagnostics.some(item => item.severity === 'error')) process.exitCode = 1;
22
+ else {
23
+ if (write) writeProject(result);
24
+ 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' : ''}.`);
25
+ }
26
+ } catch (error) { console.error(error instanceof Error ? error.message : String(error)); process.exitCode = 1; }
@@ -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,16 @@
1
+ import { type ArchitectureDiagnostic } from './diagnostics.js';
2
+ export interface HTMLContract {
3
+ filename: string;
4
+ bindings: string[];
5
+ actions: string[];
6
+ destinations: Record<string, Record<string, string>>;
7
+ validateBinding?: (path: string, offset: number, expected?: string, writable?: boolean) => void;
8
+ }
9
+ export interface HTMLResult {
10
+ code: string;
11
+ diagnostics: ArchitectureDiagnostic[];
12
+ usedBindings: string[];
13
+ usedActions: string[];
14
+ destinations: string[];
15
+ }
16
+ export declare function compileHTML(source: string, contract: HTMLContract): HTMLResult;
@@ -0,0 +1,132 @@
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'].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
+ if (attributes['h-bind'] !== undefined) {
79
+ if (node.childNodes.length)
80
+ report('HESH-BIND-003', 'h-bind cannot also contain children', at, 'Remove the children or use text interpolation.');
81
+ lines.push(`p.text(${id}, () => ${path(attributes['h-bind'], attrAt('h-bind'))});`);
82
+ }
83
+ else
84
+ node.childNodes.forEach(child => visit(child, id));
85
+ if (attributes['h-action'] !== undefined) {
86
+ const name = attributes['h-action'];
87
+ usedActions.add(name);
88
+ if (!contract.actions.includes(name))
89
+ report('HESH-ACTION-001', `Missing action ${name}`, attrAt('h-action'), 'Declare and implement the action.');
90
+ lines.push(`p.bindAction(${id}, state, ${JSON.stringify(name)});`);
91
+ }
92
+ if (attributes['h-value'] !== undefined) {
93
+ const name = attributes['h-value'];
94
+ if (!['input', 'textarea', 'select'].includes(node.tagName) || name.includes('.') || ['checkbox', 'radio', 'file'].includes(attributes.type ?? '') || attributes.multiple !== undefined)
95
+ 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.');
96
+ path(name, attrAt('h-value'), undefined, true);
97
+ lines.push(`p.bindValue(${id}, state.bindings, ${JSON.stringify(name)});`);
98
+ }
99
+ const destination = attributes['h-destination'];
100
+ const inputs = Object.keys(attributes).filter(name => name.startsWith('h-input-'));
101
+ if (destination !== undefined) {
102
+ linked.add(destination);
103
+ const schema = contract.destinations[destination];
104
+ if (!schema)
105
+ report('HESH-NAV-001', `Unknown destination ${destination}`, attrAt('h-destination'), 'Declare this destination in the application.');
106
+ if (node.tagName !== 'a' || attributes.href !== undefined)
107
+ report('HESH-NAV-002', 'h-destination requires an anchor without an explicit href', at, 'Use <a h-destination="Name" ...>.');
108
+ for (const key of Object.keys(schema ?? {}))
109
+ if (attributes[`h-input-${key.toLowerCase()}`] === undefined)
110
+ report('HESH-NAV-003', `Missing destination input ${key}`, at, `Add h-input-${key} bound to a declared value.`);
111
+ const entries = inputs.map(attr => {
112
+ const key = Object.keys(schema ?? {}).find(key => key.toLowerCase() === attr.slice(8)) ?? attr.slice(8);
113
+ if (!schema || !Object.hasOwn(schema, key))
114
+ report('HESH-NAV-003', `Unknown destination input ${key}`, attrAt(attr), 'Use only inputs declared by the destination.');
115
+ return `${JSON.stringify(key)}: ${path(attributes[attr], attrAt(attr), schema?.[key])}`;
116
+ });
117
+ lines.push(`p.attribute(${id}, 'href', () => destinations[${JSON.stringify(destination)}].href({${entries.join(',')}}));`);
118
+ }
119
+ else if (inputs.length)
120
+ report('HESH-NAV-003', 'h-input-* requires h-destination', at, 'Declare the destination on this anchor.');
121
+ };
122
+ fragment.childNodes.forEach(node => visit(node, 'parent'));
123
+ lines.push('}');
124
+ for (const name of contract.bindings)
125
+ if (!usedBindings.has(name))
126
+ report('HESH-BIND-005', `Unused binding ${name}`, 0, 'Remove the declaration if it is not needed by this template.', 'warning');
127
+ for (const name of contract.actions)
128
+ if (!usedActions.has(name))
129
+ report('HESH-ACTION-002', `Unused action ${name}`, 0, 'Remove the declaration if it is not needed by this template.', 'warning');
130
+ return { code: lines.join('\n'), diagnostics, usedBindings: [...usedBindings], usedActions: [...usedActions], destinations: [...linked] };
131
+ }
132
+ //# 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 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'].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 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;