@loom-forge/check 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.
@@ -0,0 +1,478 @@
1
+ import { Schema } from '@tslite/type-core';
2
+ import { TypeChecker, ResolvedNode, DescriptorRegistry } from '@loom-forge/core';
3
+ import { Env, Anchors, CheckResult } from '@tslite/checker';
4
+ import { ComponentDef, PropsDecl, CompiledPath, TypeRef, ComponentIR, SystemIR, CompiledDefinition, Mounting } from '@loom-forge/forge';
5
+ import { Expression } from '@tslite/core';
6
+ import { CompileDiagnostic, CompiledIsland } from '@loom-forge/tslite/compile';
7
+ import { CapabilityProfile } from '@tslite/capability';
8
+ import { Span } from '@tslite/language-service';
9
+
10
+ interface TsliteChecker extends TypeChecker {
11
+ /** infere o Schema (forma) de um valor/dados (escalares alargam à base). */
12
+ inferType(value: unknown): Schema;
13
+ /** JSON Schema → Schema do TSLite. */
14
+ fromJsonSchema(jsonSchema: unknown): Schema;
15
+ /** Schema do TSLite → JSON Schema. */
16
+ toJsonSchema(schema: Schema): unknown;
17
+ /** a forma de `value` é atribuível ao tipo descrito por `jsonSchema`? (infer + subtype) */
18
+ assignable(value: unknown, jsonSchema: unknown): boolean;
19
+ /** representação textual de um Schema (diagnóstico). */
20
+ format(schema: Schema): string;
21
+ }
22
+ declare function createTsliteChecker(): TsliteChecker;
23
+ interface DataflowIssue {
24
+ nodeId: string;
25
+ type: string;
26
+ /** tipo declarado pelo descriptor (props esperadas). */
27
+ expected: string;
28
+ /** forma efetiva das props resolvidas. */
29
+ got: string;
30
+ }
31
+ /**
32
+ * Percorre uma `ResolvedNode` e checa, em cada nó, se as props resolvidas são atribuíveis
33
+ * ao `schema` declarado no descriptor (quando há). É a verificação ponta-a-ponta da
34
+ * Linguagem: a mesma máquina que, com o actions plugado, prova `action.return ≤ props`.
35
+ */
36
+ declare function checkTree(node: ResolvedNode, registry: DescriptorRegistry, checker: TsliteChecker): DataflowIssue[];
37
+
38
+ /**
39
+ * O nome do asserter no escopo: `parseAs`, publicado pelo `@tslite/validate`. Não é `parse` porque
40
+ * a stdlib já tem um — o `JSON.parse` (`(text: string) => unknown`) —, e os dois consumidores do
41
+ * TSLite chegaram ao mesmo nome pelo mesmo obstáculo.
42
+ */
43
+ declare const DEFAULT_ASSERTER: string;
44
+ interface BuildEnvOptions {
45
+ /**
46
+ * O catálogo de contextos do sistema — `nome → tipo`. A raiz `ctx` do componente é a
47
+ * **projeção** dele: catálogo ∩ `context.uses`.
48
+ *
49
+ * É assim que se tipa um escopo DINÂMICO: o **valor** vem da posição (quem montou), o
50
+ * **tipo** é global. Se cada provedor declarasse o tipo, o tipo do consumidor dependeria de
51
+ * qual provedor está acima — tipagem dinâmica, e aí não há prova.
52
+ *
53
+ * Sem catálogo, `ctx` não é raiz: um `ctx` vazio resolvendo `undefined` em silêncio seria
54
+ * pior que a ausência.
55
+ */
56
+ contexts?: Record<string, Schema>;
57
+ /** o tipo dos dados do host — a raiz `data` do render. Sem ele, `data` não é raiz. */
58
+ data?: Schema;
59
+ /** substitui a stdlib. Para acrescentar, espalhe: `{ ...vanilla, meu }`. */
60
+ operators?: Record<string, Schema>;
61
+ /**
62
+ * o catálogo de tipos NOMEADOS. Cada um entra como híbrido (valor + tipo) e habilita
63
+ * o asserter: `{{ parseAs(Address, data.x) }}` rende `Address` em vez de `unknown`.
64
+ * O mesmo catálogo precisa estar no `globals` do binder para a prova acontecer.
65
+ *
66
+ * Ele vale também como `TypeRef` nas DECLARAÇÕES — `props: { addr: "Address" }`.
67
+ */
68
+ types?: Record<string, Schema>;
69
+ }
70
+ /**
71
+ * Monta o `Env` de um componente a partir das declarações. As raízes são as mesmas do
72
+ * runtime — `props`, `state`, e `data` quando o chamador declara o tipo dos dados —, o
73
+ * que é o que faz o que o checker prova valer para o que o binder executa.
74
+ */
75
+ declare function buildEnv(def: ComponentDef, opts?: BuildEnvOptions): Env;
76
+ /**
77
+ * O `Env` do `init` — o escopo que SEMEIA o estado.
78
+ *
79
+ * Ele tem `props` e `ctx`, e **não** tem `state` (é o que está sendo definido) nem `params` (não
80
+ * há chamada). É a mesma projeção que o runtime passa ao `initState`, e é por isso que ele existe
81
+ * separado: no env do corpo, um `init` lendo `state` tiparia limpo e valeria `undefined`.
82
+ */
83
+ declare function buildInitEnv(def: ComponentDef, opts?: BuildEnvOptions): Env;
84
+
85
+ /** O catálogo de tipos NOMEADOS — o mesmo que o `buildEnv` recebe. Um nome declarado aqui vale
86
+ * como `TypeRef` numa declaração (`props: { addr: "Address" }`). */
87
+ type TypeCatalog = Record<string, Schema>;
88
+ /**
89
+ * `TypeRef` (nome do catálogo | shorthand escalar | Schema do TSLite | JSON Schema) → Schema.
90
+ *
91
+ * O que NÃO resolve vira **`unknown`**, não `any`. `any` desligaria toda a prova daquela prop em
92
+ * silêncio — call-site, membro, span —, e um erro de digitação na declaração apagaria a máquina
93
+ * inteira sem dizer nada. `unknown` obriga o programa a lidar; quem diz o que houve é o
94
+ * `checkDeclarations`, que reporta o nome que não existe.
95
+ */
96
+ declare function resolveTypeRef(ref: TypeRef, types?: TypeCatalog): Schema;
97
+ /**
98
+ * `PropsDecl` → Schema de objeto. Prop com nome terminando em `?` é OPCIONAL (`{ "title?": … }`)
99
+ * — TS-like, JSON-native; o `?` é tirado do nome e marca `optional`.
100
+ *
101
+ * **Opcional aqui significa `T | undefined`**, e a razão é do MEIO, não de leniência: uma prop
102
+ * viaja como JSON, e em JSON `undefined` não existe — `{}` e `{ body: undefined }` são o mesmo
103
+ * documento. Distinguir "ausente" de "presente e indefinido" (o que o `exactOptionalPropertyTypes`
104
+ * do tsc faz, e o que o `subtype` do TSLite implementa) é uma distinção que este formato não
105
+ * consegue expressar. Sem isso, passar um campo opcional de um dado para uma prop opcional —
106
+ * o caso mais comum que existe — não tiparia.
107
+ */
108
+ declare function resolveProps(props: PropsDecl | undefined, types?: TypeCatalog): Schema;
109
+ /**
110
+ * O TIPO de um componente — o que ele declara sobre si.
111
+ *
112
+ * Não carrega tags: tag é **fato** derivado sobre a árvore, não tipo, e desde a separação
113
+ * árvore × fatos ela mora em `@loom-forge/forge` (`effectiveTags(sys.facts, id)`, que é a
114
+ * propagada — mais útil que a própria). Uma função que resolve o TIPO não deve ser a porta
115
+ * dos fatos.
116
+ */
117
+ interface ComponentType {
118
+ props: Schema;
119
+ category?: string;
120
+ entry: boolean;
121
+ }
122
+ /** Resolve o TIPO de um `ComponentIR`: props → Schema, mais categoria e entry. */
123
+ declare function componentType(ir: ComponentIR, types?: TypeCatalog): ComponentType;
124
+ /** Contrato no eixo de PROPS (`Component<C>`): o conjunto de props que o componente precisa
125
+ * aceitar — mesma forma de `ComponentDef.props` (um `PropsDecl`). */
126
+ interface ComponentContract {
127
+ props?: PropsDecl;
128
+ }
129
+ /**
130
+ * O componente `child` satisfaz o contrato (eixo de props)? `subtype(child.props, contrato)`
131
+ * — um componente com props MAIS amplas serve onde se exige menos (estrutural). É a máquina
132
+ * de `child ≤ Component<C>` e do `action.return ≤ component.props`. Os eixos estruturais
133
+ * (categoria/tags/cardinalidade/leaf) ficam no `checkSlots`.
134
+ */
135
+ declare function componentAssignable(child: ComponentType, contract: ComponentContract, types?: TypeCatalog): boolean;
136
+ /**
137
+ * As DECLARAÇÕES de um componente também são conferidas — `props` e `state`.
138
+ *
139
+ * Um `TypeRef` que não resolve é o furo mais caro que restava: ele não quebra nada na hora, e
140
+ * desliga a prova daquela prop para sempre. O endereço é o da declaração (`props.n`,
141
+ * `state.aberto`), não o de um nó — não há nó: é a superfície do componente.
142
+ */
143
+ declare function checkDeclarations(def: {
144
+ props?: PropsDecl;
145
+ state?: Record<string, {
146
+ type: TypeRef;
147
+ }>;
148
+ }, types?: TypeCatalog): DeclarationIssue[];
149
+ /**
150
+ * O resolvedor do catálogo de contextos: `nome → Schema`. É o que tipa a raiz `ctx` e o que
151
+ * prova um `provides`.
152
+ *
153
+ * **Um contrato de contexto precisa ser SERIALIZÁVEL** — dado, não comportamento. Efeito já
154
+ * tem porta aqui (`events` → `ActionPort`), e uma função no contexto seria uma segunda, que
155
+ * não cria aresta no grafo e some da análise. O predicado é o `isSerializable` do
156
+ * `@tslite/type-core`; um contrato que não passa vira `undefined` (não tipa), e quem acusa é o
157
+ * `checkContextCatalog`.
158
+ */
159
+ declare function declaredContextsOf(catalog: Record<string, TypeRef> | undefined, types?: TypeCatalog): (name: string) => Schema | undefined;
160
+ /**
161
+ * O catálogo de contextos, conferido: um contrato que não resolve, ou que não é dado
162
+ * serializável, não é contrato.
163
+ */
164
+ declare function checkContextCatalog(catalog: Record<string, TypeRef> | undefined, types?: TypeCatalog): DeclarationIssue[];
165
+ /**
166
+ * O resolvedor de `params` dos UPDATES locais de um componente: `action` → o `Schema` declarado.
167
+ * Ausente para o update que não os declara (e para a ação do host, que não mora aqui).
168
+ */
169
+ declare function declaredParamsOf(updates: Record<string, {
170
+ params?: PropsDecl;
171
+ }> | undefined, types?: TypeCatalog): (action: string) => Schema | undefined;
172
+ /**
173
+ * O tipo de um `set` de ação local: o estado declarado, com **tudo opcional**.
174
+ *
175
+ * Um `set` é uma atualização PARCIAL — escrever um campo não obriga a escrever os outros. É o
176
+ * mesmo mecanismo do call-site, sobre outra superfície: o objeto vai anotado com este tipo, e o
177
+ * motor acusa `not-assignable` no campo com o tipo errado e `excess-property` na chave que o
178
+ * estado não declara.
179
+ *
180
+ * O `optional` aqui é por outra razão que o das props, e por isso o tipo NÃO ganha `| undefined`:
181
+ * o campo do estado não é opcional — a ESCRITA é que é parcial. Escrever `undefined` num campo
182
+ * `number` continua errado.
183
+ */
184
+ declare function partialStateType(state: Record<string, {
185
+ type: TypeRef;
186
+ }> | undefined, types?: TypeCatalog): Schema;
187
+ /** um `TypeRef` que não resolve. Mesma forma do `CheckIssue`, sem `span`: não há texto onde
188
+ * pousar — a declaração É o nome. */
189
+ interface DeclarationIssue {
190
+ code: "unknown-type-name";
191
+ message: string;
192
+ severity: "error";
193
+ /** o caminho da declaração: `["props", "n"]`, `["state", "aberto"]`, `["contexts", "@app/x"]`. */
194
+ path: CompiledPath;
195
+ address: string;
196
+ source: string;
197
+ }
198
+ /**
199
+ * O resolvedor de props para o call-site: `type` → o `Schema` que o componente declara.
200
+ *
201
+ * É o seam entre o `SystemIR` (quem sabe o que existe) e o lowering (que é transformação de
202
+ * forma e não conhece registry). Memoiza: o mesmo chamado aparece em muitos call-sites.
203
+ */
204
+ declare function declaredPropsOf(sys: SystemIR, types?: TypeCatalog): (type: string) => Schema | undefined;
205
+ /**
206
+ * O tipo declarado de cada chave do estado — o que o `init` dela tem de render.
207
+ *
208
+ * É o mesmo `resolveTypeRef` das props: o `init` é uma expressão como qualquer outra, e o tipo
209
+ * contra o qual ela é provada é o que o autor declarou ao lado.
210
+ */
211
+ declare function stateTypeOf(state: Record<string, {
212
+ type: TypeRef;
213
+ }> | undefined, types?: TypeCatalog): (key: string) => Schema | undefined;
214
+
215
+ /** A definição compilada pela linguagem, com o que ela disse — o que o lowering consome. */
216
+ type CompiledComponent = CompiledDefinition<CompileDiagnostic, CompiledIsland>;
217
+ /**
218
+ * A âncora de um nó do corpo baixado é o CAMINHO do campo que o produziu — a lista
219
+ * (`[0, 1, "props", "title"]`, `["updates", "somar", "set", "n"]`), em que índice e chave são
220
+ * distintos no tipo. O endereço (`#0.1.props.title`) é derivado dela; o texto do campo, quando
221
+ * há um, mora ao lado, em `texts`.
222
+ */
223
+ type NodeMap = Anchors<CompiledPath>;
224
+ /** Uma raiz de expressão que o checker vai tipar, e de onde ela veio. */
225
+ interface LoweredIsland {
226
+ readonly node: Expression;
227
+ readonly path: CompiledPath;
228
+ readonly address: string;
229
+ /** o texto do campo, como o autor o escreveu. Ausente quando a ilha já chegou compilada. */
230
+ readonly source?: string;
231
+ }
232
+ interface Lowered {
233
+ /** o corpo tipável. Entregue ao `check` como está — nunca impresso no caminho. */
234
+ program: Expression;
235
+ /** os `init` do estado, num corpo à parte: eles têm OUTRO escopo (`props` e `ctx`, só). */
236
+ inits?: Expression;
237
+ /** nó → caminho do campo, por identidade. */
238
+ anchors: NodeMap;
239
+ /** endereço → o texto do campo, para o span pousar nele. Inclui os nomes declarados (`as`). */
240
+ texts: ReadonlyMap<string, string>;
241
+ /**
242
+ * Endereço → o BLOCO do corpo baixado em que os slots daquele lugar foram emitidos: o de cada nó
243
+ * (`#0.1` — o bloco do `map` do `each` mais próximo, ou o do corpo) e o de cada update
244
+ * (`updates.somar` — o frame com `params`). É a porta para o escopo de um campo: o `scopeAt`
245
+ * do checker sobre esse bloco responde que nomes o campo enxerga, pela mesma análise que o tipa
246
+ * — inclusive para um campo vazio ou que não compilou. O que não está aqui (`effects`, o
247
+ * `provides` e os `commands` do componente) vive no bloco raiz de `program`; os `init`, em
248
+ * `inits`.
249
+ */
250
+ frames: ReadonlyMap<string, object>;
251
+ /** as raízes de expressão tipadas, na ordem em que foram emitidas. */
252
+ islands: readonly LoweredIsland[];
253
+ /** a definição que foi baixada — a compilada, com o que a compilação reclamou. */
254
+ compiled: CompiledComponent;
255
+ /**
256
+ * Endereços cujo `excess-property` não é confiável — a assinatura daquela ação pode ter
257
+ * envelhecido (ver `exhaustiveParams`). Quem julga é o `checkComponent`: ali o veredito vira
258
+ * aviso em vez de erro.
259
+ */
260
+ weak: ReadonlySet<string>;
261
+ }
262
+ /** A forma de um `each`: coleção (vira `map`) ou objeto (vira aplicação direta). */
263
+ type DataShape = "list" | "value";
264
+ interface LowerOptions {
265
+ /**
266
+ * A definição já COMPILADA pela linguagem — o mesmo artefato que a bancada mostra e o bind
267
+ * executa. Ausente, o lowering compila (`compileDefinition` com o `compile` da linguagem, sem
268
+ * profile: o eixo de sintaxe não é do check). Quem compilou uma vez passa o resultado, e a
269
+ * string não é derivada duas vezes.
270
+ */
271
+ compiled?: CompiledComponent;
272
+ /**
273
+ * A forma de cada `each` — quem chama sabe, porque já tipou a expressão.
274
+ * Default `"list"`: o caso do laço, que é o que o `as` existe para nomear.
275
+ */
276
+ shapeOf?: (expression: Expression) => DataShape;
277
+ /**
278
+ * *"Que props este componente declara?"* — a pergunta que o lowering FAZ e não responde.
279
+ *
280
+ * Ele é transformação de forma: não conhece registry, `SystemIR` nem `Schema`. Quem sabe é
281
+ * quem montou o sistema, e o seam entre os dois é este resolvedor (a mesma natureza do
282
+ * `TargetResolver` do `checker-v2`).
283
+ *
284
+ * **Ausente = nenhum call-site é tipado**, e não "todos falham": quem chama o lowering só
285
+ * para VER o corpo baixado não tem sistema para perguntar, e inventar um erro ali esconderia
286
+ * justamente o que essa pessoa foi olhar.
287
+ */
288
+ propsOf?: (type: string) => Schema | undefined;
289
+ /**
290
+ * O tipo declarado de cada contexto — o catálogo do sistema. É contra ele que um
291
+ * `provides` é provado: mesma máquina do call-site, quinta superfície.
292
+ * Ausente = as provisões não são tipadas.
293
+ */
294
+ contextOf?: (name: string) => Schema | undefined;
295
+ /**
296
+ * O tipo de um `set` de update local — o estado declarado, com tudo opcional
297
+ * (`partialStateType`). Ausente = as ações não são tipadas.
298
+ */
299
+ setType?: Schema;
300
+ /**
301
+ * O tipo dos `params` de cada update local, quando ela os declara. É o que tipa o corpo do update
302
+ * e o call-site do evento que a dispara. Sem declaração, `params` vale `unknown`.
303
+ */
304
+ paramsOf?: (action: string) => Schema | undefined;
305
+ /**
306
+ * A assinatura daquela ação é EXAUSTIVA? (default: sim)
307
+ *
308
+ * Só uma prova depende disso: "esta chave não existe". Com uma assinatura que pode divergir do
309
+ * que a implementação aceita — o `declared` do contrato —, acusar `excess-property` como ERRO é
310
+ * afirmar mais do que se sabe. Então o endereço entra em `weak`, e o julgamento vira aviso.
311
+ */
312
+ exhaustiveParams?: (action: string) => boolean;
313
+ /**
314
+ * O tipo declarado de cada chave do estado — o que o `init` dela tem de render.
315
+ *
316
+ * O `init` SEMEIA o estado a partir de `props`/`ctx`, e por isso ele é baixado num programa
317
+ * SEPARADO: o escopo dele não tem `state` (é o que está sendo definido) nem `params`. Tipar os
318
+ * dois no mesmo corpo deixaria passar um `init` que lê `state`, que em runtime é `undefined`.
319
+ */
320
+ stateTypeOf?: (key: string) => Schema | undefined;
321
+ /**
322
+ * O tipo do valor que um componente REGISTRADO emite num evento — `descriptor.meta.emits`.
323
+ *
324
+ * É o tipo da raiz `event` nos `params` desse evento (ADR-018). Sem declaração, `event` é
325
+ * `unknown` — e `unknown` num param tipado é acusado: quem não declarou o que emite não ganha
326
+ * um tipo de graça. Declarar é do kit; provar (`parseAs`) é do autor.
327
+ */
328
+ emitsOf?: (type: string, event: string) => Schema | undefined;
329
+ /**
330
+ * O tipo do que uma ação do HOST devolve — o `resultOf` do Tier 1 da porta. É o tipo da raiz
331
+ * `event` no `then` da intenção que a executou. Sem declaração, `unknown`.
332
+ */
333
+ resultOf?: (action: string) => Schema | undefined;
334
+ /**
335
+ * A montagem do SISTEMA (`mountingOf` do `@loom-forge/forge`) — o que responde o que um nome de
336
+ * comando EXECUTA num nó: o vocabulário que um chamado instala no próprio `$slot`, e os nomes
337
+ * que algum vocabulário declara.
338
+ *
339
+ * **Ausente = o documento é o sistema.** O que ele declara resolve dentro dele, um chamado
340
+ * desconhecido não tem slot, e um nome que só outro componente declararia vale como o id da
341
+ * porta — que é tudo o que dá para saber sem o resto.
342
+ */
343
+ mounting?: Pick<Mounting, "slotScopesOf" | "vocabulary">;
344
+ }
345
+ /** Baixa uma definição de componente num corpo TSL. */
346
+ declare function lowerComponent(authored: ComponentDef, opts?: LowerOptions): Lowered;
347
+
348
+ /**
349
+ * O profile que vai ao `@tslite/checker`, a partir do profile do deploy: a sintaxe da Linguagem
350
+ * inteira e o eixo `types` do deploy. Sem `types` no deploy, vale o do `complete` (sem `strict`).
351
+ */
352
+ declare const checkerProfileOf: (deploy: CapabilityProfile) => CapabilityProfile;
353
+
354
+ interface CheckIssue {
355
+ /** o código do checker (`no-such-member`, `unknown-name`, `not-assignable`…). */
356
+ code: string;
357
+ message: string;
358
+ severity: "error" | "warning";
359
+ /** o caminho do campo, como lista: `[0, 1, "props", "title"]` na árvore (a raiz é o nó `0`),
360
+ * `["updates", "somar", "set", "n"]` fora dela. Índice e chave são distintos no tipo. */
361
+ path: CompiledPath;
362
+ /** o caminho como o autor o lê: `#0.1.props.title`. Derivado de `path`. */
363
+ address: string;
364
+ /** o texto do campo, como o autor o escreveu — com o `{{ }}`, quando há. Ausente quando o
365
+ * campo já vinha compilado. */
366
+ source?: string;
367
+ /** offsets dentro de `source`, na forma do `@tslite/language-service` (fim exclusivo) —
368
+ * `source.slice(span.from, span.to)` é o trecho aceso. */
369
+ span?: Span;
370
+ }
371
+ interface CheckComponentOptions {
372
+ /** limites estruturais — o drawer do editor roda isto por tecla digitada. */
373
+ limits?: {
374
+ maxDepth?: number;
375
+ maxNodes?: number;
376
+ };
377
+ /**
378
+ * A definição já COMPILADA pela linguagem (`compileDefinition(def, compile)`), quando quem
379
+ * chama já a tem — a bancada, o serviço de linguagem. A string não é derivada duas vezes, e os
380
+ * diagnósticos da compilação são de quem compilou: com `compiled`, este check não os repete.
381
+ * Ausente, o check compila (sem profile — o eixo de sintaxe não é dele) e os reporta.
382
+ */
383
+ compiled?: CompiledComponent;
384
+ /**
385
+ * O `CapabilityProfile` do DEPLOY — o mesmo que o binder executa. Default: `DEFAULT_PROFILE`
386
+ * do `@loom-forge/tslite`.
387
+ *
388
+ * Daqui sai só o eixo de TIPOS (`types.strict`): o `any` autorado e o cast que estreita
389
+ * (`{{ (props.bruto as Endereco).cep }}` é `narrowing-cast-not-allowed`). O eixo de sintaxe —
390
+ * que nós a expressão pode conter — é da compilação, e acusá-lo aqui de novo seria o mesmo
391
+ * erro duas vezes no campo. Ver `profile.ts`.
392
+ */
393
+ profile?: CapabilityProfile;
394
+ /**
395
+ * O tipo de props que cada componente CHAMADO declara — o que liga o call-site.
396
+ *
397
+ * `declaredPropsOf(systemIR)` monta este resolvedor. **Ausente = nenhum call-site é tipado**:
398
+ * sem sistema não há o que comparar, e inventar um erro ali seria pior que o silêncio.
399
+ */
400
+ propsOf?: (type: string) => Schema | undefined;
401
+ /** o catálogo de tipos nomeados — o MESMO que foi para o `buildEnv`. Sem ele, um `TypeRef`
402
+ * que seja nome de tipo é reportado como desconhecido, porque daqui ele não existe. */
403
+ types?: TypeCatalog;
404
+ /** o catálogo de CONTEXTOS do sistema (`nome → TypeRef`) — o que tipa um `provides`.
405
+ * Ausente = as provisões não são provadas contra nada. */
406
+ contexts?: Record<string, TypeRef>;
407
+ /**
408
+ * O que cada componente REGISTRADO emite num evento (`descriptor.meta.emits`) — o tipo da raiz
409
+ * `event` nos `params` desse evento (ADR-018). Sem declaração, `event` é `unknown`, e `unknown`
410
+ * num param tipado é acusado: quem não declarou o que emite não ganha um tipo de graça.
411
+ */
412
+ emitsOf?: (type: string, event: string) => Schema | undefined;
413
+ /**
414
+ * A PORTA de ação do host — de onde sai a assinatura de uma ação que não é update local.
415
+ *
416
+ * Basta ter o `paramsOf` do Tier 1 (`ActionPort`, commander, ou um objeto com o método). Com
417
+ * ele, `events.params` de uma ação do host vira um call-site como o de componente: obrigatória
418
+ * faltando, tipo errado, chave a mais. **Ausente = a ação do host não é tipada** — e isso é
419
+ * silêncio, não erro: quem não publica assinatura não afirmou nada.
420
+ */
421
+ actions?: {
422
+ paramsOf?(action: string): unknown;
423
+ /** a forma do RETORNO, em JSON Schema — o tipo do `event` no `then` de quem a executa (ADR-018). */
424
+ resultOf?(action: string): unknown;
425
+ /** quanto vale a resposta — ver `ActionPort.provenanceOf`. Ausente = `declared`. */
426
+ provenanceOf?(query: string): string;
427
+ };
428
+ /**
429
+ * A montagem do sistema — `mountingOf(sys.components.values())`, do `@loom-forge/forge`. É o
430
+ * que responde o que um nome de COMANDO executa: um evento dentro do slot de uma sessão é
431
+ * provado contra a ação que o vocabulário da sessão escolhe.
432
+ *
433
+ * **Ausente = o documento é o sistema:** o que ele declara resolve dentro dele, e o resto vale
434
+ * como o id da porta.
435
+ */
436
+ mounting?: LowerOptions["mounting"];
437
+ }
438
+ /**
439
+ * A análise de um componente — o que o `checkComponent` deriva os issues, exposto para quem
440
+ * projeta OUTRA coisa da mesma passada: o serviço de linguagem lê o `overlay` do corpo para
441
+ * responder o escopo de um campo (`scopeAt` sobre `lowered.frames`), sem tipar de novo.
442
+ */
443
+ interface ComponentAnalysis {
444
+ /** os diagnósticos, ao campo — o que o `checkComponent` devolve. */
445
+ readonly issues: readonly CheckIssue[];
446
+ readonly lowered: Lowered;
447
+ /** o resultado do checker sobre o corpo: o overlay de tipo e escopo por nó. */
448
+ readonly body: CheckResult;
449
+ /** o `Env` que semeia o estado (`props` e `ctx`) — o dos `init`, e o de um campo deles. */
450
+ readonly initEnv: Env;
451
+ /** idem sobre os `init`, quando há algum. */
452
+ readonly inits?: CheckResult;
453
+ }
454
+ /**
455
+ * Tipa todas as expressões de um componente contra o `env`.
456
+ *
457
+ * Pega campo que não existe numa raiz (`props.tituloo`), membro que não existe no item de um
458
+ * `each` — com o tipo do item **inferido** da coleção, sem anotação —, nome livre desconhecido,
459
+ * `when` que não rende `boolean`, e — com `propsOf` — o CALL-SITE: as props passadas a um
460
+ * componente custom contra o que ele declara, mesmo vindas de expressão.
461
+ */
462
+ declare function checkComponent(def: ComponentDef, env: Env, opts?: CheckComponentOptions): CheckIssue[];
463
+ /** A análise inteira — ver `ComponentAnalysis`. O `checkComponent` é a projeção dela. */
464
+ declare function analyzeComponent(def: ComponentDef, env: Env, opts?: CheckComponentOptions): ComponentAnalysis;
465
+ interface CheckExpressionOptions extends CheckComponentOptions {
466
+ /** o tipo que o slot espera render. Um `when` pede `boolean`. */
467
+ resultType?: Schema;
468
+ }
469
+ /**
470
+ * Tipa UMA expressão — o cano por slot, que é o que o drawer do editor liga quando o autor
471
+ * abre um campo. Roda **por tecla digitada**, daí os `limits`.
472
+ *
473
+ * `source` é a expressão nua (sem `{{ }}`); os `span` voltam relativos a ela. `path` é o caminho
474
+ * do campo que a contém — o issue o devolve, com o endereço derivado.
475
+ */
476
+ declare function checkExpression(source: string, env: Env, path: CompiledPath, opts?: CheckExpressionOptions): CheckIssue[];
477
+
478
+ export { type BuildEnvOptions, type CheckComponentOptions, type CheckExpressionOptions, type CheckIssue, type CompiledComponent, type ComponentAnalysis, type ComponentContract, type ComponentType, DEFAULT_ASSERTER, type DataflowIssue, type DeclarationIssue, type Lowered, type LoweredIsland, type NodeMap, type TsliteChecker, type TypeCatalog, analyzeComponent, buildEnv, buildInitEnv, checkComponent, checkContextCatalog, checkDeclarations, checkExpression, checkTree, checkerProfileOf, componentAssignable, componentType, createTsliteChecker, declaredContextsOf, declaredParamsOf, declaredPropsOf, lowerComponent, partialStateType, resolveProps, resolveTypeRef, stateTypeOf };