@heshammesalam/heshjs 0.1.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 (54) hide show
  1. package/README.md +19 -4
  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/hmvc/index.d.ts +35 -0
  24. package/dist/hmvc/index.js +49 -0
  25. package/dist/hmvc/index.js.map +1 -0
  26. package/dist/parser/index.d.ts +15 -1
  27. package/dist/parser/index.js +73 -3
  28. package/dist/parser/index.js.map +1 -1
  29. package/dist/presentation/index.d.ts +9 -0
  30. package/dist/presentation/index.js +38 -0
  31. package/dist/presentation/index.js.map +1 -0
  32. package/dist/router/index.d.ts +24 -0
  33. package/dist/router/index.js +258 -0
  34. package/dist/router/index.js.map +1 -0
  35. package/dist/vite/index.d.ts +4 -1
  36. package/dist/vite/index.js +37 -2
  37. package/dist/vite/index.js.map +1 -1
  38. package/docs/contracts.md +60 -0
  39. package/docs/domain-graph.md +205 -0
  40. package/docs/grammar.md +4 -0
  41. package/docs/hmvc.md +134 -0
  42. package/package.json +10 -3
  43. package/src/architecture/diagnostics.ts +11 -0
  44. package/src/architecture/html.ts +88 -0
  45. package/src/architecture/index.ts +283 -0
  46. package/src/compiler/index.ts +1 -0
  47. package/src/destinations/index.ts +146 -0
  48. package/src/dom/index.ts +6 -1
  49. package/src/domains/index.ts +97 -0
  50. package/src/hmvc/index.ts +71 -0
  51. package/src/parser/index.ts +55 -4
  52. package/src/presentation/index.ts +31 -0
  53. package/src/router/index.ts +171 -0
  54. package/src/vite/index.ts +25 -2
@@ -0,0 +1,110 @@
1
+ import { scope } from '../reactivity/index.js';
2
+ export class ClientPolicyDenied extends Error {
3
+ policy;
4
+ contract;
5
+ code = 'HESH-ACCESS-001';
6
+ constructor(policy, contract) {
7
+ super(`Client policy denied: ${policy} (${contract}). Server authorization is still required.`);
8
+ this.policy = policy;
9
+ this.contract = contract;
10
+ }
11
+ }
12
+ const unsafe = new Set(['__proto__', 'constructor', 'prototype']);
13
+ export function contractPath(path) {
14
+ const parts = path.split('.');
15
+ if (parts.some(p => !p || unsafe.has(p)))
16
+ throw new Error(`Invalid contract path ${path}`);
17
+ return parts;
18
+ }
19
+ function project(target, path, value) {
20
+ const name = path[0];
21
+ if (path.length === 1) {
22
+ target[name] = value;
23
+ return;
24
+ }
25
+ if (target[name] !== undefined && (typeof target[name] !== 'object' || target[name] === null))
26
+ throw new Error(`Overlapping public contracts at ${name}`);
27
+ const next = (target[name] ??= Object.create(null));
28
+ project(next, path.slice(1), value);
29
+ }
30
+ function freeze(value) {
31
+ for (const child of Object.values(value))
32
+ if (child && typeof child === 'object')
33
+ freeze(child);
34
+ return Object.freeze(value);
35
+ }
36
+ function lookup(value, parts) {
37
+ let receiver;
38
+ for (const part of parts) {
39
+ receiver = value;
40
+ value = value != null && Object.hasOwn(Object(value), part) ? value[part] : undefined;
41
+ }
42
+ return { value, receiver };
43
+ }
44
+ export function createDomainGraph(definitions, options = {}) {
45
+ const byName = new Map(definitions.map(d => [d.name, d]));
46
+ if (byName.size !== definitions.length)
47
+ throw new Error('Duplicate domain name');
48
+ const domains = Object.create(null);
49
+ const contexts = Object.create(null);
50
+ const building = new Set();
51
+ let disposed = false;
52
+ const owned = scope(() => {
53
+ const build = (name) => {
54
+ if (domains[name])
55
+ return domains[name];
56
+ const definition = byName.get(name);
57
+ if (!definition)
58
+ throw new Error(`Missing domain ${name}`);
59
+ if (building.has(name))
60
+ throw new Error(`Circular domain dependency at ${name}`);
61
+ building.add(name);
62
+ const dependencies = Object.create(null);
63
+ for (const dependency of definition.consumes) {
64
+ const [provider, ...operation] = contractPath(dependency);
65
+ if (!operation.length)
66
+ throw new Error(`Dependency must name an operation: ${dependency}`);
67
+ const target = build(provider);
68
+ const value = lookup(target, operation).value;
69
+ if (typeof value !== 'function')
70
+ throw new Error(`Missing public operation ${dependency}`);
71
+ project(dependencies[provider] ??= Object.create(null), operation, value);
72
+ }
73
+ freeze(dependencies);
74
+ const implementation = definition.factory(dependencies);
75
+ if (implementation && typeof implementation.then === 'function')
76
+ throw new Error(`Domain ${name} factory must be synchronous`);
77
+ const facade = Object.create(null);
78
+ for (const operation of definition.exposes) {
79
+ const parts = contractPath(operation);
80
+ const { value, receiver } = lookup(implementation, parts);
81
+ if (typeof value !== 'function')
82
+ throw new Error(`Unresolved implementation ${name}.${operation}`);
83
+ project(facade, parts, (...args) => {
84
+ if (disposed)
85
+ throw new Error('Domain graph is disposed');
86
+ const policy = definition.access?.[operation];
87
+ if (policy && options.authorize?.(policy) !== true)
88
+ throw new ClientPolicyDenied(policy, `${name}.${operation}`);
89
+ return Reflect.apply(value, receiver, args);
90
+ });
91
+ }
92
+ domains[name] = freeze(facade);
93
+ contexts[name] = Object.freeze({ ...dependencies, [name]: domains[name] });
94
+ building.delete(name);
95
+ return domains[name];
96
+ };
97
+ for (const definition of definitions)
98
+ build(definition.name);
99
+ freeze(domains);
100
+ });
101
+ return {
102
+ domains,
103
+ forDomain(name) { if (disposed)
104
+ throw new Error('Domain graph is disposed'); if (!contexts[name])
105
+ throw new Error(`Unknown domain context ${name}`); return contexts[name]; },
106
+ dispose() { if (disposed)
107
+ return; disposed = true; owned.dispose(); }
108
+ };
109
+ }
110
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/domains/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { scope, type Disposer } from '../reactivity/index.js';\nexport interface DomainDefinition {\n name: string;\n exposes: readonly string[];\n consumes: readonly string[];\n access?: Readonly<Record<string, string>>;\n factory: (dependencies: Record<string, Record<string, unknown>>) => unknown;\n}\nexport interface DomainOptions { authorize?: (policy: string) => boolean }\nexport class ClientPolicyDenied extends Error {\n readonly code = 'HESH-ACCESS-001';\n constructor(readonly policy: string, readonly contract: string) {\n super(`Client policy denied: ${policy} (${contract}). Server authorization is still required.`);\n }\n}\nexport interface DomainGraph<T = Record<string, Record<string, unknown>>> {\n readonly domains: T;\n forDomain(name: string): Record<string, unknown>;\n dispose: Disposer;\n}\nconst unsafe = new Set(['__proto__', 'constructor', 'prototype']);\nexport function contractPath(path: string): string[] {\n const parts = path.split('.');\n if (parts.some(p => !p || unsafe.has(p))) throw new Error(`Invalid contract path ${path}`);\n return parts;\n}\nfunction project(target: Record<string, unknown>, path: string[], value: unknown): void {\n const name = path[0]!;\n if (path.length === 1) { target[name] = value; return; }\n if (target[name] !== undefined && (typeof target[name] !== 'object' || target[name] === null)) throw new Error(`Overlapping public contracts at ${name}`);\n const next = (target[name] ??= Object.create(null)) as Record<string, unknown>;\n project(next, path.slice(1), value);\n}\nfunction freeze(value: Record<string, unknown>): Record<string, unknown> {\n for (const child of Object.values(value)) if (child && typeof child === 'object') freeze(child as Record<string, unknown>);\n return Object.freeze(value);\n}\nfunction lookup(value: unknown, parts: string[]): { value: unknown; receiver: unknown } {\n let receiver: unknown;\n for (const part of parts) {\n receiver = value;\n value = value != null && Object.hasOwn(Object(value), part) ? (value as Record<string, unknown>)[part] : undefined;\n }\n return { value, receiver };\n}\nexport function createDomainGraph(definitions: readonly DomainDefinition[], options: DomainOptions = {}): DomainGraph {\n const byName = new Map(definitions.map(d => [d.name, d]));\n if (byName.size !== definitions.length) throw new Error('Duplicate domain name');\n const domains: Record<string, Record<string, unknown>> = Object.create(null);\n const contexts: Record<string, Record<string, unknown>> = Object.create(null);\n const building = new Set<string>();\n let disposed = false;\n const owned = scope(() => {\n const build = (name: string): Record<string, unknown> => {\n if (domains[name]) return domains[name]!;\n const definition = byName.get(name);\n if (!definition) throw new Error(`Missing domain ${name}`);\n if (building.has(name)) throw new Error(`Circular domain dependency at ${name}`);\n building.add(name);\n const dependencies: Record<string, Record<string, unknown>> = Object.create(null);\n for (const dependency of definition.consumes) {\n const [provider, ...operation] = contractPath(dependency);\n if (!operation.length) throw new Error(`Dependency must name an operation: ${dependency}`);\n const target = build(provider!);\n const value = lookup(target, operation).value;\n if (typeof value !== 'function') throw new Error(`Missing public operation ${dependency}`);\n project(dependencies[provider!] ??= Object.create(null), operation, value);\n }\n freeze(dependencies);\n const implementation = definition.factory(dependencies);\n if (implementation && typeof (implementation as { then?: unknown }).then === 'function') throw new Error(`Domain ${name} factory must be synchronous`);\n const facade: Record<string, unknown> = Object.create(null);\n for (const operation of definition.exposes) {\n const parts = contractPath(operation);\n const { value, receiver } = lookup(implementation, parts);\n if (typeof value !== 'function') throw new Error(`Unresolved implementation ${name}.${operation}`);\n project(facade, parts, (...args: unknown[]) => {\n if (disposed) throw new Error('Domain graph is disposed');\n const policy = definition.access?.[operation];\n if (policy && options.authorize?.(policy) !== true) throw new ClientPolicyDenied(policy, `${name}.${operation}`);\n return Reflect.apply(value, receiver, args);\n });\n }\n domains[name] = freeze(facade);\n contexts[name] = Object.freeze({ ...dependencies, [name]: domains[name] });\n building.delete(name);\n return domains[name]!;\n };\n for (const definition of definitions) build(definition.name);\n freeze(domains);\n });\n return {\n domains,\n forDomain(name) { if (disposed) throw new Error('Domain graph is disposed'); if (!contexts[name]) throw new Error(`Unknown domain context ${name}`); return contexts[name]!; },\n dispose() { if (disposed) return; disposed = true; owned.dispose(); }\n };\n}\n"]}
@@ -0,0 +1,35 @@
1
+ import { type Component, type MountOptions } from '../dom/index.js';
2
+ import { type Signal, type Disposer } from '../reactivity/index.js';
3
+ export interface RouteLocation {
4
+ readonly url: URL;
5
+ readonly pathname: string;
6
+ readonly params: Readonly<Record<string, string>>;
7
+ readonly query: URLSearchParams;
8
+ readonly hash: string;
9
+ }
10
+ export interface ModuleContext<M = unknown, C = unknown> {
11
+ readonly route: Pick<Signal<RouteLocation>, 'get'>;
12
+ readonly parent?: ModuleContext;
13
+ readonly model: M;
14
+ readonly controller: C;
15
+ }
16
+ export interface ModuleDefinition<M, C> {
17
+ model: (context: Pick<ModuleContext, 'route' | 'parent'>) => M;
18
+ controller: (model: M, context: Pick<ModuleContext, 'route' | 'parent'>) => C;
19
+ view: Component;
20
+ }
21
+ export interface MountedModule {
22
+ readonly context: ModuleContext;
23
+ readonly outlet?: Node;
24
+ readonly dispose: Disposer;
25
+ update(location: RouteLocation): void;
26
+ }
27
+ export interface AppModule {
28
+ attach(parent: Node, location: RouteLocation, parentContext?: ModuleContext, options?: MountOptions): MountedModule;
29
+ }
30
+ export declare function useModule<M = unknown, C = unknown>(): ModuleContext<M, C>;
31
+ export declare function useController<C = unknown>(): C;
32
+ export declare function useModel<M = unknown>(): M;
33
+ /** Child route outlet. Import this component in a .hesh layout and call Outlet(). */
34
+ export declare function Outlet(parent: Node): void;
35
+ export declare function defineModule<M, C>(definition: ModuleDefinition<M, C>): AppModule;
@@ -0,0 +1,49 @@
1
+ import { mount, element } from '../dom/index.js';
2
+ import { signal } from '../reactivity/index.js';
3
+ let current;
4
+ export function useModule() {
5
+ if (!current)
6
+ throw new Error('Module context is only available during a module view mount');
7
+ return current.context;
8
+ }
9
+ export function useController() { return useModule().controller; }
10
+ export function useModel() { return useModule().model; }
11
+ /** Child route outlet. Import this component in a .hesh layout and call Outlet(). */
12
+ export function Outlet(parent) {
13
+ if (!current)
14
+ throw new Error('Outlet requires a module view');
15
+ if (current.outlet)
16
+ throw new Error('A module may render only one Outlet');
17
+ current.outlet = element(parent, 'div');
18
+ current.outlet.setAttribute('data-hesh-outlet', '');
19
+ }
20
+ export function defineModule(definition) {
21
+ return {
22
+ attach(parent, location, parentContext, options) {
23
+ const route = signal(location);
24
+ let state;
25
+ const dispose = mount(() => {
26
+ const context = { route: { get: route.get }, parent: parentContext };
27
+ const model = definition.model(context);
28
+ const controller = definition.controller(model, context);
29
+ for (const value of [model, controller]) {
30
+ if (value && typeof value.then === 'function')
31
+ throw new Error('HMVC model/controller factories must be synchronous');
32
+ }
33
+ state = { context: { ...context, model, controller } };
34
+ const previous = current;
35
+ current = state;
36
+ try {
37
+ const result = definition.view(parent);
38
+ if (result && typeof result.then === 'function')
39
+ throw new Error('HMVC views must mount synchronously');
40
+ }
41
+ finally {
42
+ current = previous;
43
+ }
44
+ }, parent, options);
45
+ return { context: state.context, outlet: state.outlet, dispose, update: next => { route.set(next); } };
46
+ }
47
+ };
48
+ }
49
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hmvc/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAqC,MAAM,iBAAiB,CAAC;AACpF,OAAO,EAAE,MAAM,EAA8B,MAAM,wBAAwB,CAAC;AA6B5E,IAAI,OAA8D,CAAC;AAEnE,MAAM,UAAU,SAAS;IACvB,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IAC7F,OAAO,OAAO,CAAC,OAA8B,CAAC;AAChD,CAAC;AACD,MAAM,UAAU,aAAa,KAAqB,OAAO,SAAS,EAAc,CAAC,UAAU,CAAC,CAAC,CAAC;AAC9F,MAAM,UAAU,QAAQ,KAAqB,OAAO,SAAS,EAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AAE3E,qFAAqF;AACrF,MAAM,UAAU,MAAM,CAAC,MAAY;IACjC,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAC/D,IAAI,OAAO,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IAC3E,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACvC,OAAO,CAAC,MAAsB,CAAC,YAAY,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,YAAY,CAAO,UAAkC;IACnE,OAAO;QACL,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO;YAC7C,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC/B,IAAI,KAA4D,CAAC;YACjE,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,EAAE;gBACzB,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;gBACrE,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBACxC,MAAM,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;gBACzD,KAAK,MAAM,KAAK,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,EAAE,CAAC;oBACxC,IAAI,KAAK,IAAI,OAAQ,KAA4B,CAAC,IAAI,KAAK,UAAU;wBAAE,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;gBAChJ,CAAC;gBACD,KAAK,GAAG,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,CAAC;gBACvD,MAAM,QAAQ,GAAG,OAAO,CAAC;gBACzB,OAAO,GAAG,KAAK,CAAC;gBAChB,IAAI,CAAC;oBACH,MAAM,MAAM,GAAY,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBAChD,IAAI,MAAM,IAAI,OAAQ,MAA6B,CAAC,IAAI,KAAK,UAAU;wBAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;gBAClI,CAAC;wBAAS,CAAC;oBAAC,OAAO,GAAG,QAAQ,CAAC;gBAAC,CAAC;YACnC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;YACpB,OAAO,EAAE,OAAO,EAAE,KAAM,CAAC,OAAO,EAAE,MAAM,EAAE,KAAM,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3G,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { mount, element, type Component, type MountOptions } from '../dom/index.js';\nimport { signal, type Signal, type Disposer } from '../reactivity/index.js';\n\nexport interface RouteLocation {\n readonly url: URL;\n readonly pathname: string;\n readonly params: Readonly<Record<string, string>>;\n readonly query: URLSearchParams;\n readonly hash: string;\n}\nexport interface ModuleContext<M = unknown, C = unknown> {\n readonly route: Pick<Signal<RouteLocation>, 'get'>;\n readonly parent?: ModuleContext;\n readonly model: M;\n readonly controller: C;\n}\nexport interface ModuleDefinition<M, C> {\n model: (context: Pick<ModuleContext, 'route' | 'parent'>) => M;\n controller: (model: M, context: Pick<ModuleContext, 'route' | 'parent'>) => C;\n view: Component;\n}\nexport interface MountedModule {\n readonly context: ModuleContext;\n readonly outlet?: Node;\n readonly dispose: Disposer;\n update(location: RouteLocation): void;\n}\nexport interface AppModule {\n attach(parent: Node, location: RouteLocation, parentContext?: ModuleContext, options?: MountOptions): MountedModule;\n}\nlet current: { context: ModuleContext; outlet?: Node } | undefined;\n\nexport function useModule<M = unknown, C = unknown>(): ModuleContext<M, C> {\n if (!current) throw new Error('Module context is only available during a module view mount');\n return current.context as ModuleContext<M, C>;\n}\nexport function useController<C = unknown>(): C { return useModule<unknown, C>().controller; }\nexport function useModel<M = unknown>(): M { return useModule<M>().model; }\n\n/** Child route outlet. Import this component in a .hesh layout and call Outlet(). */\nexport function Outlet(parent: Node): void {\n if (!current) throw new Error('Outlet requires a module view');\n if (current.outlet) throw new Error('A module may render only one Outlet');\n current.outlet = element(parent, 'div');\n (current.outlet as HTMLElement).setAttribute('data-hesh-outlet', '');\n}\n\nexport function defineModule<M, C>(definition: ModuleDefinition<M, C>): AppModule {\n return {\n attach(parent, location, parentContext, options) {\n const route = signal(location);\n let state: { context: ModuleContext; outlet?: Node } | undefined;\n const dispose = mount(() => {\n const context = { route: { get: route.get }, parent: parentContext };\n const model = definition.model(context);\n const controller = definition.controller(model, context);\n for (const value of [model, controller]) {\n if (value && typeof (value as { then?: unknown }).then === 'function') throw new Error('HMVC model/controller factories must be synchronous');\n }\n state = { context: { ...context, model, controller } };\n const previous = current;\n current = state;\n try {\n const result: unknown = definition.view(parent);\n if (result && typeof (result as { then?: unknown }).then === 'function') throw new Error('HMVC views must mount synchronously');\n } finally { current = previous; }\n }, parent, options);\n return { context: state!.context, outlet: state!.outlet, dispose, update: next => { route.set(next); } };\n }\n };\n}\n"]}
@@ -25,11 +25,25 @@ export interface View extends Location {
25
25
  default: boolean;
26
26
  body: (State | Element)[];
27
27
  }
28
+ export interface ContractEntry extends Location {
29
+ name: string;
30
+ value?: string;
31
+ }
32
+ export interface Contract extends Location {
33
+ kind: 'domain' | 'presentation' | 'destination' | 'application';
34
+ name: string;
35
+ fields: Record<string, ContractEntry>;
36
+ blocks: Record<string, ContractEntry[]>;
37
+ }
28
38
  export interface Module {
29
39
  source: string;
30
40
  filename: string;
31
41
  imports: Expression[];
32
42
  views: View[];
43
+ contracts?: Contract[];
44
+ }
45
+ export interface ParsedModule extends Module {
46
+ contracts: Contract[];
33
47
  }
34
48
  export declare class HeshError extends Error {
35
49
  readonly source: string;
@@ -44,4 +58,4 @@ export interface Token extends Location {
44
58
  kind: ts.SyntaxKind;
45
59
  }
46
60
  export declare function tokenize(source: string, filename?: string): Token[];
47
- export declare function parse(source: string, filename?: string): Module;
61
+ export declare function parse(source: string, filename?: string): ParsedModule;
@@ -169,8 +169,78 @@ export function parse(source, filename = 'component.hesh') {
169
169
  take(';');
170
170
  return { kind: 'element', name: name.text, start: name.start, end: tokens[at - 1].end, value, handler, async, children };
171
171
  };
172
- const module = { source, filename, imports: [], views: [] };
172
+ const contract = () => {
173
+ const kind = take();
174
+ const name = identifier();
175
+ take('{');
176
+ const result = { kind: kind.text, name: name.text, start: kind.start, end: 0, fields: Object.create(null), blocks: Object.create(null) };
177
+ const schemas = {
178
+ domain: { implementation: 'string', owns: 'list', exposes: 'list', consumes: 'list', access: 'map' },
179
+ presentation: { html: 'string', logic: 'string', styles: 'string', bindings: 'list', actions: 'list' },
180
+ destination: { url: 'string', input: 'map', presentation: 'identifier', access: 'string' },
181
+ application: { domains: 'list', destinations: 'list' }
182
+ };
183
+ const path = () => {
184
+ const first = identifier();
185
+ let name = first.text;
186
+ while (peek() === '.') {
187
+ take();
188
+ name += '.' + identifier().text;
189
+ }
190
+ for (const part of name.split('.'))
191
+ if (['__proto__', 'prototype', 'constructor'].includes(part))
192
+ fail('Unsafe contract identifier', first.start);
193
+ return { name, start: first.start, end: tokens[at - 1].end };
194
+ };
195
+ const string = () => {
196
+ const token = take();
197
+ if (token.kind !== ts.SyntaxKind.StringLiteral)
198
+ fail('Expected quoted string', token.start);
199
+ const parsed = ts.createSourceFile('literal.js', token.text, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
200
+ return parsed.statements[0].expression.text;
201
+ };
202
+ while (peek() && peek() !== '}') {
203
+ const key = take();
204
+ const type = Object.hasOwn(schemas[result.kind], key.text) ? schemas[result.kind][key.text] : undefined;
205
+ if (!type)
206
+ fail(`Unknown ${result.kind} field ${key.text}`, key.start);
207
+ if (result.fields[key.text] || result.blocks[key.text])
208
+ fail(`Duplicate field ${key.text}`, key.start);
209
+ if (type === 'string' || type === 'identifier') {
210
+ take(':');
211
+ const value = type === 'string' ? string() : identifier().text;
212
+ const end = take(';').end;
213
+ result.fields[key.text] = { name: key.text, value, start: key.start, end };
214
+ }
215
+ else {
216
+ take('{');
217
+ const entries = [];
218
+ const seen = new Set();
219
+ while (peek() && peek() !== '}') {
220
+ const entry = path();
221
+ if (seen.has(entry.name))
222
+ fail(`Duplicate entry ${entry.name}`, entry.start);
223
+ seen.add(entry.name);
224
+ if (type === 'map') {
225
+ take(':');
226
+ entry.value = key.text === 'input' ? identifier().text : string();
227
+ }
228
+ entry.end = take(';').end;
229
+ entries.push(entry);
230
+ }
231
+ take('}');
232
+ result.blocks[key.text] = entries;
233
+ }
234
+ }
235
+ result.end = take('}').end;
236
+ return result;
237
+ };
238
+ const module = { source, filename, imports: [], views: [], contracts: [] };
173
239
  while (tokens[at]) {
240
+ if (['domain', 'presentation', 'destination', 'application'].includes(peek() ?? '')) {
241
+ module.contracts.push(contract());
242
+ continue;
243
+ }
174
244
  if (peek() === 'import') {
175
245
  if (module.views.length)
176
246
  fail('Imports must precede views');
@@ -211,8 +281,8 @@ export function parse(source, filename = 'component.hesh') {
211
281
  const end = take('}').end;
212
282
  module.views.push({ name, body, start, end, exported, default: isDefault });
213
283
  }
214
- if (!module.views.length)
215
- fail('Expected at least one view');
284
+ if (!module.views.length && !module.contracts.length)
285
+ fail('Expected at least one view or architecture declaration');
216
286
  return module;
217
287
  }
218
288
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/parser/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAO5B,MAAM,OAAO,SAAU,SAAQ,KAAK;IAGI;IAAyB;IAAyB;IAF/E,IAAI,CAAS;IACb,MAAM,CAAS;IACxB,YAAY,OAAe,EAAW,MAAc,EAAW,MAAc,EAAW,WAAW,gBAAgB;QACjH,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,MAAM,GAAG,CAAC,CAAC;QAC7D,KAAK,CAAC,GAAG,QAAQ,IAAI,IAAI,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC,CAAC;QAHf,WAAM,GAAN,MAAM,CAAQ;QAAW,WAAM,GAAN,MAAM,CAAQ;QAAW,aAAQ,GAAR,QAAQ,CAAmB;QAIjH,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IAClE,CAAC;CACF;AAED,MAAM,UAAU,QAAQ,CAAC,MAAc,EAAE,QAAQ,GAAG,gBAAgB;IAClE,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,uPAAuP,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7R,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,MAAM,IAAI,GAAG,CAAC,OAAe,EAAE,MAAc,EAAS,EAAE,GAAG,MAAM,IAAI,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACrH,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,EAAE,CAAC;QACjB,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,CAAE,CAAC;QACvB,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YAAC,EAAE,EAAE,CAAC;YAAC,SAAS;QAAC,CAAC;QACtC,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;YAAC,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,EAAE,CAAC,KAAK,IAAI;gBAAE,EAAE,EAAE,CAAC;YAAC,SAAS;QAAC,CAAC;QACtG,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;YAChC,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;YACzC,IAAI,GAAG,GAAG,CAAC;gBAAE,IAAI,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC;YAC9C,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC;YAAC,SAAS;QACzB,CAAC;QACD,IAAI,IAAI,GAAG,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;QACjC,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YAC3C,MAAM,KAAK,GAAG,EAAE,CAAC;YACjB,EAAE,EAAE,CAAC;YAAC,IAAI,MAAM,GAAG,KAAK,CAAC;YACzB,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;gBAC1B,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,EAAE,CAAE,CAAC;gBAC9B,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;oBAAC,EAAE,EAAE,CAAC;oBAAC,SAAS;gBAAC,CAAC;gBACzC,IAAI,KAAK,KAAK,GAAG,IAAI,OAAO,KAAK,GAAG,IAAI,MAAM,CAAC,EAAE,CAAC,KAAK,GAAG;oBAAE,IAAI,CAAC,wEAAwE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;gBACnJ,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;oBAAC,MAAM,GAAG,IAAI,CAAC;oBAAC,MAAM;gBAAC,CAAC;gBAChD,IAAI,KAAK,KAAK,GAAG,IAAI,CAAC,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,IAAI,CAAC;oBAAE,IAAI,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;YAClG,CAAC;YACD,IAAI,CAAC,MAAM;gBAAE,IAAI,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;YAChD,IAAI,GAAG,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,6BAA6B,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC;QACnG,CAAC;aAAM,IAAI,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YACxC,EAAE,EAAE,CAAC;YACL,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,IAAI,iCAAiC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAE,CAAC;gBAAE,EAAE,EAAE,CAAC;YACvF,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC;QAClG,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YACzB,EAAE,EAAE,CAAC;YACL,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAE,CAAC;gBAAE,EAAE,EAAE,CAAC;YAC7D,IAAI,GAAG,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC;QACtC,CAAC;aAAM,CAAC;YACN,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;YAC1Q,EAAE,IAAI,QAAQ,EAAE,MAAM,IAAI,CAAC,CAAC;QAC9B,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,MAAc,EAAE,QAAQ,GAAG,gBAAgB;IAC/D,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC1C,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;IACpC,MAAM,IAAI,GAAG,CAAC,OAAe,EAAE,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC,EAAE,KAAK,IAAI,MAAM,CAAC,MAAM,EAAS,EAAE,GAAG,MAAM,IAAI,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAClJ,MAAM,IAAI,GAAG,CAAC,IAAa,EAAS,EAAE;QACpC,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;QACzB,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;YAAE,IAAI,CAAC,YAAY,IAAI,IAAI,OAAO,cAAc,IAAI,EAAE,IAAI,aAAa,EAAE,CAAC,CAAC;QACpI,EAAE,EAAE,CAAC;QAAC,OAAO,KAAM,CAAC;IACtB,CAAC,CAAC;IACF,MAAM,UAAU,GAAG,GAAG,EAAE;QACtB,MAAM,KAAK,GAAG,IAAI,EAAE,CAAC;QACrB,IAAI,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,UAAU;YAAE,IAAI,CAAC,qBAAqB,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACtF,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;YAAE,IAAI,CAAC,wCAAwC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QAC9F,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IACF,MAAM,UAAU,GAAG,CAAC,IAAc,EAAc,EAAE;QAChD,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,EAAE,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC;QACjD,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,MAAM,KAAK,GAA2B,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;QACvE,OAAO,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;YAClB,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAE,CAAC;YAC1B,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,MAAM;YACtD,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAE,CAAC,CAAC;iBACjD,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9C,IAAI,KAAK,CAAC,GAAG,EAAE,KAAK,KAAK,CAAC,IAAI;oBAAE,IAAI,CAAC,uBAAuB,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;YAC7E,CAAC;YACD,EAAE,EAAE,CAAC;QACP,CAAC;QACD,IAAI,KAAK,CAAC,MAAM;YAAE,IAAI,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;QACzD,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,CAAC,EAAE,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE;YAAE,IAAI,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;QACzE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IACpE,CAAC,CAAC;IACF,MAAM,OAAO,GAAG,GAAY,EAAE;QAC5B,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;QAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,KAA6B,EAAE,OAA+B,EAAE,KAAK,GAAG,KAAK,CAAC;QAClF,IAAI,IAAI,EAAE,KAAK,GAAG;YAAE,KAAK,GAAG,UAAU,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;QACnD,IAAI,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACnB,IAAI,CAAC,GAAG,CAAC,CAAC;YACV,IAAI,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC;gBAAC,IAAI,EAAE,CAAC;gBAAC,KAAK,GAAG,IAAI,CAAC;YAAC,CAAC;YACjD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC;YAC5B,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,OAAO,MAAM,CAAC,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC;gBAC3B,IAAI,IAAI,EAAE,KAAK,GAAG;oBAAE,KAAK,EAAE,CAAC;gBAC5B,IAAI,IAAI,EAAE,KAAK,GAAG;oBAAE,KAAK,EAAE,CAAC;gBAC5B,IAAI,KAAK;oBAAE,EAAE,EAAE,CAAC;YAClB,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;gBAAE,IAAI,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;YACzD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;YAC5B,OAAO,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;QAC7D,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,IAAI,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YAAC,IAAI,EAAE,CAAC;YAAC,OAAO,IAAI,EAAE,IAAI,IAAI,EAAE,KAAK,GAAG;gBAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;YAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAAC,IAAI,IAAI,EAAE,KAAK,GAAG;gBAAE,IAAI,EAAE,CAAC;QAAC,CAAC;;YAC5H,IAAI,CAAC,GAAG,CAAC,CAAC;QACf,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,GAAG,CAAC,CAAE,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;IAC5H,CAAC,CAAC;IACF,MAAM,MAAM,GAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACpE,OAAO,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;QAClB,IAAI,IAAI,EAAE,KAAK,QAAQ,EAAE,CAAC;YACxB,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM;gBAAE,IAAI,CAAC,4BAA4B,CAAC,CAAC;YAC5D,MAAM,KAAK,GAAG,IAAI,EAAE,CAAC,KAAK,CAAC;YAC3B,OAAO,IAAI,EAAE,IAAI,IAAI,EAAE,KAAK,GAAG;gBAAE,IAAI,EAAE,CAAC;YACxC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC;YAC1B,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAAC,SAAS;QAClF,CAAC;QACD,IAAI,QAAQ,GAAG,KAAK,EAAE,SAAS,GAAG,KAAK,CAAC;QACxC,IAAI,IAAI,EAAE,KAAK,QAAQ,EAAE,CAAC;YAAC,IAAI,EAAE,CAAC;YAAC,QAAQ,GAAG,IAAI,CAAC;QAAC,CAAC;QACrD,IAAI,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YAAC,IAAI,EAAE,CAAC;YAAC,SAAS,GAAG,IAAI,CAAC;YAAC,IAAI,CAAC,QAAQ;gBAAE,IAAI,CAAC,yBAAyB,CAAC,CAAC;QAAC,CAAC;QACvG,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC;QACjC,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC,IAAI,CAAC;QAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAwB,EAAE,CAAC;QACrC,OAAO,IAAI,EAAE,IAAI,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YAChC,IAAI,IAAI,EAAE,KAAK,OAAO,IAAI,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,IAAI,KAAK,GAAG,EAAE,CAAC;gBACvD,MAAM,IAAI,GAAG,IAAI,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,OAAgB,CAAC,CAAC,CAAC,CAAC,OAAgB,CAAC;gBAChF,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;gBAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAAC,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBAAC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC;gBACjG,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YACtE,CAAC;;gBAAM,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QAC9B,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC;QAC1B,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM;QAAE,IAAI,CAAC,4BAA4B,CAAC,CAAC;IAC7D,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import ts from 'typescript';\nexport interface Location { start: number; end: number }\nexport interface Expression extends Location { source: string }\nexport interface State extends Location { kind: 'state' | 'const'; name: string; value: Expression }\nexport interface Element extends Location { kind: 'element'; name: string; value?: Expression; handler?: Expression; async: boolean; children: Element[] }\nexport interface View extends Location { name: string; exported: boolean; default: boolean; body: (State | Element)[] }\nexport interface Module { source: string; filename: string; imports: Expression[]; views: View[] }\nexport class HeshError extends Error {\n readonly line: number;\n readonly column: number;\n constructor(message: string, readonly source: string, readonly offset: number, readonly filename = 'component.hesh') {\n const lines = source.slice(0, offset).split('\\n');\n const line = lines.length, column = lines.at(-1)!.length + 1;\n super(`${filename}:${line}:${column}: ${message}`);\n this.name = 'HeshError'; this.line = line; this.column = column;\n }\n}\nexport interface Token extends Location { text: string; kind: ts.SyntaxKind }\nexport function tokenize(source: string, filename = 'component.hesh'): Token[] {\n const tokens: Token[] = [];\n const keywords = new Set('break case catch class const continue debugger default delete do else enum export extends false finally for function if import in instanceof new null return super switch this throw true try typeof var void while with yield let static await async'.split(' '));\n let at = 0;\n const fail = (message: string, offset: number): never => { throw new HeshError(message, source, offset, filename); };\n while (at < source.length) {\n const start = at;\n const ch = source[at]!;\n if (/\\s/.test(ch)) { at++; continue; }\n if (source.startsWith('//', at)) { while (at < source.length && source[at] !== '\\n') at++; continue; }\n if (source.startsWith('/*', at)) {\n const end = source.indexOf('*/', at + 2);\n if (end < 0) fail('Unterminated comment', at);\n at = end + 2; continue;\n }\n let kind = ts.SyntaxKind.Unknown;\n if (ch === '\"' || ch === \"'\" || ch === '`') {\n const quote = ch;\n at++; let closed = false;\n while (at < source.length) {\n const current = source[at++]!;\n if (current === '\\\\') { at++; continue; }\n if (quote === '`' && current === '$' && source[at] === '{') fail('Template substitutions belong in imported JS/TS helpers in Milestone 1', at - 1);\n if (current === quote) { closed = true; break; }\n if (quote !== '`' && (current === '\\n' || current === '\\r')) fail('Unterminated string', start);\n }\n if (!closed) fail('Unterminated string', start);\n kind = quote === '`' ? ts.SyntaxKind.NoSubstitutionTemplateLiteral : ts.SyntaxKind.StringLiteral;\n } else if (/[$_\\p{ID_Start}]/u.test(ch)) {\n at++;\n while (at < source.length && /[$\\u200c\\u200d\\p{ID_Continue}]/u.test(source[at]!)) at++;\n kind = keywords.has(source.slice(start, at)) ? ts.SyntaxKind.Unknown : ts.SyntaxKind.Identifier;\n } else if (/\\d/.test(ch)) {\n at++;\n while (at < source.length && /[\\w.]/.test(source[at]!)) at++;\n kind = ts.SyntaxKind.NumericLiteral;\n } else {\n const operator = ['>>>=', '===', '!==', '**=', '&&=', '||=', '??=', '>>>', '<<=', '>>=', '=>', '==', '!=', '<=', '>=', '++', '--', '+=', '-=', '*=', '/=', '%=', '**', '&&', '||', '??', '?.', '<<', '>>', '&=', '|=', '^=', '...'].find(op => source.startsWith(op, at));\n at += operator?.length ?? 1;\n }\n tokens.push({ kind, text: source.slice(start, at), start, end: at });\n }\n return tokens;\n}\n\nexport function parse(source: string, filename = 'component.hesh'): Module {\n const tokens = tokenize(source, filename);\n let at = 0;\n const peek = () => tokens[at]?.text;\n const fail = (message: string, offset = tokens[at]?.start ?? source.length): never => { throw new HeshError(message, source, offset, filename); };\n const take = (text?: string): Token => {\n const token = tokens[at];\n if (!token || (text !== undefined && token.text !== text)) fail(`Expected ${text ?? 'token'}, received ${peek() ?? 'end of file'}`);\n at++; return token!;\n };\n const identifier = () => {\n const token = take();\n if (token.kind !== ts.SyntaxKind.Identifier) fail('Expected identifier', token.start);\n if (token.text.startsWith('__h')) fail('Identifiers beginning __h are reserved', token.start);\n return token;\n };\n const expression = (ends: string[]): Expression => {\n const start = tokens[at]?.start ?? source.length;\n const stack: string[] = [];\n const pairs: Record<string, string> = { '(': ')', '[': ']', '{': '}' };\n while (tokens[at]) {\n const token = tokens[at]!;\n if (!stack.length && ends.includes(token.text)) break;\n if (pairs[token.text]) stack.push(pairs[token.text]!);\n else if ([')', ']', '}'].includes(token.text)) {\n if (stack.pop() !== token.text) fail('Unbalanced expression', token.start);\n }\n at++;\n }\n if (stack.length) fail('Unterminated expression', start);\n const end = tokens[at]?.start ?? source.length;\n if (!source.slice(start, end).trim()) fail('Expected expression', start);\n return { source: source.slice(start, end).trimEnd(), start, end };\n };\n const element = (): Element => {\n const name = identifier(); take('(');\n let value: Expression | undefined, handler: Expression | undefined, async = false;\n if (peek() !== ')') value = expression([',', ')']);\n if (peek() === ',') {\n take(',');\n if (peek() === 'async') { take(); async = true; }\n const start = take('{').end;\n let depth = 1;\n while (tokens[at] && depth) {\n if (peek() === '{') depth++;\n if (peek() === '}') depth--;\n if (depth) at++;\n }\n if (!tokens[at]) fail('Unterminated event block', start);\n const end = take('}').start;\n handler = { source: source.slice(start, end), start, end };\n }\n take(')');\n const children: Element[] = [];\n if (peek() === '{') { take(); while (peek() && peek() !== '}') children.push(element()); take('}'); if (peek() === ';') take(); }\n else take(';');\n return { kind: 'element', name: name.text, start: name.start, end: tokens[at - 1]!.end, value, handler, async, children };\n };\n const module: Module = { source, filename, imports: [], views: [] };\n while (tokens[at]) {\n if (peek() === 'import') {\n if (module.views.length) fail('Imports must precede views');\n const start = take().start;\n while (peek() && peek() !== ';') take();\n const end = take(';').end;\n module.imports.push({ source: source.slice(start, end), start, end }); continue;\n }\n let exported = false, isDefault = false;\n if (peek() === 'export') { take(); exported = true; }\n if (peek() === 'default') { take(); isDefault = true; if (!exported) fail('default requires export'); }\n const start = take('view').start;\n const name = identifier().text; take('{');\n const body: (State | Element)[] = [];\n while (peek() && peek() !== '}') {\n if (peek() === 'const' || tokens[at + 1]?.text === '=') {\n const kind = peek() === 'const' ? (take(), 'const' as const) : 'state' as const;\n const name = identifier(); take('='); const value = expression([';']); const end = take(';').end;\n body.push({ kind, name: name.text, value, start: name.start, end });\n } else body.push(element());\n }\n const end = take('}').end;\n module.views.push({ name, body, start, end, exported, default: isDefault });\n }\n if (!module.views.length) fail('Expected at least one view');\n return module;\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/parser/index.ts"],"names":[],"mappings":"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","sourcesContent":["import ts from 'typescript';\nexport interface Location { start: number; end: number }\nexport interface Expression extends Location { source: string }\nexport interface State extends Location { kind: 'state' | 'const'; name: string; value: Expression }\nexport interface Element extends Location { kind: 'element'; name: string; value?: Expression; handler?: Expression; async: boolean; children: Element[] }\nexport interface View extends Location { name: string; exported: boolean; default: boolean; body: (State | Element)[] }\nexport interface ContractEntry extends Location { name: string; value?: string }\nexport interface Contract extends Location {\n kind: 'domain' | 'presentation' | 'destination' | 'application';\n name: string;\n fields: Record<string, ContractEntry>;\n blocks: Record<string, ContractEntry[]>;\n}\nexport interface Module { source: string; filename: string; imports: Expression[]; views: View[]; contracts?: Contract[] }\nexport interface ParsedModule extends Module { contracts: Contract[] }\nexport class HeshError extends Error {\n readonly line: number;\n readonly column: number;\n constructor(message: string, readonly source: string, readonly offset: number, readonly filename = 'component.hesh') {\n const lines = source.slice(0, offset).split('\\n');\n const line = lines.length, column = lines.at(-1)!.length + 1;\n super(`${filename}:${line}:${column}: ${message}`);\n this.name = 'HeshError'; this.line = line; this.column = column;\n }\n}\nexport interface Token extends Location { text: string; kind: ts.SyntaxKind }\nexport function tokenize(source: string, filename = 'component.hesh'): Token[] {\n const tokens: Token[] = [];\n const keywords = new Set('break case catch class const continue debugger default delete do else enum export extends false finally for function if import in instanceof new null return super switch this throw true try typeof var void while with yield let static await async'.split(' '));\n let at = 0;\n const fail = (message: string, offset: number): never => { throw new HeshError(message, source, offset, filename); };\n while (at < source.length) {\n const start = at;\n const ch = source[at]!;\n if (/\\s/.test(ch)) { at++; continue; }\n if (source.startsWith('//', at)) { while (at < source.length && source[at] !== '\\n') at++; continue; }\n if (source.startsWith('/*', at)) {\n const end = source.indexOf('*/', at + 2);\n if (end < 0) fail('Unterminated comment', at);\n at = end + 2; continue;\n }\n let kind = ts.SyntaxKind.Unknown;\n if (ch === '\"' || ch === \"'\" || ch === '`') {\n const quote = ch;\n at++; let closed = false;\n while (at < source.length) {\n const current = source[at++]!;\n if (current === '\\\\') { at++; continue; }\n if (quote === '`' && current === '$' && source[at] === '{') fail('Template substitutions belong in imported JS/TS helpers in Milestone 1', at - 1);\n if (current === quote) { closed = true; break; }\n if (quote !== '`' && (current === '\\n' || current === '\\r')) fail('Unterminated string', start);\n }\n if (!closed) fail('Unterminated string', start);\n kind = quote === '`' ? ts.SyntaxKind.NoSubstitutionTemplateLiteral : ts.SyntaxKind.StringLiteral;\n } else if (/[$_\\p{ID_Start}]/u.test(ch)) {\n at++;\n while (at < source.length && /[$\\u200c\\u200d\\p{ID_Continue}]/u.test(source[at]!)) at++;\n kind = keywords.has(source.slice(start, at)) ? ts.SyntaxKind.Unknown : ts.SyntaxKind.Identifier;\n } else if (/\\d/.test(ch)) {\n at++;\n while (at < source.length && /[\\w.]/.test(source[at]!)) at++;\n kind = ts.SyntaxKind.NumericLiteral;\n } else {\n const operator = ['>>>=', '===', '!==', '**=', '&&=', '||=', '??=', '>>>', '<<=', '>>=', '=>', '==', '!=', '<=', '>=', '++', '--', '+=', '-=', '*=', '/=', '%=', '**', '&&', '||', '??', '?.', '<<', '>>', '&=', '|=', '^=', '...'].find(op => source.startsWith(op, at));\n at += operator?.length ?? 1;\n }\n tokens.push({ kind, text: source.slice(start, at), start, end: at });\n }\n return tokens;\n}\n\nexport function parse(source: string, filename = 'component.hesh'): ParsedModule {\n const tokens = tokenize(source, filename);\n let at = 0;\n const peek = () => tokens[at]?.text;\n const fail = (message: string, offset = tokens[at]?.start ?? source.length): never => { throw new HeshError(message, source, offset, filename); };\n const take = (text?: string): Token => {\n const token = tokens[at];\n if (!token || (text !== undefined && token.text !== text)) fail(`Expected ${text ?? 'token'}, received ${peek() ?? 'end of file'}`);\n at++; return token!;\n };\n const identifier = () => {\n const token = take();\n if (token.kind !== ts.SyntaxKind.Identifier) fail('Expected identifier', token.start);\n if (token.text.startsWith('__h')) fail('Identifiers beginning __h are reserved', token.start);\n return token;\n };\n const expression = (ends: string[]): Expression => {\n const start = tokens[at]?.start ?? source.length;\n const stack: string[] = [];\n const pairs: Record<string, string> = { '(': ')', '[': ']', '{': '}' };\n while (tokens[at]) {\n const token = tokens[at]!;\n if (!stack.length && ends.includes(token.text)) break;\n if (pairs[token.text]) stack.push(pairs[token.text]!);\n else if ([')', ']', '}'].includes(token.text)) {\n if (stack.pop() !== token.text) fail('Unbalanced expression', token.start);\n }\n at++;\n }\n if (stack.length) fail('Unterminated expression', start);\n const end = tokens[at]?.start ?? source.length;\n if (!source.slice(start, end).trim()) fail('Expected expression', start);\n return { source: source.slice(start, end).trimEnd(), start, end };\n };\n const element = (): Element => {\n const name = identifier(); take('(');\n let value: Expression | undefined, handler: Expression | undefined, async = false;\n if (peek() !== ')') value = expression([',', ')']);\n if (peek() === ',') {\n take(',');\n if (peek() === 'async') { take(); async = true; }\n const start = take('{').end;\n let depth = 1;\n while (tokens[at] && depth) {\n if (peek() === '{') depth++;\n if (peek() === '}') depth--;\n if (depth) at++;\n }\n if (!tokens[at]) fail('Unterminated event block', start);\n const end = take('}').start;\n handler = { source: source.slice(start, end), start, end };\n }\n take(')');\n const children: Element[] = [];\n if (peek() === '{') { take(); while (peek() && peek() !== '}') children.push(element()); take('}'); if (peek() === ';') take(); }\n else take(';');\n return { kind: 'element', name: name.text, start: name.start, end: tokens[at - 1]!.end, value, handler, async, children };\n };\n const contract = (): Contract => {\n const kind = take(); const name = identifier(); take('{');\n const result: Contract = { kind: kind.text as Contract['kind'], name: name.text, start: kind.start, end: 0, fields: Object.create(null), blocks: Object.create(null) };\n const schemas: Record<Contract['kind'], Record<string, string>> = {\n domain: { implementation: 'string', owns: 'list', exposes: 'list', consumes: 'list', access: 'map' },\n presentation: { html: 'string', logic: 'string', styles: 'string', bindings: 'list', actions: 'list' },\n destination: { url: 'string', input: 'map', presentation: 'identifier', access: 'string' },\n application: { domains: 'list', destinations: 'list' }\n };\n const path = (): ContractEntry => {\n const first = identifier(); let name = first.text;\n while (peek() === '.') { take(); name += '.' + identifier().text; }\n for (const part of name.split('.')) if (['__proto__', 'prototype', 'constructor'].includes(part)) fail('Unsafe contract identifier', first.start);\n return { name, start: first.start, end: tokens[at - 1]!.end };\n };\n const string = () => {\n const token = take();\n if (token.kind !== ts.SyntaxKind.StringLiteral) fail('Expected quoted string', token.start);\n const parsed = ts.createSourceFile('literal.js', token.text, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);\n return ((parsed.statements[0] as ts.ExpressionStatement).expression as ts.StringLiteral).text;\n };\n while (peek() && peek() !== '}') {\n const key = take(); const type = Object.hasOwn(schemas[result.kind], key.text) ? schemas[result.kind][key.text] : undefined;\n if (!type) fail(`Unknown ${result.kind} field ${key.text}`, key.start);\n if (result.fields[key.text] || result.blocks[key.text]) fail(`Duplicate field ${key.text}`, key.start);\n if (type === 'string' || type === 'identifier') {\n take(':'); const value = type === 'string' ? string() : identifier().text; const end = take(';').end;\n result.fields[key.text] = { name: key.text, value, start: key.start, end };\n } else {\n take('{'); const entries: ContractEntry[] = []; const seen = new Set<string>();\n while (peek() && peek() !== '}') {\n const entry = path();\n if (seen.has(entry.name)) fail(`Duplicate entry ${entry.name}`, entry.start); seen.add(entry.name);\n if (type === 'map') { take(':'); entry.value = key.text === 'input' ? identifier().text : string(); }\n entry.end = take(';').end; entries.push(entry);\n }\n take('}'); result.blocks[key.text] = entries;\n }\n }\n result.end = take('}').end;\n return result;\n };\n const module: ParsedModule = { source, filename, imports: [], views: [], contracts: [] };\n while (tokens[at]) {\n if (['domain', 'presentation', 'destination', 'application'].includes(peek() ?? '')) { module.contracts.push(contract()); continue; }\n if (peek() === 'import') {\n if (module.views.length) fail('Imports must precede views');\n const start = take().start;\n while (peek() && peek() !== ';') take();\n const end = take(';').end;\n module.imports.push({ source: source.slice(start, end), start, end }); continue;\n }\n let exported = false, isDefault = false;\n if (peek() === 'export') { take(); exported = true; }\n if (peek() === 'default') { take(); isDefault = true; if (!exported) fail('default requires export'); }\n const start = take('view').start;\n const name = identifier().text; take('{');\n const body: (State | Element)[] = [];\n while (peek() && peek() !== '}') {\n if (peek() === 'const' || tokens[at + 1]?.text === '=') {\n const kind = peek() === 'const' ? (take(), 'const' as const) : 'state' as const;\n const name = identifier(); take('='); const value = expression([';']); const end = take(';').end;\n body.push({ kind, name: name.text, value, start: name.start, end });\n } else body.push(element());\n }\n const end = take('}').end;\n module.views.push({ name, body, start, end, exported, default: isDefault });\n }\n if (!module.views.length && !module.contracts.length) fail('Expected at least one view or architecture declaration');\n return module;\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import { nativeElement as element, text, attribute, listen } from '../dom/index.js';
2
+ export { element, text, attribute, listen };
3
+ export interface PresentationState {
4
+ bindings: Record<string, unknown>;
5
+ actions: Record<string, (event: Event) => unknown>;
6
+ }
7
+ export declare function readBinding(bindings: Record<string, unknown>, path: string): unknown;
8
+ export declare function bindValue(node: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement, bindings: Record<string, unknown>, name: string): void;
9
+ export declare function bindAction(node: HTMLElement, state: PresentationState, name: string): void;
@@ -0,0 +1,38 @@
1
+ import { effect } from '../reactivity/index.js';
2
+ import { nativeElement as element, text, attribute, listen } from '../dom/index.js';
3
+ export { element, text, attribute, listen };
4
+ export function readBinding(bindings, path) {
5
+ const unwrap = (value) => {
6
+ if (typeof value === 'function')
7
+ return value();
8
+ if (value && typeof value.get === 'function')
9
+ return value.get();
10
+ return value;
11
+ };
12
+ let value = bindings;
13
+ for (const part of path.split('.')) {
14
+ if (['__proto__', 'constructor', 'prototype'].includes(part))
15
+ throw new Error('Unsafe binding path');
16
+ value = unwrap(value)?.[part];
17
+ }
18
+ return unwrap(value);
19
+ }
20
+ export function bindValue(node, bindings, name) {
21
+ const state = bindings[name];
22
+ if (typeof state?.get !== 'function' || typeof state.set !== 'function')
23
+ throw new Error(`h-value ${name} requires a writable signal`);
24
+ effect(() => { const value = String(state.get() ?? ''); if (node.value !== value)
25
+ node.value = value; });
26
+ listen(node, 'input', () => state.set(node.value));
27
+ }
28
+ export function bindAction(node, state, name) {
29
+ const handler = state.actions[name];
30
+ if (typeof handler !== 'function')
31
+ throw new Error(`Missing presentation action ${name}`);
32
+ listen(node, node.tagName === 'FORM' ? 'submit' : 'click', event => {
33
+ if (node.tagName === 'FORM')
34
+ event.preventDefault();
35
+ return handler.call(state.actions, event);
36
+ });
37
+ }
38
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/presentation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;AAE5C,MAAM,UAAU,WAAW,CAAC,QAAiC,EAAE,IAAY;IACzE,MAAM,MAAM,GAAG,CAAC,KAAc,EAAW,EAAE;QACzC,IAAI,OAAO,KAAK,KAAK,UAAU;YAAE,OAAO,KAAK,EAAE,CAAC;QAChD,IAAI,KAAK,IAAI,OAAQ,KAA2B,CAAC,GAAG,KAAK,UAAU;YAAE,OAAQ,KAA4B,CAAC,GAAG,EAAE,CAAC;QAChH,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IACF,IAAI,KAAK,GAAY,QAAQ,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC,WAAW,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACrG,KAAK,GAAI,MAAM,CAAC,KAAK,CAAoC,EAAE,CAAC,IAAI,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,MAAM,UAAU,SAAS,CAAC,IAAgE,EAAE,QAAiC,EAAE,IAAY;IACzI,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAoD,CAAC;IAChF,IAAI,OAAO,KAAK,EAAE,GAAG,KAAK,UAAU,IAAI,OAAO,KAAK,CAAC,GAAG,KAAK,UAAU;QAAE,MAAM,IAAI,KAAK,CAAC,WAAW,IAAI,6BAA6B,CAAC,CAAC;IACvI,MAAM,CAAC,GAAG,EAAE,GAAG,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK;QAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1G,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,GAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACtD,CAAC;AACD,MAAM,UAAU,UAAU,CAAC,IAAiB,EAAE,KAAwB,EAAE,IAAY;IAClF,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,OAAO,OAAO,KAAK,UAAU;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,EAAE,CAAC,CAAC;IAC1F,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE;QACjE,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM;YAAE,KAAK,CAAC,cAAc,EAAE,CAAC;QACpD,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { effect } from '../reactivity/index.js';\nimport { nativeElement as element, text, attribute, listen } from '../dom/index.js';\nexport { element, text, attribute, listen };\nexport interface PresentationState { bindings: Record<string, unknown>; actions: Record<string, (event: Event) => unknown> }\nexport function readBinding(bindings: Record<string, unknown>, path: string): unknown {\n const unwrap = (value: unknown): unknown => {\n if (typeof value === 'function') return value();\n if (value && typeof (value as { get?: unknown }).get === 'function') return (value as { get(): unknown }).get();\n return value;\n };\n let value: unknown = bindings;\n for (const part of path.split('.')) {\n if (['__proto__', 'constructor', 'prototype'].includes(part)) throw new Error('Unsafe binding path');\n value = (unwrap(value) as Record<string, unknown> | null)?.[part];\n }\n return unwrap(value);\n}\nexport function bindValue(node: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement, bindings: Record<string, unknown>, name: string): void {\n const state = bindings[name] as { get?(): unknown; set?(value: unknown): void };\n if (typeof state?.get !== 'function' || typeof state.set !== 'function') throw new Error(`h-value ${name} requires a writable signal`);\n effect(() => { const value = String(state.get!() ?? ''); if (node.value !== value) node.value = value; });\n listen(node, 'input', () => state.set!(node.value));\n}\nexport function bindAction(node: HTMLElement, state: PresentationState, name: string): void {\n const handler = state.actions[name];\n if (typeof handler !== 'function') throw new Error(`Missing presentation action ${name}`);\n listen(node, node.tagName === 'FORM' ? 'submit' : 'click', event => {\n if (node.tagName === 'FORM') event.preventDefault();\n return handler.call(state.actions, event);\n });\n}\n"]}
@@ -0,0 +1,24 @@
1
+ import { type Disposer } from '../reactivity/index.js';
2
+ import type { AppModule, RouteLocation } from '../hmvc/index.js';
3
+ export type { RouteLocation } from '../hmvc/index.js';
4
+ export interface RouteRecord {
5
+ path: string;
6
+ module: AppModule;
7
+ children?: readonly RouteRecord[];
8
+ }
9
+ export interface RouterOptions {
10
+ routes: readonly RouteRecord[];
11
+ window?: Window;
12
+ notFound?: AppModule;
13
+ onError?: (error: unknown) => void;
14
+ }
15
+ export declare function createRouter(options: RouterOptions): {
16
+ location: {
17
+ get: () => RouteLocation;
18
+ };
19
+ navigate: (to: string, navigation?: {
20
+ replace?: boolean;
21
+ }) => void;
22
+ stop: () => void;
23
+ start(parent: Node): Disposer;
24
+ };