@loom-forge/core 0.1.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/dist/index.js ADDED
@@ -0,0 +1,442 @@
1
+ // src/events.ts
2
+ var next = (link, scope) => link.scope === void 0 && scope ? { ...link, scope } : link;
3
+ function runIntent(binding, event, rt) {
4
+ const params = rt.params(binding, event);
5
+ if (binding.local) {
6
+ if (rt.apply) rt.apply(binding.action, params);
7
+ else rt.orphan?.(binding.action);
8
+ if (binding.then)
9
+ runIntent(next(binding.then, binding.scope), void 0, rt);
10
+ return;
11
+ }
12
+ if (!rt.port) return;
13
+ rt.pending?.(binding.action, true);
14
+ dispatchIntent(rt.port, binding.action, params, (id, result) => {
15
+ rt.pending?.(binding.action, false);
16
+ rt.onResult?.(id, result);
17
+ if (result.success) {
18
+ if (!result.aborted && binding.then)
19
+ runIntent(next(binding.then, binding.scope), result.data, rt);
20
+ } else if (binding.catch)
21
+ runIntent(next(binding.catch, binding.scope), result.error, rt);
22
+ });
23
+ }
24
+ var isThenable = (v) => typeof v?.then === "function";
25
+ var isDev = () => {
26
+ const g = globalThis;
27
+ return g.process?.env?.NODE_ENV !== "production";
28
+ };
29
+ var faultOf = (error) => ({
30
+ success: false,
31
+ aborted: true,
32
+ abortedBy: "throw",
33
+ error: {
34
+ code: "UNHANDLED_ERROR",
35
+ message: String(error?.message ?? error)
36
+ }
37
+ });
38
+ var settle = (id, outcome, onResult) => {
39
+ const result = outcome ?? { success: true };
40
+ if (onResult) {
41
+ onResult(id, result);
42
+ return;
43
+ }
44
+ if (result.success === false && isDev())
45
+ console.warn(
46
+ `[loom] a\xE7\xE3o "${id}" falhou (${result.error?.code ?? "?"}) e ningu\xE9m est\xE1 escutando. Passe \`onActionResult\` ao engine para tratar.`,
47
+ result.error
48
+ );
49
+ };
50
+ function dispatchIntent(port, id, params, onResult) {
51
+ if (!port) return;
52
+ let outcome;
53
+ try {
54
+ outcome = port.invoke(id, params);
55
+ } catch (error) {
56
+ settle(id, faultOf(error), onResult);
57
+ return;
58
+ }
59
+ if (isThenable(outcome)) {
60
+ void outcome.then(
61
+ (r) => settle(id, r, onResult),
62
+ (e) => settle(id, faultOf(e), onResult)
63
+ );
64
+ return;
65
+ }
66
+ settle(id, outcome, onResult);
67
+ }
68
+ function intentParams(binder, binding, event) {
69
+ if (binding.scope === void 0) return binding.params;
70
+ const ghost = {
71
+ id: "$intent",
72
+ type: "$intent",
73
+ props: { value: binding.params }
74
+ };
75
+ const bound = binder.bind(ghost, { ...binding.scope, event });
76
+ return bound.props?.value;
77
+ }
78
+ function intentsOf(binding) {
79
+ const out = [binding];
80
+ if (binding.then) out.push(...intentsOf(binding.then));
81
+ if (binding.catch) out.push(...intentsOf(binding.catch));
82
+ return out;
83
+ }
84
+
85
+ // src/commands.ts
86
+ var EMPTY_COMMANDS = Object.freeze({});
87
+ var commandScope = (inherited, node) => node.commands ? { ...inherited, ...node.commands } : inherited;
88
+ var aliasOf = (alias) => typeof alias === "string" ? { action: alias } : alias;
89
+ function resolveIntent(binding, scope, updates) {
90
+ const written = { ...binding };
91
+ delete written.local;
92
+ if (written.then) written.then = resolveIntent(written.then, scope, updates);
93
+ if (written.catch)
94
+ written.catch = resolveIntent(written.catch, scope, updates);
95
+ if (updates?.has(written.action)) return { ...written, local: true };
96
+ const alias = scope[written.action];
97
+ if (alias === void 0) return written;
98
+ const { action, params } = aliasOf(alias);
99
+ const merged = params !== void 0 && isRecord(params) ? { ...params, ...isRecord(written.params) ? written.params : {} } : written.params;
100
+ return {
101
+ ...written,
102
+ action,
103
+ ...merged === void 0 ? {} : { params: merged },
104
+ ...updates?.has(action) ? { local: true } : {}
105
+ };
106
+ }
107
+ var isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
108
+
109
+ // src/registry.ts
110
+ function createDescriptorRegistry(initial) {
111
+ const map = /* @__PURE__ */ new Map();
112
+ const registry = {
113
+ register(descriptorOrType) {
114
+ const descriptor = typeof descriptorOrType === "string" ? { type: descriptorOrType } : descriptorOrType;
115
+ if (!descriptor.type)
116
+ throw new Error("descriptorRegistry.register: `type` \xE9 obrigat\xF3rio.");
117
+ map.set(descriptor.type, descriptor);
118
+ return registry;
119
+ },
120
+ get: (type) => map.get(type),
121
+ has: (type) => map.has(type),
122
+ list: () => [...map.values()]
123
+ };
124
+ for (const d of initial ?? []) registry.register(d);
125
+ return registry;
126
+ }
127
+
128
+ // src/resolver.ts
129
+ function createTypeResolver(options = {}) {
130
+ const caps = options.capabilities;
131
+ const supported = (node) => {
132
+ if (!node.requires) return true;
133
+ if (!caps) return false;
134
+ for (const [cap, min] of Object.entries(node.requires)) {
135
+ const have = caps[cap];
136
+ if (have == null) return false;
137
+ if (min !== "*" && cmpVersion(have, min) < 0) return false;
138
+ }
139
+ return true;
140
+ };
141
+ const resolve = (node, ctx) => {
142
+ if (!node.type) return { kind: "unknown", node };
143
+ const descriptor = ctx.registry.get(node.type);
144
+ if (descriptor && supported(node)) {
145
+ return {
146
+ kind: "render",
147
+ descriptor,
148
+ props: { ...descriptor.defaultProps ?? {}, ...node.props ?? {} }
149
+ };
150
+ }
151
+ if (node.fallback === "drop") return { kind: "drop" };
152
+ if (node.fallback && typeof node.fallback === "object")
153
+ return resolve(node.fallback, ctx);
154
+ return { kind: "unknown", node };
155
+ };
156
+ return { resolve };
157
+ }
158
+ function cmpVersion(a, b) {
159
+ const pa = a.split(".").map(Number);
160
+ const pb = b.split(".").map(Number);
161
+ const len = Math.max(pa.length, pb.length);
162
+ for (let i = 0; i < len; i++) {
163
+ const x = pa[i] ?? 0;
164
+ const y = pb[i] ?? 0;
165
+ if (x !== y) return x < y ? -1 : 1;
166
+ }
167
+ return 0;
168
+ }
169
+
170
+ // src/ports.ts
171
+ var identityBinder = { bind: (node) => node };
172
+ var noopValidator = { validate: () => null };
173
+
174
+ // src/layout.ts
175
+ var ORDER_PLACEMENT = {
176
+ type: "object",
177
+ properties: { index: { type: "number" } }
178
+ };
179
+ var clamp = (n, min, max) => Math.max(min, Math.min(max, n));
180
+ function orderedIds(children) {
181
+ return children.map((c, i) => ({
182
+ id: c.id,
183
+ k: c.placement?.index ?? i
184
+ })).sort((a, b) => a.k - b.k).map((x) => x.id);
185
+ }
186
+ function fragmentPlanner() {
187
+ return {
188
+ name: "fragment",
189
+ plan: (children) => ({ order: orderedIds(children) }),
190
+ placementSchema: ORDER_PLACEMENT
191
+ };
192
+ }
193
+ function sectionPlanner(opts = {}) {
194
+ const direction = opts.direction ?? "column";
195
+ return {
196
+ name: "section",
197
+ plan: (children) => ({
198
+ direction,
199
+ gap: opts.gap,
200
+ order: orderedIds(children)
201
+ }),
202
+ placementSchema: ORDER_PLACEMENT
203
+ };
204
+ }
205
+ function fillSpans(span, columns) {
206
+ const c = (n) => clamp(n, 1, columns);
207
+ if (span == null) {
208
+ const v = columns;
209
+ return { base: v, sm: v, md: v, lg: v, xl: v };
210
+ }
211
+ if (typeof span === "number") {
212
+ const v = c(span);
213
+ return { base: v, sm: v, md: v, lg: v, xl: v };
214
+ }
215
+ const base = c(span.base ?? columns);
216
+ const sm = span.sm != null ? c(span.sm) : base;
217
+ const md = span.md != null ? c(span.md) : sm;
218
+ const lg = span.lg != null ? c(span.lg) : md;
219
+ const xl = span.xl != null ? c(span.xl) : lg;
220
+ return { base, sm, md, lg, xl };
221
+ }
222
+ var GRID_FORM_PLACEMENT = {
223
+ type: "object",
224
+ properties: {
225
+ span: {
226
+ anyOf: [
227
+ { type: "number" },
228
+ {
229
+ type: "object",
230
+ properties: {
231
+ base: { type: "number" },
232
+ sm: { type: "number" },
233
+ md: { type: "number" },
234
+ lg: { type: "number" },
235
+ xl: { type: "number" }
236
+ },
237
+ required: ["base"]
238
+ }
239
+ ]
240
+ },
241
+ break: { type: "boolean" },
242
+ index: { type: "number" }
243
+ }
244
+ };
245
+ var varies = (s) => s.base !== s.sm || s.sm !== s.md || s.md !== s.lg || s.lg !== s.xl;
246
+ function gridFormPlanner(opts = {}) {
247
+ const columns = opts.columns ?? 12;
248
+ const gap = opts.gap ?? "1rem";
249
+ return {
250
+ name: "grid-form",
251
+ plan(children) {
252
+ const ordered = children.map((c, i) => ({
253
+ c,
254
+ k: c.placement?.index ?? i
255
+ })).sort((a, b) => a.k - b.k).map((x) => x.c);
256
+ let responsive = false;
257
+ const cells = ordered.map((c) => {
258
+ const p = c.placement ?? {};
259
+ const spans = fillSpans(p.span, columns);
260
+ if (varies(spans)) responsive = true;
261
+ return { id: c.id, span: spans.base, spans, break: p.break };
262
+ });
263
+ return { columns, gap, responsive, cells };
264
+ },
265
+ placementSchema: GRID_FORM_PLACEMENT
266
+ };
267
+ }
268
+ function defaultPlanners() {
269
+ return {
270
+ fragment: fragmentPlanner(),
271
+ section: sectionPlanner(),
272
+ "grid-form": gridFormPlanner()
273
+ };
274
+ }
275
+
276
+ // src/pipeline.ts
277
+ function resolveTree(node, opts, scope) {
278
+ const binder = opts.binder ?? identityBinder;
279
+ const resolver = opts.resolver ?? createTypeResolver();
280
+ const planners = opts.planners ?? defaultPlanners();
281
+ const defaultLayout = opts.defaultLayout ?? "fragment";
282
+ const planLayout = (renderable, name) => {
283
+ if (!renderable.length) return void 0;
284
+ const planner = planners[name];
285
+ if (!planner) return void 0;
286
+ return {
287
+ name,
288
+ plan: planner.plan(
289
+ renderable.map((c) => ({ id: c.id, placement: c.placement }))
290
+ )
291
+ };
292
+ };
293
+ const resolveChildren = (children) => (children ?? []).map((c) => ({ id: c.id, placement: c.placement, out: resolveNode(c) })).filter((c) => c.out.kind !== "drop");
294
+ const resolveNode = (def) => {
295
+ if (def.el != null) {
296
+ const renderable2 = resolveChildren(def.children);
297
+ return {
298
+ kind: "node",
299
+ id: def.id,
300
+ type: def.el,
301
+ el: true,
302
+ props: def.props ?? {},
303
+ events: def.events,
304
+ ...def.origins ? { origins: def.origins } : {},
305
+ layout: planLayout(renderable2, def.layout ?? defaultLayout),
306
+ children: renderable2.map((c) => c.out)
307
+ };
308
+ }
309
+ const type = def.type;
310
+ if (type == null) return { kind: "unknown", id: def.id, type: "" };
311
+ const res = resolver.resolve(def, { registry: opts.registry });
312
+ if (res.kind === "drop") return { kind: "drop", id: def.id };
313
+ if (res.kind === "unknown") return { kind: "unknown", id: def.id, type };
314
+ const renderable = resolveChildren(def.children);
315
+ const layout = planLayout(
316
+ renderable,
317
+ def.layout ?? res.descriptor.layout ?? defaultLayout
318
+ );
319
+ return {
320
+ kind: "node",
321
+ id: def.id,
322
+ type,
323
+ props: res.props,
324
+ events: def.events,
325
+ ...def.origins ? { origins: def.origins } : {},
326
+ layout,
327
+ children: renderable.map((c) => c.out)
328
+ };
329
+ };
330
+ return resolveNode(binder.bind(binder.compile?.(node) ?? node, scope));
331
+ }
332
+
333
+ // src/tree.ts
334
+ function walk(node, visit, parent = null) {
335
+ visit(node, parent);
336
+ for (const child of node.children ?? []) walk(child, visit, node);
337
+ }
338
+ function findById(root, id) {
339
+ if (root.id === id) return root;
340
+ for (const child of root.children ?? []) {
341
+ const found = findById(child, id);
342
+ if (found) return found;
343
+ }
344
+ return void 0;
345
+ }
346
+ function pathToId(root, id) {
347
+ if (root.id === id) return [root.id];
348
+ for (const child of root.children ?? []) {
349
+ const sub = pathToId(child, id);
350
+ if (sub) return [root.id, ...sub];
351
+ }
352
+ return null;
353
+ }
354
+ function mapNodes(node, fn) {
355
+ const children = node.children?.map((c) => mapNodes(c, fn));
356
+ const next2 = children ? { ...node, children } : node;
357
+ return fn(next2);
358
+ }
359
+
360
+ // src/slots.ts
361
+ var FIELDS = {
362
+ id: "identity",
363
+ type: "data",
364
+ el: "data",
365
+ layout: "data",
366
+ version: "data",
367
+ requires: "data",
368
+ as: "data",
369
+ // o NOME que o `each` liga — identificador, não expressão
370
+ children: "tree",
371
+ fallback: "tree",
372
+ // `"drop"` ou um DefNode inteiro
373
+ props: "slot",
374
+ placement: "slot",
375
+ events: "slot",
376
+ // a expressão mora em `events[*].params`
377
+ each: "slot",
378
+ when: "slot",
379
+ provides: "slot",
380
+ commands: "slot",
381
+ // o VOCABULÁRIO da subárvore; os `params` do alias são expressão
382
+ origins: "identity"
383
+ // de onde o nó veio — escrito pela expansão, e nunca tocado
384
+ };
385
+ var SLOTS = {
386
+ props: {
387
+ shape: "value",
388
+ expects: "unknown",
389
+ stage: "value",
390
+ directives: false
391
+ },
392
+ placement: {
393
+ shape: "value",
394
+ expects: "unknown",
395
+ stage: "value",
396
+ directives: false
397
+ },
398
+ events: {
399
+ shape: "intentParams",
400
+ expects: "unknown",
401
+ stage: "value",
402
+ directives: false
403
+ },
404
+ /** o alias é ROTEADOR: o nome não é expressão, mas os `params` da aplicação parcial são. */
405
+ commands: {
406
+ shape: "intentParams",
407
+ expects: "unknown",
408
+ stage: "value",
409
+ directives: false
410
+ },
411
+ /** os valores providos à subárvore; o tipo de cada um vem do catálogo de contextos. */
412
+ provides: {
413
+ shape: "value",
414
+ expects: "unknown",
415
+ stage: "value",
416
+ directives: false
417
+ },
418
+ each: {
419
+ shape: "value",
420
+ expects: "unknown",
421
+ stage: "structural",
422
+ directives: false
423
+ },
424
+ /** predicado — uma condição que renda `string` é erro de tipo, não nó sempre-visível. */
425
+ when: {
426
+ shape: "value",
427
+ expects: "boolean",
428
+ stage: "structural",
429
+ directives: false
430
+ }
431
+ };
432
+ var isSlot = (field) => Object.prototype.hasOwnProperty.call(SLOTS, field);
433
+ var slotOf = (field) => SLOTS[field];
434
+ var TREE = {
435
+ children: "list",
436
+ fallback: "node"
437
+ // pode ser a string `"drop"`; quem desce estreita antes
438
+ };
439
+
440
+ export { EMPTY_COMMANDS, FIELDS, SLOTS, TREE, aliasOf, commandScope, createDescriptorRegistry, createTypeResolver, defaultPlanners, dispatchIntent, findById, fragmentPlanner, gridFormPlanner, identityBinder, intentParams, intentsOf, isSlot, mapNodes, noopValidator, pathToId, resolveIntent, resolveTree, runIntent, sectionPlanner, slotOf, walk };
441
+ //# sourceMappingURL=index.js.map
442
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/events.ts","../src/commands.ts","../src/registry.ts","../src/resolver.ts","../src/ports.ts","../src/layout.ts","../src/pipeline.ts","../src/tree.ts","../src/slots.ts"],"names":["renderable","next"],"mappings":"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","file":"index.js","sourcesContent":["import type { DefNode, EventBinding } from \"./types\";\nimport type {\n ActionOutcome,\n ActionPort,\n ActionResult,\n BindingEngine,\n} from \"./ports\";\n\n/* ──────────────────────────────────────────────────────────────────────────────\n A INTENÇÃO em execução — a fronteira por onde um valor ENTRA no sistema, e o\n caminho que ela segue depois (ADR-018).\n\n Tudo o que uma intenção recebe entra pelos `params`, e o autor escreve o mapeamento:\n a raiz `event` é o valor recebido — o que o widget emitiu, o `data` da ação anterior\n num `then`, o `error` num `catch`. Os `params` são avaliados no DESPACHO, com o\n escopo do render mais `event`; quem sabe avaliar é o binder, e ele entra por porta.\n\n `then`/`catch` são intenções aninhadas: a leitura é a de uma promise chain. Um\n update local resolve quando o estado foi escrito (`event` = `undefined`); um\n despacho ao host resolve com `data` ou falha com `error`. O host recebe TODO\n resultado pelo `onResult`, com ou sem continuação: são consumidores diferentes.\n ────────────────────────────────────────────────────────────────────────────── */\n\n/** O que o despacho de uma cadeia precisa de quem a executa — a view, o boundary. */\nexport interface IntentRuntime {\n /** avalia os `params` de UMA intenção: o escopo dela (o do render) mais `event`. */\n params(binding: EventBinding, event: unknown): unknown;\n /** aplica um update local — o componente vivo. Ausente = não há boundary aqui. */\n apply?(action: string, params: unknown): void;\n /** o que fazer com uma intenção local sem boundary — em dev, avisar. */\n orphan?(action: string): void;\n port?: ActionPort;\n onResult?(id: string, result: ActionResult): void;\n /** o pendente da instância: `true` do despacho ao resultado. Ausente = não há instância. */\n pending?(action: string, flag: boolean): void;\n}\n\n/** o elo seguinte herda o escopo do render de quem o escreveu — a cadeia inteira vê o mesmo escopo. */\nconst next = (\n link: EventBinding,\n scope: EventBinding[\"scope\"],\n): EventBinding =>\n link.scope === undefined && scope ? { ...link, scope } : link;\n\n/**\n * Executa uma intenção e a cadeia dela. Nunca devolve nada — o resultado é evento.\n *\n * Local: aplica e segue para o `then` com `event` = `undefined`. Host: despacha; no\n * `success`, segue para o `then` com `data`; na falha, para o `catch` com `error`;\n * `aborted` não é nenhum dos dois e fica só com o host.\n */\nexport function runIntent(\n binding: EventBinding,\n event: unknown,\n rt: IntentRuntime,\n): void {\n const params = rt.params(binding, event);\n if (binding.local) {\n if (rt.apply) rt.apply(binding.action, params);\n else rt.orphan?.(binding.action);\n if (binding.then)\n runIntent(next(binding.then, binding.scope), undefined, rt);\n return;\n }\n if (!rt.port) return;\n rt.pending?.(binding.action, true);\n dispatchIntent(rt.port, binding.action, params, (id, result) => {\n rt.pending?.(binding.action, false);\n rt.onResult?.(id, result);\n // um fluxo CANCELADO (`aborted` com sucesso) não é resultado: fica só com o host. Um port\n // que lançou também sai `aborted`, mas é falha — e o `catch` é dele.\n if (result.success) {\n if (!result.aborted && binding.then)\n runIntent(next(binding.then, binding.scope), result.data, rt);\n } else if (binding.catch)\n runIntent(next(binding.catch, binding.scope), result.error, rt);\n });\n}\n\n/* ──────────────────────────────────────────────────────────────────────────────\n O DESPACHO — e a regra que ele encarna: **o handler é síncrono e devolve\n `void`; o RESULTADO é evento, não retorno.**\n\n É o contrato do React, não uma escolha nossa: um handler de evento não é\n aguardado, e devolver promessa dele não faz nada. O handler INICIA a ação; quem\n espera é quem tem onde mostrar o resultado.\n\n E o resultado não pode sumir. Hoje ele sumia por ser síncrono e ignorado; com\n async, sumir é pior — uma promessa rejeitada sem `catch` é evento de nível de\n processo em Node e ruído no console no browser. Então o tratamento mora AQUI,\n uma vez, em vez de em cada call-site.\n ────────────────────────────────────────────────────────────────────────────── */\n\nconst isThenable = (v: unknown): v is Promise<unknown> =>\n typeof (v as { then?: unknown })?.then === \"function\";\n\nconst isDev = (): boolean => {\n const g = globalThis as { process?: { env?: { NODE_ENV?: string } } };\n return g.process?.env?.NODE_ENV !== \"production\";\n};\n\n/** Erro ESTRUTURAL — o port lançou, o que é bug de programa, não falha de domínio. */\nconst faultOf = (error: unknown): ActionResult => ({\n success: false,\n aborted: true,\n abortedBy: \"throw\",\n error: {\n code: \"UNHANDLED_ERROR\",\n message: String((error as Error)?.message ?? error),\n },\n});\n\n/** Nada dito é nada errado: um host que não devolve envelope não está reportando falha. */\nconst settle = (\n id: string,\n outcome: void | ActionResult,\n onResult: ((id: string, result: ActionResult) => void) | undefined,\n): void => {\n const result: ActionResult = outcome ?? { success: true };\n if (onResult) {\n onResult(id, result);\n return;\n }\n if (result.success === false && isDev())\n console.warn(\n `[loom] ação \"${id}\" falhou (${result.error?.code ?? \"?\"}) e ninguém está escutando.` +\n \" Passe `onActionResult` ao engine para tratar.\",\n result.error,\n );\n};\n\n/**\n * Dispara uma intenção e NUNCA devolve nada — nem promessa, nem valor.\n *\n * O resultado, sync ou async, vai para `onResult`. Falha de domínio chega como\n * `{ success: false, error }`; um port que LANÇA vira `UNHANDLED_ERROR`, porque isso é bug de\n * programa e não pode derrubar um clique.\n */\nexport function dispatchIntent(\n port: ActionPort | undefined,\n id: string,\n params?: unknown,\n onResult?: (id: string, result: ActionResult) => void,\n): void {\n if (!port) return;\n let outcome: ActionOutcome;\n try {\n outcome = port.invoke(id, params);\n } catch (error) {\n settle(id, faultOf(error), onResult);\n return;\n }\n if (isThenable(outcome)) {\n void outcome.then(\n (r) => settle(id, r as void | ActionResult, onResult),\n (e) => settle(id, faultOf(e), onResult),\n );\n return;\n }\n settle(id, outcome, onResult);\n}\n\n/**\n * Os `params` de uma intenção, avaliados no despacho — pelo MESMO caminho do render.\n *\n * O binder liga um nó-fantasma cuja prop é o `params` compilado, sobre o escopo que o `bind`\n * guardou no binding mais a raiz `event`. Reusar o binder é o que garante o mesmo gate de\n * capability, o mesmo orçamento e o mesmo escopo que o clique enxergava. Sem escopo guardado\n * não há expressão nos `params`, e eles são dado como estão.\n */\nexport function intentParams(\n binder: BindingEngine,\n binding: EventBinding,\n event: unknown,\n): unknown {\n if (binding.scope === undefined) return binding.params;\n const ghost: DefNode = {\n id: \"$intent\",\n type: \"$intent\",\n props: { value: binding.params },\n };\n const bound = binder.bind(ghost, { ...binding.scope, event });\n return (bound.props as Record<string, unknown> | undefined)?.value;\n}\n\n/** A intenção e cada elo da cadeia dela (`then`/`catch`, em profundidade), na ordem de escrita. */\nexport function intentsOf(binding: EventBinding): EventBinding[] {\n const out: EventBinding[] = [binding];\n if (binding.then) out.push(...intentsOf(binding.then));\n if (binding.catch) out.push(...intentsOf(binding.catch));\n return out;\n}\n","import type { CommandAlias, EventBinding } from \"./types\";\n\n/* ──────────────────────────────────────────────────────────────────────────────\n O ESCOPO DE COMANDO — o vocabulário que uma subárvore enxerga.\n\n É o mesmo mecanismo do `provides`, no eixo do comportamento, e com a mesma\n restrição: o que viaja é **nome**, nunca função. Função no escopo seria uma\n segunda porta de efeito que não cria aresta no grafo — e aí a propagação de\n tags, o `unable` e o dirty degradariam em silêncio.\n\n Estas funções são a ÚNICA resposta para \"que ação este nome executa?\". Elas\n moram aqui porque três consumidores precisam dela e nenhum pode ter a sua: a\n expansão (runtime), o `check` (prova) e o `eject` (tradução). Duas respostas\n para a mesma pergunta divergem, e a divergência é silenciosa.\n ────────────────────────────────────────────────────────────────────────────── */\n\n/** O que está em vigor num ponto da árvore — nome local → ação. */\nexport type CommandScope = Readonly<Record<string, CommandAlias>>;\n\nexport const EMPTY_COMMANDS: CommandScope = Object.freeze({});\n\n/**\n * O escopo em vigor ABAIXO de um nó: o herdado com o que ele instala por cima.\n *\n * O sombreamento é literalmente o merge — o mais próximo ganha, como no `provides`.\n */\nexport const commandScope = (\n inherited: CommandScope,\n node: { commands?: Record<string, CommandAlias> },\n): CommandScope =>\n node.commands ? { ...inherited, ...node.commands } : inherited;\n\n/** O alias normalizado: a forma curta é açúcar para `{ action }`. */\nexport const aliasOf = (\n alias: CommandAlias,\n): { action: string; params?: unknown } =>\n typeof alias === \"string\" ? { action: alias } : alias;\n\n/**\n * Resolve uma intenção contra o escopo — e a ordem é a do runtime.\n *\n * `updates` são os UPDATES do componente que ESCREVEU a intenção: um nome que resolve ali é\n * chamada interna e **não** passa pelo escopo, porque ele não sai do componente (ADR-014). O que\n * não é update nem alias segue como está, e vai parar na porta raiz.\n *\n * Os params do alias são **aplicação parcial**: eles entram por baixo, e o que o call-site passa\n * ganha. Quem dispara é mais específico que quem declarou o vocabulário.\n *\n * O que termina num update — pelo nome, ou pelo alvo de um alias — sai MARCADO (`local`). A marca\n * é a resposta, e não o nome: a view entrega ao componente vivo só o que foi marcado, então uma\n * intenção de outro componente com o mesmo nome não alcança o update dele.\n *\n * `then` e `catch` são intenções, e resolvem pela mesma régua — cada elo da cadeia no mesmo\n * escopo em que a cadeia foi escrita.\n */\nexport function resolveIntent(\n binding: EventBinding,\n scope: CommandScope,\n updates?: ReadonlySet<string>,\n): EventBinding {\n const written: EventBinding = { ...binding };\n delete written.local; // quem marca é a resolução, nunca o documento\n if (written.then) written.then = resolveIntent(written.then, scope, updates);\n if (written.catch)\n written.catch = resolveIntent(written.catch, scope, updates);\n\n if (updates?.has(written.action)) return { ...written, local: true };\n const alias = scope[written.action];\n if (alias === undefined) return written;\n\n const { action, params } = aliasOf(alias);\n const merged =\n params !== undefined && isRecord(params)\n ? { ...params, ...(isRecord(written.params) ? written.params : {}) }\n : written.params;\n\n return {\n ...written,\n action,\n ...(merged === undefined ? {} : { params: merged }),\n ...(updates?.has(action) ? { local: true as const } : {}),\n };\n}\n\nconst isRecord = (v: unknown): v is Record<string, unknown> =>\n typeof v === \"object\" && v !== null && !Array.isArray(v);\n","import type { Descriptor, DescriptorRegistry } from \"./types\";\n\n/** Registry ABERTO de descriptors (metadado headless por `type`). Encadeável.\n * Aceita a forma completa (`Descriptor`) ou só o `type` (descriptor nu). */\nexport function createDescriptorRegistry(\n initial?: Descriptor[],\n): DescriptorRegistry {\n const map = new Map<string, Descriptor>();\n\n const registry: DescriptorRegistry = {\n register(descriptorOrType: Descriptor | string): DescriptorRegistry {\n const descriptor: Descriptor =\n typeof descriptorOrType === \"string\"\n ? { type: descriptorOrType }\n : descriptorOrType;\n if (!descriptor.type)\n throw new Error(\"descriptorRegistry.register: `type` é obrigatório.\");\n map.set(descriptor.type, descriptor);\n return registry;\n },\n get: (type) => map.get(type),\n has: (type) => map.has(type),\n list: () => [...map.values()],\n };\n\n for (const d of initial ?? []) registry.register(d);\n return registry;\n}\n","import type { DefNode, Descriptor, DescriptorRegistry } from \"./types\";\n\nexport interface ResolveCtx {\n registry: DescriptorRegistry;\n}\n\nexport type ResolveResult =\n | { kind: \"render\"; descriptor: Descriptor; props: Record<string, unknown> }\n | { kind: \"drop\" }\n | { kind: \"unknown\"; node: DefNode };\n\nexport interface Resolver {\n resolve(node: DefNode, ctx: ResolveCtx): ResolveResult;\n}\n\nexport interface TypeResolverOptions {\n /** capacidades do host (capability → versão). Habilita o gating por `node.requires`. */\n capabilities?: Record<string, string>;\n}\n\n/** Estratégia de resolução EXPLÍCITA (`node.type` → descriptor). Mescla `defaultProps`,\n * aplica `requires` e a cadeia de `fallback`. */\nexport function createTypeResolver(\n options: TypeResolverOptions = {},\n): Resolver {\n const caps = options.capabilities;\n\n const supported = (node: DefNode): boolean => {\n if (!node.requires) return true;\n if (!caps) return false;\n for (const [cap, min] of Object.entries(node.requires)) {\n const have = caps[cap];\n if (have == null) return false; // capability ausente\n if (min !== \"*\" && cmpVersion(have, min) < 0) return false; // versão insuficiente\n }\n return true;\n };\n\n const resolve = (node: DefNode, ctx: ResolveCtx): ResolveResult => {\n if (!node.type) return { kind: \"unknown\", node }; // sem type (nó el/malformado) — não resolve\n const descriptor = ctx.registry.get(node.type);\n if (descriptor && supported(node)) {\n return {\n kind: \"render\",\n descriptor,\n props: { ...(descriptor.defaultProps ?? {}), ...(node.props ?? {}) },\n };\n }\n if (node.fallback === \"drop\") return { kind: \"drop\" };\n if (node.fallback && typeof node.fallback === \"object\")\n return resolve(node.fallback, ctx);\n return { kind: \"unknown\", node };\n };\n\n return { resolve };\n}\n\nfunction cmpVersion(a: string, b: string): number {\n const pa = a.split(\".\").map(Number);\n const pb = b.split(\".\").map(Number);\n const len = Math.max(pa.length, pb.length);\n for (let i = 0; i < len; i++) {\n const x = pa[i] ?? 0;\n const y = pb[i] ?? 0;\n if (x !== y) return x < y ? -1 : 1;\n }\n return 0;\n}\n","import type { DefNode } from \"./types\";\n\n/* ──────────────────────────────────────────────────────────────────────────────\n PORTS — os SEAMS (DI). O core depende destas INTERFACES, nunca de uma lib.\n Os adapters (tslite / json-myers / node-actions / ajv-zod) plugam por fora.\n ────────────────────────────────────────────────────────────────────────────── */\n\n/** Bind: expande a definição contra dados (pré-passo). Adapter alvo: TSLite. */\nexport interface BindingEngine {\n /**\n * Avalia a definição COMPILADA contra o escopo. O segundo argumento é o mapa de RAÍZES\n * — `{ data }` no render, `{ props, state }` no corpo de um componente. Nada entra no\n * escopo implicitamente: o resto dos nomes é declarado pelo `as` de um `each`.\n */\n bind(node: DefNode, scope: unknown): DefNode;\n /**\n * Traduz a definição AUTORADA para a forma que este binder consome — em geral, expressão\n * em texto vira expressão em árvore. **Idempotente e memoizada por identidade**, então\n * chamar de novo é barato e chamar sobre já-compilado é no-op.\n *\n * Ausente = o binder consome o autorado direto (é o caso do `identityBinder`).\n *\n * As duas fases ficam separadas de propósito: compilar pode acontecer no servidor, no save\n * ou no build, e o resultado é dado serializável. Quem chama é o PONTO DE ENTRADA (o\n * `resolveTree`, a expansão do forge), não o `bind` por dentro — um `bind` que compilasse\n * escondido apagaria a fronteira que torna a consolidação possível.\n */\n compile?(node: DefNode): DefNode;\n}\nexport const identityBinder: BindingEngine = { bind: (node) => node };\n\n/** Validação de um valor contra um schema. Adapter alvo: AJV / Zod (escolha do consumidor). */\nexport interface ValidationIssue {\n code: string;\n path?: string;\n message?: string;\n}\nexport interface ValidationProvider {\n validate(schema: unknown, value: unknown): ValidationIssue[] | null;\n}\n/** Default: sem validação. */\nexport const noopValidator: ValidationProvider = { validate: () => null };\n\n/* ──────────────────────────────────────────────────────────────────────────────\n A PORTA DE AÇÃO — a projeção do **Tier 0** do contrato de actions\n (`@node-actions/protocol`), declarada ESTRUTURALMENTE.\n\n Não importamos o contrato: o core não tem dependência nenhuma (ADR-105), e o\n que atravessa aqui é forma, não código. Um runtime que cumpra o contrato — engine de\n diretivas, `lite` ou o commander — é assignável à porta como está, sem adapter (ADR-115).\n\n É o ADR-104 apontado para o contrato certo: ele previa que o actions migrasse\n POR DENTRO mantendo a superfície, e o que aconteceu foi outra coisa — nasceu um\n contrato público, com envelope de resultado, admissão e introspecção.\n ────────────────────────────────────────────────────────────────────────────── */\n\n/**\n * O ENVELOPE de um despacho. **`invoke` nunca lança por erro de domínio** — falha é DADO.\n *\n * `code` é o contrato do erro: discrimine por ele, nunca por regex na mensagem.\n */\nexport interface ActionResult<T = unknown> {\n readonly success: boolean;\n /** o fluxo foi interrompido (vs. completou)? */\n readonly aborted?: boolean;\n readonly abortedBy?: string;\n readonly data?: T;\n readonly error?: {\n readonly code: string;\n readonly message?: string;\n readonly data?: unknown;\n };\n}\n\n/**\n * O que um `invoke` devolve.\n *\n * **Async é o piso por física**, não por gosto: async embrulha sync, sync não embrulha async. Um\n * host que não tem o que dizer devolve `void`, e quem normaliza é o `dispatchIntent`.\n */\nexport type ActionOutcome = void | ActionResult | Promise<void | ActionResult>;\n\n/** Execução de ações da aplicação — o destino do events-out. */\nexport interface ActionPort {\n /** dispara. Domínio falho volta como `{ success: false, error }`; não lança. */\n invoke(id: string, params?: unknown, ctx?: unknown): ActionOutcome;\n has?(id: string): boolean;\n\n /* ── Tier 1 — introspecção. Opcional, e cada um tem um consumidor aqui ──────────── */\n\n /** pode rodar agora? Alimenta o `computeUnable` e o estado desabilitado de um botão. */\n isAvailable?(id: string): boolean;\n /** a FORMA dos params, em JSON Schema — é o que tipa o call-site de um evento. */\n paramsOf?(id: string): unknown;\n /** a forma do RETORNO, em JSON Schema — é o que tipa \"o retorno vira estado\". */\n resultOf?(id: string): unknown;\n /** rótulo, ícone, categoria, atalho — o que uma paleta mostra. */\n metadataOf?(id: string): Record<string, unknown> | undefined;\n /**\n * **Quanto vale** cada resposta do Tier 1 — `\"inferred\" | \"declared\" | \"verified\" | \"none\"`.\n *\n * Não é enfeite: uma assinatura `declared` pode divergir do que a implementação de fato aceita,\n * e a única prova que depende dela ser COMPLETA é \"esta chave não existe\". Por isso o `check`\n * usa isto para decidir se um `excess-property` é erro ou aviso.\n */\n provenanceOf?(query: string): string;\n}\n\n/** Endereço/diff/patch do documento (editor). Adapter alvo: json-myers (ou RFC 6902). */\nexport interface AddressPort {\n diff(a: unknown, b: unknown): unknown;\n patch(base: unknown, diff: unknown): unknown;\n}\n\n/** Checagem de tipos — compat `action.return ≤ component.props`, bindings. Adapter: @tslite/type-core. */\nexport interface TypeChecker {\n /** `a` é atribuível a `b`? */\n subtype(a: unknown, b: unknown): boolean;\n}\n\n/** ESCAPE imperativo: capabilities vivas do host (router, mapa, ws, focus-handle…) que NÃO\n * cabem em data-in/events-out. O caminho canônico é via ActionPort; isto é a exceção.\n * Pode ser preenchido pelo kernel/providers do host. */\nexport interface CapabilityPort {\n get(name: string): unknown;\n has(name: string): boolean;\n}\n","/* ──────────────────────────────────────────────────────────────────────────────\n LAYOUT — metade HEADLESS (planner): calcula o PLANO (dados) de arrumação a partir\n dos `placement` dos filhos. A metade de VIEW (renderer, plan→JSX) vive na camada\n de render. Pareados por `name`; o renderer consome o shape do plano daqui.\n ────────────────────────────────────────────────────────────────────────────── */\n\nexport interface PlannerChild {\n id: string;\n placement?: unknown;\n}\n\nexport interface LayoutPlanner {\n name: string;\n plan(children: PlannerChild[]): unknown;\n /**\n * A FORMA do `placement` que este layout lê, em JSON Schema — o contrato do filho.\n *\n * É o `descriptor.schema` do eixo de arrumação: um editor monta os campos de posição a partir\n * dele, sem saber que layout é. Ausente = o layout não publica a forma, e quem edita fica com o\n * objeto cru.\n */\n placementSchema?: unknown;\n}\n\ninterface IndexPlacement {\n index?: number;\n}\n\n/** o `placement` de quem só ORDENA: a posição entre os irmãos. */\nconst ORDER_PLACEMENT = {\n type: \"object\",\n properties: { index: { type: \"number\" } },\n} as const;\nconst clamp = (n: number, min: number, max: number) =>\n Math.max(min, Math.min(max, n));\n\n/** ordem por `placement.index` (estável; default = ordem do array). */\nfunction orderedIds(children: PlannerChild[]): string[] {\n return children\n .map((c, i) => ({\n id: c.id,\n k: (c.placement as IndexPlacement | undefined)?.index ?? i,\n }))\n .sort((a, b) => a.k - b.k)\n .map((x) => x.id);\n}\n\n/* ── fragment ─────────────────────────────────────────────────────────────────── */\nexport interface FragmentPlan {\n order: string[];\n}\nexport function fragmentPlanner(): LayoutPlanner {\n return {\n name: \"fragment\",\n plan: (children): FragmentPlan => ({ order: orderedIds(children) }),\n placementSchema: ORDER_PLACEMENT,\n };\n}\n\n/* ── section (índice) ─────────────────────────────────────────────────────────── */\nexport interface SectionPlan {\n direction: \"column\" | \"row\";\n gap?: string | number;\n order: string[];\n}\nexport interface SectionOptions {\n direction?: \"column\" | \"row\";\n gap?: string | number;\n}\nexport function sectionPlanner(opts: SectionOptions = {}): LayoutPlanner {\n const direction = opts.direction ?? \"column\";\n return {\n name: \"section\",\n plan: (children): SectionPlan => ({\n direction,\n gap: opts.gap,\n order: orderedIds(children),\n }),\n placementSchema: ORDER_PLACEMENT,\n };\n}\n\n/* ── grid-form (slots, responsivo por breakpoint) ─────────────────────────────── */\n\n/** span por breakpoint (mobile-first; cada nível herda o anterior se ausente). */\nexport interface ResponsiveSpan {\n base: number;\n sm?: number;\n md?: number;\n lg?: number;\n xl?: number;\n}\n/** spans preenchidos pra todos os breakpoints (forward-fill). */\nexport interface FilledSpans {\n base: number;\n sm: number;\n md: number;\n lg: number;\n xl: number;\n}\nexport interface GridFormCell {\n id: string;\n /** span no breakpoint base — back-compat + caminho inline (não-responsivo). */\n span: number;\n /** spans por breakpoint (forward-filled) — caminho responsivo. */\n spans: FilledSpans;\n break?: boolean;\n}\nexport interface GridFormPlan {\n columns: number;\n gap: string | number;\n /** algum slot varia entre breakpoints? (decide inline vs CSS no renderer). */\n responsive: boolean;\n cells: GridFormCell[];\n}\nexport interface GridFormPlacement {\n /** número (fixo) ou objeto `{ base, sm, md, lg, xl }` (responsivo). */\n span?: number | ResponsiveSpan;\n break?: boolean;\n index?: number;\n}\nexport interface GridFormOptions {\n columns?: number;\n gap?: string | number;\n}\n\nfunction fillSpans(\n span: number | ResponsiveSpan | undefined,\n columns: number,\n): FilledSpans {\n const c = (n: number) => clamp(n, 1, columns);\n if (span == null) {\n const v = columns;\n return { base: v, sm: v, md: v, lg: v, xl: v };\n }\n if (typeof span === \"number\") {\n const v = c(span);\n return { base: v, sm: v, md: v, lg: v, xl: v };\n }\n const base = c(span.base ?? columns);\n const sm = span.sm != null ? c(span.sm) : base;\n const md = span.md != null ? c(span.md) : sm;\n const lg = span.lg != null ? c(span.lg) : md;\n const xl = span.xl != null ? c(span.xl) : lg;\n return { base, sm, md, lg, xl };\n}\n\n/** o `placement` do grid-form: um span fixo ou por breakpoint, a quebra de linha, e a ordem. */\nconst GRID_FORM_PLACEMENT = {\n type: \"object\",\n properties: {\n span: {\n anyOf: [\n { type: \"number\" },\n {\n type: \"object\",\n properties: {\n base: { type: \"number\" },\n sm: { type: \"number\" },\n md: { type: \"number\" },\n lg: { type: \"number\" },\n xl: { type: \"number\" },\n },\n required: [\"base\"],\n },\n ],\n },\n break: { type: \"boolean\" },\n index: { type: \"number\" },\n },\n} as const;\n\nconst varies = (s: FilledSpans): boolean =>\n s.base !== s.sm || s.sm !== s.md || s.md !== s.lg || s.lg !== s.xl;\n\nexport function gridFormPlanner(opts: GridFormOptions = {}): LayoutPlanner {\n const columns = opts.columns ?? 12;\n const gap = opts.gap ?? \"1rem\";\n return {\n name: \"grid-form\",\n plan(children): GridFormPlan {\n const ordered = children\n .map((c, i) => ({\n c,\n k: (c.placement as GridFormPlacement | undefined)?.index ?? i,\n }))\n .sort((a, b) => a.k - b.k)\n .map((x) => x.c);\n let responsive = false;\n const cells: GridFormCell[] = ordered.map((c) => {\n const p = (c.placement as GridFormPlacement | undefined) ?? {};\n const spans = fillSpans(p.span, columns);\n if (varies(spans)) responsive = true;\n return { id: c.id, span: spans.base, spans, break: p.break };\n });\n return { columns, gap, responsive, cells };\n },\n placementSchema: GRID_FORM_PLACEMENT,\n };\n}\n\n/** planners default (`fragment` · `section` · `grid-form`). */\nexport function defaultPlanners(): Record<string, LayoutPlanner> {\n return {\n fragment: fragmentPlanner(),\n section: sectionPlanner(),\n \"grid-form\": gridFormPlanner(),\n };\n}\n","import type { BindingEngine } from \"./ports\";\nimport { identityBinder } from \"./ports\";\nimport { createTypeResolver, type Resolver } from \"./resolver\";\nimport { defaultPlanners, type LayoutPlanner } from \"./layout\";\nimport type {\n DefNode,\n ResolvedLayout,\n ResolvedNode,\n DescriptorRegistry,\n} from \"./types\";\n\nexport interface ResolveTreeOptions {\n registry: DescriptorRegistry;\n resolver?: Resolver;\n binder?: BindingEngine;\n planners?: Record<string, LayoutPlanner>;\n /** layout usado quando o nó/descriptor não declara um. */\n defaultLayout?: string;\n}\n\n/** Um filho renderizável + a placement de origem (pro plano do pai). */\ninterface Child {\n id: string;\n placement: unknown;\n out: ResolvedNode;\n}\n\n/**\n * O PIPELINE headless do COMPOSITOR: `bind` (pré-passo) → `resolve` (type→descriptor+props) →\n * `plan` (layout). Produz uma `ResolvedNode` — DADOS puros. Compõe componentes REGISTRADOS +\n * elementos intrínsecos (`el`) + data-binding. **Não conhece componente custom** — a expansão\n * de `ComponentDef` é do construtor (`forge`), que entrega uma árvore pura pra cá.\n *\n * `el`: `type` vem da tag (`{ el: \"div\" }`) → `createElement(type, …)` na view (`el: true`).\n * `fallback:\"drop\"` some da árvore E do plano; `unknown` permanece (a view degrada).\n */\nexport function resolveTree(\n node: DefNode,\n opts: ResolveTreeOptions,\n scope?: unknown,\n): ResolvedNode {\n const binder = opts.binder ?? identityBinder;\n const resolver = opts.resolver ?? createTypeResolver();\n const planners = opts.planners ?? defaultPlanners();\n const defaultLayout = opts.defaultLayout ?? \"fragment\";\n\n /** plano de arrumação dos filhos renderizáveis para um `layout` nomeado (ou nenhum). */\n const planLayout = (\n renderable: Child[],\n name: string,\n ): ResolvedLayout | undefined => {\n if (!renderable.length) return undefined;\n const planner = planners[name];\n if (!planner) return undefined;\n return {\n name,\n plan: planner.plan(\n renderable.map((c) => ({ id: c.id, placement: c.placement })),\n ),\n };\n };\n\n const resolveChildren = (children: DefNode[] | undefined): Child[] =>\n (children ?? [])\n .map((c) => ({ id: c.id, placement: c.placement, out: resolveNode(c) }))\n .filter((c) => c.out.kind !== \"drop\");\n\n const resolveNode = (def: DefNode): ResolvedNode => {\n // `el` — createElement de TAG intrínseca (a tag está em `el`; bypassa o registry).\n if (def.el != null) {\n const renderable = resolveChildren(def.children);\n return {\n kind: \"node\",\n id: def.id,\n type: def.el,\n el: true,\n props: def.props ?? {},\n events: def.events,\n ...(def.origins ? { origins: def.origins } : {}),\n layout: planLayout(renderable, def.layout ?? defaultLayout),\n children: renderable.map((c) => c.out),\n };\n }\n\n const type = def.type;\n if (type == null) return { kind: \"unknown\", id: def.id, type: \"\" };\n\n const res = resolver.resolve(def, { registry: opts.registry });\n if (res.kind === \"drop\") return { kind: \"drop\", id: def.id };\n if (res.kind === \"unknown\") return { kind: \"unknown\", id: def.id, type };\n\n const renderable = resolveChildren(def.children);\n const layout = planLayout(\n renderable,\n def.layout ?? res.descriptor.layout ?? defaultLayout,\n );\n\n return {\n kind: \"node\",\n id: def.id,\n type,\n props: res.props,\n events: def.events,\n ...(def.origins ? { origins: def.origins } : {}),\n layout,\n children: renderable.map((c) => c.out),\n };\n };\n\n // as duas fases, explícitas: compilar (autorado → árvore) e ligar (contra os dados).\n return resolveNode(binder.bind(binder.compile?.(node) ?? node, scope));\n}\n","import type { DefNode } from \"./types\";\n\n/* Utilitários PUROS de árvore — base pro core e pro editor (endereço por id).\n Mutação real do documento deve ir pelo AddressPort (json-myers / RFC 6902). */\n\n/** Percorre em pré-ordem. `visit(node, parent)` — `parent` é `null` na raiz. */\nexport function walk(\n node: DefNode,\n visit: (node: DefNode, parent: DefNode | null) => void,\n parent: DefNode | null = null,\n): void {\n visit(node, parent);\n for (const child of node.children ?? []) walk(child, visit, node);\n}\n\n/** Primeiro nó com o `id` dado (busca em profundidade). */\nexport function findById(root: DefNode, id: string): DefNode | undefined {\n if (root.id === id) return root;\n for (const child of root.children ?? []) {\n const found = findById(child, id);\n if (found) return found;\n }\n return undefined;\n}\n\n/** Caminho de ids da raiz ao alvo (inclusive), ou `null`. */\nexport function pathToId(root: DefNode, id: string): string[] | null {\n if (root.id === id) return [root.id];\n for (const child of root.children ?? []) {\n const sub = pathToId(child, id);\n if (sub) return [root.id, ...sub];\n }\n return null;\n}\n\n/** Mapeia a árvore imutavelmente, bottom-up (filhos já transformados quando `fn` roda). */\nexport function mapNodes(\n node: DefNode,\n fn: (node: DefNode) => DefNode,\n): DefNode {\n const children = node.children?.map((c) => mapNodes(c, fn));\n const next = children ? { ...node, children } : node;\n return fn(next);\n}\n","import type { DefNode } from \"./types\";\n\n/* ──────────────────────────────────────────────────────────────────────────────\n A FORMA do DefNode como DADO — quem responde \"isto é valor ou expressão?\" é a\n POSIÇÃO, nunca uma heurística sobre o texto.\n\n A tabela existe porque quem precisa da resposta não é um só: o compilador (o que\n traduzir), o binder (o que avaliar), o checker (o que tipar) e o canvas (o que\n desenhar como campo de expressão). Descrição espalhada por `switch` produz\n validação incompleta em silêncio — um campo novo vira ausência em quem esqueceu.\n\n A exaustividade é do TypeScript: `Record<keyof DefNode, FieldRole>` não compila\n com um campo a menos.\n ────────────────────────────────────────────────────────────────────────────── */\n\n/** O papel de um campo do `DefNode` na travessia. */\nexport type FieldRole =\n /** identidade — nunca tocada. */\n | \"identity\"\n /** dado do documento: nome de tipo, tag, layout. Não é código, não é subárvore. */\n | \"data\"\n /** carrega nó(s) — a travessia desce por aqui. */\n | \"tree\"\n /** aceita EXPRESSÃO — ver `SLOTS`. */\n | \"slot\";\n\nexport const FIELDS: Readonly<Record<keyof DefNode, FieldRole>> = {\n id: \"identity\",\n type: \"data\",\n el: \"data\",\n layout: \"data\",\n version: \"data\",\n requires: \"data\",\n as: \"data\", // o NOME que o `each` liga — identificador, não expressão\n children: \"tree\",\n fallback: \"tree\", // `\"drop\"` ou um DefNode inteiro\n props: \"slot\",\n placement: \"slot\",\n events: \"slot\", // a expressão mora em `events[*].params`\n each: \"slot\",\n when: \"slot\",\n provides: \"slot\",\n commands: \"slot\", // o VOCABULÁRIO da subárvore; os `params` do alias são expressão\n origins: \"identity\", // de onde o nó veio — escrito pela expansão, e nunca tocado\n};\n\n/** Onde, dentro do campo, os valores compiláveis estão. */\nexport type SlotShape =\n /** o próprio valor do campo. */\n | \"value\"\n /** um mapa de INTENÇÕES (`events`, `commands`); o valor é o `params` de cada entrada. */\n | \"intentParams\";\n\nexport interface SlotDecl {\n shape: SlotShape;\n /** o que o slot espera render. O checker usa isto como `resultType`; `unknown` = não restringe. */\n expects: \"boolean\" | \"unknown\";\n /**\n * Em que estágio do bind o slot é resolvido.\n *\n * `structural` muda a ÁRVORE e é consumido (não aparece na saída) — `each` repete o nó,\n * `when` o dropa. `value` liga o campo NO LUGAR. Sem isto, quem liga valores teria de\n * lembrar de excluir os estruturais à mão, que é a forma de esquecimento que esta tabela\n * existe para impedir.\n */\n stage: \"value\" | \"structural\";\n /**\n * Se `{% %}` e `{# #}` são marcação neste slot, além do `{{ }}`.\n *\n * O dado não se auto-declara: é o slot que diz o que uma string dele pode conter. Hoje\n * nenhum slot aceita controle de fluxo — `{%` e `{#` são texto em todos —, e a coluna existe\n * para que a compilação pergunte à tabela, e não a um padrão implícito.\n */\n directives: boolean;\n}\n\nexport const SLOTS: Readonly<Record<string, SlotDecl>> = {\n props: {\n shape: \"value\",\n expects: \"unknown\",\n stage: \"value\",\n directives: false,\n },\n placement: {\n shape: \"value\",\n expects: \"unknown\",\n stage: \"value\",\n directives: false,\n },\n events: {\n shape: \"intentParams\",\n expects: \"unknown\",\n stage: \"value\",\n directives: false,\n },\n /** o alias é ROTEADOR: o nome não é expressão, mas os `params` da aplicação parcial são. */\n commands: {\n shape: \"intentParams\",\n expects: \"unknown\",\n stage: \"value\",\n directives: false,\n },\n /** os valores providos à subárvore; o tipo de cada um vem do catálogo de contextos. */\n provides: {\n shape: \"value\",\n expects: \"unknown\",\n stage: \"value\",\n directives: false,\n },\n each: {\n shape: \"value\",\n expects: \"unknown\",\n stage: \"structural\",\n directives: false,\n },\n /** predicado — uma condição que renda `string` é erro de tipo, não nó sempre-visível. */\n when: {\n shape: \"value\",\n expects: \"boolean\",\n stage: \"structural\",\n directives: false,\n },\n};\n\n/** Este campo aceita expressão? Campo fora da tabela NÃO tem porta: expressão ali é erro,\n * e a resposta sai sem avaliar nada. */\nexport const isSlot = (field: string): boolean =>\n Object.prototype.hasOwnProperty.call(SLOTS, field);\n\n/** A declaração do slot, ou `undefined` se o campo não é um. */\nexport const slotOf = (field: string): SlotDecl | undefined => SLOTS[field];\n\n/** Como cada campo `tree` carrega nó: uma lista, ou um nó só. */\nexport type TreeShape = \"list\" | \"node\";\n\n/** Os campos por onde a travessia desce em busca de mais nós. Um campo `tree` novo entra aqui\n * e todo mundo que anda a árvore passa a cobri-lo — travessia divergente é o bug que só\n * aparece quando um campo novo entra. */\nexport const TREE: Readonly<Record<string, TreeShape>> = {\n children: \"list\",\n fallback: \"node\", // pode ser a string `\"drop\"`; quem desce estreita antes\n};\n"]}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@loom-forge/core",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "loom · o kernel HEADLESS: DefNode → ResolvedNode via bind → resolve → plan. Zero React, zero ambiente, zero dependências. Os ports (bind/validação/ações/endereço/tipos) são os seams de DI.",
6
+ "keywords": [
7
+ "json",
8
+ "dsl",
9
+ "ui",
10
+ "composition",
11
+ "headless",
12
+ "nocode",
13
+ "react"
14
+ ],
15
+ "license": "MIT",
16
+ "author": {
17
+ "name": "Anderson D. Rosa",
18
+ "url": "https://github.com/andersondrosa"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/andersondrosa/loom-forge.git",
23
+ "directory": "packages/core"
24
+ },
25
+ "homepage": "https://github.com/andersondrosa/loom-forge/tree/main/packages/core#readme",
26
+ "bugs": {
27
+ "url": "https://github.com/andersondrosa/loom-forge/issues"
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "sideEffects": false,
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/index.d.ts",
36
+ "import": "./dist/index.js"
37
+ }
38
+ },
39
+ "files": [
40
+ "dist"
41
+ ],
42
+ "devDependencies": {
43
+ "tsup": "^8.0.0",
44
+ "typescript": "^5.9.3"
45
+ },
46
+ "scripts": {
47
+ "build": "tsup",
48
+ "dev": "tsup --watch",
49
+ "test": "vitest run",
50
+ "test:watch": "vitest",
51
+ "typecheck": "tsc --noEmit",
52
+ "clean": "rm -rf dist"
53
+ }
54
+ }