@loom-forge/eject 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 +155 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +772 -0
- package/dist/index.js.map +1 -0
- package/package.json +62 -0
package/README.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# @loom-forge/eject
|
|
2
|
+
|
|
3
|
+
A definição JSON traduzida para o **componente React que ela descreve**. Dev/CI e
|
|
4
|
+
tooling — nunca no caminho de render.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
pnpm add -D @loom-forge/eject
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { ejectComponent } from "@loom-forge/eject";
|
|
12
|
+
|
|
13
|
+
const { code, notes } = ejectComponent(def);
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## O que é nosso, e o que não é
|
|
19
|
+
|
|
20
|
+
**O printer não é daqui.** Quem imprime é o [`@tslite/emit`](https://www.npmjs.com/package/@tslite/emit),
|
|
21
|
+
o emissor de FONTE do TSLite: contrato invertido do printer de execução — preserva
|
|
22
|
+
tipo, preserva JSX, imprime comentário, quebra por largura. Aqui não há parser,
|
|
23
|
+
precedência nem quebra de linha.
|
|
24
|
+
|
|
25
|
+
O que é nosso é o **mapeamento**: o que `each` significa em React, o que vira
|
|
26
|
+
`useState`, de onde sai a `key`. Isso ninguém mais sabe.
|
|
27
|
+
|
|
28
|
+
| no JSON | no TSX |
|
|
29
|
+
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
30
|
+
| `props` declaradas | `type XProps = { … }` + o parâmetro anotado |
|
|
31
|
+
| `el: "div"` | `<div>` · `type: "Card"` → `<Card>` |
|
|
32
|
+
| `props.children` | o FILHO, nunca um atributo |
|
|
33
|
+
| `each` + `as` | `.map((item, index) => …)` com `key={item.id ?? index}` |
|
|
34
|
+
| `when` | `{cond && …}` — por item quando há laço |
|
|
35
|
+
| `$slot` | `{props.children}` |
|
|
36
|
+
| `state` | `useState` por chave, com o setter |
|
|
37
|
+
| `updates[x].set` | um `useCallback` que chama os setters — deps do que o `set` lê |
|
|
38
|
+
| `updates[x].params` | o parâmetro da função, tipado |
|
|
39
|
+
| `effects[x]` | `useEffect`, com `on` virando o array de dependências e `cleanup` no `return` |
|
|
40
|
+
| `events` → update local | a chamada da função |
|
|
41
|
+
| `event` nos `params` | o PARÂMETRO do handler: `onChange={(event) => editar({ campo: "cpf", valor: event })}` |
|
|
42
|
+
| `events` → ação do host | `invoke("nome", params)` |
|
|
43
|
+
| `then` / `catch` | `async` + `const r = await invoke(...)`; `!r.success` roda o `catch` com `r.error`, `!r.aborted` o `then` com `r.data` |
|
|
44
|
+
| `pending["x/y"]` | um `useState` de pendentes, ligado e desligado em volta do `await` |
|
|
45
|
+
| apelido de `commands` | `invoke("id", { ...ligados, ...passados })` — sai resolvido |
|
|
46
|
+
| texto com `{{ }}` no meio | template literal |
|
|
47
|
+
|
|
48
|
+
A **`key` repete a identidade do motor** (`item.id ?? índice`), e não é escolha de
|
|
49
|
+
estilo: é o que faz o TSX e a árvore resolvida concordarem sobre qual nó é qual.
|
|
50
|
+
|
|
51
|
+
**O update é um `useCallback`, e as dependências saem do que o `set` LÊ** — a regra do
|
|
52
|
+
`exhaustive-deps`, derivada da expressão (o `freeVars` do `@tslite/analysis`), não escrita à mão:
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
const alternar = useCallback(() => {
|
|
56
|
+
setAberto((aberto) => !aberto); // escreve o que lê → functional update, e a chave sai das deps
|
|
57
|
+
}, []);
|
|
58
|
+
const aplicar = useCallback(() => {
|
|
59
|
+
setTotal(count * props.fator); // lê OUTRA chave e um membro de props → os dois nas deps
|
|
60
|
+
}, [count, props.fator]);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
O setter é estável e `params` é argumento: nenhum dos dois entra. O functional update é a
|
|
64
|
+
forma que não perde um disparo quando dois entram no mesmo batch — e é a que o React Compiler
|
|
65
|
+
produziria. O `useEffect` continua com o `on` do documento como dependências: é o contrato do
|
|
66
|
+
modelo, não o do lint.
|
|
67
|
+
|
|
68
|
+
**Uma intenção é uma promise chain, e o TSX lê como uma** (ADR-018 do repo). O que a intenção
|
|
69
|
+
RECEBE é a raiz `event` dos `params` — o valor que o widget emitiu, o `data` da ação anterior num
|
|
70
|
+
`then`, o `error` num `catch` — e o autor escreveu o mapeamento; o handler emitido é a tradução
|
|
71
|
+
literal dele:
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
onChange={(event) => editar({ campo: "cpf", valor: event })}
|
|
75
|
+
|
|
76
|
+
onClick={async () => {
|
|
77
|
+
iniciar();
|
|
78
|
+
setPending((p) => ({ ...p, "corretor/validar-email": true }));
|
|
79
|
+
const r = await invoke("corretor/validar-email", { email: props.email });
|
|
80
|
+
setPending((p) => ({ ...p, "corretor/validar-email": false }));
|
|
81
|
+
if (!r.success) falhou({ motivo: r.error.code });
|
|
82
|
+
else if (!r.aborted) marcar({ valido: r.data.valido });
|
|
83
|
+
}}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
O `then` de um update local roda depois do `set`, com `event` = `undefined` — é o `iniciar()`
|
|
87
|
+
seguido do `invoke` acima. Um fluxo cancelado (`aborted` com sucesso) não roda nem `then` nem
|
|
88
|
+
`catch`, e é o `!r.aborted` que o diz. Uma intenção que não lê `event` sai como `() => …`, e uma
|
|
89
|
+
que não espera nada continua síncrona. O `pending` só existe num componente vivo — é o boundary
|
|
90
|
+
que o guarda no motor, e aqui é um `useState` do próprio componente, declarado quando alguma
|
|
91
|
+
expressão o lê; a partir daí **todo** despacho ao host o liga e desliga, como o motor faz.
|
|
92
|
+
Dentro de um `useEffect`, cuja função não pode ser `async`, a cadeia que espera roda numa IIFE
|
|
93
|
+
(`void (async () => { … })()`).
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Ele consome a definição COMPILADA
|
|
98
|
+
|
|
99
|
+
A fase de compilação (`@loom-forge/tslite/compile`) já respondeu onde uma ilha
|
|
100
|
+
começa e termina, e já decidiu que texto interpolado vira template literal.
|
|
101
|
+
Segmentar de novo aqui seria a terceira resposta para a mesma pergunta.
|
|
102
|
+
|
|
103
|
+
As expressões de um **update** e de um **efeito** não moram na árvore, e quem as
|
|
104
|
+
alcança é o `compileDefinition` do [`@loom-forge/forge`](../forge/README.md) — o
|
|
105
|
+
mesmo que o runtime usa. O eject não tem caminho próprio de compilação: ele recebe
|
|
106
|
+
a definição compilada e traduz.
|
|
107
|
+
|
|
108
|
+
O que cada intenção EXECUTA também não é pergunta daqui: vem da rota do forge
|
|
109
|
+
(`settledRoute`), a mesma que o grafo e o `check` usam. Passe a montagem do sistema
|
|
110
|
+
para que o eject saiba o que o documento sozinho não decide:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
ejectComponent(def, { mounting: mountingOf(sys.components.values()) });
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Sem ela, o documento é o sistema: o que ele declara sai resolvido, e o resto sai como id.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## O que a tradução NÃO alcança sai em `notes`
|
|
121
|
+
|
|
122
|
+
Nunca em silêncio. Hoje:
|
|
123
|
+
|
|
124
|
+
- **`placement` e `layout`** — quem posiciona é o renderer do layout; o TSX mostra
|
|
125
|
+
os filhos, não o arranjo que o planner calcula. O caminho é um _emitter_ pareado
|
|
126
|
+
por nome, ao lado do renderer;
|
|
127
|
+
- **`provides`** — seria um Provider ao redor;
|
|
128
|
+
- **o vocabulário de comando** — o que o documento resolve sai resolvido; um nome que depende de
|
|
129
|
+
onde o componente monta (o `$slot` de uma sessão, um vocabulário de outro componente) sai como
|
|
130
|
+
nome, e no React pediria um vocabulário de comando do host. Quem declara `commands` ganha a nota
|
|
131
|
+
pelo mesmo motivo;
|
|
132
|
+
- **nome livre** que venha da stdlib ou do host (`length`, `map`) — no TSX
|
|
133
|
+
precisaria de um import que o JSON não declara;
|
|
134
|
+
- **um nó com `props.children` E filhos na árvore** — no motor a árvore
|
|
135
|
+
sobrescreve a prop, em silêncio;
|
|
136
|
+
- **um campo que não compila** — ele ficou com o texto que o autor escreveu, e sai assim no
|
|
137
|
+
TSX, como string. A nota traz o endereço e o código do diagnóstico da compilação;
|
|
138
|
+
- **os imports das peças** — `<Card>` sai sem `import`, porque de qual módulo ele
|
|
139
|
+
vem é conhecimento do host. O seam previsto é um resolvedor (`descriptor.meta`
|
|
140
|
+
ou um `moduleOf` injetado), como o `propsOf` do `check`.
|
|
141
|
+
|
|
142
|
+
> [!WARNING]
|
|
143
|
+
> **O TSX gerado não é o que o palco renderiza.** O motor resolve por
|
|
144
|
+
> `bind → expand → resolve`; este package traduz. São dois caminhos, e sem um teste
|
|
145
|
+
> de paridade que execute o ejetado e compare com o render, eles divergem em
|
|
146
|
+
> silêncio. O teste existe como plano, não como código — ver o `TODO.md` do root.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Porta de mão única
|
|
151
|
+
|
|
152
|
+
O cabeçalho do arquivo emitido diz isso, e é contrato: editar o TSX não volta para
|
|
153
|
+
o JSON. `{xs.map(f)}` até levantaria para um `each`, mas `{fazAlgo(xs)}` não
|
|
154
|
+
levanta para nada — a volta não existe em geral, e inventá-la poria código na
|
|
155
|
+
árvore.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Mounting, ComponentDef, TypeRef } from '@loom-forge/forge';
|
|
2
|
+
|
|
3
|
+
interface Ejected {
|
|
4
|
+
readonly code: string;
|
|
5
|
+
/** o que a tradução NÃO alcançou. Dito em voz alta, nunca omitido. */
|
|
6
|
+
readonly notes: readonly string[];
|
|
7
|
+
}
|
|
8
|
+
interface EjectOptions {
|
|
9
|
+
/**
|
|
10
|
+
* A montagem do SISTEMA (`mountingOf` do `@loom-forge/forge`) — o que diz que um nome de comando
|
|
11
|
+
* é resolvido em outro lugar: pelo `$slot` de uma sessão, ou por um vocabulário de outro
|
|
12
|
+
* componente.
|
|
13
|
+
*
|
|
14
|
+
* **Ausente = o documento é o sistema.** O que ele declara sai resolvido, e o resto sai como id.
|
|
15
|
+
* Com ela, o que o documento sozinho não determina sai como nome, e a nota diz por quê.
|
|
16
|
+
*/
|
|
17
|
+
mounting?: Pick<Mounting, "slotScopesOf" | "vocabulary">;
|
|
18
|
+
}
|
|
19
|
+
declare function ejectComponent(authored: ComponentDef, opts?: EjectOptions): Ejected;
|
|
20
|
+
|
|
21
|
+
type TypeNode = Record<string, unknown> & {
|
|
22
|
+
type: string;
|
|
23
|
+
};
|
|
24
|
+
/** Traduz o que a declaração escreveu. O que não resolve vira `unknown`, nunca `any`. */
|
|
25
|
+
declare function typeNodeOf(ref: TypeRef | undefined): TypeNode;
|
|
26
|
+
/** `nome?` é opcional, TS-like — a mesma regra da declaração (ADR-214). */
|
|
27
|
+
declare function propsTypeNode(props: Readonly<Record<string, TypeRef>> | undefined): TypeNode;
|
|
28
|
+
|
|
29
|
+
export { type EjectOptions, type Ejected, type TypeNode, ejectComponent, propsTypeNode, typeNodeOf };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,772 @@
|
|
|
1
|
+
import * as b from '@tslite/core/builders';
|
|
2
|
+
import { emit } from '@tslite/emit';
|
|
3
|
+
import { s } from '@tslite/type-core';
|
|
4
|
+
import { freeVars } from '@tslite/analysis';
|
|
5
|
+
import { compile } from '@loom-forge/tslite/compile';
|
|
6
|
+
import { isExprMarker, walk, mutate } from '@tslite/core';
|
|
7
|
+
import { compileDefinition, isLive, mountingOf, compileComponent, mountScopesOf, settledRoute, EMPTY_MOUNT } from '@loom-forge/forge';
|
|
8
|
+
|
|
9
|
+
// src/emit.ts
|
|
10
|
+
|
|
11
|
+
// src/types.ts
|
|
12
|
+
var keyword = (kind) => ({ type: "TSKeywordType", kind });
|
|
13
|
+
var KEYWORDS = ["string", "number", "boolean", "unknown", "any", "null"];
|
|
14
|
+
function typeNodeOf(ref) {
|
|
15
|
+
if (ref === void 0) return keyword("unknown");
|
|
16
|
+
if (typeof ref === "string")
|
|
17
|
+
return KEYWORDS.includes(ref) ? keyword(ref) : { type: "TSTypeReference", typeName: ref };
|
|
18
|
+
const schema = ref;
|
|
19
|
+
if (schema.type === "array")
|
|
20
|
+
return {
|
|
21
|
+
type: "TSArrayType",
|
|
22
|
+
elementType: typeNodeOf(schema.items)
|
|
23
|
+
};
|
|
24
|
+
if (schema.type === "object" && schema.properties)
|
|
25
|
+
return {
|
|
26
|
+
type: "TSTypeLiteral",
|
|
27
|
+
members: Object.entries(schema.properties).map(([key, value]) => ({
|
|
28
|
+
type: "TSPropertySignature",
|
|
29
|
+
key,
|
|
30
|
+
typeAnnotation: typeNodeOf(value),
|
|
31
|
+
...schema.required?.includes(key) ? {} : { optional: true }
|
|
32
|
+
}))
|
|
33
|
+
};
|
|
34
|
+
if (typeof schema.type === "string" && KEYWORDS.includes(schema.type))
|
|
35
|
+
return keyword(schema.type);
|
|
36
|
+
return keyword("unknown");
|
|
37
|
+
}
|
|
38
|
+
function propsTypeNode(props) {
|
|
39
|
+
return {
|
|
40
|
+
type: "TSTypeLiteral",
|
|
41
|
+
members: Object.entries(props ?? {}).map(([key, ref]) => ({
|
|
42
|
+
type: "TSPropertySignature",
|
|
43
|
+
key: key.endsWith("?") ? key.slice(0, -1) : key,
|
|
44
|
+
typeAnnotation: typeNodeOf(ref),
|
|
45
|
+
...key.endsWith("?") ? { optional: true } : {}
|
|
46
|
+
}))
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
var isRootAccess = (roots) => (node) => {
|
|
50
|
+
const n = node;
|
|
51
|
+
return n?.type === "MemberExpression" && n.computed !== true && n.object?.type === "Identifier" && roots.includes(n.object.name) && n.property?.type === "Identifier";
|
|
52
|
+
};
|
|
53
|
+
function unroot(ast, roots) {
|
|
54
|
+
return mutate(
|
|
55
|
+
ast,
|
|
56
|
+
isRootAccess(roots),
|
|
57
|
+
((node) => ({
|
|
58
|
+
type: "Identifier",
|
|
59
|
+
name: node.property.name
|
|
60
|
+
}))
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
function rebind(ast, name, replacement) {
|
|
64
|
+
const isName = (n) => n?.type === "Identifier" && n.name === name;
|
|
65
|
+
const match = (n) => {
|
|
66
|
+
const node = n;
|
|
67
|
+
return isName(node) || node?.type === "MemberExpression" && node.computed !== true && isName(node.property) || node?.type === "Property" && node.computed !== true && isName(node.key) || node?.type === "ArrowFunctionExpression" && (node.params ?? []).some(isName);
|
|
68
|
+
};
|
|
69
|
+
return mutate(
|
|
70
|
+
ast,
|
|
71
|
+
match,
|
|
72
|
+
((node) => {
|
|
73
|
+
if (isName(node)) return replacement;
|
|
74
|
+
if (node.type === "MemberExpression")
|
|
75
|
+
return { ...node, object: rebind(node.object, name, replacement) };
|
|
76
|
+
if (node.type === "Property") {
|
|
77
|
+
const value = rebind(node.value, name, replacement);
|
|
78
|
+
return {
|
|
79
|
+
...node,
|
|
80
|
+
shorthand: node.shorthand === true && isName(value),
|
|
81
|
+
value
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return node;
|
|
85
|
+
})
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
function unresolved(ast, known) {
|
|
89
|
+
return [...freeVars(ast)].filter((name) => !known.includes(name));
|
|
90
|
+
}
|
|
91
|
+
function reactDeps(ast, opts) {
|
|
92
|
+
const free = freeVars(ast);
|
|
93
|
+
const deps = /* @__PURE__ */ new Set();
|
|
94
|
+
for (const root of opts.roots ?? ["props", "ctx"]) {
|
|
95
|
+
if (!free.has(root)) continue;
|
|
96
|
+
let bare = false;
|
|
97
|
+
const members = /* @__PURE__ */ new Set();
|
|
98
|
+
walk(ast, {
|
|
99
|
+
Identifier: (node, parent) => {
|
|
100
|
+
const id = node;
|
|
101
|
+
if (id.name !== root) return;
|
|
102
|
+
const p = parent;
|
|
103
|
+
if (p?.type === "MemberExpression" && p.object === node && p.computed !== true && p.property?.type === "Identifier")
|
|
104
|
+
members.add(`${root}.${p.property.name}`);
|
|
105
|
+
else bare = true;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
if (bare || members.size === 0) deps.add(root);
|
|
109
|
+
else for (const m of members) deps.add(m);
|
|
110
|
+
}
|
|
111
|
+
for (const key of opts.stateKeys) if (free.has(key)) deps.add(key);
|
|
112
|
+
return [...deps].sort();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// src/emit.ts
|
|
116
|
+
var NO_SYSTEM = {
|
|
117
|
+
slotScopesOf: () => void 0,
|
|
118
|
+
vocabulary: /* @__PURE__ */ new Set()
|
|
119
|
+
};
|
|
120
|
+
var isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v) && !isExprMarker(v);
|
|
121
|
+
var SCHEMA_OF = {
|
|
122
|
+
string: s.string,
|
|
123
|
+
number: s.number,
|
|
124
|
+
boolean: s.boolean
|
|
125
|
+
};
|
|
126
|
+
var schemaOf = (ref) => typeof ref === "string" ? SCHEMA_OF[ref] : void 0;
|
|
127
|
+
var IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
128
|
+
var keyAst = (key) => IDENTIFIER.test(key) ? b.identifier(key) : b.literal(key);
|
|
129
|
+
var propAst = (key, value) => {
|
|
130
|
+
const v = value;
|
|
131
|
+
const prop = b.property(
|
|
132
|
+
keyAst(key),
|
|
133
|
+
value
|
|
134
|
+
);
|
|
135
|
+
if (v?.type === "Identifier" && v.name === key && IDENTIFIER.test(key))
|
|
136
|
+
prop.shorthand = true;
|
|
137
|
+
return prop;
|
|
138
|
+
};
|
|
139
|
+
var NOTHING = b.identifier("undefined");
|
|
140
|
+
var statementOrBlock = (statements) => statements.length === 1 ? statements[0] : b.blockStatement(statements);
|
|
141
|
+
var memberOf = (object, property2) => b.memberExpression(
|
|
142
|
+
b.identifier(object),
|
|
143
|
+
b.identifier(property2)
|
|
144
|
+
);
|
|
145
|
+
function ejectComponent(authored, opts = {}) {
|
|
146
|
+
const notes = /* @__PURE__ */ new Set();
|
|
147
|
+
const compiled = compileDefinition(authored, compile);
|
|
148
|
+
const def = compiled.def;
|
|
149
|
+
for (const d of compiled.diagnostics)
|
|
150
|
+
notes.add(
|
|
151
|
+
`\`${d.address}\` n\xE3o compila (${d.code}): o campo saiu como o texto que o autor escreveu.`
|
|
152
|
+
);
|
|
153
|
+
const tree = {
|
|
154
|
+
...def.body,
|
|
155
|
+
...def.provides ? { provides: { ...def.provides, ...def.body.provides } } : {},
|
|
156
|
+
...def.commands ? { commands: { ...def.commands, ...def.body.commands } } : {}
|
|
157
|
+
};
|
|
158
|
+
const stateKeys = Object.keys(def.state ?? {});
|
|
159
|
+
const hooks = /* @__PURE__ */ new Set();
|
|
160
|
+
let needsInvoke = false;
|
|
161
|
+
const live = isLive(def);
|
|
162
|
+
const readsPending = live && compiled.islands.some((i) => freeVars(i.node).has("pending"));
|
|
163
|
+
let usesProps = false;
|
|
164
|
+
let hasSlot = false;
|
|
165
|
+
const routing = {
|
|
166
|
+
updates: new Set(Object.keys(def.updates ?? {})),
|
|
167
|
+
vocabulary: /* @__PURE__ */ new Set([
|
|
168
|
+
...mountingOf([
|
|
169
|
+
compileComponent(authored, {
|
|
170
|
+
components: /* @__PURE__ */ new Set([authored.component])
|
|
171
|
+
})
|
|
172
|
+
]).vocabulary,
|
|
173
|
+
...opts.mounting?.vocabulary ?? []
|
|
174
|
+
])
|
|
175
|
+
};
|
|
176
|
+
const alone = mountScopesOf(tree, NO_SYSTEM);
|
|
177
|
+
const mounted = opts.mounting ? mountScopesOf(tree, opts.mounting) : alone;
|
|
178
|
+
const routeOf = (action, node) => settledRoute(
|
|
179
|
+
action,
|
|
180
|
+
node === void 0 ? [EMPTY_MOUNT] : [...alone.get(node) ?? [], ...mounted.get(node) ?? []],
|
|
181
|
+
routing
|
|
182
|
+
);
|
|
183
|
+
const setterOf = (key) => `set${key.charAt(0).toUpperCase()}${key.slice(1)}`;
|
|
184
|
+
const valueAst = (value, bound) => {
|
|
185
|
+
if (Array.isArray(value))
|
|
186
|
+
return b.arrayExpression(
|
|
187
|
+
value.map((item) => valueAst(item, bound))
|
|
188
|
+
);
|
|
189
|
+
if (!isExprMarker(value)) {
|
|
190
|
+
if (value && typeof value === "object")
|
|
191
|
+
return b.objectExpression(
|
|
192
|
+
Object.entries(value).map(
|
|
193
|
+
([key, v]) => propAst(key, valueAst(v, bound))
|
|
194
|
+
)
|
|
195
|
+
);
|
|
196
|
+
return b.literal(value);
|
|
197
|
+
}
|
|
198
|
+
const ast = unroot(b.fromExprMarker(value), ["state"]);
|
|
199
|
+
const free = unresolved(ast, []);
|
|
200
|
+
if (free.includes("props")) usesProps = true;
|
|
201
|
+
const known = /* @__PURE__ */ new Set([
|
|
202
|
+
"props",
|
|
203
|
+
"ctx",
|
|
204
|
+
...stateKeys,
|
|
205
|
+
...live ? ["pending"] : [],
|
|
206
|
+
...bound
|
|
207
|
+
]);
|
|
208
|
+
for (const name of free.filter((n) => !known.has(n)))
|
|
209
|
+
notes.add(
|
|
210
|
+
`\`${name}\` n\xE3o \xE9 raiz nem item de la\xE7o: vem da stdlib ou do host, e no TSX precisaria de um import que o JSON n\xE3o declara.`
|
|
211
|
+
);
|
|
212
|
+
return ast;
|
|
213
|
+
};
|
|
214
|
+
const paramsAst = (route, written, bound, received) => {
|
|
215
|
+
const scope = [...bound, "event"];
|
|
216
|
+
const aliased = route !== void 0 && route.kind !== "command" && isRecord(route.bound) ? route.bound : void 0;
|
|
217
|
+
let ast;
|
|
218
|
+
if (aliased === void 0)
|
|
219
|
+
ast = written === void 0 ? void 0 : valueAst(written, scope);
|
|
220
|
+
else {
|
|
221
|
+
const props = [];
|
|
222
|
+
for (const [key, value] of Object.entries(aliased))
|
|
223
|
+
if (!(isRecord(written) && key in written))
|
|
224
|
+
props.push(propAst(key, valueAst(value, scope)));
|
|
225
|
+
if (isRecord(written))
|
|
226
|
+
for (const [key, value] of Object.entries(written))
|
|
227
|
+
props.push(propAst(key, valueAst(value, scope)));
|
|
228
|
+
else if (written !== void 0)
|
|
229
|
+
props.push(b.spreadElement(valueAst(written, scope)));
|
|
230
|
+
ast = b.objectExpression(props);
|
|
231
|
+
}
|
|
232
|
+
return ast === void 0 ? void 0 : rebind(ast, "event", received);
|
|
233
|
+
};
|
|
234
|
+
const pendingAst = (id, flag) => b.expressionStatement(
|
|
235
|
+
b.callExpression(
|
|
236
|
+
b.identifier("setPending"),
|
|
237
|
+
[
|
|
238
|
+
b.arrowFunctionExpression(
|
|
239
|
+
[b.identifier("p")],
|
|
240
|
+
b.objectExpression([
|
|
241
|
+
b.spreadElement(b.identifier("p")),
|
|
242
|
+
propAst(id, b.literal(flag))
|
|
243
|
+
])
|
|
244
|
+
)
|
|
245
|
+
]
|
|
246
|
+
)
|
|
247
|
+
);
|
|
248
|
+
const chainAst = (link, node, bound, received, depth) => {
|
|
249
|
+
const route = routeOf(link.action, node);
|
|
250
|
+
const params = paramsAst(route, link.params, bound, received);
|
|
251
|
+
const args = params === void 0 ? [] : [params];
|
|
252
|
+
const readsEvent = params !== void 0 && freeVars(params).has("event");
|
|
253
|
+
if (link.resolve?.length)
|
|
254
|
+
notes.add(
|
|
255
|
+
`\`${link.resolve.join("`, `")}\`: a camada de comando resolve (token, default ou perguntando), ent\xE3o o TSX n\xE3o os passa.`
|
|
256
|
+
);
|
|
257
|
+
if (route?.kind === "update") {
|
|
258
|
+
const statements2 = [
|
|
259
|
+
b.expressionStatement(
|
|
260
|
+
b.callExpression(
|
|
261
|
+
b.identifier(route.action),
|
|
262
|
+
args
|
|
263
|
+
)
|
|
264
|
+
)
|
|
265
|
+
];
|
|
266
|
+
if (link.then === void 0)
|
|
267
|
+
return { statements: statements2, awaits: false, readsEvent };
|
|
268
|
+
const then2 = chainAst(link.then, node, bound, NOTHING, depth);
|
|
269
|
+
return {
|
|
270
|
+
statements: [...statements2, ...then2.statements],
|
|
271
|
+
awaits: then2.awaits,
|
|
272
|
+
readsEvent
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
if (route?.kind !== "action")
|
|
276
|
+
notes.add(
|
|
277
|
+
`\`${link.action}\` \xE9 um nome de COMANDO que este documento n\xE3o resolve: o que ele executa depende de onde o componente monta, e o TSX o passa como est\xE1 \u2014 no React, isso pediria um vocabul\xE1rio de comando do host.`
|
|
278
|
+
);
|
|
279
|
+
needsInvoke = true;
|
|
280
|
+
const id = route?.kind === "action" ? route.action : link.action;
|
|
281
|
+
const invoke = b.callExpression(
|
|
282
|
+
b.identifier("invoke"),
|
|
283
|
+
[b.literal(id), ...args]
|
|
284
|
+
);
|
|
285
|
+
const chained = link.then !== void 0 || link.catch !== void 0;
|
|
286
|
+
if (!chained && !readsPending)
|
|
287
|
+
return {
|
|
288
|
+
statements: [b.expressionStatement(invoke)],
|
|
289
|
+
awaits: false,
|
|
290
|
+
readsEvent
|
|
291
|
+
};
|
|
292
|
+
const statements = [];
|
|
293
|
+
const result = depth === 0 ? "r" : `r${depth + 1}`;
|
|
294
|
+
if (readsPending) statements.push(pendingAst(id, true));
|
|
295
|
+
const awaited = b.awaitExpression(invoke);
|
|
296
|
+
statements.push(
|
|
297
|
+
chained ? b.variableDeclaration("const", [
|
|
298
|
+
b.variableDeclarator(
|
|
299
|
+
b.identifier(result),
|
|
300
|
+
awaited
|
|
301
|
+
)
|
|
302
|
+
]) : b.expressionStatement(awaited)
|
|
303
|
+
);
|
|
304
|
+
if (readsPending) statements.push(pendingAst(id, false));
|
|
305
|
+
const then = link.then && chainAst(link.then, node, bound, memberOf(result, "data"), depth + 1);
|
|
306
|
+
const failed = link.catch && chainAst(link.catch, node, bound, memberOf(result, "error"), depth + 1);
|
|
307
|
+
const success = memberOf(result, "success");
|
|
308
|
+
const notAborted = b.unaryExpression(
|
|
309
|
+
"!",
|
|
310
|
+
memberOf(result, "aborted")
|
|
311
|
+
);
|
|
312
|
+
const onThen = then && b.ifStatement(
|
|
313
|
+
notAborted,
|
|
314
|
+
statementOrBlock(then.statements)
|
|
315
|
+
);
|
|
316
|
+
if (failed)
|
|
317
|
+
statements.push(
|
|
318
|
+
b.ifStatement(
|
|
319
|
+
b.unaryExpression("!", success),
|
|
320
|
+
statementOrBlock(failed.statements),
|
|
321
|
+
onThen ?? null
|
|
322
|
+
)
|
|
323
|
+
);
|
|
324
|
+
else if (then)
|
|
325
|
+
statements.push(
|
|
326
|
+
b.ifStatement(
|
|
327
|
+
b.logicalExpression(
|
|
328
|
+
"&&",
|
|
329
|
+
success,
|
|
330
|
+
notAborted
|
|
331
|
+
),
|
|
332
|
+
statementOrBlock(then.statements)
|
|
333
|
+
)
|
|
334
|
+
);
|
|
335
|
+
return { statements, awaits: true, readsEvent };
|
|
336
|
+
};
|
|
337
|
+
const handlerAst = (chain) => {
|
|
338
|
+
const params = chain.readsEvent ? [b.identifier("event")] : [];
|
|
339
|
+
const single = chain.statements[0];
|
|
340
|
+
const body2 = chain.statements.length === 1 && !chain.awaits && single.type === "ExpressionStatement" ? single.expression : b.blockStatement(chain.statements);
|
|
341
|
+
return b.arrowFunctionExpression(
|
|
342
|
+
params,
|
|
343
|
+
body2,
|
|
344
|
+
chain.awaits
|
|
345
|
+
);
|
|
346
|
+
};
|
|
347
|
+
const effectStatements = (chain) => chain.awaits ? [
|
|
348
|
+
b.expressionStatement(
|
|
349
|
+
b.unaryExpression(
|
|
350
|
+
"void",
|
|
351
|
+
b.callExpression(
|
|
352
|
+
b.arrowFunctionExpression(
|
|
353
|
+
[],
|
|
354
|
+
b.blockStatement(chain.statements),
|
|
355
|
+
true
|
|
356
|
+
),
|
|
357
|
+
[]
|
|
358
|
+
)
|
|
359
|
+
)
|
|
360
|
+
)
|
|
361
|
+
] : chain.statements;
|
|
362
|
+
const attrsOf = (node, bound) => {
|
|
363
|
+
const out = [];
|
|
364
|
+
for (const [name, value] of Object.entries(node.props ?? {})) {
|
|
365
|
+
if (name === "children") continue;
|
|
366
|
+
out.push(
|
|
367
|
+
b.jsxAttribute(
|
|
368
|
+
b.jsxIdentifier(name),
|
|
369
|
+
typeof value === "string" && !isExprMarker(value) ? b.literal(value) : b.jsxExpressionContainer(
|
|
370
|
+
valueAst(value, bound)
|
|
371
|
+
)
|
|
372
|
+
)
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
for (const [name, binding] of Object.entries(node.events ?? {}))
|
|
376
|
+
out.push(
|
|
377
|
+
b.jsxAttribute(
|
|
378
|
+
b.jsxIdentifier(name),
|
|
379
|
+
b.jsxExpressionContainer(
|
|
380
|
+
handlerAst(
|
|
381
|
+
chainAst(binding, node, bound, b.identifier("event"), 0)
|
|
382
|
+
)
|
|
383
|
+
)
|
|
384
|
+
)
|
|
385
|
+
);
|
|
386
|
+
if (node.placement !== void 0)
|
|
387
|
+
notes.add(
|
|
388
|
+
"`placement` n\xE3o tem tradu\xE7\xE3o direta: quem posiciona \xE9 o renderer do layout, e no TSX isso vira markup do arranjo."
|
|
389
|
+
);
|
|
390
|
+
if (node.layout !== void 0)
|
|
391
|
+
notes.add(
|
|
392
|
+
`o layout \`${node.layout}\` \xE9 do renderer: o TSX abaixo mostra os filhos, n\xE3o o arranjo que o planner calcula.`
|
|
393
|
+
);
|
|
394
|
+
if (node.provides !== void 0)
|
|
395
|
+
notes.add(
|
|
396
|
+
"`provides` ainda n\xE3o \xE9 traduzido \u2014 seria um Provider ao redor."
|
|
397
|
+
);
|
|
398
|
+
if (node.commands !== void 0)
|
|
399
|
+
notes.add(
|
|
400
|
+
"`commands` instala vocabul\xE1rio para o que monta abaixo: o que este documento resolve sai resolvido no TSX, mas quem monta aqui vindo de fora (filhos de slot, componentes compostos) precisaria de um vocabul\xE1rio de comando do host."
|
|
401
|
+
);
|
|
402
|
+
return out;
|
|
403
|
+
};
|
|
404
|
+
const childrenOf = (node, bound) => {
|
|
405
|
+
const out = [];
|
|
406
|
+
const text = node.props?.children;
|
|
407
|
+
if (text !== void 0)
|
|
408
|
+
out.push(
|
|
409
|
+
typeof text === "string" && !isExprMarker(text) ? b.jsxText(text) : b.jsxExpressionContainer(valueAst(text, bound))
|
|
410
|
+
);
|
|
411
|
+
if (text !== void 0 && (node.children?.length ?? 0) > 0)
|
|
412
|
+
notes.add(
|
|
413
|
+
"este n\xF3 tem `props.children` E filhos na \xE1rvore: no motor a \xE1rvore sobrescreve a prop, em sil\xEAncio (est\xE1 no `TODO.md`)."
|
|
414
|
+
);
|
|
415
|
+
for (const child of node.children ?? []) out.push(...jsxOf(child, bound));
|
|
416
|
+
return out;
|
|
417
|
+
};
|
|
418
|
+
function jsxOf(node, bound) {
|
|
419
|
+
if (node.type === "$slot") {
|
|
420
|
+
usesProps = true;
|
|
421
|
+
hasSlot = true;
|
|
422
|
+
return [
|
|
423
|
+
b.jsxExpressionContainer(
|
|
424
|
+
b.memberExpression(
|
|
425
|
+
b.identifier("props"),
|
|
426
|
+
b.identifier("children")
|
|
427
|
+
)
|
|
428
|
+
)
|
|
429
|
+
];
|
|
430
|
+
}
|
|
431
|
+
const item = node.as;
|
|
432
|
+
const inner = item ? [...bound, item, "index"] : bound;
|
|
433
|
+
const name = node.el ?? node.type ?? "div";
|
|
434
|
+
const attrs = attrsOf(node, inner);
|
|
435
|
+
const kids = childrenOf(node, inner);
|
|
436
|
+
if (item)
|
|
437
|
+
attrs.unshift(
|
|
438
|
+
b.jsxAttribute(
|
|
439
|
+
b.jsxIdentifier("key"),
|
|
440
|
+
b.jsxExpressionContainer(
|
|
441
|
+
b.logicalExpression(
|
|
442
|
+
"??",
|
|
443
|
+
b.memberExpression(
|
|
444
|
+
b.identifier(item),
|
|
445
|
+
b.identifier("id")
|
|
446
|
+
),
|
|
447
|
+
b.identifier("index")
|
|
448
|
+
)
|
|
449
|
+
)
|
|
450
|
+
)
|
|
451
|
+
);
|
|
452
|
+
let element = b.jsxElement(
|
|
453
|
+
b.jsxOpeningElement(
|
|
454
|
+
b.jsxIdentifier(name),
|
|
455
|
+
attrs,
|
|
456
|
+
kids.length === 0
|
|
457
|
+
),
|
|
458
|
+
kids,
|
|
459
|
+
kids.length === 0 ? null : b.jsxClosingElement(b.jsxIdentifier(name))
|
|
460
|
+
);
|
|
461
|
+
if (node.when !== void 0)
|
|
462
|
+
element = b.logicalExpression(
|
|
463
|
+
"&&",
|
|
464
|
+
valueAst(node.when, inner),
|
|
465
|
+
element
|
|
466
|
+
);
|
|
467
|
+
if (node.each !== void 0) {
|
|
468
|
+
element = b.callExpression(
|
|
469
|
+
b.memberExpression(
|
|
470
|
+
valueAst(node.each, bound),
|
|
471
|
+
b.identifier("map")
|
|
472
|
+
),
|
|
473
|
+
[
|
|
474
|
+
b.arrowFunctionExpression(
|
|
475
|
+
[b.identifier(item ?? "item"), b.identifier("index")],
|
|
476
|
+
element
|
|
477
|
+
)
|
|
478
|
+
]
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
const isExpression = node.when !== void 0 || node.each !== void 0;
|
|
482
|
+
return [
|
|
483
|
+
isExpression ? b.jsxExpressionContainer(element) : element
|
|
484
|
+
];
|
|
485
|
+
}
|
|
486
|
+
const body = [];
|
|
487
|
+
if (def.context?.uses?.length) {
|
|
488
|
+
hooks.add("useContext");
|
|
489
|
+
body.push(
|
|
490
|
+
b.variableDeclaration("const", [
|
|
491
|
+
b.variableDeclarator(
|
|
492
|
+
b.identifier("ctx"),
|
|
493
|
+
b.callExpression(
|
|
494
|
+
b.identifier("useContext"),
|
|
495
|
+
[b.identifier("HostContext")]
|
|
496
|
+
)
|
|
497
|
+
)
|
|
498
|
+
])
|
|
499
|
+
);
|
|
500
|
+
notes.add(
|
|
501
|
+
`contexto: \`${def.context.uses.join("`, `")}\` \u2014 no motor ele viaja pela expans\xE3o; aqui \xE9 um React Context do host.`
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
for (const [key, decl] of Object.entries(def.state ?? {})) {
|
|
505
|
+
hooks.add("useState");
|
|
506
|
+
const call = b.callExpression(
|
|
507
|
+
b.identifier("useState"),
|
|
508
|
+
[valueAst(decl.init, [])]
|
|
509
|
+
);
|
|
510
|
+
const schema = schemaOf(decl.type);
|
|
511
|
+
if (schema) call.typeArguments = [schema];
|
|
512
|
+
body.push(
|
|
513
|
+
b.variableDeclaration("const", [
|
|
514
|
+
b.variableDeclarator(
|
|
515
|
+
b.arrayPattern([
|
|
516
|
+
b.identifier(key),
|
|
517
|
+
b.identifier(setterOf(key))
|
|
518
|
+
]),
|
|
519
|
+
call
|
|
520
|
+
)
|
|
521
|
+
])
|
|
522
|
+
);
|
|
523
|
+
}
|
|
524
|
+
if (readsPending) {
|
|
525
|
+
hooks.add("useState");
|
|
526
|
+
const call = b.callExpression(
|
|
527
|
+
b.identifier("useState"),
|
|
528
|
+
[b.objectExpression([])]
|
|
529
|
+
);
|
|
530
|
+
call.typeArguments = [
|
|
531
|
+
{ t: "apply", name: "Record", args: [s.string, s.boolean] }
|
|
532
|
+
];
|
|
533
|
+
body.push(
|
|
534
|
+
b.variableDeclaration("const", [
|
|
535
|
+
b.variableDeclarator(
|
|
536
|
+
b.arrayPattern([
|
|
537
|
+
b.identifier("pending"),
|
|
538
|
+
b.identifier("setPending")
|
|
539
|
+
]),
|
|
540
|
+
call
|
|
541
|
+
)
|
|
542
|
+
])
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
for (const [name, action] of Object.entries(def.updates ?? {})) {
|
|
546
|
+
const param2 = b.identifier("params");
|
|
547
|
+
const declared = action.params;
|
|
548
|
+
if (declared) {
|
|
549
|
+
const fields = Object.fromEntries(
|
|
550
|
+
Object.entries(declared).map(([key, ref]) => [key, schemaOf(ref)]).filter(([, schema]) => schema)
|
|
551
|
+
);
|
|
552
|
+
if (Object.keys(fields).length)
|
|
553
|
+
param2.typeAnnotation = s.object(
|
|
554
|
+
Object.fromEntries(
|
|
555
|
+
Object.entries(fields).map(([key, type]) => [key, { type }])
|
|
556
|
+
)
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
const deps = /* @__PURE__ */ new Set();
|
|
560
|
+
const writes = Object.entries(action.set ?? {}).map(([key, value]) => {
|
|
561
|
+
let expr = valueAst(value, []);
|
|
562
|
+
for (const dep of reactDeps(expr, { stateKeys })) {
|
|
563
|
+
if (dep === key)
|
|
564
|
+
expr = b.arrowFunctionExpression(
|
|
565
|
+
[b.identifier(key)],
|
|
566
|
+
expr
|
|
567
|
+
);
|
|
568
|
+
else deps.add(dep);
|
|
569
|
+
}
|
|
570
|
+
return b.expressionStatement(
|
|
571
|
+
b.callExpression(
|
|
572
|
+
b.identifier(setterOf(key)),
|
|
573
|
+
[expr]
|
|
574
|
+
)
|
|
575
|
+
);
|
|
576
|
+
});
|
|
577
|
+
if ([...deps].some((dep) => dep.startsWith("props"))) usesProps = true;
|
|
578
|
+
hooks.add("useCallback");
|
|
579
|
+
body.push(
|
|
580
|
+
b.variableDeclaration("const", [
|
|
581
|
+
b.variableDeclarator(
|
|
582
|
+
b.identifier(name),
|
|
583
|
+
b.callExpression(
|
|
584
|
+
b.identifier("useCallback"),
|
|
585
|
+
[
|
|
586
|
+
b.arrowFunctionExpression(
|
|
587
|
+
declared ? [param2] : [],
|
|
588
|
+
b.blockStatement(writes)
|
|
589
|
+
),
|
|
590
|
+
b.arrayExpression(
|
|
591
|
+
[...deps].sort().map(
|
|
592
|
+
(dep) => dep.split(".").map((part) => b.identifier(part)).reduce(
|
|
593
|
+
(acc, part) => b.memberExpression(
|
|
594
|
+
acc,
|
|
595
|
+
part
|
|
596
|
+
)
|
|
597
|
+
)
|
|
598
|
+
)
|
|
599
|
+
)
|
|
600
|
+
]
|
|
601
|
+
)
|
|
602
|
+
)
|
|
603
|
+
])
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
for (const [name, effect] of Object.entries(
|
|
607
|
+
def.effects ?? {}
|
|
608
|
+
)) {
|
|
609
|
+
hooks.add("useEffect");
|
|
610
|
+
const deps = (effect.on ?? []).map((path) => {
|
|
611
|
+
const [root, ...rest] = path.split(".");
|
|
612
|
+
if (root === "props") usesProps = true;
|
|
613
|
+
const head = root === "state" ? b.identifier(rest.shift() ?? "") : b.identifier(root);
|
|
614
|
+
return rest.reduce(
|
|
615
|
+
(acc, part) => b.memberExpression(acc, b.identifier(part)),
|
|
616
|
+
head
|
|
617
|
+
);
|
|
618
|
+
});
|
|
619
|
+
const statements = effectStatements(
|
|
620
|
+
chainAst(effect, void 0, [], NOTHING, 0)
|
|
621
|
+
);
|
|
622
|
+
if (effect.cleanup)
|
|
623
|
+
statements.push(
|
|
624
|
+
b.returnStatement(
|
|
625
|
+
handlerAst({
|
|
626
|
+
statements: effectStatements(
|
|
627
|
+
chainAst(effect.cleanup, void 0, [], NOTHING, 0)
|
|
628
|
+
),
|
|
629
|
+
awaits: false,
|
|
630
|
+
readsEvent: false
|
|
631
|
+
})
|
|
632
|
+
)
|
|
633
|
+
);
|
|
634
|
+
const call = b.callExpression(
|
|
635
|
+
b.identifier("useEffect"),
|
|
636
|
+
[
|
|
637
|
+
b.arrowFunctionExpression(
|
|
638
|
+
[],
|
|
639
|
+
b.blockStatement(statements)
|
|
640
|
+
),
|
|
641
|
+
b.arrayExpression(deps)
|
|
642
|
+
]
|
|
643
|
+
);
|
|
644
|
+
call.leadingComments = [{ type: "Line", value: ` efeito \`${name}\`` }];
|
|
645
|
+
body.push(b.expressionStatement(call));
|
|
646
|
+
}
|
|
647
|
+
const rendered = jsxOf(tree, []);
|
|
648
|
+
const returned = rendered.length === 1 ? rendered[0] : b.jsxFragment(rendered);
|
|
649
|
+
if (needsInvoke) {
|
|
650
|
+
body.unshift(
|
|
651
|
+
b.variableDeclaration("const", [
|
|
652
|
+
b.variableDeclarator(
|
|
653
|
+
b.objectPattern([
|
|
654
|
+
propAst("invoke", b.identifier("invoke"))
|
|
655
|
+
]),
|
|
656
|
+
b.callExpression(
|
|
657
|
+
b.identifier("useActions"),
|
|
658
|
+
[]
|
|
659
|
+
)
|
|
660
|
+
)
|
|
661
|
+
])
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
const propsName = `${def.component}Props`;
|
|
665
|
+
const hasProps = Object.keys(def.props ?? {}).length > 0;
|
|
666
|
+
const typedProps = hasProps || usesProps || hasSlot;
|
|
667
|
+
const param = b.identifier("props");
|
|
668
|
+
if (typedProps)
|
|
669
|
+
param.typeAnnotation = { t: "apply", name: propsName, args: [] };
|
|
670
|
+
const component = b.variableDeclaration("const", [
|
|
671
|
+
b.variableDeclarator(
|
|
672
|
+
b.identifier(def.component),
|
|
673
|
+
b.arrowFunctionExpression(
|
|
674
|
+
hasProps || usesProps ? [param] : [],
|
|
675
|
+
body.length === 0 ? returned : b.blockStatement([
|
|
676
|
+
...body,
|
|
677
|
+
b.returnStatement(returned)
|
|
678
|
+
])
|
|
679
|
+
)
|
|
680
|
+
)
|
|
681
|
+
]);
|
|
682
|
+
const banner = [
|
|
683
|
+
{
|
|
684
|
+
type: "Block",
|
|
685
|
+
value: `*
|
|
686
|
+
* ${def.component} \u2014 emitido da defini\xE7\xE3o JSON.
|
|
687
|
+
*
|
|
688
|
+
* Porta de M\xC3O \xDANICA: editar este arquivo n\xE3o volta para o JSON.
|
|
689
|
+
`
|
|
690
|
+
}
|
|
691
|
+
];
|
|
692
|
+
const program2 = [];
|
|
693
|
+
if (hooks.size)
|
|
694
|
+
program2.push({
|
|
695
|
+
type: "ImportDeclaration",
|
|
696
|
+
specifiers: [...hooks].sort().map((name) => ({
|
|
697
|
+
type: "ImportSpecifier",
|
|
698
|
+
imported: b.identifier(name),
|
|
699
|
+
local: b.identifier(name)
|
|
700
|
+
})),
|
|
701
|
+
source: b.literal("react")
|
|
702
|
+
});
|
|
703
|
+
if (needsInvoke || hooks.has("useContext"))
|
|
704
|
+
program2.push({
|
|
705
|
+
type: "ImportDeclaration",
|
|
706
|
+
specifiers: [
|
|
707
|
+
...needsInvoke ? [
|
|
708
|
+
{
|
|
709
|
+
type: "ImportSpecifier",
|
|
710
|
+
imported: b.identifier("useActions"),
|
|
711
|
+
local: b.identifier("useActions")
|
|
712
|
+
}
|
|
713
|
+
] : [],
|
|
714
|
+
...hooks.has("useContext") ? [
|
|
715
|
+
{
|
|
716
|
+
type: "ImportSpecifier",
|
|
717
|
+
imported: b.identifier("HostContext"),
|
|
718
|
+
local: b.identifier("HostContext")
|
|
719
|
+
}
|
|
720
|
+
] : []
|
|
721
|
+
],
|
|
722
|
+
source: b.literal("./host")
|
|
723
|
+
});
|
|
724
|
+
if (typedProps) {
|
|
725
|
+
const typeNode = propsTypeNode(def.props);
|
|
726
|
+
if (hasSlot) {
|
|
727
|
+
typeNode.members.push({
|
|
728
|
+
type: "TSPropertySignature",
|
|
729
|
+
key: "children",
|
|
730
|
+
optional: true,
|
|
731
|
+
typeAnnotation: { type: "TSTypeReference", typeName: "ReactNode" }
|
|
732
|
+
});
|
|
733
|
+
program2.unshift({
|
|
734
|
+
type: "ImportDeclaration",
|
|
735
|
+
importKind: "type",
|
|
736
|
+
specifiers: [
|
|
737
|
+
{
|
|
738
|
+
type: "ImportSpecifier",
|
|
739
|
+
imported: b.identifier("ReactNode"),
|
|
740
|
+
local: b.identifier("ReactNode")
|
|
741
|
+
}
|
|
742
|
+
],
|
|
743
|
+
source: b.literal("react")
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
program2.push({
|
|
747
|
+
type: "TSTypeAliasDeclaration",
|
|
748
|
+
id: b.identifier(propsName),
|
|
749
|
+
typeParameters: [],
|
|
750
|
+
typeNode
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
program2.push({
|
|
754
|
+
type: "ExportNamedDeclaration",
|
|
755
|
+
declaration: component,
|
|
756
|
+
specifiers: [],
|
|
757
|
+
source: null,
|
|
758
|
+
leadingComments: banner
|
|
759
|
+
});
|
|
760
|
+
if (needsInvoke)
|
|
761
|
+
notes.add(
|
|
762
|
+
"`invoke` vem do host: o events-out \xE9 o caminho can\xF4nico de efeito, e o componente nunca v\xEA o servi\xE7o."
|
|
763
|
+
);
|
|
764
|
+
return {
|
|
765
|
+
code: emit(b.program(program2)),
|
|
766
|
+
notes: [...notes]
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
export { ejectComponent, propsTypeNode, typeNodeOf };
|
|
771
|
+
//# sourceMappingURL=index.js.map
|
|
772
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/scope.ts","../src/emit.ts"],"names":["isIsland","property","freeVars","statements","then","body","param","program"],"mappings":"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","file":"index.js","sourcesContent":["// `TypeRef` → type-node do TSLite.\n//\n// O type-node é a camada SINTÁTICA (é dele que o `@tslite/emit` imprime tipo\n// legível e quebrado em linhas); o `Schema` é a semântica, e sai numa linha só.\n// Para uma superfície de props com seis campos, a diferença é entre uma tela e um\n// parágrafo.\nimport type { TypeRef } from \"@loom-forge/forge\";\n\nexport type TypeNode = Record<string, unknown> & { type: string };\n\nconst keyword = (kind: string): TypeNode => ({ type: \"TSKeywordType\", kind });\n\nconst KEYWORDS = [\"string\", \"number\", \"boolean\", \"unknown\", \"any\", \"null\"];\n\ninterface JsonSchemaish {\n type?: string;\n items?: unknown;\n properties?: Record<string, unknown>;\n required?: readonly string[];\n}\n\n/** Traduz o que a declaração escreveu. O que não resolve vira `unknown`, nunca `any`. */\nexport function typeNodeOf(ref: TypeRef | undefined): TypeNode {\n if (ref === undefined) return keyword(\"unknown\");\n\n if (typeof ref === \"string\")\n return KEYWORDS.includes(ref)\n ? keyword(ref)\n : { type: \"TSTypeReference\", typeName: ref };\n\n const schema = ref as JsonSchemaish;\n\n if (schema.type === \"array\")\n return {\n type: \"TSArrayType\",\n elementType: typeNodeOf(schema.items as TypeRef),\n };\n\n if (schema.type === \"object\" && schema.properties)\n return {\n type: \"TSTypeLiteral\",\n members: Object.entries(schema.properties).map(([key, value]) => ({\n type: \"TSPropertySignature\",\n key,\n typeAnnotation: typeNodeOf(value as TypeRef),\n ...(schema.required?.includes(key) ? {} : { optional: true }),\n })),\n };\n\n if (typeof schema.type === \"string\" && KEYWORDS.includes(schema.type))\n return keyword(schema.type);\n\n return keyword(\"unknown\");\n}\n\n/** `nome?` é opcional, TS-like — a mesma regra da declaração (ADR-214). */\nexport function propsTypeNode(\n props: Readonly<Record<string, TypeRef>> | undefined,\n): TypeNode {\n return {\n type: \"TSTypeLiteral\",\n members: Object.entries(props ?? {}).map(([key, ref]) => ({\n type: \"TSPropertySignature\",\n key: key.endsWith(\"?\") ? key.slice(0, -1) : key,\n typeAnnotation: typeNodeOf(ref),\n ...(key.endsWith(\"?\") ? { optional: true } : {}),\n })),\n };\n}\n","// ════════════════════════════════════════════════════════════════════════\n// A tradução de ESCOPO — o que muda quando a expressão sai do JSON e entra num\n// componente React.\n//\n// No JSON o escopo é nomeado por raízes (`props`, `state`, `params`, `ctx`); no\n// TSX, `props` continua um objeto, mas `state` vira uma variável por chave\n// (`useState`) e `params` vira o parâmetro da função da ação. Então `state.count`\n// precisa virar `count`.\n//\n// **Nada disto é travessia nossa.** O clone-com-substituição é o `mutate` do\n// `@tslite/core`, e os nomes livres são o `freeVars` do `@tslite/analysis` — que\n// já sabe o que é ligado, e que `obj.prop` fala de `obj`, não de `prop`.\n// ════════════════════════════════════════════════════════════════════════\n\nimport { mutate, walk } from \"@tslite/core\";\nimport { freeVars } from \"@tslite/analysis\";\n\ninterface MemberLike {\n type: string;\n computed?: boolean;\n object?: { type?: string; name?: string };\n property?: { type?: string; name?: string };\n}\n\nconst isRootAccess =\n (roots: readonly string[]) =>\n (node: unknown): boolean => {\n const n = node as MemberLike;\n return (\n n?.type === \"MemberExpression\" &&\n n.computed !== true &&\n n.object?.type === \"Identifier\" &&\n roots.includes(n.object.name as string) &&\n n.property?.type === \"Identifier\"\n );\n };\n\n/** `raiz.campo` → `campo`, o identificador solto que o TSX usa. */\nexport function unroot(ast: unknown, roots: readonly string[]): unknown {\n return mutate(\n ast as never,\n isRootAccess(roots) as never,\n ((node: MemberLike) => ({\n type: \"Identifier\",\n name: node.property!.name,\n })) as never,\n );\n}\n\ninterface NodeLike {\n type: string;\n name?: string;\n computed?: boolean;\n object?: unknown;\n property?: unknown;\n key?: unknown;\n value?: unknown;\n shorthand?: boolean;\n params?: unknown[];\n}\n\n/**\n * A variável LIVRE `name` → `replacement` — e só ela. O que apenas se parece com o nome fica:\n * a chave de `{ name: 1 }`, a propriedade de `x.name`, e o corpo de uma arrow que liga o mesmo\n * nome (ali, o nome é outro).\n *\n * É o `event` de uma intenção mudando de forma no TSX: o parâmetro do handler no evento,\n * `r.data`/`r.error` num `then`/`catch`, `undefined` depois de um update local.\n */\nexport function rebind(\n ast: unknown,\n name: string,\n replacement: unknown,\n): unknown {\n const isName = (n: unknown): boolean =>\n (n as NodeLike)?.type === \"Identifier\" && (n as NodeLike).name === name;\n const match = (n: unknown): boolean => {\n const node = n as NodeLike;\n return (\n isName(node) ||\n (node?.type === \"MemberExpression\" &&\n node.computed !== true &&\n isName(node.property)) ||\n (node?.type === \"Property\" &&\n node.computed !== true &&\n isName(node.key)) ||\n (node?.type === \"ArrowFunctionExpression\" &&\n (node.params ?? []).some(isName))\n );\n };\n return mutate(\n ast as never,\n match as never,\n ((node: NodeLike): unknown => {\n if (isName(node)) return replacement;\n if (node.type === \"MemberExpression\")\n return { ...node, object: rebind(node.object, name, replacement) };\n if (node.type === \"Property\") {\n // `{ event }` é `{ event: event }`: a chave fica, o valor muda — e a forma abreviada só\n // sobrevive se o valor continuou sendo o mesmo nome\n const value = rebind(node.value, name, replacement);\n return {\n ...node,\n shorthand: node.shorthand === true && isName(value),\n value,\n };\n }\n return node; // a arrow que sombreia: nada dentro dela é este nome\n }) as never,\n );\n}\n\n/**\n * Os nomes que a expressão usa e o componente não declara — operador da stdlib,\n * nome do host. No TSX ejetado eles precisariam de um import que o JSON não tem,\n * e é melhor a bancada dizer isso do que emitir um identificador órfão.\n */\nexport function unresolved(ast: unknown, known: readonly string[]): string[] {\n return [...freeVars(ast as never)].filter((name) => !known.includes(name));\n}\n\n/**\n * O que um handler React LÊ do componente — a lista de dependências de um `useCallback`.\n *\n * A expressão já chega desenraizada (`state.count` → `count`), então uma chave de estado livre\n * é dependência por nome; `props` e `ctx` continuam objetos, e o que entra é o MEMBRO lido\n * (`props.fator`), como o `exhaustive-deps` pede — só um uso bruto (`props` inteiro, ou um acesso\n * computado) põe o objeto. Setter, `params` e a stdlib não entram: o setter é estável, o\n * `params` é argumento, e a stdlib é import.\n */\nexport function reactDeps(\n ast: unknown,\n opts: {\n readonly stateKeys: readonly string[];\n readonly roots?: readonly string[];\n },\n): string[] {\n const free = freeVars(ast as never);\n const deps = new Set<string>();\n for (const root of opts.roots ?? [\"props\", \"ctx\"]) {\n if (!free.has(root)) continue;\n let bare = false;\n const members = new Set<string>();\n walk(ast as never, {\n Identifier: (node, parent) => {\n const id = node as unknown as { name: string };\n if (id.name !== root) return;\n const p = parent as MemberLike | null;\n if (\n p?.type === \"MemberExpression\" &&\n p.object === (node as unknown) &&\n p.computed !== true &&\n p.property?.type === \"Identifier\"\n )\n members.add(`${root}.${p.property.name}`);\n else bare = true;\n },\n });\n if (bare || members.size === 0) deps.add(root);\n else for (const m of members) deps.add(m);\n }\n for (const key of opts.stateKeys) if (free.has(key)) deps.add(key);\n return [...deps].sort();\n}\n","// ════════════════════════════════════════════════════════════════════════\n// O EJECT — a definição JSON vista como o componente React que ela descreve.\n//\n// **Nada de compilador aqui.** Quem imprime é o `@tslite/emit` (o emissor de\n// FONTE do TSLite, contrato invertido do printer de execução: preserva tipo,\n// preserva JSX, imprime comentário, quebra por largura). O que é nosso é o\n// MAPEAMENTO — o que `each` significa em React, o que `state` vira, onde a `key`\n// entra —, e isso ninguém mais sabe.\n//\n// Ele consome a definição **compilada**, e quem compila é o `compileDefinition` do\n// `forge` — a árvore e o que mora fora dela, num lugar só. A fase de compilação já\n// respondeu onde uma ilha começa e termina, e já decidiu que texto interpolado vira\n// template literal: segmentar de novo aqui seria a terceira resposta para a mesma\n// pergunta.\n//\n// É primeira passada e a tradução não cobre tudo — o que ela não alcança sai em\n// `notes`, nunca em silêncio.\n// ════════════════════════════════════════════════════════════════════════\n\nimport * as b from \"@tslite/core/builders\";\nimport { emit } from \"@tslite/emit\";\nimport { s, type Schema } from \"@tslite/type-core\";\nimport { freeVars } from \"@tslite/analysis\";\nimport { compile } from \"@loom-forge/tslite/compile\";\nimport { isExprMarker as isIsland } from \"@tslite/core\";\nimport {\n compileComponent,\n compileDefinition,\n EMPTY_MOUNT,\n isLive,\n mountingOf,\n mountScopesOf,\n settledRoute,\n type IntentRoute,\n type Mounting,\n} from \"@loom-forge/forge\";\nimport type { DefNode, EventBinding } from \"@loom-forge/core\";\nimport type { ComponentDef, EffectDecl, TypeRef } from \"@loom-forge/forge\";\nimport { propsTypeNode } from \"./types\";\nimport { reactDeps, rebind, unresolved, unroot } from \"./scope\";\n\nexport interface Ejected {\n readonly code: string;\n /** o que a tradução NÃO alcançou. Dito em voz alta, nunca omitido. */\n readonly notes: readonly string[];\n}\n\nexport interface EjectOptions {\n /**\n * A montagem do SISTEMA (`mountingOf` do `@loom-forge/forge`) — o que diz que um nome de comando\n * é resolvido em outro lugar: pelo `$slot` de uma sessão, ou por um vocabulário de outro\n * componente.\n *\n * **Ausente = o documento é o sistema.** O que ele declara sai resolvido, e o resto sai como id.\n * Com ela, o que o documento sozinho não determina sai como nome, e a nota diz por quê.\n */\n mounting?: Pick<Mounting, \"slotScopesOf\" | \"vocabulary\">;\n}\n\n/** sem sistema, nenhum `type` é componente conhecido: não há slot, e ninguém declara nada. */\nconst NO_SYSTEM: Pick<Mounting, \"slotScopesOf\" | \"vocabulary\"> = {\n slotScopesOf: () => undefined,\n vocabulary: new Set(),\n};\n\n/** um objeto de dado — nem lista, nem ilha. */\nconst isRecord = (v: unknown): v is Record<string, unknown> =>\n typeof v === \"object\" && v !== null && !Array.isArray(v) && !isIsland(v);\n\n/** Os nós que recebem um campo a mais (tipo, comentário) — o AST é POJO, e esses\n * campos são apagáveis por desenho. */\ntype Extensible = Record<string, unknown>;\n\nconst SCHEMA_OF: Record<string, Schema> = {\n string: s.string,\n number: s.number,\n boolean: s.boolean,\n};\n\nconst schemaOf = (ref: TypeRef | undefined): Schema | undefined =>\n typeof ref === \"string\" ? SCHEMA_OF[ref] : undefined;\n\nconst IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\n\n/** A chave de um objeto: identificador quando pode, string quando precisa. */\nconst keyAst = (key: string): unknown =>\n IDENTIFIER.test(key) ? b.identifier(key) : b.literal(key);\n\n/**\n * Uma propriedade de objeto — em forma ABREVIADA quando a chave e o valor são o mesmo nome.\n *\n * `{ para }` é o que uma pessoa escreve; `{ para: para }` é o que um gerador escreve. A diferença\n * é só de leitura, e ler é o produto deste package.\n */\nconst propAst = (key: string, value: unknown): unknown => {\n const v = value as { type?: string; name?: string };\n const prop = b.property(\n keyAst(key) as never,\n value as never,\n ) as unknown as Record<string, unknown>;\n if (v?.type === \"Identifier\" && v.name === key && IDENTIFIER.test(key))\n prop.shorthand = true;\n return prop;\n};\n\n/** Um ELO de uma intenção: o evento, o efeito, o cleanup, e cada `then`/`catch` (ADR-018). */\ninterface Link {\n readonly action: string;\n readonly params?: unknown;\n readonly then?: EventBinding;\n readonly catch?: EventBinding;\n readonly resolve?: readonly string[];\n}\n\n/** O que a cadeia de uma intenção vira: as sentenças, e se alguma delas ESPERA. */\ninterface Chain {\n readonly statements: unknown[];\n /** há um `await` — o handler que as contém é `async`. */\n readonly awaits: boolean;\n /** o primeiro elo lê `event` — o handler precisa do parâmetro. */\n readonly readsEvent: boolean;\n}\n\n/** `event` depois de um update local e num efeito: nada foi recebido. */\nconst NOTHING = b.identifier(\"undefined\");\n\n/** uma sentença solta quando é uma só; um bloco quando são várias. */\nconst statementOrBlock = (statements: unknown[]): unknown =>\n statements.length === 1\n ? statements[0]\n : b.blockStatement(statements as never);\n\n/** `r.data` / `r.error` — o que o elo seguinte recebe do envelope. */\nconst memberOf = (object: string, property: string): unknown =>\n b.memberExpression(\n b.identifier(object) as never,\n b.identifier(property) as never,\n );\n\nexport function ejectComponent(\n authored: ComponentDef,\n opts: EjectOptions = {},\n): Ejected {\n const notes = new Set<string>();\n\n // a definição COMPILADA — árvore e o que mora fora dela (o `provides`, o `set` de um update,\n // os `params` de um efeito). Quem sabe ONDE é o `forge`; quem sabe TRADUZIR é a linguagem.\n const compiled = compileDefinition(authored, compile);\n const def = compiled.def;\n // o campo que não compilou ficou TEXTO, e vai sair como string no TSX: dito, nunca omitido\n for (const d of compiled.diagnostics)\n notes.add(\n `\\`${d.address}\\` não compila (${d.code}): o campo saiu como o texto que o autor escreveu.`,\n );\n // o corpo com o açúcar do componente: o `provides` e os `commands` dele JUNTAM com os da raiz,\n // como na expansão. É ESTE objeto que a tradução anda — as rotas são por identidade do nó.\n const tree: DefNode = {\n ...def.body,\n ...(def.provides\n ? { provides: { ...def.provides, ...def.body.provides } }\n : {}),\n ...(def.commands\n ? { commands: { ...def.commands, ...def.body.commands } }\n : {}),\n };\n\n const stateKeys = Object.keys(def.state ?? {});\n const hooks = new Set<string>();\n let needsInvoke = false;\n /* `pending` é raiz da INSTÂNCIA viva (ADR-018): existe num componente com `updates` ou\n `effects`, e aqui é um `useState` do próprio componente. Ele só vale a declaração — e o\n marcar em volta de cada despacho ao host — quando alguma expressão o lê; sem leitura, o\n estado seria uma variável que ninguém usa. Decidido ANTES de traduzir, porque a forma de\n cada handler depende disto. */\n const live = isLive(def);\n const readsPending =\n live &&\n compiled.islands.some((i) => freeVars(i.node as never).has(\"pending\"));\n /** alguém lê `props`? Então o componente precisa do parâmetro, tenha o autor declarado props ou não. */\n let usesProps = false;\n /** há um `$slot`? Então as props têm `children`, e o tipo precisa dizer. */\n let hasSlot = false;\n\n /* O que cada intenção EXECUTA — a rota do forge, nos degraus da expansão. O TSX só traduz o\n que o PRÓPRIO documento determina: uma rota que muda quando o sistema entra (o `$slot` de uma\n sessão, um vocabulário de outro componente) depende de onde este componente monta, e ali o\n React precisaria de um vocabulário de comando do host. */\n const routing = {\n updates: new Set(Object.keys(def.updates ?? {})),\n vocabulary: new Set([\n ...mountingOf([\n compileComponent(authored, {\n components: new Set([authored.component]),\n }),\n ]).vocabulary,\n ...(opts.mounting?.vocabulary ?? []),\n ]),\n };\n const alone = mountScopesOf(tree, NO_SYSTEM);\n const mounted = opts.mounting ? mountScopesOf(tree, opts.mounting) : alone;\n\n /** a rota que vale igual com e sem o sistema — `undefined` quando o documento não a decide. */\n const routeOf = (action: string, node?: DefNode): IntentRoute | undefined =>\n settledRoute(\n action,\n node === undefined\n ? [EMPTY_MOUNT] // o efeito: só o lugar onde o componente montou\n : [...(alone.get(node) ?? []), ...(mounted.get(node) ?? [])],\n routing,\n );\n\n const setterOf = (key: string): string =>\n `set${key.charAt(0).toUpperCase()}${key.slice(1)}`;\n\n /**\n * Um valor de campo: ilha vira expressão, e o resto é dado — **em qualquer\n * profundidade**.\n *\n * A recursão é o ponto. Uma ilha mora DENTRO de um objeto com frequência (os\n * `params` de um evento são `{ email: \"{{ … }}\" }`), e uma travessia separada\n * para \"JSON puro\" imprimia o marcador `#expr` como se fosse chave de objeto. É\n * a mesma lição da tabela de slots: duas travessias sobre a mesma forma\n * divergem, e a divergência é silenciosa.\n */\n const valueAst = (value: unknown, bound: readonly string[]): unknown => {\n if (Array.isArray(value))\n return b.arrayExpression(\n value.map((item) => valueAst(item, bound)) as never,\n );\n\n if (!isIsland(value)) {\n if (value && typeof value === \"object\")\n return b.objectExpression(\n Object.entries(value).map(([key, v]) =>\n propAst(key, valueAst(v, bound)),\n ) as never,\n );\n return b.literal(value as never);\n }\n\n // `state.x` vira `x` porque o TSX tem uma variável por chave; `params.x` FICA, porque o\n // parâmetro emitido é o objeto `params` — desenraizar ali produziria um nome que não existe.\n const ast = unroot(b.fromExprMarker(value as never), [\"state\"]);\n const free = unresolved(ast, []);\n if (free.includes(\"props\")) usesProps = true;\n const known = new Set([\n \"props\",\n \"ctx\",\n ...stateKeys,\n ...(live ? [\"pending\"] : []),\n ...bound,\n ]);\n for (const name of free.filter((n) => !known.has(n)))\n notes.add(\n `\\`${name}\\` não é raiz nem item de laço: vem da stdlib ou do host, e no TSX precisaria de um import que o JSON não declara.`,\n );\n return ast;\n };\n\n /**\n * Os params de uma intenção: o que o alias liga POR BAIXO e o que ela escreve por cima (quem\n * dispara é mais específico que quem declarou o vocabulário). Dentro deles `event` é raiz — o\n * que o elo recebeu —, e aqui ele toma a forma que tem no TSX (`received`).\n */\n const paramsAst = (\n route: IntentRoute | undefined,\n written: unknown,\n bound: readonly string[],\n received: unknown,\n ): unknown => {\n const scope = [...bound, \"event\"];\n const aliased =\n route !== undefined && route.kind !== \"command\" && isRecord(route.bound)\n ? route.bound\n : undefined;\n let ast: unknown;\n if (aliased === undefined)\n ast = written === undefined ? undefined : valueAst(written, scope);\n else {\n const props: unknown[] = [];\n for (const [key, value] of Object.entries(aliased))\n if (!(isRecord(written) && key in written))\n props.push(propAst(key, valueAst(value, scope)));\n if (isRecord(written))\n for (const [key, value] of Object.entries(written))\n props.push(propAst(key, valueAst(value, scope)));\n // uma expressão inteira não se abre em chaves aqui: ela ESPALHA por cima, como no runtime\n else if (written !== undefined)\n props.push(b.spreadElement(valueAst(written, scope) as never));\n ast = b.objectExpression(props as never);\n }\n return ast === undefined ? undefined : rebind(ast, \"event\", received);\n };\n\n /** `setPending((p) => ({ ...p, \"x/y\": flag }))` — o pendente da instância, como o motor marca. */\n const pendingAst = (id: string, flag: boolean): unknown =>\n b.expressionStatement(\n b.callExpression(\n b.identifier(\"setPending\") as never,\n [\n b.arrowFunctionExpression(\n [b.identifier(\"p\")] as never,\n b.objectExpression([\n b.spreadElement(b.identifier(\"p\") as never),\n propAst(id, b.literal(flag)),\n ] as never) as never,\n ),\n ] as never,\n ) as never,\n );\n\n /**\n * Uma intenção e a cadeia dela, como sentenças — a leitura de uma promise chain (ADR-018).\n *\n * Update local vira chamada, e o `then` dele vem em seguida com `event` = `undefined`. O que\n * sai vai ao host pelo id resolvido; com `then`/`catch`, o resultado é esperado e lido pelo\n * envelope: `if (!r.success) <catch> else if (!r.aborted) <then>` — o `catch` recebe `r.error`,\n * o `then` recebe `r.data`, e um fluxo cancelado (`aborted` com sucesso) não roda nenhum, como\n * no motor. O nome que o documento não decide sai como está, com a nota.\n *\n * `received` é o que ESTE elo recebeu, já na forma do TSX; `depth` numera o envelope de um elo\n * aninhado (`r`, `r2`, …) para os ramos não sombrearem o de fora.\n */\n const chainAst = (\n link: Link,\n node: DefNode | undefined,\n bound: readonly string[],\n received: unknown,\n depth: number,\n ): Chain => {\n const route = routeOf(link.action, node);\n const params = paramsAst(route, link.params, bound, received);\n const args = params === undefined ? [] : [params];\n const readsEvent =\n params !== undefined && freeVars(params as never).has(\"event\");\n\n // o `resolve` não vira código: quem preenche aqueles params é a camada de COMANDO, em\n // runtime. O TSX sai sem eles de propósito, e a nota diz por quê — senão quem lê conclui\n // que a chamada está incompleta.\n if (link.resolve?.length)\n notes.add(\n `\\`${link.resolve.join(\"`, `\")}\\`: a camada de comando resolve (token, default ou perguntando), então o TSX não os passa.`,\n );\n\n if (route?.kind === \"update\") {\n const statements: unknown[] = [\n b.expressionStatement(\n b.callExpression(\n b.identifier(route.action) as never,\n args as never,\n ) as never,\n ),\n ];\n if (link.then === undefined)\n return { statements, awaits: false, readsEvent };\n // \"resolveu\" = o estado foi escrito: o `then` vem em seguida, sem ter recebido nada\n const then = chainAst(link.then, node, bound, NOTHING, depth);\n return {\n statements: [...statements, ...then.statements],\n awaits: then.awaits,\n readsEvent,\n };\n }\n\n if (route?.kind !== \"action\")\n notes.add(\n `\\`${link.action}\\` é um nome de COMANDO que este documento não resolve: o que ele executa depende de onde o componente monta, e o TSX o passa como está — no React, isso pediria um vocabulário de comando do host.`,\n );\n needsInvoke = true;\n const id = route?.kind === \"action\" ? route.action : link.action;\n const invoke = b.callExpression(\n b.identifier(\"invoke\") as never,\n [b.literal(id), ...args] as never,\n );\n const chained = link.then !== undefined || link.catch !== undefined;\n if (!chained && !readsPending)\n return {\n statements: [b.expressionStatement(invoke as never)],\n awaits: false,\n readsEvent,\n };\n\n const statements: unknown[] = [];\n const result = depth === 0 ? \"r\" : `r${depth + 1}`;\n if (readsPending) statements.push(pendingAst(id, true));\n const awaited = b.awaitExpression(invoke as never);\n statements.push(\n chained\n ? b.variableDeclaration(\"const\", [\n b.variableDeclarator(\n b.identifier(result) as never,\n awaited as never,\n ),\n ] as never)\n : b.expressionStatement(awaited as never),\n );\n if (readsPending) statements.push(pendingAst(id, false));\n\n const then =\n link.then &&\n chainAst(link.then, node, bound, memberOf(result, \"data\"), depth + 1);\n const failed =\n link.catch &&\n chainAst(link.catch, node, bound, memberOf(result, \"error\"), depth + 1);\n const success = memberOf(result, \"success\");\n const notAborted = b.unaryExpression(\n \"!\",\n memberOf(result, \"aborted\") as never,\n );\n const onThen =\n then &&\n b.ifStatement(\n notAborted as never,\n statementOrBlock(then.statements) as never,\n );\n if (failed)\n statements.push(\n b.ifStatement(\n b.unaryExpression(\"!\", success as never) as never,\n statementOrBlock(failed.statements) as never,\n (onThen ?? null) as never,\n ),\n );\n else if (then)\n statements.push(\n b.ifStatement(\n b.logicalExpression(\n \"&&\",\n success as never,\n notAborted as never,\n ) as never,\n statementOrBlock(then.statements) as never,\n ),\n );\n\n return { statements, awaits: true, readsEvent };\n };\n\n /**\n * O handler de um evento: `(event) => …` quando a intenção lê o que o widget emitiu, `() => …`\n * quando ignora; `async` quando a cadeia espera. Uma sentença só sai como expressão — é o que\n * uma pessoa escreve.\n */\n const handlerAst = (chain: Chain): unknown => {\n const params = chain.readsEvent ? [b.identifier(\"event\")] : [];\n const single = chain.statements[0] as {\n type: string;\n expression?: unknown;\n };\n const body =\n chain.statements.length === 1 &&\n !chain.awaits &&\n single.type === \"ExpressionStatement\"\n ? single.expression\n : b.blockStatement(chain.statements as never);\n return b.arrowFunctionExpression(\n params as never,\n body as never,\n chain.awaits,\n );\n };\n\n /**\n * O corpo de um efeito (e do cleanup dele): o callback do `useEffect` não pode ser `async`,\n * então uma cadeia que espera roda numa IIFE — `void (async () => { … })()`.\n */\n const effectStatements = (chain: Chain): unknown[] =>\n chain.awaits\n ? [\n b.expressionStatement(\n b.unaryExpression(\n \"void\",\n b.callExpression(\n b.arrowFunctionExpression(\n [],\n b.blockStatement(chain.statements as never) as never,\n true,\n ) as never,\n [] as never,\n ) as never,\n ) as never,\n ),\n ]\n : chain.statements;\n\n // ── a árvore ──────────────────────────────────────────────────────────────\n\n const attrsOf = (node: DefNode, bound: readonly string[]): unknown[] => {\n const out: unknown[] = [];\n\n for (const [name, value] of Object.entries(node.props ?? {})) {\n if (name === \"children\") continue; // vira FILHO, não atributo\n out.push(\n b.jsxAttribute(\n b.jsxIdentifier(name) as never,\n typeof value === \"string\" && !isIsland(value)\n ? (b.literal(value) as never)\n : (b.jsxExpressionContainer(\n valueAst(value, bound) as never,\n ) as never),\n ),\n );\n }\n\n // o que o widget emite é o `event` do primeiro elo — o parâmetro do handler\n for (const [name, binding] of Object.entries(node.events ?? {}))\n out.push(\n b.jsxAttribute(\n b.jsxIdentifier(name) as never,\n b.jsxExpressionContainer(\n handlerAst(\n chainAst(binding, node, bound, b.identifier(\"event\"), 0),\n ) as never,\n ) as never,\n ),\n );\n\n if (node.placement !== undefined)\n notes.add(\n \"`placement` não tem tradução direta: quem posiciona é o renderer do layout, e no TSX isso vira markup do arranjo.\",\n );\n if (node.layout !== undefined)\n notes.add(\n `o layout \\`${node.layout}\\` é do renderer: o TSX abaixo mostra os filhos, não o arranjo que o planner calcula.`,\n );\n if (node.provides !== undefined)\n notes.add(\n \"`provides` ainda não é traduzido — seria um Provider ao redor.\",\n );\n if (node.commands !== undefined)\n notes.add(\n \"`commands` instala vocabulário para o que monta abaixo: o que este documento resolve sai resolvido no TSX, mas quem monta aqui vindo de fora (filhos de slot, componentes compostos) precisaria de um vocabulário de comando do host.\",\n );\n\n return out;\n };\n\n const childrenOf = (node: DefNode, bound: readonly string[]): unknown[] => {\n const out: unknown[] = [];\n const text = node.props?.children;\n\n if (text !== undefined)\n out.push(\n typeof text === \"string\" && !isIsland(text)\n ? (b.jsxText(text) as never)\n : (b.jsxExpressionContainer(valueAst(text, bound) as never) as never),\n );\n\n if (text !== undefined && (node.children?.length ?? 0) > 0)\n notes.add(\n \"este nó tem `props.children` E filhos na árvore: no motor a árvore sobrescreve a prop, em silêncio (está no `TODO.md`).\",\n );\n\n for (const child of node.children ?? []) out.push(...jsxOf(child, bound));\n\n return out;\n };\n\n /** Um nó → os filhos JSX que ele produz (zero, um, ou um laço). */\n function jsxOf(node: DefNode, bound: readonly string[]): unknown[] {\n if (node.type === \"$slot\") {\n usesProps = true;\n hasSlot = true;\n return [\n b.jsxExpressionContainer(\n b.memberExpression(\n b.identifier(\"props\") as never,\n b.identifier(\"children\") as never,\n ) as never,\n ),\n ];\n }\n\n const item = node.as;\n const inner = item ? [...bound, item, \"index\"] : bound;\n const name = node.el ?? node.type ?? \"div\";\n\n const attrs = attrsOf(node, inner);\n const kids = childrenOf(node, inner);\n\n // a key repete a identidade que o motor dá ao nó repetido: `item.id ?? índice`\n if (item)\n attrs.unshift(\n b.jsxAttribute(\n b.jsxIdentifier(\"key\") as never,\n b.jsxExpressionContainer(\n b.logicalExpression(\n \"??\",\n b.memberExpression(\n b.identifier(item) as never,\n b.identifier(\"id\") as never,\n ) as never,\n b.identifier(\"index\") as never,\n ) as never,\n ) as never,\n ),\n );\n\n let element: unknown = b.jsxElement(\n b.jsxOpeningElement(\n b.jsxIdentifier(name) as never,\n attrs as never,\n kids.length === 0,\n ) as never,\n kids as never,\n kids.length === 0\n ? null\n : (b.jsxClosingElement(b.jsxIdentifier(name) as never) as never),\n );\n\n // `when` é POR ITEM quando há laço: o motor dropa a cópia, não a lista\n if (node.when !== undefined)\n element = b.logicalExpression(\n \"&&\",\n valueAst(node.when, inner) as never,\n element as never,\n );\n\n if (node.each !== undefined) {\n element = b.callExpression(\n b.memberExpression(\n valueAst(node.each, bound) as never,\n b.identifier(\"map\") as never,\n ) as never,\n [\n b.arrowFunctionExpression(\n [b.identifier(item ?? \"item\"), b.identifier(\"index\")] as never,\n element as never,\n ),\n ] as never,\n );\n }\n\n const isExpression = node.when !== undefined || node.each !== undefined;\n return [\n isExpression\n ? b.jsxExpressionContainer(element as never)\n : (element as never),\n ];\n }\n\n // ── o corpo do componente ─────────────────────────────────────────────────\n\n const body: unknown[] = [];\n\n if (def.context?.uses?.length) {\n hooks.add(\"useContext\");\n body.push(\n b.variableDeclaration(\"const\", [\n b.variableDeclarator(\n b.identifier(\"ctx\") as never,\n b.callExpression(\n b.identifier(\"useContext\") as never,\n [b.identifier(\"HostContext\")] as never,\n ) as never,\n ),\n ] as never),\n );\n notes.add(\n `contexto: \\`${def.context.uses.join(\"`, `\")}\\` — no motor ele viaja pela expansão; aqui é um React Context do host.`,\n );\n }\n\n for (const [key, decl] of Object.entries(def.state ?? {})) {\n hooks.add(\"useState\");\n const call = b.callExpression(\n b.identifier(\"useState\") as never,\n [valueAst(decl.init, [])] as never,\n ) as unknown as Extensible;\n const schema = schemaOf(decl.type);\n if (schema) call.typeArguments = [schema];\n body.push(\n b.variableDeclaration(\"const\", [\n b.variableDeclarator(\n b.arrayPattern([\n b.identifier(key),\n b.identifier(setterOf(key)),\n ] as never) as never,\n call as never,\n ),\n ] as never),\n );\n }\n\n // o pendente da instância: `true` do despacho ao resultado, por ação — o que o motor guarda no\n // boundary, aqui é estado do próprio componente\n if (readsPending) {\n hooks.add(\"useState\");\n const call = b.callExpression(\n b.identifier(\"useState\") as never,\n [b.objectExpression([])] as never,\n ) as unknown as Extensible;\n // `Record<string, boolean>` — o nome que o motor usa, não a assinatura de índice equivalente\n call.typeArguments = [\n { t: \"apply\", name: \"Record\", args: [s.string, s.boolean] },\n ];\n body.push(\n b.variableDeclaration(\"const\", [\n b.variableDeclarator(\n b.arrayPattern([\n b.identifier(\"pending\"),\n b.identifier(\"setPending\"),\n ] as never) as never,\n call as never,\n ),\n ] as never),\n );\n }\n\n for (const [name, action] of Object.entries(def.updates ?? {})) {\n const param = b.identifier(\"params\") as unknown as Extensible;\n const declared = action.params;\n if (declared) {\n const fields = Object.fromEntries(\n Object.entries(declared)\n .map(([key, ref]) => [key, schemaOf(ref)])\n .filter(([, schema]) => schema) as [string, Schema][],\n );\n if (Object.keys(fields).length)\n param.typeAnnotation = s.object(\n Object.fromEntries(\n Object.entries(fields).map(([key, type]) => [key, { type }]),\n ) as never,\n );\n }\n\n /* O handler desce como prop, então é `useCallback` — e as dependências saem do que cada\n `set` LÊ, como o `exhaustive-deps` pediria. A chave que o `set` escreve e também lê vira\n functional update (`setCount((count) => count + params.n)`): é a forma que não perde um\n incremento quando dois disparos entram no mesmo batch, e tira a chave das deps. O que\n resta — `props.x`, `ctx.x`, OUTRA chave de estado — entra na lista; o setter é estável e\n `params` é argumento, então nenhum dos dois entra. */\n const deps = new Set<string>();\n const writes = Object.entries(action.set ?? {}).map(([key, value]) => {\n let expr = valueAst(value, []);\n for (const dep of reactDeps(expr, { stateKeys })) {\n if (dep === key)\n expr = b.arrowFunctionExpression(\n [b.identifier(key)] as never,\n expr as never,\n );\n else deps.add(dep);\n }\n return b.expressionStatement(\n b.callExpression(\n b.identifier(setterOf(key)) as never,\n [expr] as never,\n ) as never,\n );\n });\n if ([...deps].some((dep) => dep.startsWith(\"props\"))) usesProps = true;\n\n hooks.add(\"useCallback\");\n body.push(\n b.variableDeclaration(\"const\", [\n b.variableDeclarator(\n b.identifier(name) as never,\n b.callExpression(\n b.identifier(\"useCallback\") as never,\n [\n b.arrowFunctionExpression(\n (declared ? [param] : []) as never,\n b.blockStatement(writes as never) as never,\n ),\n b.arrayExpression(\n [...deps].sort().map((dep) =>\n dep\n .split(\".\")\n .map((part) => b.identifier(part))\n .reduce(\n (acc, part) =>\n b.memberExpression(\n acc as never,\n part as never,\n ) as never,\n ),\n ) as never,\n ),\n ] as never,\n ) as never,\n ),\n ] as never),\n );\n }\n\n for (const [name, effect] of Object.entries(\n (def.effects ?? {}) as Record<string, EffectDecl>,\n )) {\n hooks.add(\"useEffect\");\n const deps = (effect.on ?? []).map((path) => {\n const [root, ...rest] = path.split(\".\");\n if (root === \"props\") usesProps = true;\n const head: unknown =\n root === \"state\"\n ? b.identifier(rest.shift() ?? \"\")\n : b.identifier(root);\n return rest.reduce<unknown>(\n (acc, part) =>\n b.memberExpression(acc as never, b.identifier(part) as never),\n head,\n );\n });\n\n // o efeito é intenção do COMPONENTE: a rota é a do lugar onde ele montou (sem nó), e ele\n // não recebe nada — o `event` dele é `undefined`\n const statements: unknown[] = effectStatements(\n chainAst(effect, undefined, [], NOTHING, 0),\n );\n // o cleanup é uma função síncrona para o React: uma cadeia que espera roda na IIFE dela\n if (effect.cleanup)\n statements.push(\n b.returnStatement(\n handlerAst({\n statements: effectStatements(\n chainAst(effect.cleanup, undefined, [], NOTHING, 0),\n ),\n awaits: false,\n readsEvent: false,\n }) as never,\n ),\n );\n\n const call = b.callExpression(\n b.identifier(\"useEffect\") as never,\n [\n b.arrowFunctionExpression(\n [],\n b.blockStatement(statements as never) as never,\n ),\n b.arrayExpression(deps as never),\n ] as never,\n ) as unknown as Extensible;\n call.leadingComments = [{ type: \"Line\", value: ` efeito \\`${name}\\`` }];\n body.push(b.expressionStatement(call as never));\n }\n\n // o JSX ANTES do prelúdio: é traduzindo a árvore que se descobre se um evento invoca e se\n // alguém lê `props`. Decidir o prelúdio antes perderia os dois, e o TSX não compilaria.\n const rendered = jsxOf(tree, []);\n const returned =\n rendered.length === 1 ? rendered[0] : b.jsxFragment(rendered as never);\n\n if (needsInvoke) {\n body.unshift(\n b.variableDeclaration(\"const\", [\n b.variableDeclarator(\n b.objectPattern([\n propAst(\"invoke\", b.identifier(\"invoke\")),\n ] as never) as never,\n b.callExpression(\n b.identifier(\"useActions\") as never,\n [] as never,\n ) as never,\n ),\n ] as never),\n );\n }\n\n // ── o módulo ──────────────────────────────────────────────────────────────\n\n const propsName = `${def.component}Props`;\n const hasProps = Object.keys(def.props ?? {}).length > 0;\n\n /* O parâmetro é ANOTADO sempre que o componente lê `props` — declarado ou não. Sem props\n declaradas o tipo é `{}` (ou só `children`, se há slot): um `props.x` que o autor escreveu\n sem declarar é erro de TIPO no TSX, o mesmo que o `check` acusa, e não um `any` implícito. */\n const typedProps = hasProps || usesProps || hasSlot;\n const param = b.identifier(\"props\") as unknown as Extensible;\n if (typedProps)\n param.typeAnnotation = { t: \"apply\", name: propsName, args: [] };\n\n const component = b.variableDeclaration(\"const\", [\n b.variableDeclarator(\n b.identifier(def.component) as never,\n b.arrowFunctionExpression(\n (hasProps || usesProps ? [param] : []) as never,\n body.length === 0\n ? (returned as never)\n : (b.blockStatement([\n ...body,\n b.returnStatement(returned as never),\n ] as never) as never),\n ) as never,\n ),\n ] as never) as unknown as Extensible;\n\n // O comentário vai no nó do EXPORT, não no do `const`: ancorado no de dentro,\n // ele sai IMPRESSO entre `export` e `const` — compila, e lê torto.\n const banner = [\n {\n type: \"Block\",\n value: `*\\n * ${def.component} — emitido da definição JSON.\\n *\\n * Porta de MÃO ÚNICA: editar este arquivo não volta para o JSON.\\n `,\n },\n ];\n\n const program: unknown[] = [];\n\n if (hooks.size)\n program.push({\n type: \"ImportDeclaration\",\n specifiers: [...hooks].sort().map((name) => ({\n type: \"ImportSpecifier\",\n imported: b.identifier(name),\n local: b.identifier(name),\n })),\n source: b.literal(\"react\"),\n });\n\n if (needsInvoke || hooks.has(\"useContext\"))\n program.push({\n type: \"ImportDeclaration\",\n specifiers: [\n ...(needsInvoke\n ? [\n {\n type: \"ImportSpecifier\",\n imported: b.identifier(\"useActions\"),\n local: b.identifier(\"useActions\"),\n },\n ]\n : []),\n ...(hooks.has(\"useContext\")\n ? [\n {\n type: \"ImportSpecifier\",\n imported: b.identifier(\"HostContext\"),\n local: b.identifier(\"HostContext\"),\n },\n ]\n : []),\n ],\n source: b.literal(\"./host\"),\n });\n\n if (typedProps) {\n const typeNode = propsTypeNode(def.props);\n // o `$slot` é `props.children`: o tipo diz, e o `ReactNode` entra como import de tipo\n if (hasSlot) {\n (typeNode.members as unknown[]).push({\n type: \"TSPropertySignature\",\n key: \"children\",\n optional: true,\n typeAnnotation: { type: \"TSTypeReference\", typeName: \"ReactNode\" },\n });\n program.unshift({\n type: \"ImportDeclaration\",\n importKind: \"type\",\n specifiers: [\n {\n type: \"ImportSpecifier\",\n imported: b.identifier(\"ReactNode\"),\n local: b.identifier(\"ReactNode\"),\n },\n ],\n source: b.literal(\"react\"),\n });\n }\n program.push({\n type: \"TSTypeAliasDeclaration\",\n id: b.identifier(propsName),\n typeParameters: [],\n typeNode,\n });\n }\n\n program.push({\n type: \"ExportNamedDeclaration\",\n declaration: component,\n specifiers: [],\n source: null,\n leadingComments: banner,\n });\n\n if (needsInvoke)\n notes.add(\n \"`invoke` vem do host: o events-out é o caminho canônico de efeito, e o componente nunca vê o serviço.\",\n );\n\n return {\n code: emit(b.program(program as never) as never),\n notes: [...notes],\n };\n}\n\n/** O tipo de um `TypeRef` isolado, para quem quiser mostrar a declaração. */\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@loom-forge/eject",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "eject · a definição JSON traduzida para o componente React que ela descreve — o MAPEAMENTO (o que `each` significa em React); quem imprime é o @tslite/emit.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"react",
|
|
8
|
+
"codegen",
|
|
9
|
+
"tsx",
|
|
10
|
+
"eject",
|
|
11
|
+
"json",
|
|
12
|
+
"dsl"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"author": {
|
|
16
|
+
"name": "Anderson D. Rosa",
|
|
17
|
+
"url": "https://github.com/andersondrosa"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/andersondrosa/loom-forge.git",
|
|
22
|
+
"directory": "packages/eject"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/andersondrosa/loom-forge/tree/main/packages/eject#readme",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/andersondrosa/loom-forge/issues"
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"sideEffects": false,
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"import": "./dist/index.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist"
|
|
40
|
+
],
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@tslite/analysis": "^0.2.14",
|
|
43
|
+
"@tslite/core": "^0.11.0",
|
|
44
|
+
"@tslite/emit": "^0.1.7",
|
|
45
|
+
"@tslite/type-core": "^0.6.0",
|
|
46
|
+
"@loom-forge/core": "0.1.0",
|
|
47
|
+
"@loom-forge/tslite": "0.1.0",
|
|
48
|
+
"@loom-forge/forge": "0.1.0"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"tsup": "^8.0.0",
|
|
52
|
+
"typescript": "^5.9.3"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "tsup",
|
|
56
|
+
"dev": "tsup --watch",
|
|
57
|
+
"test": "vitest run",
|
|
58
|
+
"test:watch": "vitest",
|
|
59
|
+
"typecheck": "tsc --noEmit",
|
|
60
|
+
"clean": "rm -rf dist"
|
|
61
|
+
}
|
|
62
|
+
}
|