@orkastery/cli 0.4.3 → 0.5.1

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.
Files changed (146) hide show
  1. package/adapters/README.md +11 -0
  2. package/adapters/claude-code/.claude-plugin/plugin.json +3 -1
  3. package/adapters/claude-code/README.md +11 -2
  4. package/adapters/claude-code/agents/ork-check.md +1 -1
  5. package/adapters/claude-code/agents/ork-go.md +2 -2
  6. package/adapters/claude-code/agents/ork-goal.md +1 -1
  7. package/adapters/claude-code/agents/ork-master.md +1 -1
  8. package/adapters/claude-code/agents/ork-plan.md +1 -1
  9. package/adapters/claude-code/agents/ork-ship.md +1 -1
  10. package/adapters/claude-code/commands/master.md +11 -8
  11. package/adapters/claude-code/commands/onboarding.md +3 -2
  12. package/adapters/claude-code/commands/ork.md +8 -0
  13. package/adapters/claude-code/commands/ship.md +2 -2
  14. package/adapters/codex/skills/ork/SKILL.md +12 -1
  15. package/adapters/hermes/README.md +3 -0
  16. package/adapters/hermes/bin/ork-abrir-thread.sh +17 -2
  17. package/adapters/hermes/bin/ork-brain.sh +3 -0
  18. package/adapters/hermes/bin/ork-maestro.sh +4 -1
  19. package/adapters/hermes/bin/ork-network-roadmap.sh +11 -0
  20. package/adapters/hermes/bin/ork-roadmap-status.sh +9 -0
  21. package/adapters/hermes/hermes.plugin.json +2 -0
  22. package/adapters/hermes/hitl-ingress/__init__.py +36 -3
  23. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +19 -20
  24. package/adapters/openclaw/README.md +45 -2
  25. package/adapters/openclaw/dist/hitl-ingress.js +37 -3
  26. package/adapters/openclaw/dist/index.js +93 -21
  27. package/adapters/openclaw/openclaw.plugin.json +10 -1
  28. package/adapters/openclaw/package.json +2 -2
  29. package/adapters/openclaw/src/hitl-ingress.ts +32 -3
  30. package/adapters/openclaw/src/index.ts +109 -21
  31. package/assets/docs/padroes/documentacao-de-produto.md +2 -2
  32. package/assets/docs/padroes/roadmap-de-produto.md +1 -1
  33. package/assets/docs/produto/_modelo-feature.md +2 -0
  34. package/assets/orkmind_bridge.py +214 -1
  35. package/dist/adapters/claude-bg.js +24 -7
  36. package/dist/auditrun.js +1 -1
  37. package/dist/board.js +74 -0
  38. package/dist/branch-de-estado.js +5 -4
  39. package/dist/busca-semantica.js +161 -0
  40. package/dist/ci.js +141 -10
  41. package/dist/claim-lint.js +3 -1
  42. package/dist/company-brain-cli.js +27 -2
  43. package/dist/company-brain-context.js +132 -0
  44. package/dist/company-brain-dossie.js +376 -0
  45. package/dist/company-brain-mcp.js +4 -1
  46. package/dist/conducao.js +71 -18
  47. package/dist/decisao-autonoma.js +42 -0
  48. package/dist/docs.js +135 -25
  49. package/dist/doctor.js +242 -32
  50. package/dist/entrega-pr.js +116 -5
  51. package/dist/experiencia-instalacao.js +256 -0
  52. package/dist/experiencia.js +72 -0
  53. package/dist/fabrica-estado.js +63 -12
  54. package/dist/fechamento.js +105 -0
  55. package/dist/fix.js +3 -3
  56. package/dist/forja.js +435 -0
  57. package/dist/gates.js +9 -1
  58. package/dist/hitl-classificacao.js +11 -1
  59. package/dist/hitl-contract.js +50 -7
  60. package/dist/hitl-curto.js +158 -0
  61. package/dist/hitl-gates.js +67 -1
  62. package/dist/hitl-lote.js +30 -15
  63. package/dist/hitl-presentation.js +10 -7
  64. package/dist/hitl-resumo.js +57 -13
  65. package/dist/hitl-texto-livre.js +150 -0
  66. package/dist/hosts.js +92 -3
  67. package/dist/index.js +637 -45
  68. package/dist/indice-vetorial.js +317 -0
  69. package/dist/init.js +24 -5
  70. package/dist/integracoes-locais.js +3 -1
  71. package/dist/intelligence-benchmark-contract.js +570 -0
  72. package/dist/intelligence-graph-cli.js +584 -0
  73. package/dist/intelligence-graph-contract.js +636 -0
  74. package/dist/intelligence-graph-extract-md.js +487 -0
  75. package/dist/intelligence-graph-extract-ts.js +980 -0
  76. package/dist/intelligence-graph-extract.js +546 -0
  77. package/dist/intelligence-graph-index.js +693 -0
  78. package/dist/intelligence-graph-parsers.js +327 -0
  79. package/dist/intelligence-graph-query.js +344 -0
  80. package/dist/intelligence-graph-repo.js +197 -0
  81. package/dist/leases.js +100 -0
  82. package/dist/ledger.js +23 -0
  83. package/dist/licoes.js +5 -4
  84. package/dist/liveness.js +2 -1
  85. package/dist/maestro-cli.js +10 -1
  86. package/dist/maestro-contract.js +5 -1
  87. package/dist/maestro-discovery.js +16 -2
  88. package/dist/maestro-runtime.js +3 -0
  89. package/dist/maestro-snapshot.js +6 -2
  90. package/dist/manifest.js +166 -5
  91. package/dist/master-batch.js +3 -2
  92. package/dist/master-digest.js +2 -2
  93. package/dist/master-nota.js +203 -0
  94. package/dist/master.js +4 -0
  95. package/dist/mcp-artifacts.js +2 -0
  96. package/dist/mcp-experiencia.js +164 -0
  97. package/dist/mcp-git.js +64 -12
  98. package/dist/mcp-grafo-worker.js +91 -0
  99. package/dist/mcp-grafo.js +233 -0
  100. package/dist/mcp-install.js +5 -2
  101. package/dist/mcp-maestro.js +3 -2
  102. package/dist/mcp-server.js +93 -5
  103. package/dist/mcp-ship.js +2 -0
  104. package/dist/mcp-verify.js +3 -1
  105. package/dist/memoria.js +147 -1
  106. package/dist/network-roadmap.js +907 -0
  107. package/dist/ocupacao.js +43 -3
  108. package/dist/onboarding.js +122 -11
  109. package/dist/orkmind.js +165 -9
  110. package/dist/orquestracao.js +2 -1
  111. package/dist/parado-no-condutor.js +933 -0
  112. package/dist/phase.js +166 -13
  113. package/dist/policies.js +29 -2
  114. package/dist/projeto-alvo.js +551 -0
  115. package/dist/prompts.js +1 -1
  116. package/dist/prova-ativacao.js +345 -0
  117. package/dist/pulse-consentimento.js +4 -2
  118. package/dist/pulse-delivery.js +32 -6
  119. package/dist/pulse-resposta.js +674 -49
  120. package/dist/pulse.js +74 -3
  121. package/dist/retry.js +51 -8
  122. package/dist/roadmap-reservas.js +262 -20
  123. package/dist/roadmap-status.js +348 -0
  124. package/dist/runtime-context.js +5 -1
  125. package/dist/sessoes-inventario.js +7 -1
  126. package/dist/sessoes.js +4 -1
  127. package/dist/ship.js +25 -1
  128. package/dist/thread-close.js +3 -0
  129. package/dist/thread.js +21 -2
  130. package/dist/util.js +71 -4
  131. package/dist/verify.js +6 -5
  132. package/dist/worktree.js +29 -6
  133. package/eval/casos/onboarding.json +1 -1
  134. package/eval/casos/orchestration-experience-pt-br.json +48 -0
  135. package/eval/casos/orchestration-experience.json +48 -0
  136. package/package.json +1 -1
  137. package/schemas/code-artifact-graph.v1.schema.json +581 -0
  138. package/schemas/graph-benchmark.v1.schema.json +2240 -0
  139. package/schemas/maestro-snapshot.schema.json +23 -0
  140. package/skills/README.md +7 -5
  141. package/skills/core/onboarding/SKILL.md +10 -2
  142. package/skills/core/orchestration-experience/SKILL.md +113 -0
  143. package/skills/core/orchestration-experience-pt-br/SKILL.md +112 -0
  144. package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
  145. package/skills/phases/go-implementation/SKILL.md +2 -0
  146. package/skills/phases/ship-release/SKILL.md +6 -3
@@ -0,0 +1,980 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OPCOES_TS_DESCRITAS = void 0;
4
+ exports.casaSonda = casaSonda;
5
+ exports.extrairTypeScript = extrairTypeScript;
6
+ /** Extensoes que o extrator TS le; as do `extensaoDe` do KG2. */
7
+ const EXTENSOES_DO_PROGRAMA = ['.cjs', '.cts', '.js', '.jsx', '.mjs', '.mts', '.ts', '.tsx'];
8
+ const DECLARACOES_TS = ['.d.ts', '.d.mts', '.d.cts'];
9
+ /** A base sem a extensao (o TypeScript troca `.js` por `.ts`, e `.d.ts` conta inteira). */
10
+ function semExtensao(base) {
11
+ const nome = base.slice(base.lastIndexOf('/') + 1);
12
+ for (const d of DECLARACOES_TS)
13
+ if (nome.endsWith(d) && nome.length > d.length)
14
+ return base.slice(0, -d.length);
15
+ const i = nome.lastIndexOf('.');
16
+ return i <= 0 ? base : base.slice(0, base.length - (nome.length - i));
17
+ }
18
+ /**
19
+ * RM-031 KG4 (D3): o caminho `p`, novo ou removido, pode mudar uma resolucao de base `base`? O
20
+ * TypeScript e o Node so tentam a base exata, a base com extensao, a base como pasta (`index`,
21
+ * `package.json`) e o mesmo sem a extensao; base vazia (a raiz) casa tudo.
22
+ */
23
+ function casaSonda(base, p) {
24
+ if (base === '')
25
+ return true;
26
+ if (p === base || p.startsWith(`${base}.`) || p.startsWith(`${base}/`))
27
+ return true;
28
+ const sem = semExtensao(base);
29
+ return sem !== base && (p === sem || p.startsWith(`${sem}.`) || p.startsWith(`${sem}/`));
30
+ }
31
+ /** D2: opcoes fixas do compilador, descritas por nome para entrar no `config_hash`. */
32
+ exports.OPCOES_TS_DESCRITAS = Object.freeze({
33
+ allowJs: true, checkJs: false, esModuleInterop: true, jsx: 'preserve', module: 'commonjs', moduleResolution: 'node10',
34
+ noLib: true, resolveJsonModule: true, target: 'es2022', types: [], node_modules: 'fora-da-resolucao',
35
+ });
36
+ const EXTENSOES_JS = ['.cjs', '.js', '.jsx', '.mjs'];
37
+ /**
38
+ * B3: o especificador ESM e URL. A leitura como URL so coincide com o caminho literal quando nao ha
39
+ * busca nem fragmento (`?`, `#`), escape (`%`), barra invertida (vira `/`), espaco nem controle (a URL
40
+ * apara as pontas e descarta tab e quebra de linha) e quando o ultimo segmento e um nome (barra final,
41
+ * `.` e `..` apontam para pasta, que o ESM nao importa).
42
+ */
43
+ function urlComoCaminho(especificador) {
44
+ for (let i = 0; i < especificador.length; i++) {
45
+ const c = especificador.charCodeAt(i);
46
+ if (c <= 0x20 || c === 0x7f || c === 0x23 || c === 0x25 || c === 0x3f || c === 0x5c)
47
+ return false;
48
+ }
49
+ const ultimo = especificador.slice(especificador.lastIndexOf('/') + 1);
50
+ return ultimo !== '' && ultimo !== '.' && ultimo !== '..';
51
+ }
52
+ /** Texto sem surrogate solto (o `JSON.parse` aceita o escape de D800 sem par; o leitor do Node, nao). */
53
+ function textoBemFormado(t) {
54
+ for (let i = 0; i < t.length; i++) {
55
+ const c = t.charCodeAt(i);
56
+ if (c >= 0xd800 && c <= 0xdbff) {
57
+ const d = t.charCodeAt(i + 1);
58
+ if (!(d >= 0xdc00 && d <= 0xdfff))
59
+ return false;
60
+ i++;
61
+ }
62
+ else if (c >= 0xdc00 && c <= 0xdfff)
63
+ return false;
64
+ }
65
+ return true;
66
+ }
67
+ function opcoes(ts) {
68
+ return {
69
+ allowJs: true, checkJs: false, esModuleInterop: true, jsx: ts.JsxEmit.Preserve, module: ts.ModuleKind.CommonJS,
70
+ moduleResolution: ts.ModuleResolutionKind.Node10, noLib: true, resolveJsonModule: true, target: ts.ScriptTarget.ES2022,
71
+ types: [], noEmit: true, skipLibCheck: true,
72
+ };
73
+ }
74
+ const extensao = (p) => {
75
+ const nome = p.slice(p.lastIndexOf('/') + 1), i = nome.lastIndexOf('.');
76
+ return i <= 0 ? '' : nome.slice(i).toLowerCase();
77
+ };
78
+ const emNodeModules = (p) => p.split('/').includes('node_modules');
79
+ /** Caminho relativo a raiz de um especificador relativo; `null` se sair do repositorio. */
80
+ function caminhoLiteral(de, especificador) {
81
+ if (!especificador.startsWith('./') && !especificador.startsWith('../'))
82
+ return null;
83
+ const partes = [...de.split('/').slice(0, -1), ...especificador.split('/')], r = [];
84
+ for (const p of partes) {
85
+ if (p === '' || p === '.')
86
+ continue;
87
+ if (p === '..') {
88
+ if (!r.length)
89
+ return null;
90
+ r.pop();
91
+ }
92
+ else
93
+ r.push(p);
94
+ }
95
+ return r.join('/');
96
+ }
97
+ /**
98
+ * RM-031 KG4 (D3): modulo vazio fora da raiz virtual (nenhum caminho do manifesto o nomeia, e nada o
99
+ * resolve), so para ler o escopo global do checker sem local que esconda global de mesmo nome.
100
+ */
101
+ const TEXTO_DO_SINTETICO = 'export {};\n';
102
+ function criarHost(ts, e, sintetico) {
103
+ const arquivos = new Set(e.arquivos), dirs = new Set([e.raiz]);
104
+ for (const p of e.arquivos) {
105
+ const partes = p.split('/');
106
+ for (let i = 1; i < partes.length; i++)
107
+ dirs.add(`${e.raiz}/${partes.slice(0, i).join('/')}`);
108
+ }
109
+ const dentro = (nome) => (nome.startsWith(`${e.raiz}/`) ? nome.slice(e.raiz.length + 1) : null);
110
+ // A resolucao de modulo nunca entra em node_modules, mesmo versionado: pacote de terceiro e externo.
111
+ const resolvivel = (nome) => {
112
+ const p = dentro(nome);
113
+ return p !== null && !emNodeModules(p) ? p : null;
114
+ };
115
+ return {
116
+ getSourceFile: (nome, alvo) => {
117
+ if (nome === sintetico)
118
+ return ts.createSourceFile(nome, TEXTO_DO_SINTETICO, alvo, true);
119
+ const p = dentro(nome), t = p === null ? undefined : e.texto(p);
120
+ return t === undefined ? undefined : ts.createSourceFile(nome, t, alvo, true);
121
+ },
122
+ getDefaultLibFileName: () => `${e.raiz}/__sem-biblioteca__.d.ts`,
123
+ writeFile: () => undefined,
124
+ getCurrentDirectory: () => e.raiz,
125
+ getDirectories: () => [],
126
+ fileExists: (nome) => {
127
+ const p = resolvivel(nome);
128
+ return p !== null && arquivos.has(p);
129
+ },
130
+ readFile: (nome) => {
131
+ const p = resolvivel(nome);
132
+ return p === null || !arquivos.has(p) ? undefined : e.texto(p);
133
+ },
134
+ directoryExists: (nome) => {
135
+ const n = nome.length > 1 && nome.endsWith('/') ? nome.slice(0, -1) : nome, p = n === e.raiz ? '' : resolvivel(n);
136
+ return p !== null && dirs.has(n);
137
+ },
138
+ realpath: (p) => p,
139
+ getCanonicalFileName: (p) => p,
140
+ useCaseSensitiveFileNames: () => true,
141
+ getNewLine: () => '\n',
142
+ };
143
+ }
144
+ function extrairTypeScript(e, ts) {
145
+ const resultado = { unidades: new Map(), globais: [], faltantes: [] };
146
+ if (e.fontes.length === 0)
147
+ return resultado;
148
+ const absoluto = (p) => `${e.raiz}/${p}`;
149
+ const relativo = (p) => (p.startsWith(`${e.raiz}/`) ? p.slice(e.raiz.length + 1) : null);
150
+ const sintetico = `${e.raiz}-escopo-global.ts`;
151
+ const host = criarHost(ts, e, sintetico), opts = opcoes(ts);
152
+ const programa = ts.createProgram([...e.fontes.map((f) => absoluto(f.path)), sintetico], opts, host);
153
+ const checker = programa.getTypeChecker();
154
+ const cache = ts.createModuleResolutionCache(e.raiz, (p) => p, opts);
155
+ const arquivos = new Set(e.arquivos);
156
+ const S = ts.SymbolFlags, K = ts.SyntaxKind;
157
+ const ehTopo = (n) => !!n.parent && ts.isSourceFile(n.parent);
158
+ const exportaDefault = (n) => (ts.getCombinedModifierFlags(n) & ts.ModifierFlags.Default) !== 0;
159
+ const variavelDoTopo = (d) => ts.isVariableDeclarationList(d.parent) && ts.isVariableStatement(d.parent.parent) && ehTopo(d.parent.parent);
160
+ const membroDeClasse = (n) => ts.isMethodDeclaration(n) || ts.isPropertyDeclaration(n) || ts.isGetAccessorDeclaration(n) || ts.isSetAccessorDeclaration(n)
161
+ || ts.isConstructorDeclaration(n);
162
+ const nomeDe = (n) => n && (ts.isIdentifier(n) || ts.isPrivateIdentifier(n) || ts.isStringLiteral(n) || ts.isNumericLiteral(n)) ? n.text : null;
163
+ const nomeDaClasse = (c) => (c.name ? c.name.text : exportaDefault(c) ? 'default' : null);
164
+ /** D4: nome do simbolo de uma declaracao, antes da regra de texto do contrato. */
165
+ function nomeDoSimbolo(d) {
166
+ if (ts.isBindingElement(d)) {
167
+ let p = d;
168
+ while (ts.isBindingElement(p) || ts.isObjectBindingPattern(p) || ts.isArrayBindingPattern(p))
169
+ p = p.parent;
170
+ return ts.isVariableDeclaration(p) && variavelDoTopo(p) && ts.isIdentifier(d.name) ? d.name.text : null;
171
+ }
172
+ if (ts.isVariableDeclaration(d))
173
+ return variavelDoTopo(d) && ts.isIdentifier(d.name) ? d.name.text : null;
174
+ if (ts.isFunctionDeclaration(d))
175
+ return ehTopo(d) ? (d.name ? d.name.text : exportaDefault(d) ? 'default' : null) : null;
176
+ if (ts.isClassDeclaration(d))
177
+ return ehTopo(d) ? nomeDaClasse(d) : null;
178
+ if (ts.isInterfaceDeclaration(d) || ts.isTypeAliasDeclaration(d) || ts.isEnumDeclaration(d))
179
+ return ehTopo(d) ? d.name.text : null;
180
+ if (ts.isModuleDeclaration(d)) {
181
+ return ehTopo(d) && ts.isIdentifier(d.name) && (d.flags & ts.NodeFlags.GlobalAugmentation) === 0 ? d.name.text : null;
182
+ }
183
+ // `export default nome` so reexporta: o import resolve ate a declaracao de `nome`.
184
+ if (ts.isExportAssignment(d))
185
+ return ehTopo(d) && !d.isExportEquals && !ts.isIdentifier(d.expression) ? 'default' : null;
186
+ if (membroDeClasse(d) && ts.isClassDeclaration(d.parent) && ehTopo(d.parent)) {
187
+ const classe = nomeDaClasse(d.parent), membro = ts.isConstructorDeclaration(d) ? 'constructor' : nomeDe(d.name);
188
+ return classe !== null && membro !== null ? `${classe}.${membro}` : null;
189
+ }
190
+ return null;
191
+ }
192
+ /** Ref do simbolo; nome que o contrato recusaria (vazio, longo, com controle) nao vira no. */
193
+ const refDe = (d) => {
194
+ const fragment = nomeDoSimbolo(d), path = relativo(d.getSourceFile().fileName);
195
+ return fragment === null || path === null || !e.aceitaFragmento(fragment) ? null : { kind: 'symbol', path, fragment };
196
+ };
197
+ const semAlias = (s) => (s && s.flags & S.Alias ? checker.getAliasedSymbol(s) : s);
198
+ /** O alvo precisa cair num no so: declaracao fora do grafo ou em mais de um no nao liga. */
199
+ function alvoDo(s) {
200
+ const decls = s?.declarations ?? [];
201
+ if (decls.length === 0)
202
+ return { ref: null, categoria: 'chamada-nao-resolvida' };
203
+ const refs = new Map();
204
+ for (const d of decls) {
205
+ const r = refDe(d);
206
+ if (!r)
207
+ return { ref: null, categoria: 'chamada-alvo-fora-do-grafo' };
208
+ refs.set(`${r.path}\u0000${r.fragment}`, r);
209
+ }
210
+ return refs.size === 1 ? { ref: [...refs.values()][0], categoria: '' } : { ref: null, categoria: 'chamada-alvo-ambiguo' };
211
+ }
212
+ /** Resolucao do compilador, restrita ao manifesto e fora de node_modules. */
213
+ function resolver(especificador, de) {
214
+ const r = ts.resolveModuleName(especificador, absoluto(de), opts, host, cache).resolvedModule;
215
+ const p = r && !r.isExternalLibraryImport ? relativo(r.resolvedFileName) : null;
216
+ return p !== null && arquivos.has(p) && !emNodeModules(p) ? p : null;
217
+ }
218
+ const literal = (n) => n && (ts.isStringLiteral(n) || ts.isNoSubstitutionTemplateLiteral(n)) ? n.text : null;
219
+ const ehRequire = (n) => ts.isCallExpression(n) && ts.isIdentifier(n.expression)
220
+ && n.expression.text === 'require' && n.arguments.length === 1 && !(checker.getSymbolAtLocation(n.expression)?.declarations ?? []).length;
221
+ const ehImportDinamico = (n) => ts.isCallExpression(n) && n.expression.kind === K.ImportKeyword;
222
+ /** Declaracao local que liga um nome a um modulo: import, `import = require` ou `require` atribuido. */
223
+ function ehImportLocal(d, sf) {
224
+ if (d.getSourceFile() !== sf)
225
+ return false;
226
+ if (ts.isImportSpecifier(d) || ts.isImportClause(d) || ts.isNamespaceImport(d))
227
+ return true;
228
+ if (ts.isImportEqualsDeclaration(d))
229
+ return ts.isExternalModuleReference(d.moduleReference);
230
+ let v = d;
231
+ while (ts.isBindingElement(v) || ts.isObjectBindingPattern(v) || ts.isArrayBindingPattern(v))
232
+ v = v.parent;
233
+ return ts.isVariableDeclaration(v) && !!v.initializer && ehRequire(v.initializer);
234
+ }
235
+ const viaImportLocal = (s, sf) => !!s && (s.flags & S.Alias) !== 0 && (s.declarations ?? []).some((d) => ehImportLocal(d, sf));
236
+ /** O nome importado so traz tipo: o alvo existe e nao tem valor (interface, tipo). */
237
+ const semValor = (nome) => {
238
+ const s0 = checker.getSymbolAtLocation(nome), alvo = s0 && s0.flags & S.Alias ? checker.getAliasedSymbol(s0) : s0;
239
+ return !!alvo && (alvo.declarations?.length ?? 0) > 0 && (alvo.flags & S.Value) === 0;
240
+ };
241
+ /**
242
+ * Chave do especificador de um no de import. `t`: so traz tipo (`import type`, nomes que so sao tipo,
243
+ * `import('x').T`) e some na compilacao, entao segue o compilador; so vale em fonte TypeScript, porque
244
+ * JavaScript nao e compilado e o import roda (B-R1). `d`: `import()`, que o Node resolve como ESM.
245
+ * `r`: `require` literal. `v`: o resto.
246
+ */
247
+ function chaveDoImport(n, compilado) {
248
+ let esp = null, tipo = 'v';
249
+ if (ts.isImportDeclaration(n)) {
250
+ esp = literal(n.moduleSpecifier);
251
+ const ic = n.importClause, nomes = ic?.namedBindings && ts.isNamedImports(ic.namedBindings) ? ic.namedBindings.elements : [];
252
+ const soTipo = compilado && !!ic && (ic.isTypeOnly || (!(ic.namedBindings && ts.isNamespaceImport(ic.namedBindings))
253
+ && (!ic.name || semValor(ic.name)) && (!!ic.name || nomes.length > 0) && nomes.every((el) => el.isTypeOnly || semValor(el.name))));
254
+ if (soTipo)
255
+ tipo = 't';
256
+ }
257
+ else if (ts.isExportDeclaration(n) && n.moduleSpecifier) {
258
+ esp = literal(n.moduleSpecifier);
259
+ const nomes = n.exportClause && ts.isNamedExports(n.exportClause) ? n.exportClause.elements : null;
260
+ if (compilado && (n.isTypeOnly || (nomes && nomes.length > 0 && nomes.every((el) => el.isTypeOnly || semValor(el.name)))))
261
+ tipo = 't';
262
+ }
263
+ else if (ts.isImportEqualsDeclaration(n) && ts.isExternalModuleReference(n.moduleReference)) {
264
+ esp = literal(n.moduleReference.expression);
265
+ if (compilado && n.isTypeOnly)
266
+ tipo = 't';
267
+ }
268
+ else if (ts.isImportTypeNode(n) && ts.isLiteralTypeNode(n.argument)) {
269
+ esp = literal(n.argument.literal);
270
+ tipo = 't';
271
+ }
272
+ else if (ehImportDinamico(n)) {
273
+ esp = literal(n.arguments[0]);
274
+ tipo = 'd';
275
+ }
276
+ else if (ehRequire(n)) {
277
+ esp = literal(n.arguments[0]);
278
+ tipo = 'r';
279
+ }
280
+ return esp === null ? null : `${tipo}\u0000${esp}`;
281
+ }
282
+ const especificadorDaChave = (chave) => chave.slice(2);
283
+ /** Fonte TypeScript, que o compilador transforma; JavaScript roda como esta. */
284
+ const compiladoEm = (arquivo) => !EXTENSOES_JS.includes(extensao(arquivo));
285
+ /** Chaves de todos os imports dentro de um no. */
286
+ function especificadoresEm(raiz) {
287
+ const r = [], compilado = compiladoEm(raiz.getSourceFile().fileName);
288
+ const coletar = (n) => {
289
+ const chave = chaveDoImport(n, compilado);
290
+ if (chave !== null)
291
+ r.push(chave);
292
+ ts.forEachChild(n, coletar);
293
+ };
294
+ coletar(raiz);
295
+ return r;
296
+ }
297
+ const DECLARACOES = [['.d.ts', '.js'], ['.d.cts', '.cjs'], ['.d.mts', '.mjs']];
298
+ const existe = (p) => (p !== '' && arquivos.has(p) && !emNodeModules(p) ? p : null);
299
+ /** Implementacao ao lado de um arquivo de declaracao: e ela que roda. */
300
+ function implementacaoDe(declaracao) {
301
+ for (const [ext, impl] of DECLARACOES)
302
+ if (declaracao.endsWith(ext))
303
+ return existe(declaracao.slice(0, -ext.length) + impl);
304
+ return null;
305
+ }
306
+ const junta = (pasta, nome) => (pasta ? `${pasta}/${nome}` : nome);
307
+ /** JSON como o `JSON.parse` do Node o le, sem o BOM; `undefined` se nao for JSON. */
308
+ function lerJson(caminho) {
309
+ const bruto = e.texto(caminho);
310
+ if (bruto === undefined)
311
+ return undefined;
312
+ try {
313
+ return JSON.parse(bruto.charCodeAt(0) === 0xfeff ? bruto.slice(1) : bruto);
314
+ }
315
+ catch {
316
+ return undefined;
317
+ }
318
+ }
319
+ /**
320
+ * package.json como o Node 22 o le: BOM ignorado, raiz objeto, `name` e `type` texto sem surrogate
321
+ * solto quando presentes. Fora disso o Node lanca `ERR_INVALID_PACKAGE_CONFIG` e o resultado e `null`.
322
+ */
323
+ const pacotes = new Map();
324
+ function lerPacote(caminho) {
325
+ const lido = pacotes.get(caminho);
326
+ if (lido !== undefined)
327
+ return lido;
328
+ let r = null;
329
+ const v = lerJson(caminho);
330
+ if (v !== null && typeof v === 'object' && !Array.isArray(v)) {
331
+ const o = v;
332
+ const texto = (k) => !(k in o) || (typeof o[k] === 'string' && textoBemFormado(o[k]));
333
+ if (texto('name') && texto('type'))
334
+ r = o;
335
+ }
336
+ pacotes.set(caminho, r);
337
+ return r;
338
+ }
339
+ /**
340
+ * Resolucao do Node para especificador relativo: exato em ESM; em CommonJS, primeiro como arquivo
341
+ * (exato, `.js`, `.json`, `.node`) e depois como pasta (`main` do package.json, `index`). Barra
342
+ * final, `.` e `..` so valem como pasta. package.json invalido faz o Node falhar; `main` absoluto ou
343
+ * que sai do repositorio aponta para fora do que o manifesto ve, e nao liga.
344
+ */
345
+ function resolverNode(de, especificador, esm) {
346
+ const base = caminhoLiteral(de, especificador === '.' || especificador === '..' ? `./${especificador}` : especificador);
347
+ if (base === null)
348
+ return null;
349
+ if (esm)
350
+ return existe(base);
351
+ const comoArquivo = (p) => (p ? existe(p) ?? existe(`${p}.js`) ?? existe(`${p}.json`) ?? existe(`${p}.node`) : null);
352
+ const comoIndice = (p) => existe(junta(p, 'index.js')) ?? existe(junta(p, 'index.json')) ?? existe(junta(p, 'index.node'));
353
+ const comoPasta = (p) => {
354
+ const arquivoDoPacote = junta(p, 'package.json');
355
+ if (existe(arquivoDoPacote)) {
356
+ const pacote = lerPacote(arquivoDoPacote);
357
+ if (pacote === null)
358
+ return null;
359
+ const main = pacote.main;
360
+ if (typeof main === 'string' && main) {
361
+ // `main` e relativo a pasta, mesmo quando comeca com ponto (`.`, `..`, `.oculto.js`).
362
+ const m = main.startsWith('/') ? null : caminhoLiteral(arquivoDoPacote, `./${main}`);
363
+ if (m === null)
364
+ return null;
365
+ const r = comoArquivo(m) ?? comoIndice(m);
366
+ if (r !== null)
367
+ return r;
368
+ }
369
+ }
370
+ return comoIndice(p);
371
+ };
372
+ const soPasta = especificador.endsWith('/') || /(^|\/)\.\.?$/.test(especificador);
373
+ return soPasta ? comoPasta(base) : comoArquivo(base) ?? comoPasta(base);
374
+ }
375
+ /** package.json mais proximo acima do arquivo: `type` e se o Node o consegue ler. */
376
+ const escopos = new Map();
377
+ function escopoDe(arquivo) {
378
+ const caminho = [];
379
+ let dir = arquivo.includes('/') ? arquivo.slice(0, arquivo.lastIndexOf('/')) : '';
380
+ let r;
381
+ for (;;) {
382
+ r = escopos.get(dir);
383
+ if (r)
384
+ break;
385
+ caminho.push(dir);
386
+ const pacote = junta(dir, 'package.json');
387
+ if (arquivos.has(pacote)) {
388
+ const lido = lerPacote(pacote);
389
+ r = lido === null ? { invalido: true, tipo: undefined } : { invalido: false, tipo: lido.type };
390
+ break;
391
+ }
392
+ if (dir === '') {
393
+ r = { invalido: false, tipo: undefined };
394
+ break;
395
+ }
396
+ dir = dir.includes('/') ? dir.slice(0, dir.lastIndexOf('/')) : '';
397
+ }
398
+ for (const d of caminho)
399
+ escopos.set(d, r);
400
+ return r;
401
+ }
402
+ const VARIAVEIS_DO_CJS = new Set(['require', 'module', 'exports', '__filename', '__dirname']);
403
+ /**
404
+ * Sintaxe que o Node 22 so aceita em ESM: import e export estaticos, `import.meta`, `await` no topo e
405
+ * `let`/`const`/`class` no topo que declara variavel do CommonJS, tambem por desestruturacao. Em `.js`
406
+ * sem `type`, e ela que leva o Node a tentar ESM quando o CommonJS nao compila.
407
+ */
408
+ const nomesDaLigacao = (b) => (ts.isIdentifier(b) ? [b.text]
409
+ : b.elements.flatMap((el) => (ts.isBindingElement(el) ? nomesDaLigacao(el.name) : [])));
410
+ function sintaxeEsm(sf) {
411
+ for (const st of sf.statements) {
412
+ if (ts.isImportDeclaration(st) || ts.isExportDeclaration(st) || ts.isExportAssignment(st))
413
+ return true;
414
+ if (ts.canHaveModifiers(st) && ts.getModifiers(st)?.some((m) => m.kind === K.ExportKeyword))
415
+ return true;
416
+ if (ts.isVariableStatement(st) && (st.declarationList.flags & ts.NodeFlags.BlockScoped) !== 0
417
+ && st.declarationList.declarations.some((d) => nomesDaLigacao(d.name).some((x) => VARIAVEIS_DO_CJS.has(x))))
418
+ return true;
419
+ if (ts.isClassDeclaration(st) && st.name && VARIAVEIS_DO_CJS.has(st.name.text))
420
+ return true;
421
+ }
422
+ let achou = false;
423
+ const visitar = (n, topo) => {
424
+ if (achou)
425
+ return;
426
+ if ((ts.isMetaProperty(n) && n.keywordToken === K.ImportKeyword)
427
+ || (topo && (ts.isAwaitExpression(n) || (ts.isForOfStatement(n) && !!n.awaitModifier)))) {
428
+ achou = true;
429
+ return;
430
+ }
431
+ const dentro = topo && !ts.isFunctionLike(n) && !ts.isClassStaticBlockDeclaration(n);
432
+ ts.forEachChild(n, (f) => visitar(f, dentro));
433
+ };
434
+ visitar(sf, true);
435
+ return achou;
436
+ }
437
+ /**
438
+ * Como o Node 22 carrega a fonte JavaScript: `esm`, `cjs` ou `falha`. O juiz de sintaxe e o V8 do Node
439
+ * (D16), alem do parser do TypeScript: `.mjs` so como ESM, `.cjs` so como CommonJS, `.js` pelo `type`
440
+ * do escopo e, sem ele, como o Node 22 detecta: CommonJS se compila, senao ESM se tem sintaxe de ESM e
441
+ * compila como tal. `.jsx` nao tem formato ESM no Node e so carrega por `require`, como CommonJS.
442
+ * Escopo invalido tambem e `falha`.
443
+ */
444
+ const formatos = new Map();
445
+ {
446
+ // Decidido de uma vez para toda fonte JavaScript: uma chamada ao juiz, que compila o ESM em lote.
447
+ const regras = [];
448
+ for (const f of e.fontes) {
449
+ const ext = extensao(f.path), sf = programa.getSourceFile(absoluto(f.path));
450
+ if (!EXTENSOES_JS.includes(ext))
451
+ continue;
452
+ if (!sf || sf.fileName !== absoluto(f.path) || programa.getSyntacticDiagnostics(sf).length > 0) {
453
+ formatos.set(f.path, 'falha');
454
+ continue;
455
+ }
456
+ const escopo = ext === '.mjs' || ext === '.cjs' ? null : escopoDe(f.path);
457
+ const regra = (r, esmPossivel) => {
458
+ regras.push({ caminho: f.path, regra: r, esmPossivel });
459
+ };
460
+ if (escopo?.invalido)
461
+ formatos.set(f.path, 'falha');
462
+ else if (ext === '.mjs' || (ext === '.js' && escopo?.tipo === 'module'))
463
+ regra('esm', true);
464
+ else if (ext === '.cjs' || ext === '.jsx' || escopo?.tipo === 'commonjs')
465
+ regra('cjs', false);
466
+ else
467
+ regra('ambiguo', sintaxeEsm(sf));
468
+ }
469
+ const pedidos = [];
470
+ const indices = regras.map((r) => {
471
+ const texto = e.texto(r.caminho) ?? '', i = { cjs: -1, esm: -1 };
472
+ if (r.regra !== 'esm')
473
+ i.cjs = pedidos.push({ texto, formato: 'cjs' }) - 1;
474
+ if (r.esmPossivel)
475
+ i.esm = pedidos.push({ texto, formato: 'esm' }) - 1;
476
+ return i;
477
+ });
478
+ const aceitos = pedidos.length ? e.sintaxe(pedidos) : [];
479
+ const aceito = (i) => i >= 0 && aceitos[i] === true;
480
+ regras.forEach((r, k) => {
481
+ const cjs = aceito(indices[k].cjs), esm = aceito(indices[k].esm);
482
+ if (r.regra === 'esm')
483
+ formatos.set(r.caminho, esm ? 'esm' : 'falha');
484
+ else
485
+ formatos.set(r.caminho, cjs ? 'cjs' : r.regra === 'ambiguo' && esm ? 'esm' : 'falha');
486
+ });
487
+ }
488
+ const formatoDe = (caminho) => formatos.get(caminho) ?? 'falha';
489
+ /**
490
+ * Alvo que o Node carrega de verdade. Por `import`: `.js`, `.mjs` e `.cjs` (JSON pede atributo e
491
+ * extensao desconhecida falha). Por `require`: `.js` e `.cjs` em CommonJS, e `.json` que e JSON. O
492
+ * `.js` so carrega com o proprio escopo valido; o resto (TypeScript por remocao de tipos, `.node`, sem
493
+ * extensao, ESM por `require`) fica fora por nao ser provado.
494
+ */
495
+ function carregavel(alvo, porImport) {
496
+ const ext = extensao(alvo);
497
+ if (ext === '.json')
498
+ return !porImport && lerJson(alvo) !== undefined;
499
+ if (ext !== '.js' && ext !== '.cjs' && ext !== '.mjs')
500
+ return false;
501
+ const formato = formatoDe(alvo);
502
+ return porImport ? formato !== 'falha' : formato === 'cjs';
503
+ }
504
+ /**
505
+ * Alvo do especificador para o Node: `import()` resolve como ESM em qualquer formato; import estatico,
506
+ * so em ESM; `require`, so em CommonJS e com o escopo de quem importa valido (o Node le esse escopo e
507
+ * lanca erro). Especificador nao relativo vai a node_modules e fica sem alvo. Em ESM o especificador e
508
+ * URL: so liga o que a URL le como o caminho literal (`urlComoCaminho`).
509
+ */
510
+ /** KG4 (D3): `bruto` e o caminho que a resolucao do Node achou, antes de conferir se ele carrega. */
511
+ function alvoNoNode(de, chave) {
512
+ const esp = especificadorDaChave(chave), formato = formatoDe(de);
513
+ const relativoAoArquivo = esp === '.' || esp === '..' || esp.startsWith('./') || esp.startsWith('../');
514
+ if (!relativoAoArquivo || formato === 'falha')
515
+ return { alvo: null, bruto: null };
516
+ let alvo;
517
+ if (chave[0] === 'd' || (chave[0] === 'v' && formato === 'esm'))
518
+ alvo = urlComoCaminho(esp) ? resolverNode(de, esp, true) : null;
519
+ else if (chave[0] === 'r' && formato === 'cjs' && !escopoDe(de).invalido)
520
+ alvo = resolverNode(de, esp, false);
521
+ else
522
+ return { alvo: null, bruto: null };
523
+ return { alvo: alvo !== null && carregavel(alvo, chave[0] !== 'r') ? alvo : null, bruto: alvo };
524
+ }
525
+ /**
526
+ * KG4 (D3): os nomes de modulo que o TypeScript coleta do arquivo para o programa (import, export,
527
+ * require, import(), tipo importado, inclusive no JSDoc de JavaScript). Sem a lista, nao ha como provar
528
+ * as dependencias e a extracao falha, em vez de reaproveitar sem prova.
529
+ */
530
+ const nomesDeModulo = (sf) => {
531
+ const imports = sf.imports;
532
+ if (!Array.isArray(imports))
533
+ throw new Error('extracao.interna.typescript-sem-imports');
534
+ return imports.map((n) => n.text);
535
+ };
536
+ /** Caminho relativo a raiz por segmentos; `null` se sobe acima da raiz. */
537
+ const normalizar = (partes) => {
538
+ const r = [];
539
+ for (const p of partes) {
540
+ if (p === '' || p === '.')
541
+ continue;
542
+ if (p === '..') {
543
+ if (!r.length)
544
+ return null;
545
+ r.pop();
546
+ }
547
+ else
548
+ r.push(p);
549
+ }
550
+ return r.join('/');
551
+ };
552
+ /** KG4 (D3): base de uma resolucao relativa como o TypeScript a ve (a barra invertida tambem separa); `null` se nao e relativa ou sai da raiz. */
553
+ const baseDaSonda = (de, nome) => (/^\.\.?($|[\\/])/.test(nome) ? normalizar([...de.split('/').slice(0, -1), ...nome.replace(/\\/g, '/').split('/')]) : null);
554
+ /** `/// <reference path>`: relativo ao arquivo, com ou sem `./`. */
555
+ const baseDaReferencia = (de, nome) => (nome.startsWith('/') || nome.startsWith('\\') ? null : normalizar([...de.split('/').slice(0, -1), ...nome.replace(/\\/g, '/').split('/')]));
556
+ /**
557
+ * KG4 (D3): a resolucao de uma pasta le o `package.json` dela, e `main`, `types` e `typings` podem
558
+ * apontar para fora da base: os alvos entram como sondas, tambem com a barra invertida trocada, como o
559
+ * TypeScript le. `typesVersions` remapeia qualquer caminho, e entao a sonda casa tudo; o mesmo vale
560
+ * para `package.json` que nao e JSON estrito (CHECK, A1: o TypeScript aceita comentario e virgula
561
+ * final). Mudanca no proprio `package.json` extrai o TypeScript inteiro.
562
+ */
563
+ const sondasDoPacote = (base, sondas) => {
564
+ for (const pasta of new Set([base, semExtensao(base)])) {
565
+ const arquivo = junta(pasta, 'package.json');
566
+ if (!arquivos.has(arquivo))
567
+ continue;
568
+ const v = lerJson(arquivo);
569
+ if (v === null || typeof v !== 'object' || Array.isArray(v)) {
570
+ sondas.add('');
571
+ continue;
572
+ }
573
+ const o = v;
574
+ if ('typesVersions' in o)
575
+ sondas.add('');
576
+ for (const campo of ['main', 'types', 'typings']) {
577
+ const alvo = o[campo];
578
+ if (typeof alvo !== 'string' || !alvo)
579
+ continue;
580
+ for (const forma of new Set([alvo, alvo.replace(/\\/g, '/')])) {
581
+ const t = forma.startsWith('/') ? null : caminhoLiteral(arquivo, `./${forma}`);
582
+ if (t !== null)
583
+ sondas.add(t);
584
+ }
585
+ }
586
+ }
587
+ };
588
+ const sondar = (base, sondas) => {
589
+ if (base === null)
590
+ return;
591
+ sondas.add(base);
592
+ sondasDoPacote(base, sondas);
593
+ };
594
+ // Primeira passada, em todos os arquivos: o alvo de cada especificador para o compilador e para o
595
+ // runtime. Onde divergem, a aresta de import vai ao que roda e nenhum simbolo passa por ali (D3).
596
+ const resolucoes = new Map();
597
+ const divergentesGlobais = new Set();
598
+ // KG4 (D3): por fonte, os caminhos a que as referencias de modulo resolvem e as bases das relativas.
599
+ const dependenciasDe = new Map(), sondasDe = new Map();
600
+ for (const fonte of e.fontes) {
601
+ const sf = programa.getSourceFile(absoluto(fonte.path));
602
+ if (!sf || sf.fileName !== absoluto(fonte.path))
603
+ continue;
604
+ const ext = extensao(fonte.path), mapa = new Map();
605
+ const dependencias = new Set(), sondas = new Set();
606
+ for (const chave of especificadoresEm(sf)) {
607
+ if (mapa.has(chave))
608
+ continue;
609
+ const esp = especificadorDaChave(chave), doCompilador = resolver(esp, fonte.path);
610
+ sondar(baseDaSonda(fonte.path, esp), sondas);
611
+ let alvo = doCompilador, divergente = false;
612
+ // Import so de tipo nao roda: vale o que o compilador liga. Fonte JavaScript roda no Node, e onde
613
+ // o Node falha (formato, escopo, alvo que nao carrega) nao ha aresta.
614
+ if (chave[0] !== 't' && EXTENSOES_JS.includes(ext)) {
615
+ const runtime = alvoNoNode(fonte.path, chave);
616
+ if (runtime.bruto !== null)
617
+ dependencias.add(runtime.bruto);
618
+ if (runtime.alvo !== doCompilador) {
619
+ divergente = true;
620
+ alvo = runtime.alvo;
621
+ }
622
+ }
623
+ const impl = chave[0] !== 't' && !divergente && doCompilador !== null ? implementacaoDe(doCompilador) : null;
624
+ if (impl !== null) {
625
+ divergente = true;
626
+ alvo = impl;
627
+ }
628
+ for (const x of [doCompilador, alvo])
629
+ if (x !== null)
630
+ dependencias.add(x);
631
+ mapa.set(chave, { alvo, divergente, doCompilador });
632
+ if (divergente)
633
+ divergentesGlobais.add(`${fonte.path}\u0000${chave}`);
634
+ }
635
+ // O que o TypeScript coleta e a varredura nao ve (tipo importado no JSDoc) tambem liga o checker a outro arquivo.
636
+ for (const nome of nomesDeModulo(sf)) {
637
+ sondar(baseDaSonda(fonte.path, nome), sondas);
638
+ const alvo = resolver(nome, fonte.path);
639
+ if (alvo !== null)
640
+ dependencias.add(alvo);
641
+ }
642
+ for (const r of sf.referencedFiles) {
643
+ const base = baseDaReferencia(fonte.path, r.fileName);
644
+ if (base === null)
645
+ continue;
646
+ sondas.add(base);
647
+ for (const x of [base, `${base}.ts`, `${base}.tsx`, `${base}.d.ts`, `${base}.js`, `${base}.jsx`])
648
+ if (arquivos.has(x))
649
+ dependencias.add(x);
650
+ }
651
+ resolucoes.set(fonte.path, mapa);
652
+ dependenciasDe.set(fonte.path, dependencias);
653
+ sondasDe.set(fonte.path, sondas);
654
+ }
655
+ // KG4 (D3): no programa parcial, todo alvo TS/JS das fontes precisa ser fonte, para ter formato e
656
+ // resolucoes; senao o caminho cresce e a extracao recomeca.
657
+ if (e.emitir) {
658
+ const noPrograma = new Set(e.fontes.map((f) => f.path)), faltantes = new Set();
659
+ for (const dependencias of dependenciasDe.values()) {
660
+ for (const d of dependencias) {
661
+ if (!noPrograma.has(d) && EXTENSOES_DO_PROGRAMA.includes(extensao(d)) && e.texto(d) !== undefined)
662
+ faltantes.add(d);
663
+ }
664
+ }
665
+ if (faltantes.size)
666
+ return { ...resultado, faltantes: [...faltantes].sort() };
667
+ }
668
+ // B-N2: modulo que importa, direto ou por outro modulo, um arquivo com import divergente pode reexportar
669
+ // o que o compilador liga e o runtime nao (`export *`, `module.exports = require(...)`). O fecho segue
670
+ // o grafo de import inteiro, e so vale para simbolo que nao e declarado no proprio salto.
671
+ const dependentes = new Map();
672
+ for (const [p, mapa] of resolucoes) {
673
+ for (const r of mapa.values()) {
674
+ for (const alvo of [r.doCompilador, r.alvo]) {
675
+ if (alvo === null)
676
+ continue;
677
+ let d = dependentes.get(alvo);
678
+ if (!d)
679
+ dependentes.set(alvo, (d = new Set()));
680
+ d.add(p);
681
+ }
682
+ }
683
+ }
684
+ const contaminados = new Set([...divergentesGlobais].map((k) => k.slice(0, k.indexOf('\u0000'))));
685
+ for (const fila = [...contaminados]; fila.length;) {
686
+ for (const d of dependentes.get(fila.pop()) ?? []) {
687
+ if (!contaminados.has(d)) {
688
+ contaminados.add(d);
689
+ fila.push(d);
690
+ }
691
+ }
692
+ }
693
+ /**
694
+ * A cadeia de alias passa por um import divergente: num salto dela, ou num modulo intermediario que
695
+ * reexporta o que o compilador liga e o runtime nao (`module.exports = require('./a.js')`).
696
+ */
697
+ const especificadoresDaDeclaracao = new Map();
698
+ function cadeiaDivergente(s, destino) {
699
+ const vistos = new Set();
700
+ for (let atual = s; atual && (atual.flags & S.Alias) !== 0 && !vistos.has(atual); atual = checker.getImmediateAliasedSymbol(atual)) {
701
+ vistos.add(atual);
702
+ for (const d of atual.declarations ?? []) {
703
+ const p = relativo(d.getSourceFile().fileName);
704
+ if (p === null)
705
+ continue;
706
+ let topo = d;
707
+ while (topo.parent && !ts.isSourceFile(topo.parent))
708
+ topo = topo.parent;
709
+ let esps = especificadoresDaDeclaracao.get(topo);
710
+ if (!esps)
711
+ especificadoresDaDeclaracao.set(topo, (esps = especificadoresEm(topo)));
712
+ for (const esp of esps) {
713
+ if (divergentesGlobais.has(`${p}\u0000${esp}`))
714
+ return true;
715
+ const salto = resolucoes.get(p)?.get(esp)?.doCompilador ?? null;
716
+ if (salto !== null && salto !== destino && contaminados.has(salto))
717
+ return true;
718
+ }
719
+ }
720
+ }
721
+ return false;
722
+ }
723
+ for (const fonte of e.fontes) {
724
+ if (e.emitir && !e.emitir.has(fonte.path))
725
+ continue;
726
+ // KG4 (D2): os achados ficam por arquivo, com as dependencias e as sondas, para as unidades do indice.
727
+ const saida = { nos: [], arestas: [], diagnosticos: [], lacunas: [] };
728
+ resultado.unidades.set(fonte.path, {
729
+ dependencias: [...(dependenciasDe.get(fonte.path) ?? [])].sort(), sondas: [...(sondasDe.get(fonte.path) ?? [])].sort(), achados: saida,
730
+ });
731
+ const sf = programa.getSourceFile(absoluto(fonte.path));
732
+ // Fonte que o compilador trocou por outra (pacote duplicado) nao e lida: o no seria do outro arquivo.
733
+ if (!sf || sf.fileName !== absoluto(fonte.path)) {
734
+ saida.lacunas.push({ categoria: sf ? 'fonte-redirecionada' : 'fonte-nao-lida', path: fonte.path, inicio: null, detalhe: null });
735
+ continue;
736
+ }
737
+ const arquivo = { kind: 'file', path: fonte.path, fragment: null };
738
+ const trecho = (n, fim = n.getEnd()) => ({ path: fonte.path, inicio: n.getStart(sf), fim });
739
+ const aresta = (kind, from, to, t) => {
740
+ saida.arestas.push({ kind, from, to, extrator: e.extrator, metodo: 'ast', trecho: t });
741
+ };
742
+ const lacuna = (categoria, n, detalhe = null) => {
743
+ saida.lacunas.push({ categoria, path: fonte.path, inicio: n ? n.getStart(sf) : null, detalhe });
744
+ };
745
+ const diagnostico = (kind, reference) => {
746
+ saida.diagnosticos.push({ kind, path: fonte.path, reference: reference.replace(/\s+/g, ' '), extrator: e.extrator });
747
+ };
748
+ const alvos = resolucoes.get(fonte.path) ?? new Map();
749
+ // Arquivo que o compilador ligou no lugar do que roda: nenhuma chamada deste arquivo vai a ele.
750
+ const divergentes = new Set([...alvos.values()].filter((r) => r.divergente && r.doCompilador !== null).map((r) => r.doCompilador));
751
+ // AN3: classes importadas por nome aqui; `this` e `super` so ligam a membro delas em outro arquivo.
752
+ const classesImportadas = new Set();
753
+ const importada = (nome) => {
754
+ const s0 = nome ? checker.getSymbolAtLocation(nome) : undefined;
755
+ if (!s0 || (s0.flags & S.Alias) === 0)
756
+ return;
757
+ const alvo = checker.getAliasedSymbol(s0), arquivoDoAlvo = alvo.declarations?.[0] ? relativo(alvo.declarations[0].getSourceFile().fileName) : null;
758
+ if (cadeiaDivergente(s0, arquivoDoAlvo))
759
+ return;
760
+ if (alvo.flags & S.Class)
761
+ classesImportadas.add(alvo);
762
+ // Modulo importado inteiro (`* as ns`, `import = require`, `require` atribuido): as classes que ele exporta.
763
+ else if (alvo.flags & S.ValueModule) {
764
+ for (const x of checker.getExportsOfModule(alvo)) {
765
+ const c = semAlias(x), arquivoDaClasse = c?.declarations?.[0] ? relativo(c.declarations[0].getSourceFile().fileName) : null;
766
+ // B-N1: a classe pode chegar por reexport divergente; confere a cadeia ate o arquivo dela.
767
+ if (c && c.flags & S.Class && !cadeiaDivergente(s0, arquivoDaClasse))
768
+ classesImportadas.add(c);
769
+ }
770
+ }
771
+ };
772
+ const nomesDoPadrao = (n) => {
773
+ if (ts.isIdentifier(n))
774
+ importada(n);
775
+ else
776
+ for (const el of n.elements)
777
+ if (ts.isBindingElement(el))
778
+ nomesDoPadrao(el.name);
779
+ };
780
+ const juntarImportadas = (n) => {
781
+ if (ts.isImportClause(n))
782
+ importada(n.name);
783
+ else if (ts.isImportSpecifier(n) || ts.isNamespaceImport(n))
784
+ importada(n.name);
785
+ else if (ts.isImportEqualsDeclaration(n) && ts.isExternalModuleReference(n.moduleReference))
786
+ importada(n.name);
787
+ else if (ts.isVariableDeclaration(n) && n.initializer && ehRequire(n.initializer))
788
+ nomesDoPadrao(n.name);
789
+ ts.forEachChild(n, juntarImportadas);
790
+ };
791
+ juntarImportadas(sf);
792
+ // Declaracoes de topo e membros de classe de topo (D4).
793
+ const declarar = (d) => {
794
+ const r = refDe(d);
795
+ if (r && r.path === fonte.path) {
796
+ saida.nos.push(r);
797
+ aresta('declares', arquivo, r, trecho(d));
798
+ return r;
799
+ }
800
+ if (nomeDoSimbolo(d) !== null)
801
+ lacuna('simbolo-recusado', d);
802
+ return null;
803
+ };
804
+ const elementos = (padrao, visitar) => {
805
+ for (const el of padrao.elements) {
806
+ if (!ts.isBindingElement(el))
807
+ continue;
808
+ if (ts.isIdentifier(el.name))
809
+ visitar(el);
810
+ else
811
+ elementos(el.name, visitar);
812
+ }
813
+ };
814
+ const simbolosDoTopo = new Map();
815
+ for (const st of sf.statements) {
816
+ if (ts.isVariableStatement(st)) {
817
+ for (const d of st.declarationList.declarations) {
818
+ if (ts.isIdentifier(d.name))
819
+ simbolosDoTopo.set(d, declarar(d));
820
+ else
821
+ elementos(d.name, (el) => { declarar(el); });
822
+ }
823
+ }
824
+ else if (ts.isFunctionDeclaration(st) || ts.isClassDeclaration(st) || ts.isInterfaceDeclaration(st) || ts.isTypeAliasDeclaration(st)
825
+ || ts.isEnumDeclaration(st) || ts.isModuleDeclaration(st) || ts.isExportAssignment(st)) {
826
+ const r = declarar(st);
827
+ simbolosDoTopo.set(st, r);
828
+ if (r && ts.isClassDeclaration(st)) {
829
+ for (const m of st.members) {
830
+ const rm = refDe(m);
831
+ if (!rm) {
832
+ if (nomeDoSimbolo(m) !== null)
833
+ lacuna('simbolo-recusado', m);
834
+ continue;
835
+ }
836
+ saida.nos.push(rm);
837
+ aresta('contains', r, rm, trecho(m));
838
+ simbolosDoTopo.set(m, rm);
839
+ }
840
+ }
841
+ }
842
+ }
843
+ const importar = (chave, t) => {
844
+ const r = alvos.get(chave) ?? { alvo: null, divergente: false }, especificador = especificadorDaChave(chave);
845
+ if (r.alvo === null)
846
+ diagnostico('unresolved-import', especificador);
847
+ else
848
+ aresta('imports', arquivo, { kind: 'file', path: r.alvo, fragment: null }, t);
849
+ if (r.divergente)
850
+ saida.lacunas.push({ categoria: 'import-divergente', path: fonte.path, inicio: t.inicio, detalhe: especificador });
851
+ return r;
852
+ };
853
+ const simboloImportado = (nome, t) => {
854
+ const s0 = checker.getSymbolAtLocation(nome), { ref } = alvoDo(semAlias(s0));
855
+ if (ref && !divergentes.has(ref.path) && !cadeiaDivergente(s0, ref.path))
856
+ aresta('imports', arquivo, ref, t);
857
+ else
858
+ lacuna('import-sem-simbolo', nome);
859
+ };
860
+ /** D3: alvo de chamada pela ligacao lexica do callee, nunca pelo tipo inferido do objeto. */
861
+ function alvoDaChamada(callee) {
862
+ let r, ligado, alias;
863
+ if (ts.isIdentifier(callee)) {
864
+ alias = checker.getSymbolAtLocation(callee);
865
+ r = alvoDo(semAlias(alias));
866
+ ligado = viaImportLocal(alias, sf);
867
+ }
868
+ else if (ts.isPropertyAccessExpression(callee)) {
869
+ const objeto = callee.expression;
870
+ if (objeto.kind === K.ThisKeyword || objeto.kind === K.SuperKeyword) {
871
+ // Membro de outro arquivo so liga se a classe que o declara foi importada por nome aqui.
872
+ const membro = semAlias(checker.getSymbolAtLocation(callee.name)), classe = membro?.declarations?.[0]?.parent;
873
+ const simboloDaClasse = classe && ts.isClassDeclaration(classe) && classe.name ? checker.getSymbolAtLocation(classe.name) : undefined;
874
+ r = alvoDo(membro);
875
+ ligado = !!simboloDaClasse && classesImportadas.has(simboloDaClasse);
876
+ }
877
+ else if (ts.isIdentifier(objeto)) {
878
+ alias = checker.getSymbolAtLocation(objeto);
879
+ const dono = semAlias(alias);
880
+ if (!dono || (dono.flags & (S.Class | S.Enum | S.ValueModule | S.NamespaceModule)) === 0)
881
+ return { ref: null, categoria: 'chamada-por-tipo' };
882
+ r = alvoDo(semAlias(checker.getSymbolAtLocation(callee.name)));
883
+ ligado = viaImportLocal(alias, sf);
884
+ }
885
+ else
886
+ return { ref: null, categoria: 'chamada-por-tipo' };
887
+ }
888
+ else
889
+ return { ref: null, categoria: 'chamada-nao-resolvida' };
890
+ if (!r.ref)
891
+ return r;
892
+ if (cadeiaDivergente(alias, r.ref.path))
893
+ return { ref: null, categoria: 'chamada-por-import-divergente' };
894
+ // Alvo em outro arquivo so com ligacao deste arquivo: import local, nunca global de script.
895
+ if (r.ref.path !== fonte.path && !ligado)
896
+ return { ref: null, categoria: 'chamada-global-entre-arquivos' };
897
+ if (divergentes.has(r.ref.path))
898
+ return { ref: null, categoria: 'chamada-por-import-divergente' };
899
+ return r;
900
+ }
901
+ const chamada = (n, atual) => {
902
+ if (!atual) {
903
+ lacuna('chamada-fora-de-simbolo', n);
904
+ return;
905
+ }
906
+ const { ref, categoria } = alvoDaChamada(n.expression);
907
+ if (!ref) {
908
+ const listada = categoria === 'chamada-alvo-ambiguo' || categoria === 'chamada-global-entre-arquivos' || categoria === 'chamada-por-import-divergente';
909
+ lacuna(categoria, n, listada ? n.expression.getText(sf) : null);
910
+ return;
911
+ }
912
+ // O trecho vai do inicio da chamada ao parentese de abertura: `soma(`, `new Classe(`.
913
+ const fim = n.arguments ? n.arguments.pos : n.expression.getEnd();
914
+ aresta('calls', atual, ref, trecho(n, fim));
915
+ };
916
+ const compilado = compiladoEm(fonte.path);
917
+ const visitar = (n, atual) => {
918
+ const proximo = simbolosDoTopo.has(n) ? (simbolosDoTopo.get(n) ?? null) : atual;
919
+ const chave = chaveDoImport(n, compilado);
920
+ if (ts.isImportDeclaration(n)) {
921
+ const r = chave === null ? null : importar(chave, trecho(n));
922
+ if (r && r.alvo !== null && !r.divergente && n.importClause) {
923
+ const ic = n.importClause;
924
+ if (ic.name)
925
+ simboloImportado(ic.name, trecho(ic.name));
926
+ if (ic.namedBindings && ts.isNamedImports(ic.namedBindings))
927
+ for (const el of ic.namedBindings.elements)
928
+ simboloImportado(el.name, trecho(el));
929
+ }
930
+ return;
931
+ }
932
+ if (ts.isExportDeclaration(n) && n.moduleSpecifier) {
933
+ const r = chave === null ? null : importar(chave, trecho(n));
934
+ if (r && r.alvo !== null && !r.divergente && n.exportClause && ts.isNamedExports(n.exportClause)) {
935
+ for (const el of n.exportClause.elements)
936
+ simboloImportado(el.name, trecho(el));
937
+ }
938
+ return;
939
+ }
940
+ if (ts.isImportEqualsDeclaration(n) && ts.isExternalModuleReference(n.moduleReference)) {
941
+ if (chave !== null)
942
+ importar(chave, trecho(n));
943
+ return;
944
+ }
945
+ if (ts.isImportTypeNode(n) && chave !== null)
946
+ importar(chave, trecho(n));
947
+ if (ehRequire(n) || ehImportDinamico(n)) {
948
+ if (chave !== null)
949
+ importar(chave, trecho(n));
950
+ else
951
+ diagnostico('dynamic-resolution', n.arguments[0] ? n.arguments[0].getText(sf) : '');
952
+ }
953
+ else if (ts.isCallExpression(n) || ts.isNewExpression(n))
954
+ chamada(n, proximo);
955
+ ts.forEachChild(n, (filho) => visitar(filho, proximo));
956
+ };
957
+ for (const st of sf.statements)
958
+ visitar(st, null);
959
+ }
960
+ // KG4 (D3): quem declara no escopo global (visto de um modulo vazio, sem local que o esconda) ou
961
+ // aumenta modulo alcanca arquivo que nao o importa; mudanca nele reextrai o TypeScript inteiro.
962
+ const doEscopoGlobal = programa.getSourceFile(sintetico);
963
+ if (!doEscopoGlobal)
964
+ throw new Error('extracao.interna.escopo-global');
965
+ const globais = new Set();
966
+ for (const simbolo of checker.getSymbolsInScope(doEscopoGlobal, -1)) {
967
+ for (const d of simbolo.declarations ?? []) {
968
+ const p = relativo(d.getSourceFile().fileName);
969
+ if (p !== null)
970
+ globais.add(p);
971
+ }
972
+ }
973
+ for (const sf of programa.getSourceFiles()) {
974
+ const aumentos = sf.moduleAugmentations, p = relativo(sf.fileName);
975
+ if (p !== null && aumentos && aumentos.length)
976
+ globais.add(p);
977
+ }
978
+ resultado.globais = [...globais].sort();
979
+ return resultado;
980
+ }