@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.
- package/README.md +8 -2
- package/cli.js +26 -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 +16 -0
- package/dist/architecture/html.js +132 -0
- package/dist/architecture/html.js.map +1 -0
- package/dist/architecture/index.d.ts +42 -0
- package/dist/architecture/index.js +418 -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 +185 -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/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 +9 -0
- package/dist/presentation/index.js +38 -0
- package/dist/presentation/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 +60 -0
- package/docs/domain-graph.md +205 -0
- package/docs/grammar.md +4 -0
- package/package.json +8 -3
- package/src/architecture/diagnostics.ts +11 -0
- package/src/architecture/html.ts +88 -0
- package/src/architecture/index.ts +283 -0
- package/src/compiler/index.ts +1 -0
- package/src/destinations/index.ts +146 -0
- package/src/dom/index.ts +6 -1
- package/src/domains/index.ts +97 -0
- package/src/parser/index.ts +55 -4
- package/src/presentation/index.ts +31 -0
- package/src/vite/index.ts +24 -2
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import { readFileSync, existsSync, realpathSync, mkdirSync, writeFileSync, statSync } from 'node:fs';
|
|
3
|
+
import { resolve, dirname, relative, extname, join } from 'node:path';
|
|
4
|
+
import { parse, HeshError } from '../parser/index.js';
|
|
5
|
+
import { compileHTML } from './html.js';
|
|
6
|
+
import { diagnostic, formatDiagnostic } from './diagnostics.js';
|
|
7
|
+
export { compileHTML, formatDiagnostic };
|
|
8
|
+
const canonical = (file) => {
|
|
9
|
+
const path = resolve(file);
|
|
10
|
+
const real = existsSync(path) ? realpathSync(path) : path;
|
|
11
|
+
return (ts.sys.useCaseSensitiveFileNames ? real : real.toLowerCase()).replace(/\\/g, '/');
|
|
12
|
+
};
|
|
13
|
+
const inside = (file, folder) => file === folder || file.startsWith(folder + '/');
|
|
14
|
+
const isFile = (file) => existsSync(file) && statSync(file).isFile();
|
|
15
|
+
const modulePath = (from, to) => { const path = relative(dirname(from), to).replace(/\\/g, '/'); return path.startsWith('.') ? path : './' + path; };
|
|
16
|
+
export function createArchitectureCompiler() {
|
|
17
|
+
const cache = new Map();
|
|
18
|
+
return { clear() { cache.clear(); }, check(options) {
|
|
19
|
+
const root = canonical(options.root), entry = canonical(resolve(root, options.entry ?? 'app.hesh'));
|
|
20
|
+
const outDir = resolve(root, options.outDir ?? '.hesh-generated');
|
|
21
|
+
const diagnostics = [], descriptors = new Map(), declarations = new Map();
|
|
22
|
+
const files = new Set();
|
|
23
|
+
let parsed = 0, reused = 0;
|
|
24
|
+
const error = (code, message, item, position = item.node.start, suggestion = 'Correct the declared contract.') => diagnostics.push(diagnostic(code, message, item.file, item.source, position, suggestion));
|
|
25
|
+
const read = (file) => { files.add(file); return readFileSync(file, 'utf8'); };
|
|
26
|
+
const load = (file) => {
|
|
27
|
+
if (descriptors.has(file))
|
|
28
|
+
return;
|
|
29
|
+
if (!inside(file, root) || !isFile(file)) {
|
|
30
|
+
diagnostics.push(diagnostic('HESH-ARCH-001', 'Missing or out-of-project descriptor', file, '', 0, 'Import an existing .hesh file within the application root.'));
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const source = read(file);
|
|
34
|
+
let ast;
|
|
35
|
+
try {
|
|
36
|
+
const saved = cache.get(file);
|
|
37
|
+
if (saved?.source === source) {
|
|
38
|
+
ast = saved.ast;
|
|
39
|
+
reused++;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
ast = parse(source, file);
|
|
43
|
+
cache.set(file, { source, ast });
|
|
44
|
+
parsed++;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (failure) {
|
|
48
|
+
diagnostics.push(diagnostic('HESH-SYNTAX-001', failure instanceof Error ? failure.message : String(failure), file, source, failure instanceof HeshError ? failure.offset : 0, 'Fix the Hesh declaration syntax.'));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
descriptors.set(file, ast);
|
|
52
|
+
if (ast.views.length)
|
|
53
|
+
diagnostics.push(diagnostic('HESH-ARCH-001', 'Architecture descriptor files cannot also contain view implementations', file, source, ast.views[0].start, 'Keep existing .hesh views in separate component files.'));
|
|
54
|
+
for (const node of ast.contracts ?? []) {
|
|
55
|
+
const item = { node, file, source };
|
|
56
|
+
if (declarations.has(node.name))
|
|
57
|
+
error('HESH-ARCH-002', `Duplicate declaration ${node.name}`, item);
|
|
58
|
+
else
|
|
59
|
+
declarations.set(node.name, item);
|
|
60
|
+
}
|
|
61
|
+
for (const item of ast.imports) {
|
|
62
|
+
const syntax = ts.createSourceFile(file, item.source, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
|
63
|
+
const statement = syntax.statements[0];
|
|
64
|
+
if (!statement || !ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier) || statement.importClause || !statement.moduleSpecifier.text.endsWith('.hesh')) {
|
|
65
|
+
diagnostics.push(diagnostic('HESH-ARCH-001', 'Architecture imports must be side-effect imports of .hesh descriptors', file, source, item.start, 'Use import "./domains/inventory/domain.hesh";.'));
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
load(canonical(resolve(dirname(file), statement.moduleSpecifier.text)));
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
load(entry);
|
|
72
|
+
const all = [...declarations.values()];
|
|
73
|
+
const applications = all.filter(d => d.node.kind === 'application');
|
|
74
|
+
const app = applications[0];
|
|
75
|
+
if (applications.length !== 1)
|
|
76
|
+
diagnostics.push(diagnostic('HESH-ARCH-001', 'Exactly one application declaration is required', entry, descriptors.get(entry)?.source ?? '', 0, 'Declare one application listing domains and destinations.'));
|
|
77
|
+
const select = (kind, names) => (names ?? []).flatMap(name => {
|
|
78
|
+
const target = declarations.get(name.name);
|
|
79
|
+
if (!target || target.node.kind !== kind) {
|
|
80
|
+
if (app)
|
|
81
|
+
error('HESH-ARCH-003', `Missing ${kind} ${name.name}`, app, name.start);
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
return [target];
|
|
85
|
+
});
|
|
86
|
+
const domains = select('domain', app?.node.blocks.domains), destinations = select('destination', app?.node.blocks.destinations);
|
|
87
|
+
const presentations = all.filter(d => d.node.kind === 'presentation');
|
|
88
|
+
const declaredDomains = all.filter(d => d.node.kind === 'domain');
|
|
89
|
+
const owner = (file) => declaredDomains.filter(d => inside(file, canonical(dirname(d.file)))).sort((a, b) => dirname(b.file).length - dirname(a.file).length)[0];
|
|
90
|
+
const field = (item, name, required = true) => {
|
|
91
|
+
const value = item.node.fields[name]?.value;
|
|
92
|
+
if (required && !value)
|
|
93
|
+
error('HESH-ARCH-003', `Missing field ${name} in ${item.node.name}`, item);
|
|
94
|
+
return value ?? '';
|
|
95
|
+
};
|
|
96
|
+
const list = (item, name, required = false) => {
|
|
97
|
+
if (required && !item.node.blocks[name])
|
|
98
|
+
error('HESH-ARCH-003', `Missing block ${name}`, item);
|
|
99
|
+
return item.node.blocks[name] ?? [];
|
|
100
|
+
};
|
|
101
|
+
if (app) {
|
|
102
|
+
list(app, 'domains', true);
|
|
103
|
+
list(app, 'destinations', true);
|
|
104
|
+
}
|
|
105
|
+
const factories = new Map();
|
|
106
|
+
for (const item of [...domains, ...presentations]) {
|
|
107
|
+
const specifier = field(item, item.node.kind === 'domain' ? 'implementation' : 'logic');
|
|
108
|
+
const hash = specifier.lastIndexOf('#'), path = specifier.slice(0, hash), name = specifier.slice(hash + 1);
|
|
109
|
+
if (hash < 1 || !/^[$_\p{ID_Start}][$_\u200c\u200d\p{ID_Continue}]*$/u.test(name) || !path.startsWith('.') || !['.js', '.ts', '.mjs'].includes(extname(path)) || path.endsWith('.d.ts')) {
|
|
110
|
+
error('HESH-ARCH-003', `Invalid implementation reference ${specifier}`, item, item.node.start, 'Use ./module.js#exportName (or .ts/.mjs).');
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
const file = canonical(resolve(dirname(item.file), path));
|
|
114
|
+
if (!existsSync(file) || !inside(file, root) || owner(file) !== owner(item.file)) {
|
|
115
|
+
error('HESH-ARCH-004', `Implementation must exist inside its owning domain: ${specifier}`, item);
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
factories.set(item, { file, name });
|
|
119
|
+
files.add(file);
|
|
120
|
+
}
|
|
121
|
+
const byDomain = new Map(domains.map(item => [item.node.name, item]));
|
|
122
|
+
for (const item of declaredDomains)
|
|
123
|
+
if (declaredDomains.some(other => other !== item && dirname(other.file) === dirname(item.file)))
|
|
124
|
+
error('HESH-ARCH-002', 'Each domain needs its own directory boundary', item);
|
|
125
|
+
const edges = new Map();
|
|
126
|
+
for (const item of domains) {
|
|
127
|
+
const exposes = list(item, 'exposes', true).map(v => v.name);
|
|
128
|
+
if (!exposes.length)
|
|
129
|
+
error('HESH-ARCH-003', `Domain ${item.node.name} must expose at least one operation`, item);
|
|
130
|
+
for (const name of exposes)
|
|
131
|
+
if (exposes.some(other => other !== name && other.startsWith(name + '.')))
|
|
132
|
+
error('HESH-ARCH-003', `Overlapping public operation ${name}`, item);
|
|
133
|
+
const dependencies = [];
|
|
134
|
+
for (const consume of list(item, 'consumes')) {
|
|
135
|
+
const [provider, ...path] = consume.name.split('.'), target = byDomain.get(provider);
|
|
136
|
+
if (!target || !path.length || !list(target, 'exposes').some(v => v.name === path.join('.')))
|
|
137
|
+
error('HESH-ARCH-003', `Unresolved consumed operation ${consume.name}`, item, consume.start, 'Consume an operation explicitly exposed by a selected domain.');
|
|
138
|
+
dependencies.push(provider);
|
|
139
|
+
}
|
|
140
|
+
for (const policy of list(item, 'access'))
|
|
141
|
+
if (!exposes.includes(policy.name))
|
|
142
|
+
error('HESH-ARCH-003', `Access policy refers to unexposed operation ${policy.name}`, item, policy.start);
|
|
143
|
+
edges.set(item.node.name, dependencies);
|
|
144
|
+
}
|
|
145
|
+
const visited = new Set(), visiting = [];
|
|
146
|
+
const visit = (name) => {
|
|
147
|
+
if (visiting.includes(name)) {
|
|
148
|
+
const item = byDomain.get(name);
|
|
149
|
+
if (item)
|
|
150
|
+
error('HESH-ARCH-005', `Circular dependency: ${[...visiting, name].join(' -> ')}`, item, item.node.start, 'Remove the cycle or extract an explicit shared contract.');
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (visited.has(name))
|
|
154
|
+
return;
|
|
155
|
+
visiting.push(name);
|
|
156
|
+
for (const next of edges.get(name) ?? [])
|
|
157
|
+
visit(next);
|
|
158
|
+
visiting.pop();
|
|
159
|
+
visited.add(name);
|
|
160
|
+
};
|
|
161
|
+
for (const name of byDomain.keys())
|
|
162
|
+
visit(name);
|
|
163
|
+
let settings = { target: ts.ScriptTarget.ES2022, module: ts.ModuleKind.ESNext, moduleResolution: ts.ModuleResolutionKind.Bundler, allowJs: true, checkJs: true, noEmit: true, skipLibCheck: true, allowImportingTsExtensions: true, types: [] };
|
|
164
|
+
if (options.tsconfig) {
|
|
165
|
+
const configFile = resolve(root, options.tsconfig), config = ts.readConfigFile(configFile, ts.sys.readFile);
|
|
166
|
+
if (config.error)
|
|
167
|
+
diagnostics.push(diagnostic('HESH-ARCH-001', ts.flattenDiagnosticMessageText(config.error.messageText, '\n'), configFile, '', 0, 'Correct the TypeScript project configuration.'));
|
|
168
|
+
else
|
|
169
|
+
settings = { ...settings, ...ts.parseJsonConfigFileContent(config.config, ts.sys, dirname(configFile)).options, noEmit: true, allowJs: true, checkJs: true };
|
|
170
|
+
}
|
|
171
|
+
const program = ts.createProgram([...factories.values()].map(f => f.file), settings);
|
|
172
|
+
const checker = program.getTypeChecker();
|
|
173
|
+
const resolvedFactories = new Map();
|
|
174
|
+
const getMember = (type, path, unwrap = false) => {
|
|
175
|
+
let current = type;
|
|
176
|
+
const unwrapped = (value) => {
|
|
177
|
+
const get = checker.getPropertyOfType(value, 'get');
|
|
178
|
+
const callable = get ? checker.getTypeOfSymbolAtLocation(get, get.valueDeclaration ?? program.getSourceFiles()[0]) : value;
|
|
179
|
+
return checker.getSignaturesOfType(callable, ts.SignatureKind.Call)[0]?.getReturnType() ?? value;
|
|
180
|
+
};
|
|
181
|
+
for (const piece of path) {
|
|
182
|
+
if (unwrap)
|
|
183
|
+
current = unwrapped(current);
|
|
184
|
+
if (current.flags & ts.TypeFlags.Any)
|
|
185
|
+
return current;
|
|
186
|
+
const symbol = checker.getPropertyOfType(current, piece);
|
|
187
|
+
if (!symbol)
|
|
188
|
+
return;
|
|
189
|
+
current = checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration ?? program.getSourceFiles()[0]);
|
|
190
|
+
}
|
|
191
|
+
return unwrap ? unwrapped(current) : current;
|
|
192
|
+
};
|
|
193
|
+
for (const [item, reference] of factories) {
|
|
194
|
+
const sourceFile = program.getSourceFile(reference.file);
|
|
195
|
+
const symbol = sourceFile && checker.getSymbolAtLocation(sourceFile);
|
|
196
|
+
let exported = symbol && checker.getExportsOfModule(symbol).find(v => v.name === reference.name);
|
|
197
|
+
if (exported?.flags && exported.flags & ts.SymbolFlags.Alias)
|
|
198
|
+
exported = checker.getAliasedSymbol(exported);
|
|
199
|
+
const type = exported && checker.getTypeOfSymbolAtLocation(exported, exported.valueDeclaration ?? sourceFile);
|
|
200
|
+
const signature = type && checker.getSignaturesOfType(type, ts.SignatureKind.Call)[0];
|
|
201
|
+
if (!signature) {
|
|
202
|
+
error('HESH-ARCH-003', `Missing callable export ${reference.name} in ${reference.file}`, item);
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
const result = signature.getReturnType();
|
|
206
|
+
if (result.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown) || checker.getPropertyOfType(result, 'then')) {
|
|
207
|
+
error('HESH-ARCH-003', `Factory ${reference.name} must return a statically inspectable synchronous object`, item);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
resolvedFactories.set(item, { ...reference, result });
|
|
211
|
+
if (item.node.kind === 'domain')
|
|
212
|
+
for (const operation of list(item, 'exposes')) {
|
|
213
|
+
const target = getMember(result, operation.name.split('.'));
|
|
214
|
+
if (!target || !checker.getSignaturesOfType(target, ts.SignatureKind.Call).length)
|
|
215
|
+
error('HESH-ARCH-003', `Unresolved callable implementation ${item.node.name}.${operation.name}`, item, operation.start, 'Return this operation from the declared implementation factory.');
|
|
216
|
+
}
|
|
217
|
+
else
|
|
218
|
+
for (const block of ['bindings', 'actions']) {
|
|
219
|
+
if (!getMember(result, [block]))
|
|
220
|
+
error('HESH-BIND-002', `Presentation factory must return a ${block} object`, item);
|
|
221
|
+
for (const binding of list(item, block, true)) {
|
|
222
|
+
const target = getMember(result, [block, binding.name]);
|
|
223
|
+
if (!target || (block === 'actions' && !checker.getSignaturesOfType(target, ts.SignatureKind.Call).length))
|
|
224
|
+
error(block === 'actions' ? 'HESH-ACTION-001' : 'HESH-BIND-002', `Missing ${block} implementation ${binding.name}`, item, binding.start, `Return ${block}.${binding.name} from the presentation factory.`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// Validate actual imports/re-exports, including aliases and files shared by domains.
|
|
229
|
+
const sources = ts.sys.readDirectory(root, ['.ts', '.js', '.mjs'], ['**/node_modules/**', '**/dist/**', '**/.hesh-generated/**'], ['**/*']);
|
|
230
|
+
for (const path of sources) {
|
|
231
|
+
const file = canonical(path);
|
|
232
|
+
if (inside(file, canonical(outDir)))
|
|
233
|
+
continue;
|
|
234
|
+
files.add(file);
|
|
235
|
+
const source = read(file), syntax = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, true, file.endsWith('.ts') ? ts.ScriptKind.TS : ts.ScriptKind.JS);
|
|
236
|
+
const checkImport = (specifier) => {
|
|
237
|
+
if (!specifier)
|
|
238
|
+
return;
|
|
239
|
+
if (!ts.isStringLiteralLike(specifier)) {
|
|
240
|
+
diagnostics.push(diagnostic('HESH-ARCH-007', 'Computed module imports cannot be architecture-validated', file, source, specifier.getStart(syntax), 'Use literal imports and explicit injected dependencies.'));
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
if (specifier.text.startsWith('node:') || ['fs', 'path', 'child_process', 'worker_threads', 'net', 'tls', 'http', 'https', 'os', 'module'].includes(specifier.text)) {
|
|
244
|
+
diagnostics.push(diagnostic('HESH-SEC-001', `Node/server-only import in client code: ${specifier.text}`, file, source, specifier.getStart(syntax), 'Call server infrastructure through an API rather than bundling it.'));
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const target = ts.resolveModuleName(specifier.text, file, settings, ts.sys).resolvedModule?.resolvedFileName;
|
|
248
|
+
const generated = canonical(resolve(dirname(file), specifier.text));
|
|
249
|
+
if (inside(generated, canonical(outDir)))
|
|
250
|
+
return;
|
|
251
|
+
if (!target) {
|
|
252
|
+
if (!specifier.text.endsWith('.css') && !specifier.text.endsWith('.hesh'))
|
|
253
|
+
diagnostics.push(diagnostic('HESH-ARCH-006', `Unresolved module ${specifier.text}`, file, source, specifier.getStart(syntax), 'Fix the path or supply the correct tsconfig alias.'));
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const targetFile = canonical(target);
|
|
257
|
+
files.add(targetFile);
|
|
258
|
+
if (/(?:^|\/)server(?:\/|$)|\.server\.[cm]?[jt]s$/.test(targetFile))
|
|
259
|
+
diagnostics.push(diagnostic('HESH-SEC-001', `Server-only module in client graph: ${specifier.text}`, file, source, specifier.getStart(syntax), 'Move server calls behind a server API; never import server-only code into the browser.'));
|
|
260
|
+
const targetDomain = owner(targetFile), sourceDomain = owner(file);
|
|
261
|
+
if (targetDomain && targetDomain !== sourceDomain)
|
|
262
|
+
diagnostics.push(diagnostic('HESH-ARCH-004', `Illegal cross-domain dependency. Source domain: ${sourceDomain?.node.name ?? 'shared/application'}. Target domain: ${targetDomain.node.name}. The imported module is private.`, file, source, specifier.getStart(syntax), `Use an explicitly exposed ${targetDomain.node.name} operation through declared dependency injection.`));
|
|
263
|
+
};
|
|
264
|
+
const walk = (node) => {
|
|
265
|
+
if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node))
|
|
266
|
+
checkImport(node.moduleSpecifier);
|
|
267
|
+
else if (ts.isImportTypeNode(node) && ts.isLiteralTypeNode(node.argument))
|
|
268
|
+
checkImport(node.argument.literal);
|
|
269
|
+
else if (ts.isCallExpression(node) && (node.expression.kind === ts.SyntaxKind.ImportKeyword || (ts.isIdentifier(node.expression) && node.expression.text === 'require')))
|
|
270
|
+
checkImport(node.arguments[0]);
|
|
271
|
+
ts.forEachChild(node, walk);
|
|
272
|
+
};
|
|
273
|
+
walk(syntax);
|
|
274
|
+
}
|
|
275
|
+
for (const failure of [...program.getSyntacticDiagnostics(), ...program.getSemanticDiagnostics()])
|
|
276
|
+
if (failure.file && inside(canonical(failure.file.fileName), root))
|
|
277
|
+
diagnostics.push(diagnostic('HESH-TYPE-001', ts.flattenDiagnosticMessageText(failure.messageText, '\n'), failure.file.fileName, failure.file.text, failure.start ?? 0, 'Correct the implementation type/syntax error.'));
|
|
278
|
+
const schemas = Object.create(null), urls = new Map();
|
|
279
|
+
const graph = { domains: domains.map(d => ({ name: d.node.name, exposes: list(d, 'exposes').map(e => e.name), consumes: list(d, 'consumes').map(e => e.name) })), destinations: [], links: [] };
|
|
280
|
+
const presentationFor = new Map();
|
|
281
|
+
for (const item of destinations) {
|
|
282
|
+
const url = field(item, 'url'), inputs = Object.fromEntries(list(item, 'input', true).map(e => [e.name, e.value ?? '']));
|
|
283
|
+
const segments = url.split('/').filter(Boolean), params = segments.filter(p => p.startsWith(':')).map(p => p.slice(1));
|
|
284
|
+
if (!url.startsWith('/') || url.startsWith('//') || /[?#*%]/.test(url) || new Set(params).size !== params.length || params.some(p => !Object.hasOwn(inputs, p)) || Object.keys(inputs).some(p => !params.includes(p)))
|
|
285
|
+
error('HESH-NAV-003', `URL/input mismatch for ${item.node.name}`, item, item.node.start, 'Use an absolute URL whose :params exactly match the input block; use plain static segments.');
|
|
286
|
+
for (const input of list(item, 'input'))
|
|
287
|
+
if (!['string', 'number', 'boolean'].includes(input.value ?? '') || input.name.includes('.'))
|
|
288
|
+
error('HESH-NAV-003', `Invalid input schema ${input.name}`, item, input.start);
|
|
289
|
+
for (const key of Object.keys(inputs))
|
|
290
|
+
if (!/^[A-Za-z_][A-Za-z\d_]*$/.test(key))
|
|
291
|
+
error('HESH-NAV-003', `Unsupported URL parameter name ${key}`, item, item.node.start, 'Use ASCII letters/digits/underscore with a letter or underscore first.');
|
|
292
|
+
if (new Set(Object.keys(inputs).map(key => key.toLowerCase())).size !== Object.keys(inputs).length)
|
|
293
|
+
error('HESH-NAV-003', 'Destination input names must be unique ignoring case for HTML attributes', item);
|
|
294
|
+
const signature = segments.map(p => p.startsWith(':') ? ':' : p).join('/');
|
|
295
|
+
if (urls.has(signature))
|
|
296
|
+
error('HESH-NAV-004', `Conflicting destination URL ${url}`, item);
|
|
297
|
+
else
|
|
298
|
+
urls.set(signature, item);
|
|
299
|
+
for (const previous of destinations.slice(0, destinations.indexOf(item))) {
|
|
300
|
+
const other = (previous.node.fields.url?.value ?? '').split('/').filter(Boolean);
|
|
301
|
+
if (other.length === segments.length && other.every((part, index) => part === segments[index] || part.startsWith(':') || segments[index].startsWith(':')))
|
|
302
|
+
error('HESH-NAV-004', `Overlapping destination URLs: ${url} and ${previous.node.fields.url?.value}`, item, item.node.start, 'Use non-overlapping addresses so destination input always resolves to the declared screen.');
|
|
303
|
+
}
|
|
304
|
+
const presentation = declarations.get(field(item, 'presentation'));
|
|
305
|
+
if (!presentation || presentation.node.kind !== 'presentation')
|
|
306
|
+
error('HESH-NAV-001', `Missing presentation for ${item.node.name}`, item);
|
|
307
|
+
else {
|
|
308
|
+
const own = owner(presentation.file);
|
|
309
|
+
if (!own || !byDomain.has(own.node.name) || owner(item.file) !== own)
|
|
310
|
+
error('HESH-ARCH-004', 'Destination and presentation must belong to the same selected domain', item);
|
|
311
|
+
else {
|
|
312
|
+
presentationFor.set(item, presentation);
|
|
313
|
+
graph.destinations.push({ name: item.node.name, url, input: inputs, owner: own.node.name });
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
schemas[item.node.name] = inputs;
|
|
317
|
+
}
|
|
318
|
+
const outputs = {}, htmlModules = new Map();
|
|
319
|
+
for (const item of new Set(presentationFor.values())) {
|
|
320
|
+
const html = canonical(resolve(dirname(item.file), field(item, 'html'))), stylePath = field(item, 'styles', false);
|
|
321
|
+
if (!isFile(html) || !html.endsWith('.html') || !inside(html, canonical(dirname(item.file)))) {
|
|
322
|
+
error('HESH-HTML-001', `Missing or private presentation HTML ${html}`, item);
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
const source = read(html), factory = resolvedFactories.get(item);
|
|
326
|
+
const compiled = compileHTML(source, { filename: html, bindings: list(item, 'bindings', true).map(e => e.name), actions: list(item, 'actions', true).map(e => e.name), destinations: schemas,
|
|
327
|
+
validateBinding(path, offset, expected, writable) {
|
|
328
|
+
if (!factory)
|
|
329
|
+
return;
|
|
330
|
+
const type = getMember(factory.result, ['bindings', ...path.split('.')], true);
|
|
331
|
+
if (type && type.flags & ts.TypeFlags.Any)
|
|
332
|
+
diagnostics.push(diagnostic('HESH-TYPE-002', `Binding ${path} has a dynamic any type; its nested shape/input type cannot be proven`, html, source, offset, 'Add JSDoc or a TypeScript type if static checking is required; runtime destination validation still applies.', 'warning'));
|
|
333
|
+
if (!type)
|
|
334
|
+
diagnostics.push(diagnostic('HESH-BIND-002', `Missing nested data path ${path}`, html, source, offset, 'Return this field in the declared bindings.'));
|
|
335
|
+
if (writable) {
|
|
336
|
+
const raw = getMember(factory.result, ['bindings', path]);
|
|
337
|
+
if (!raw || !checker.getPropertyOfType(raw, 'set'))
|
|
338
|
+
diagnostics.push(diagnostic('HESH-BIND-004', `Binding ${path} is not writable`, html, source, offset, 'Use a writable signal for h-value.'));
|
|
339
|
+
}
|
|
340
|
+
if (expected && type && !(type.flags & ts.TypeFlags.Any)) {
|
|
341
|
+
const actual = type.flags & ts.TypeFlags.StringLike ? 'string' : type.flags & ts.TypeFlags.NumberLike ? 'number' : type.flags & ts.TypeFlags.BooleanLike ? 'boolean' : 'object/unknown';
|
|
342
|
+
if (actual !== expected)
|
|
343
|
+
diagnostics.push(diagnostic('HESH-NAV-003', `Destination binding ${path} is ${actual}, expected ${expected}`, html, source, offset, 'Bind a value of the destination input type.'));
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
diagnostics.push(...compiled.diagnostics);
|
|
348
|
+
for (const [destination, screen] of presentationFor)
|
|
349
|
+
if (screen === item)
|
|
350
|
+
for (const target of compiled.destinations)
|
|
351
|
+
graph.links.push({ from: destination.node.name, to: target });
|
|
352
|
+
const output = join(outDir, `${item.node.name}.js`);
|
|
353
|
+
htmlModules.set(item, output);
|
|
354
|
+
let css = '';
|
|
355
|
+
if (stylePath) {
|
|
356
|
+
const style = canonical(resolve(dirname(item.file), stylePath));
|
|
357
|
+
if (!isFile(style) || !style.endsWith('.css') || !inside(style, canonical(dirname(item.file))))
|
|
358
|
+
error('HESH-HTML-001', `Missing/private CSS resource ${stylePath}`, item);
|
|
359
|
+
else {
|
|
360
|
+
files.add(style);
|
|
361
|
+
css = `import ${JSON.stringify(modulePath(output, style))};\n`;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
outputs[output] = css + compiled.code;
|
|
365
|
+
}
|
|
366
|
+
const output = join(outDir, 'app.js'), types = join(outDir, 'app.d.ts');
|
|
367
|
+
const js = ["import { createGraphApplication, createDomainGraph } from '@heshammesalam/heshjs/destinations';"];
|
|
368
|
+
const domainValues = [], pageValues = [], typeImports = [], domainTypes = [];
|
|
369
|
+
let index = 0;
|
|
370
|
+
for (const item of domains) {
|
|
371
|
+
const factory = resolvedFactories.get(item);
|
|
372
|
+
if (!factory)
|
|
373
|
+
continue;
|
|
374
|
+
const alias = `factory${index++}`, spec = modulePath(output, factory.file);
|
|
375
|
+
js.push(`import { ${factory.name} as ${alias} } from ${JSON.stringify(spec)};`);
|
|
376
|
+
typeImports.push(`import { ${factory.name} as ${alias} } from ${JSON.stringify(spec)};`);
|
|
377
|
+
const operations = list(item, 'exposes').map(e => e.name);
|
|
378
|
+
domainValues.push(`{name:${JSON.stringify(item.node.name)}, factory:${alias}, exposes:${JSON.stringify(operations)}, consumes:${JSON.stringify(list(item, 'consumes').map(e => e.name))}, access:${JSON.stringify(Object.fromEntries(list(item, 'access').map(e => [e.name, e.value])))}}`);
|
|
379
|
+
const tree = {};
|
|
380
|
+
for (const operation of operations) {
|
|
381
|
+
let node = tree;
|
|
382
|
+
const parts = operation.split('.');
|
|
383
|
+
parts.forEach((part, i) => { if (i === parts.length - 1)
|
|
384
|
+
node[part] = `ReturnType<typeof ${alias}>${parts.map(p => `[${JSON.stringify(p)}]`).join('')}`;
|
|
385
|
+
else
|
|
386
|
+
node = (node[part] ??= {}); });
|
|
387
|
+
}
|
|
388
|
+
const typeTree = (value) => '{' + Object.entries(value).map(([key, value]) => `readonly ${JSON.stringify(key)}:${typeof value === 'string' ? value : typeTree(value)}`).join(';') + '}';
|
|
389
|
+
domainTypes.push(`${JSON.stringify(item.node.name)}:${typeTree(tree)}`);
|
|
390
|
+
}
|
|
391
|
+
for (const item of destinations) {
|
|
392
|
+
const presentation = presentationFor.get(item), factory = presentation && resolvedFactories.get(presentation), html = presentation && htmlModules.get(presentation);
|
|
393
|
+
const data = graph.destinations.find(d => d.name === item.node.name);
|
|
394
|
+
if (!presentation || !factory || !html || !data)
|
|
395
|
+
continue;
|
|
396
|
+
pageValues.push(`{...${JSON.stringify({ ...data, access: item.node.fields.access?.value })}, load:async()=>{const [logic,template]=await Promise.all([import(${JSON.stringify(modulePath(output, factory.file))}),import(${JSON.stringify(modulePath(output, html))})]);return {create:logic[${JSON.stringify(factory.name)}],view:template.default};}}`);
|
|
397
|
+
}
|
|
398
|
+
js.push(`const domains = [${domainValues.join(',\n')}];`, `const pages = [${pageValues.join(',\n')}];`, 'export const metadata = ' + JSON.stringify(graph) + ';', 'export const createDomains = (options = {}) => createDomainGraph(domains, options);', 'export const createApplication = (options = {}) => createGraphApplication(domains, pages, options);');
|
|
399
|
+
const destinationTypes = graph.destinations.map(d => `${JSON.stringify(d.name)}: Destination<${Object.keys(d.input).length ? '{' + Object.entries(d.input).map(([key, type]) => `${JSON.stringify(key)}:${type}`).join(';') + '}' : 'Record<string, never>'}>`);
|
|
400
|
+
outputs[output] = js.join('\n');
|
|
401
|
+
outputs[types] = ["import type { Destination, GraphApplication, ApplicationOptions, DomainGraph } from '@heshammesalam/heshjs/destinations';", ...typeImports, `export interface DomainAPIs {${domainTypes.join(';')}}`, `export interface Destinations {${destinationTypes.join(';')}}`, 'export declare function createDomains(options?: ApplicationOptions): DomainGraph<DomainAPIs>;', 'export declare function createApplication(options?: ApplicationOptions): GraphApplication<Destinations, DomainAPIs>;', 'export declare const metadata: unknown;'].join('\n');
|
|
402
|
+
if (diagnostics.some(d => d.severity === 'error'))
|
|
403
|
+
for (const name of Object.keys(outputs))
|
|
404
|
+
delete outputs[name];
|
|
405
|
+
return { diagnostics, files: [...files].sort(), outputs, graph, statistics: { parsed, reused } };
|
|
406
|
+
} };
|
|
407
|
+
}
|
|
408
|
+
export function checkProject(options) { return createArchitectureCompiler().check(options); }
|
|
409
|
+
export function writeProject(result) {
|
|
410
|
+
if (result.diagnostics.some(d => d.severity === 'error'))
|
|
411
|
+
throw new Error(result.diagnostics.map(formatDiagnostic).join('\n'));
|
|
412
|
+
for (const [file, source] of Object.entries(result.outputs)) {
|
|
413
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
414
|
+
if (!existsSync(file) || readFileSync(file, 'utf8') !== source)
|
|
415
|
+
writeFileSync(file, source);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/architecture/index.ts"],"names":[],"mappings":"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","sourcesContent":["import ts from 'typescript';\nimport { readFileSync, existsSync, realpathSync, mkdirSync, writeFileSync, statSync } from 'node:fs';\nimport { resolve, dirname, relative, extname, join } from 'node:path';\nimport { parse, HeshError, type Module, type Contract, type ContractEntry } from '../parser/index.js';\nimport { compileHTML } from './html.js';\nimport { diagnostic, formatDiagnostic, type ArchitectureDiagnostic } from './diagnostics.js';\nexport { compileHTML, formatDiagnostic };\nexport type { ArchitectureDiagnostic };\nexport interface ProjectOptions { root: string; entry?: string; tsconfig?: string; outDir?: string }\nexport interface ProjectResult {\n diagnostics: ArchitectureDiagnostic[]; files: string[]; outputs: Record<string, string>;\n graph: { domains: { name: string; exposes: string[]; consumes: string[] }[]; destinations: { name: string; url: string; input: Record<string, string>; owner: string }[]; links: { from: string; to: string }[] };\n statistics: { parsed: number; reused: number };\n}\ninterface Located { node: Contract; file: string; source: string }\ninterface Factory { file: string; name: string; result: ts.Type }\nconst canonical = (file: string) => {\n const path = resolve(file); const real = existsSync(path) ? realpathSync(path) : path;\n return (ts.sys.useCaseSensitiveFileNames ? real : real.toLowerCase()).replace(/\\\\/g, '/');\n};\nconst inside = (file: string, folder: string) => file === folder || file.startsWith(folder + '/');\nconst isFile = (file: string) => existsSync(file) && statSync(file).isFile();\nconst modulePath = (from: string, to: string) => { const path = relative(dirname(from), to).replace(/\\\\/g, '/'); return path.startsWith('.') ? path : './' + path; };\nexport function createArchitectureCompiler() {\n const cache = new Map<string, { source: string; ast: Module }>();\n return { clear() { cache.clear(); }, check(options: ProjectOptions): ProjectResult {\n const root = canonical(options.root), entry = canonical(resolve(root, options.entry ?? 'app.hesh'));\n const outDir = resolve(root, options.outDir ?? '.hesh-generated');\n const diagnostics: ArchitectureDiagnostic[] = [], descriptors = new Map<string, Module>(), declarations = new Map<string, Located>();\n const files = new Set<string>(); let parsed = 0, reused = 0;\n const error = (code: string, message: string, item: Located, position = item.node.start, suggestion = 'Correct the declared contract.') => diagnostics.push(diagnostic(code, message, item.file, item.source, position, suggestion));\n const read = (file: string): string => { files.add(file); return readFileSync(file, 'utf8'); };\n const load = (file: string): void => {\n if (descriptors.has(file)) return;\n if (!inside(file, root) || !isFile(file)) { diagnostics.push(diagnostic('HESH-ARCH-001', 'Missing or out-of-project descriptor', file, '', 0, 'Import an existing .hesh file within the application root.')); return; }\n const source = read(file); let ast: Module;\n try {\n const saved = cache.get(file);\n if (saved?.source === source) { ast = saved.ast; reused++; }\n else { ast = parse(source, file); cache.set(file, { source, ast }); parsed++; }\n } catch (failure) {\n diagnostics.push(diagnostic('HESH-SYNTAX-001', failure instanceof Error ? failure.message : String(failure), file, source, failure instanceof HeshError ? failure.offset : 0, 'Fix the Hesh declaration syntax.')); return;\n }\n descriptors.set(file, ast);\n if (ast.views.length) diagnostics.push(diagnostic('HESH-ARCH-001', 'Architecture descriptor files cannot also contain view implementations', file, source, ast.views[0]!.start, 'Keep existing .hesh views in separate component files.'));\n for (const node of ast.contracts ?? []) {\n const item = { node, file, source };\n if (declarations.has(node.name)) error('HESH-ARCH-002', `Duplicate declaration ${node.name}`, item);\n else declarations.set(node.name, item);\n }\n for (const item of ast.imports) {\n const syntax = ts.createSourceFile(file, item.source, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);\n const statement = syntax.statements[0];\n if (!statement || !ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier) || statement.importClause || !statement.moduleSpecifier.text.endsWith('.hesh')) {\n diagnostics.push(diagnostic('HESH-ARCH-001', 'Architecture imports must be side-effect imports of .hesh descriptors', file, source, item.start, 'Use import \"./domains/inventory/domain.hesh\";.')); continue;\n }\n load(canonical(resolve(dirname(file), statement.moduleSpecifier.text)));\n }\n };\n load(entry);\n const all = [...declarations.values()];\n const applications = all.filter(d => d.node.kind === 'application');\n const app = applications[0];\n if (applications.length !== 1) diagnostics.push(diagnostic('HESH-ARCH-001', 'Exactly one application declaration is required', entry, descriptors.get(entry)?.source ?? '', 0, 'Declare one application listing domains and destinations.'));\n const select = (kind: Contract['kind'], names: ContractEntry[] | undefined) => (names ?? []).flatMap(name => {\n const target = declarations.get(name.name);\n if (!target || target.node.kind !== kind) { if (app) error('HESH-ARCH-003', `Missing ${kind} ${name.name}`, app, name.start); return []; }\n return [target];\n });\n const domains = select('domain', app?.node.blocks.domains), destinations = select('destination', app?.node.blocks.destinations);\n const presentations = all.filter(d => d.node.kind === 'presentation');\n const declaredDomains = all.filter(d => d.node.kind === 'domain');\n const owner = (file: string): Located | undefined => declaredDomains.filter(d => inside(file, canonical(dirname(d.file)))).sort((a, b) => dirname(b.file).length - dirname(a.file).length)[0];\n const field = (item: Located, name: string, required = true) => {\n const value = item.node.fields[name]?.value;\n if (required && !value) error('HESH-ARCH-003', `Missing field ${name} in ${item.node.name}`, item);\n return value ?? '';\n };\n const list = (item: Located, name: string, required = false): ContractEntry[] => {\n if (required && !item.node.blocks[name]) error('HESH-ARCH-003', `Missing block ${name}`, item);\n return item.node.blocks[name] ?? [];\n };\n if (app) { list(app, 'domains', true); list(app, 'destinations', true); }\n const factories = new Map<Located, { file: string; name: string }>();\n for (const item of [...domains, ...presentations]) {\n const specifier = field(item, item.node.kind === 'domain' ? 'implementation' : 'logic');\n const hash = specifier.lastIndexOf('#'), path = specifier.slice(0, hash), name = specifier.slice(hash + 1);\n if (hash < 1 || !/^[$_\\p{ID_Start}][$_\\u200c\\u200d\\p{ID_Continue}]*$/u.test(name) || !path.startsWith('.') || !['.js', '.ts', '.mjs'].includes(extname(path)) || path.endsWith('.d.ts')) { error('HESH-ARCH-003', `Invalid implementation reference ${specifier}`, item, item.node.start, 'Use ./module.js#exportName (or .ts/.mjs).'); continue; }\n const file = canonical(resolve(dirname(item.file), path));\n if (!existsSync(file) || !inside(file, root) || owner(file) !== owner(item.file)) { error('HESH-ARCH-004', `Implementation must exist inside its owning domain: ${specifier}`, item); continue; }\n factories.set(item, { file, name }); files.add(file);\n }\n const byDomain = new Map(domains.map(item => [item.node.name, item]));\n for (const item of declaredDomains) if (declaredDomains.some(other => other !== item && dirname(other.file) === dirname(item.file))) error('HESH-ARCH-002', 'Each domain needs its own directory boundary', item);\n const edges = new Map<string, string[]>();\n for (const item of domains) {\n const exposes = list(item, 'exposes', true).map(v => v.name);\n if (!exposes.length) error('HESH-ARCH-003', `Domain ${item.node.name} must expose at least one operation`, item);\n for (const name of exposes) if (exposes.some(other => other !== name && other.startsWith(name + '.'))) error('HESH-ARCH-003', `Overlapping public operation ${name}`, item);\n const dependencies: string[] = [];\n for (const consume of list(item, 'consumes')) {\n const [provider, ...path] = consume.name.split('.'), target = byDomain.get(provider!);\n if (!target || !path.length || !list(target, 'exposes').some(v => v.name === path.join('.'))) error('HESH-ARCH-003', `Unresolved consumed operation ${consume.name}`, item, consume.start, 'Consume an operation explicitly exposed by a selected domain.');\n dependencies.push(provider!);\n }\n for (const policy of list(item, 'access')) if (!exposes.includes(policy.name)) error('HESH-ARCH-003', `Access policy refers to unexposed operation ${policy.name}`, item, policy.start);\n edges.set(item.node.name, dependencies);\n }\n const visited = new Set<string>(), visiting: string[] = [];\n const visit = (name: string) => {\n if (visiting.includes(name)) { const item = byDomain.get(name); if (item) error('HESH-ARCH-005', `Circular dependency: ${[...visiting, name].join(' -> ')}`, item, item.node.start, 'Remove the cycle or extract an explicit shared contract.'); return; }\n if (visited.has(name)) return;\n visiting.push(name); for (const next of edges.get(name) ?? []) visit(next); visiting.pop(); visited.add(name);\n };\n for (const name of byDomain.keys()) visit(name);\n let settings: ts.CompilerOptions = { target: ts.ScriptTarget.ES2022, module: ts.ModuleKind.ESNext, moduleResolution: ts.ModuleResolutionKind.Bundler, allowJs: true, checkJs: true, noEmit: true, skipLibCheck: true, allowImportingTsExtensions: true, types: [] };\n if (options.tsconfig) {\n const configFile = resolve(root, options.tsconfig), config = ts.readConfigFile(configFile, ts.sys.readFile);\n if (config.error) diagnostics.push(diagnostic('HESH-ARCH-001', ts.flattenDiagnosticMessageText(config.error.messageText, '\\n'), configFile, '', 0, 'Correct the TypeScript project configuration.'));\n else settings = { ...settings, ...ts.parseJsonConfigFileContent(config.config, ts.sys, dirname(configFile)).options, noEmit: true, allowJs: true, checkJs: true };\n }\n const program = ts.createProgram([...factories.values()].map(f => f.file), settings);\n const checker = program.getTypeChecker();\n const resolvedFactories = new Map<Located, Factory>();\n const getMember = (type: ts.Type, path: string[], unwrap = false): ts.Type | undefined => {\n let current = type;\n const unwrapped = (value: ts.Type): ts.Type => {\n const get = checker.getPropertyOfType(value, 'get');\n const callable = get ? checker.getTypeOfSymbolAtLocation(get, get.valueDeclaration ?? program.getSourceFiles()[0]!) : value;\n return checker.getSignaturesOfType(callable, ts.SignatureKind.Call)[0]?.getReturnType() ?? value;\n };\n for (const piece of path) {\n if (unwrap) current = unwrapped(current);\n if (current.flags & ts.TypeFlags.Any) return current;\n const symbol = checker.getPropertyOfType(current, piece); if (!symbol) return;\n current = checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration ?? program.getSourceFiles()[0]!);\n }\n return unwrap ? unwrapped(current) : current;\n };\n for (const [item, reference] of factories) {\n const sourceFile = program.getSourceFile(reference.file);\n const symbol = sourceFile && checker.getSymbolAtLocation(sourceFile);\n let exported = symbol && checker.getExportsOfModule(symbol).find(v => v.name === reference.name);\n if (exported?.flags && exported.flags & ts.SymbolFlags.Alias) exported = checker.getAliasedSymbol(exported);\n const type = exported && checker.getTypeOfSymbolAtLocation(exported, exported.valueDeclaration ?? sourceFile!);\n const signature = type && checker.getSignaturesOfType(type, ts.SignatureKind.Call)[0];\n if (!signature) { error('HESH-ARCH-003', `Missing callable export ${reference.name} in ${reference.file}`, item); continue; }\n const result = signature.getReturnType();\n if (result.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown) || checker.getPropertyOfType(result, 'then')) { error('HESH-ARCH-003', `Factory ${reference.name} must return a statically inspectable synchronous object`, item); continue; }\n resolvedFactories.set(item, { ...reference, result });\n if (item.node.kind === 'domain') for (const operation of list(item, 'exposes')) {\n const target = getMember(result, operation.name.split('.'));\n if (!target || !checker.getSignaturesOfType(target, ts.SignatureKind.Call).length) error('HESH-ARCH-003', `Unresolved callable implementation ${item.node.name}.${operation.name}`, item, operation.start, 'Return this operation from the declared implementation factory.');\n }\n else for (const block of ['bindings', 'actions']) {\n if (!getMember(result, [block])) error('HESH-BIND-002', `Presentation factory must return a ${block} object`, item);\n for (const binding of list(item, block, true)) {\n const target = getMember(result, [block, binding.name]);\n if (!target || (block === 'actions' && !checker.getSignaturesOfType(target, ts.SignatureKind.Call).length)) error(block === 'actions' ? 'HESH-ACTION-001' : 'HESH-BIND-002', `Missing ${block} implementation ${binding.name}`, item, binding.start, `Return ${block}.${binding.name} from the presentation factory.`);\n }\n }\n }\n // Validate actual imports/re-exports, including aliases and files shared by domains.\n const sources = ts.sys.readDirectory(root, ['.ts', '.js', '.mjs'], ['**/node_modules/**', '**/dist/**', '**/.hesh-generated/**'], ['**/*']);\n for (const path of sources) {\n const file = canonical(path); if (inside(file, canonical(outDir))) continue;\n files.add(file); const source = read(file), syntax = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, true, file.endsWith('.ts') ? ts.ScriptKind.TS : ts.ScriptKind.JS);\n const checkImport = (specifier: ts.Node | undefined): void => {\n if (!specifier) return;\n if (!ts.isStringLiteralLike(specifier)) { diagnostics.push(diagnostic('HESH-ARCH-007', 'Computed module imports cannot be architecture-validated', file, source, specifier.getStart(syntax), 'Use literal imports and explicit injected dependencies.')); return; }\n if (specifier.text.startsWith('node:') || ['fs', 'path', 'child_process', 'worker_threads', 'net', 'tls', 'http', 'https', 'os', 'module'].includes(specifier.text)) {\n diagnostics.push(diagnostic('HESH-SEC-001', `Node/server-only import in client code: ${specifier.text}`, file, source, specifier.getStart(syntax), 'Call server infrastructure through an API rather than bundling it.')); return;\n }\n const target = ts.resolveModuleName(specifier.text, file, settings, ts.sys).resolvedModule?.resolvedFileName;\n const generated = canonical(resolve(dirname(file), specifier.text));\n if (inside(generated, canonical(outDir))) return;\n if (!target) { if (!specifier.text.endsWith('.css') && !specifier.text.endsWith('.hesh')) diagnostics.push(diagnostic('HESH-ARCH-006', `Unresolved module ${specifier.text}`, file, source, specifier.getStart(syntax), 'Fix the path or supply the correct tsconfig alias.')); return; }\n const targetFile = canonical(target); files.add(targetFile);\n if (/(?:^|\\/)server(?:\\/|$)|\\.server\\.[cm]?[jt]s$/.test(targetFile)) diagnostics.push(diagnostic('HESH-SEC-001', `Server-only module in client graph: ${specifier.text}`, file, source, specifier.getStart(syntax), 'Move server calls behind a server API; never import server-only code into the browser.'));\n const targetDomain = owner(targetFile), sourceDomain = owner(file);\n if (targetDomain && targetDomain !== sourceDomain) diagnostics.push(diagnostic('HESH-ARCH-004', `Illegal cross-domain dependency. Source domain: ${sourceDomain?.node.name ?? 'shared/application'}. Target domain: ${targetDomain.node.name}. The imported module is private.`, file, source, specifier.getStart(syntax), `Use an explicitly exposed ${targetDomain.node.name} operation through declared dependency injection.`));\n };\n const walk = (node: ts.Node): void => {\n if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) checkImport(node.moduleSpecifier);\n else if (ts.isImportTypeNode(node) && ts.isLiteralTypeNode(node.argument)) checkImport(node.argument.literal);\n else if (ts.isCallExpression(node) && (node.expression.kind === ts.SyntaxKind.ImportKeyword || (ts.isIdentifier(node.expression) && node.expression.text === 'require'))) checkImport(node.arguments[0]);\n ts.forEachChild(node, walk);\n };\n walk(syntax);\n }\n for (const failure of [...program.getSyntacticDiagnostics(), ...program.getSemanticDiagnostics()]) if (failure.file && inside(canonical(failure.file.fileName), root)) diagnostics.push(diagnostic('HESH-TYPE-001', ts.flattenDiagnosticMessageText(failure.messageText, '\\n'), failure.file.fileName, failure.file.text, failure.start ?? 0, 'Correct the implementation type/syntax error.'));\n const schemas: Record<string, Record<string, string>> = Object.create(null), urls = new Map<string, Located>();\n const graph: ProjectResult['graph'] = { domains: domains.map(d => ({ name: d.node.name, exposes: list(d, 'exposes').map(e => e.name), consumes: list(d, 'consumes').map(e => e.name) })), destinations: [], links: [] };\n const presentationFor = new Map<Located, Located>();\n for (const item of destinations) {\n const url = field(item, 'url'), inputs = Object.fromEntries(list(item, 'input', true).map(e => [e.name, e.value ?? '']));\n const segments = url.split('/').filter(Boolean), params = segments.filter(p => p.startsWith(':')).map(p => p.slice(1));\n if (!url.startsWith('/') || url.startsWith('//') || /[?#*%]/.test(url) || new Set(params).size !== params.length || params.some(p => !Object.hasOwn(inputs, p)) || Object.keys(inputs).some(p => !params.includes(p))) error('HESH-NAV-003', `URL/input mismatch for ${item.node.name}`, item, item.node.start, 'Use an absolute URL whose :params exactly match the input block; use plain static segments.');\n for (const input of list(item, 'input')) if (!['string', 'number', 'boolean'].includes(input.value ?? '') || input.name.includes('.')) error('HESH-NAV-003', `Invalid input schema ${input.name}`, item, input.start);\n for (const key of Object.keys(inputs)) if (!/^[A-Za-z_][A-Za-z\\d_]*$/.test(key)) error('HESH-NAV-003', `Unsupported URL parameter name ${key}`, item, item.node.start, 'Use ASCII letters/digits/underscore with a letter or underscore first.');\n if (new Set(Object.keys(inputs).map(key => key.toLowerCase())).size !== Object.keys(inputs).length) error('HESH-NAV-003', 'Destination input names must be unique ignoring case for HTML attributes', item);\n const signature = segments.map(p => p.startsWith(':') ? ':' : p).join('/');\n if (urls.has(signature)) error('HESH-NAV-004', `Conflicting destination URL ${url}`, item); else urls.set(signature, item);\n for (const previous of destinations.slice(0, destinations.indexOf(item))) {\n const other = (previous.node.fields.url?.value ?? '').split('/').filter(Boolean);\n if (other.length === segments.length && other.every((part, index) => part === segments[index] || part.startsWith(':') || segments[index]!.startsWith(':'))) error('HESH-NAV-004', `Overlapping destination URLs: ${url} and ${previous.node.fields.url?.value}`, item, item.node.start, 'Use non-overlapping addresses so destination input always resolves to the declared screen.');\n }\n const presentation = declarations.get(field(item, 'presentation'));\n if (!presentation || presentation.node.kind !== 'presentation') error('HESH-NAV-001', `Missing presentation for ${item.node.name}`, item);\n else {\n const own = owner(presentation.file);\n if (!own || !byDomain.has(own.node.name) || owner(item.file) !== own) error('HESH-ARCH-004', 'Destination and presentation must belong to the same selected domain', item);\n else { presentationFor.set(item, presentation); graph.destinations.push({ name: item.node.name, url, input: inputs, owner: own.node.name }); }\n }\n schemas[item.node.name] = inputs;\n }\n const outputs: Record<string, string> = {}, htmlModules = new Map<Located, string>();\n for (const item of new Set(presentationFor.values())) {\n const html = canonical(resolve(dirname(item.file), field(item, 'html'))), stylePath = field(item, 'styles', false);\n if (!isFile(html) || !html.endsWith('.html') || !inside(html, canonical(dirname(item.file)))) { error('HESH-HTML-001', `Missing or private presentation HTML ${html}`, item); continue; }\n const source = read(html), factory = resolvedFactories.get(item);\n const compiled = compileHTML(source, { filename: html, bindings: list(item, 'bindings', true).map(e => e.name), actions: list(item, 'actions', true).map(e => e.name), destinations: schemas,\n validateBinding(path, offset, expected, writable) {\n if (!factory) return;\n const type = getMember(factory.result, ['bindings', ...path.split('.')], true);\n if (type && type.flags & ts.TypeFlags.Any) diagnostics.push(diagnostic('HESH-TYPE-002', `Binding ${path} has a dynamic any type; its nested shape/input type cannot be proven`, html, source, offset, 'Add JSDoc or a TypeScript type if static checking is required; runtime destination validation still applies.', 'warning'));\n if (!type) diagnostics.push(diagnostic('HESH-BIND-002', `Missing nested data path ${path}`, html, source, offset, 'Return this field in the declared bindings.'));\n if (writable) {\n const raw = getMember(factory.result, ['bindings', path]);\n if (!raw || !checker.getPropertyOfType(raw, 'set')) diagnostics.push(diagnostic('HESH-BIND-004', `Binding ${path} is not writable`, html, source, offset, 'Use a writable signal for h-value.'));\n }\n if (expected && type && !(type.flags & ts.TypeFlags.Any)) {\n const actual = type.flags & ts.TypeFlags.StringLike ? 'string' : type.flags & ts.TypeFlags.NumberLike ? 'number' : type.flags & ts.TypeFlags.BooleanLike ? 'boolean' : 'object/unknown';\n if (actual !== expected) diagnostics.push(diagnostic('HESH-NAV-003', `Destination binding ${path} is ${actual}, expected ${expected}`, html, source, offset, 'Bind a value of the destination input type.'));\n }\n }\n });\n diagnostics.push(...compiled.diagnostics);\n for (const [destination, screen] of presentationFor) if (screen === item) for (const target of compiled.destinations) graph.links.push({ from: destination.node.name, to: target });\n const output = join(outDir, `${item.node.name}.js`); htmlModules.set(item, output);\n let css = '';\n if (stylePath) {\n const style = canonical(resolve(dirname(item.file), stylePath));\n if (!isFile(style) || !style.endsWith('.css') || !inside(style, canonical(dirname(item.file)))) error('HESH-HTML-001', `Missing/private CSS resource ${stylePath}`, item);\n else { files.add(style); css = `import ${JSON.stringify(modulePath(output, style))};\\n`; }\n }\n outputs[output] = css + compiled.code;\n }\n const output = join(outDir, 'app.js'), types = join(outDir, 'app.d.ts');\n const js = [\"import { createGraphApplication, createDomainGraph } from '@heshammesalam/heshjs/destinations';\"];\n const domainValues: string[] = [], pageValues: string[] = [], typeImports: string[] = [], domainTypes: string[] = [];\n let index = 0;\n for (const item of domains) {\n const factory = resolvedFactories.get(item); if (!factory) continue;\n const alias = `factory${index++}`, spec = modulePath(output, factory.file);\n js.push(`import { ${factory.name} as ${alias} } from ${JSON.stringify(spec)};`);\n typeImports.push(`import { ${factory.name} as ${alias} } from ${JSON.stringify(spec)};`);\n const operations = list(item, 'exposes').map(e => e.name);\n domainValues.push(`{name:${JSON.stringify(item.node.name)}, factory:${alias}, exposes:${JSON.stringify(operations)}, consumes:${JSON.stringify(list(item, 'consumes').map(e => e.name))}, access:${JSON.stringify(Object.fromEntries(list(item, 'access').map(e => [e.name, e.value])))}}`);\n const tree: Record<string, unknown> = {};\n for (const operation of operations) { let node = tree; const parts = operation.split('.'); parts.forEach((part, i) => { if (i === parts.length - 1) node[part] = `ReturnType<typeof ${alias}>${parts.map(p => `[${JSON.stringify(p)}]`).join('')}`; else node = (node[part] ??= {}) as Record<string, unknown>; }); }\n const typeTree = (value: Record<string, unknown>): string => '{' + Object.entries(value).map(([key, value]) => `readonly ${JSON.stringify(key)}:${typeof value === 'string' ? value : typeTree(value as Record<string, unknown>)}`).join(';') + '}';\n domainTypes.push(`${JSON.stringify(item.node.name)}:${typeTree(tree)}`);\n }\n for (const item of destinations) {\n const presentation = presentationFor.get(item), factory = presentation && resolvedFactories.get(presentation), html = presentation && htmlModules.get(presentation);\n const data = graph.destinations.find(d => d.name === item.node.name);\n if (!presentation || !factory || !html || !data) continue;\n pageValues.push(`{...${JSON.stringify({ ...data, access: item.node.fields.access?.value })}, load:async()=>{const [logic,template]=await Promise.all([import(${JSON.stringify(modulePath(output, factory.file))}),import(${JSON.stringify(modulePath(output, html))})]);return {create:logic[${JSON.stringify(factory.name)}],view:template.default};}}`);\n }\n js.push(`const domains = [${domainValues.join(',\\n')}];`, `const pages = [${pageValues.join(',\\n')}];`, 'export const metadata = ' + JSON.stringify(graph) + ';', 'export const createDomains = (options = {}) => createDomainGraph(domains, options);', 'export const createApplication = (options = {}) => createGraphApplication(domains, pages, options);');\n const destinationTypes = graph.destinations.map(d => `${JSON.stringify(d.name)}: Destination<${Object.keys(d.input).length ? '{' + Object.entries(d.input).map(([key, type]) => `${JSON.stringify(key)}:${type}`).join(';') + '}' : 'Record<string, never>'}>`);\n outputs[output] = js.join('\\n');\n outputs[types] = [\"import type { Destination, GraphApplication, ApplicationOptions, DomainGraph } from '@heshammesalam/heshjs/destinations';\", ...typeImports, `export interface DomainAPIs {${domainTypes.join(';')}}`, `export interface Destinations {${destinationTypes.join(';')}}`, 'export declare function createDomains(options?: ApplicationOptions): DomainGraph<DomainAPIs>;', 'export declare function createApplication(options?: ApplicationOptions): GraphApplication<Destinations, DomainAPIs>;', 'export declare const metadata: unknown;'].join('\\n');\n if (diagnostics.some(d => d.severity === 'error')) for (const name of Object.keys(outputs)) delete outputs[name];\n return { diagnostics, files: [...files].sort(), outputs, graph, statistics: { parsed, reused } };\n } };\n}\nexport function checkProject(options: ProjectOptions): ProjectResult { return createArchitectureCompiler().check(options); }\nexport function writeProject(result: ProjectResult): void {\n if (result.diagnostics.some(d => d.severity === 'error')) throw new Error(result.diagnostics.map(formatDiagnostic).join('\\n'));\n for (const [file, source] of Object.entries(result.outputs)) { mkdirSync(dirname(file), { recursive: true }); if (!existsSync(file) || readFileSync(file, 'utf8') !== source) writeFileSync(file, source); }\n}\n"]}
|
package/dist/compiler/index.js
CHANGED
|
@@ -4,6 +4,8 @@ const printer = ts.createPrinter();
|
|
|
4
4
|
const f = ts.factory;
|
|
5
5
|
export function compile(source, options = {}) {
|
|
6
6
|
const ast = parse(source, options.filename);
|
|
7
|
+
if (ast.contracts.length)
|
|
8
|
+
throw new HeshError('Architecture declarations require the project compiler (hesh check or hesh({ architecture: ... }))', source, ast.contracts[0].start, ast.filename);
|
|
7
9
|
const metadata = [];
|
|
8
10
|
const fail = (message, offset) => { throw new HeshError(message, source, offset, ast.filename); };
|
|
9
11
|
const names = new Set();
|