@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.
- package/README.md +444 -0
- package/dist/index.d.ts +478 -0
- package/dist/index.js +867 -0
- package/dist/index.js.map +1 -0
- package/package.json +69 -0
package/dist/index.d.ts
ADDED
|
@@ -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 };
|