@miguelduran14/knowflow 0.1.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 (192) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +182 -0
  3. package/dist/advisories.d.ts +16 -0
  4. package/dist/advisories.js +364 -0
  5. package/dist/advisories.js.map +1 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +104 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/copy-resolver.d.ts +22 -0
  10. package/dist/copy-resolver.js +74 -0
  11. package/dist/copy-resolver.js.map +1 -0
  12. package/dist/dataflow.d.ts +2 -0
  13. package/dist/dataflow.js +88 -0
  14. package/dist/dataflow.js.map +1 -0
  15. package/dist/dossier.d.ts +20 -0
  16. package/dist/dossier.js +331 -0
  17. package/dist/dossier.js.map +1 -0
  18. package/dist/explain/claude.d.ts +14 -0
  19. package/dist/explain/claude.js +91 -0
  20. package/dist/explain/claude.js.map +1 -0
  21. package/dist/explain/explain.d.ts +72 -0
  22. package/dist/explain/explain.js +126 -0
  23. package/dist/explain/explain.js.map +1 -0
  24. package/dist/explain/facts.d.ts +23 -0
  25. package/dist/explain/facts.js +266 -0
  26. package/dist/explain/facts.js.map +1 -0
  27. package/dist/explain/fake.d.ts +14 -0
  28. package/dist/explain/fake.js +27 -0
  29. package/dist/explain/fake.js.map +1 -0
  30. package/dist/explain/openai.d.ts +42 -0
  31. package/dist/explain/openai.js +102 -0
  32. package/dist/explain/openai.js.map +1 -0
  33. package/dist/explain/provider.d.ts +19 -0
  34. package/dist/explain/provider.js +2 -0
  35. package/dist/explain/provider.js.map +1 -0
  36. package/dist/explain/sse.d.ts +10 -0
  37. package/dist/explain/sse.js +44 -0
  38. package/dist/explain/sse.js.map +1 -0
  39. package/dist/flow-parser.d.ts +10 -0
  40. package/dist/flow-parser.js +503 -0
  41. package/dist/flow-parser.js.map +1 -0
  42. package/dist/glossary.d.ts +54 -0
  43. package/dist/glossary.js +340 -0
  44. package/dist/glossary.js.map +1 -0
  45. package/dist/index.d.ts +17 -0
  46. package/dist/index.js +16 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/inventory.d.ts +7 -0
  49. package/dist/inventory.js +453 -0
  50. package/dist/inventory.js.map +1 -0
  51. package/dist/lines.d.ts +15 -0
  52. package/dist/lines.js +53 -0
  53. package/dist/lines.js.map +1 -0
  54. package/dist/linker.d.ts +17 -0
  55. package/dist/linker.js +56 -0
  56. package/dist/linker.js.map +1 -0
  57. package/dist/mermaid.d.ts +27 -0
  58. package/dist/mermaid.js +133 -0
  59. package/dist/mermaid.js.map +1 -0
  60. package/dist/parser.d.ts +19 -0
  61. package/dist/parser.js +442 -0
  62. package/dist/parser.js.map +1 -0
  63. package/dist/pic.d.ts +29 -0
  64. package/dist/pic.js +197 -0
  65. package/dist/pic.js.map +1 -0
  66. package/dist/references.d.ts +24 -0
  67. package/dist/references.js +906 -0
  68. package/dist/references.js.map +1 -0
  69. package/dist/source-lines.d.ts +56 -0
  70. package/dist/source-lines.js +114 -0
  71. package/dist/source-lines.js.map +1 -0
  72. package/dist/types.d.ts +499 -0
  73. package/dist/types.js +2 -0
  74. package/dist/types.js.map +1 -0
  75. package/gui/dist/assets/ChainCanvas-C37KyhnE.js +1 -0
  76. package/gui/dist/assets/FlowCanvas-BRklWBCp.js +3 -0
  77. package/gui/dist/assets/RobotProfessor-BtTDTBDq.js +4220 -0
  78. package/gui/dist/assets/fira-code-cyrillic-400-normal-UC0NFL4U.woff2 +0 -0
  79. package/gui/dist/assets/fira-code-cyrillic-400-normal-dc1q3VD7.woff +0 -0
  80. package/gui/dist/assets/fira-code-cyrillic-500-normal-Bu7VCL72.woff +0 -0
  81. package/gui/dist/assets/fira-code-cyrillic-500-normal-CX35h3Mg.woff2 +0 -0
  82. package/gui/dist/assets/fira-code-cyrillic-600-normal-BD56RyRT.woff +0 -0
  83. package/gui/dist/assets/fira-code-cyrillic-600-normal-CPRdbepc.woff2 +0 -0
  84. package/gui/dist/assets/fira-code-cyrillic-ext-400-normal-Buh61xzB.woff +0 -0
  85. package/gui/dist/assets/fira-code-cyrillic-ext-400-normal-txZ9Fk_1.woff2 +0 -0
  86. package/gui/dist/assets/fira-code-cyrillic-ext-500-normal-CYRspHgm.woff2 +0 -0
  87. package/gui/dist/assets/fira-code-cyrillic-ext-500-normal-CwtLmSFD.woff +0 -0
  88. package/gui/dist/assets/fira-code-cyrillic-ext-600-normal-B9wE0zmr.woff2 +0 -0
  89. package/gui/dist/assets/fira-code-cyrillic-ext-600-normal-DldcyWhZ.woff +0 -0
  90. package/gui/dist/assets/fira-code-greek-400-normal-B2Gh_Y8s.woff2 +0 -0
  91. package/gui/dist/assets/fira-code-greek-400-normal-DobhaxvF.woff +0 -0
  92. package/gui/dist/assets/fira-code-greek-500-normal-CVO0IRNt.woff2 +0 -0
  93. package/gui/dist/assets/fira-code-greek-500-normal-DEXIWiey.woff +0 -0
  94. package/gui/dist/assets/fira-code-greek-600-normal-D_h3X2X5.woff +0 -0
  95. package/gui/dist/assets/fira-code-greek-600-normal-Dxp52_By.woff2 +0 -0
  96. package/gui/dist/assets/fira-code-greek-ext-400-normal-DR7mBgIM.woff2 +0 -0
  97. package/gui/dist/assets/fira-code-greek-ext-400-normal-DSPUheWg.woff +0 -0
  98. package/gui/dist/assets/fira-code-greek-ext-500-normal-BO3iq16n.woff2 +0 -0
  99. package/gui/dist/assets/fira-code-greek-ext-500-normal-CMiNLXER.woff +0 -0
  100. package/gui/dist/assets/fira-code-greek-ext-600-normal-C-cQDoOk.woff +0 -0
  101. package/gui/dist/assets/fira-code-greek-ext-600-normal-DtBpFRLc.woff2 +0 -0
  102. package/gui/dist/assets/fira-code-latin-400-normal-C-QZfXAs.woff +0 -0
  103. package/gui/dist/assets/fira-code-latin-400-normal-DGosTW8U.woff2 +0 -0
  104. package/gui/dist/assets/fira-code-latin-500-normal-B6gioGu8.woff2 +0 -0
  105. package/gui/dist/assets/fira-code-latin-500-normal-aMLC2AMm.woff +0 -0
  106. package/gui/dist/assets/fira-code-latin-600-normal-BmSSHshu.woff +0 -0
  107. package/gui/dist/assets/fira-code-latin-600-normal-CvYZpPHg.woff2 +0 -0
  108. package/gui/dist/assets/fira-code-latin-ext-400-normal-DG73JjOf.woff +0 -0
  109. package/gui/dist/assets/fira-code-latin-ext-400-normal-KSMg0QLl.woff2 +0 -0
  110. package/gui/dist/assets/fira-code-latin-ext-500-normal-CaANqXjI.woff +0 -0
  111. package/gui/dist/assets/fira-code-latin-ext-500-normal-Crd9e_oI.woff2 +0 -0
  112. package/gui/dist/assets/fira-code-latin-ext-600-normal-0PFQL1eg.woff +0 -0
  113. package/gui/dist/assets/fira-code-latin-ext-600-normal-Cb7jxoAi.woff2 +0 -0
  114. package/gui/dist/assets/fira-code-symbols2-400-normal-_QEZCEwe.woff +0 -0
  115. package/gui/dist/assets/fira-code-symbols2-500-normal-DwsgbIjQ.woff +0 -0
  116. package/gui/dist/assets/fira-code-symbols2-600-normal-Dvq6IQE5.woff +0 -0
  117. package/gui/dist/assets/fira-sans-cyrillic-300-normal-BO7tmGom.woff2 +0 -0
  118. package/gui/dist/assets/fira-sans-cyrillic-300-normal-BtNmWoqn.woff +0 -0
  119. package/gui/dist/assets/fira-sans-cyrillic-400-normal-CKu2TFQr.woff2 +0 -0
  120. package/gui/dist/assets/fira-sans-cyrillic-400-normal-D9eUeF-O.woff +0 -0
  121. package/gui/dist/assets/fira-sans-cyrillic-500-normal-CXfldnQ8.woff2 +0 -0
  122. package/gui/dist/assets/fira-sans-cyrillic-500-normal-Daski1k2.woff +0 -0
  123. package/gui/dist/assets/fira-sans-cyrillic-600-normal-CJ5P9t7t.woff +0 -0
  124. package/gui/dist/assets/fira-sans-cyrillic-600-normal-JSBvCpTs.woff2 +0 -0
  125. package/gui/dist/assets/fira-sans-cyrillic-700-normal-Bl-HczEO.woff2 +0 -0
  126. package/gui/dist/assets/fira-sans-cyrillic-700-normal-KyW5QH4H.woff +0 -0
  127. package/gui/dist/assets/fira-sans-cyrillic-ext-300-normal-BRn8Tsce.woff2 +0 -0
  128. package/gui/dist/assets/fira-sans-cyrillic-ext-300-normal-DOtRq9zH.woff +0 -0
  129. package/gui/dist/assets/fira-sans-cyrillic-ext-400-normal-Cycyekte.woff2 +0 -0
  130. package/gui/dist/assets/fira-sans-cyrillic-ext-400-normal-Dd5dApAy.woff +0 -0
  131. package/gui/dist/assets/fira-sans-cyrillic-ext-500-normal-Cixivk4R.woff +0 -0
  132. package/gui/dist/assets/fira-sans-cyrillic-ext-500-normal-Dkk5LlrU.woff2 +0 -0
  133. package/gui/dist/assets/fira-sans-cyrillic-ext-600-normal-BKgjRriM.woff +0 -0
  134. package/gui/dist/assets/fira-sans-cyrillic-ext-600-normal-CE6oUZE1.woff2 +0 -0
  135. package/gui/dist/assets/fira-sans-cyrillic-ext-700-normal-BfO9TR-w.woff2 +0 -0
  136. package/gui/dist/assets/fira-sans-cyrillic-ext-700-normal-Gcpdxicj.woff +0 -0
  137. package/gui/dist/assets/fira-sans-greek-300-normal-D3JfF3y9.woff2 +0 -0
  138. package/gui/dist/assets/fira-sans-greek-300-normal-DSgcXl_1.woff +0 -0
  139. package/gui/dist/assets/fira-sans-greek-400-normal-BFCFncbp.woff2 +0 -0
  140. package/gui/dist/assets/fira-sans-greek-400-normal-DQ8sF22y.woff +0 -0
  141. package/gui/dist/assets/fira-sans-greek-500-normal-C9KT8sAy.woff +0 -0
  142. package/gui/dist/assets/fira-sans-greek-500-normal-Cy-TUuxE.woff2 +0 -0
  143. package/gui/dist/assets/fira-sans-greek-600-normal-BlqpLOpF.woff2 +0 -0
  144. package/gui/dist/assets/fira-sans-greek-600-normal-DfHu91YF.woff +0 -0
  145. package/gui/dist/assets/fira-sans-greek-700-normal-BVfcrbV7.woff2 +0 -0
  146. package/gui/dist/assets/fira-sans-greek-700-normal-CJu31rC4.woff +0 -0
  147. package/gui/dist/assets/fira-sans-greek-ext-300-normal-CodlqOxk.woff +0 -0
  148. package/gui/dist/assets/fira-sans-greek-ext-300-normal-DVDwbKuK.woff2 +0 -0
  149. package/gui/dist/assets/fira-sans-greek-ext-400-normal-ByG7UNQ2.woff2 +0 -0
  150. package/gui/dist/assets/fira-sans-greek-ext-400-normal-ClCfNE6D.woff +0 -0
  151. package/gui/dist/assets/fira-sans-greek-ext-500-normal-Bem4H9fH.woff +0 -0
  152. package/gui/dist/assets/fira-sans-greek-ext-500-normal-nq-cjB3m.woff2 +0 -0
  153. package/gui/dist/assets/fira-sans-greek-ext-600-normal-DPxZoeHL.woff +0 -0
  154. package/gui/dist/assets/fira-sans-greek-ext-600-normal-fS0evUH3.woff2 +0 -0
  155. package/gui/dist/assets/fira-sans-greek-ext-700-normal-C1m6bE4Q.woff2 +0 -0
  156. package/gui/dist/assets/fira-sans-greek-ext-700-normal-C8J5qYMq.woff +0 -0
  157. package/gui/dist/assets/fira-sans-latin-300-normal-B2LrTgQS.woff2 +0 -0
  158. package/gui/dist/assets/fira-sans-latin-300-normal-Dwkm-oZ7.woff +0 -0
  159. package/gui/dist/assets/fira-sans-latin-400-normal-66xCkunx.woff +0 -0
  160. package/gui/dist/assets/fira-sans-latin-400-normal-a0AnQzuD.woff2 +0 -0
  161. package/gui/dist/assets/fira-sans-latin-500-normal-Bkfzcwmr.woff +0 -0
  162. package/gui/dist/assets/fira-sans-latin-500-normal-Bvbxc8ch.woff2 +0 -0
  163. package/gui/dist/assets/fira-sans-latin-600-normal-CXKlxLG9.woff2 +0 -0
  164. package/gui/dist/assets/fira-sans-latin-600-normal-DtSgd811.woff +0 -0
  165. package/gui/dist/assets/fira-sans-latin-700-normal-CRhwpWTq.woff2 +0 -0
  166. package/gui/dist/assets/fira-sans-latin-700-normal-DgqLm3Fi.woff +0 -0
  167. package/gui/dist/assets/fira-sans-latin-ext-300-normal-CAROBYR0.woff +0 -0
  168. package/gui/dist/assets/fira-sans-latin-ext-300-normal-GNF4Ac3G.woff2 +0 -0
  169. package/gui/dist/assets/fira-sans-latin-ext-400-normal-BCUwhuGB.woff +0 -0
  170. package/gui/dist/assets/fira-sans-latin-ext-400-normal-BLG_mAEf.woff2 +0 -0
  171. package/gui/dist/assets/fira-sans-latin-ext-500-normal-CFRf4jcC.woff +0 -0
  172. package/gui/dist/assets/fira-sans-latin-ext-500-normal-OO1QnNpY.woff2 +0 -0
  173. package/gui/dist/assets/fira-sans-latin-ext-600-normal-DLMQsaV4.woff +0 -0
  174. package/gui/dist/assets/fira-sans-latin-ext-600-normal-DTQBTt1m.woff2 +0 -0
  175. package/gui/dist/assets/fira-sans-latin-ext-700-normal-cfTxGFzJ.woff +0 -0
  176. package/gui/dist/assets/fira-sans-latin-ext-700-normal-g2Yrd4J5.woff2 +0 -0
  177. package/gui/dist/assets/fira-sans-vietnamese-300-normal-BO7He0nF.woff2 +0 -0
  178. package/gui/dist/assets/fira-sans-vietnamese-300-normal-CeyOCBN-.woff +0 -0
  179. package/gui/dist/assets/fira-sans-vietnamese-400-normal-DUVG35gE.woff +0 -0
  180. package/gui/dist/assets/fira-sans-vietnamese-400-normal-ljDTQFsx.woff2 +0 -0
  181. package/gui/dist/assets/fira-sans-vietnamese-500-normal-ChEXCnJy.woff2 +0 -0
  182. package/gui/dist/assets/fira-sans-vietnamese-500-normal-UV7M6ot_.woff +0 -0
  183. package/gui/dist/assets/fira-sans-vietnamese-600-normal-Bxjaclsw.woff +0 -0
  184. package/gui/dist/assets/fira-sans-vietnamese-600-normal-Dh2KAvU8.woff2 +0 -0
  185. package/gui/dist/assets/fira-sans-vietnamese-700-normal-DFi88MGY.woff +0 -0
  186. package/gui/dist/assets/fira-sans-vietnamese-700-normal-j5oLGLJY.woff2 +0 -0
  187. package/gui/dist/assets/index-CwQzep9r.js +413 -0
  188. package/gui/dist/assets/index-DUFjnEFT.css +1 -0
  189. package/gui/dist/assets/theme-BnuhLJ6X.css +1 -0
  190. package/gui/dist/assets/theme-G7EkTZY2.js +30 -0
  191. package/gui/dist/index.html +13 -0
  192. package/package.json +62 -0
@@ -0,0 +1,364 @@
1
+ import { cleanLines } from './source-lines.js';
2
+ /**
3
+ * Trampas de mantenimiento COBOL conocidas, detectadas sobre hechos YA
4
+ * verificados por el parser (datos, flujo, inventario) — nunca sobre una
5
+ * interpretación nueva. Es una pasada determinista más, hermana de
6
+ * `factsFidelity`: mientras esa marca lo que NO se pudo verificar, esta
7
+ * marca lo que SÍ está verificado pero es arriesgado. Ver el tipo
8
+ * `Advisory` en `types.ts` para la distinción completa.
9
+ *
10
+ * Cada regla es independiente y de alta confianza — prefiere no avisar a
11
+ * avisar con un falso positivo. Ninguna regla necesita el fuente crudo
12
+ * salvo la de STOP RUN (que masca literales y recorta columnas fijas con
13
+ * las mismas utilidades que ya usan flow-parser/inventory, para no
14
+ * duplicar esa lógica con una regex ingenua).
15
+ */
16
+ export function checkAdvisories(source, data, flow, inventory) {
17
+ const out = [];
18
+ if (flow) {
19
+ out.push(...stopRunInSubprogram(source, data, flow));
20
+ out.push(...gotoCrossesSection(flow));
21
+ out.push(...alterStatements(source, flow));
22
+ out.push(...unreachableParagraphs(source, flow));
23
+ }
24
+ if (inventory) {
25
+ out.push(...sqlWriteWithoutWhere(inventory));
26
+ out.push(...fileOpenedNotClosed(inventory));
27
+ out.push(...cursorAdvisories(inventory));
28
+ out.push(...unusedCursors(inventory));
29
+ out.push(...unusedFiles(inventory));
30
+ }
31
+ return out.sort((a, b) => a.line - b.line);
32
+ }
33
+ const STOP_RUN_RE = /(?<![\w-])STOP\s+RUN(?![\w-])/i;
34
+ function hasLinkageParams(data) {
35
+ const isLinkage = (f) => f.dataSection === 'LINKAGE' || f.children.some(isLinkage);
36
+ return (data?.records ?? []).some(isLinkage);
37
+ }
38
+ /**
39
+ * STOP RUN termina el job ENTERO, no solo el módulo actual (GOBACK/EXIT
40
+ * PROGRAM sí devuelven al llamador). Un programa con LINKAGE SECTION
41
+ * recibe parámetros — solo llega ahí una CALL, así que es (casi con toda
42
+ * certeza) un subprograma. STOP RUN en un párrafo suyo es la trampa
43
+ * clásica: quien lo mantiene ve el job entero morir por un módulo que
44
+ * "solo" fallaba una validación.
45
+ */
46
+ function stopRunInSubprogram(source, data, flow) {
47
+ if (!hasLinkageParams(data))
48
+ return [];
49
+ const declared = flow.paragraphs.filter((p) => !p.implicit && p.line !== undefined);
50
+ if (declared.length === 0)
51
+ return [];
52
+ const lines = cleanLines(source);
53
+ const out = [];
54
+ for (let i = 0; i < declared.length; i++) {
55
+ const para = declared[i];
56
+ if (!para.terminates)
57
+ continue;
58
+ const end = declared[i + 1]?.line ?? Infinity;
59
+ const hit = lines.find(l => l.line >= para.line && l.line < end && STOP_RUN_RE.test(l.masked));
60
+ if (hit) {
61
+ out.push({
62
+ rule: 'stop-run-in-subprogram',
63
+ title: 'STOP RUN en un subprograma',
64
+ message: `El párrafo ${para.name} ejecuta STOP RUN, pero el programa tiene LINKAGE SECTION (recibe parámetros por CALL): parece un subprograma. ` +
65
+ 'STOP RUN termina el job ENTERO, no solo este módulo — probablemente debería ser GOBACK.',
66
+ line: hit.line,
67
+ paragraph: para.name,
68
+ });
69
+ }
70
+ }
71
+ return out;
72
+ }
73
+ /**
74
+ * Un GO TO que cruza de una SECTION a otra puede saltarse la limpieza o
75
+ * inicialización propia de la sección en la que estaba (cierres de
76
+ * fichero, ROLLBACK) — el mismo riesgo que documenta el glosario para
77
+ * GO TO, pero aquí verificado contra el fuente: sección de origen y de
78
+ * destino son distintas de verdad, no una suposición.
79
+ */
80
+ function gotoCrossesSection(flow) {
81
+ // COBOL es case-insensitive: el mapa y las consultas van en mayúsculas para
82
+ // que un `GO TO Para-B` case contra el párrafo `PARA-B`. Sin normalizar, una
83
+ // diferencia de grafía dejaba el aviso sin disparar (falso negativo).
84
+ const sectionOf = new Map();
85
+ for (const p of flow.paragraphs) {
86
+ if (p.section)
87
+ sectionOf.set(p.name.toUpperCase(), p.section);
88
+ }
89
+ if (sectionOf.size === 0)
90
+ return [];
91
+ const out = [];
92
+ for (const edge of flow.edges) {
93
+ if (edge.kind !== 'goto')
94
+ continue;
95
+ const from = sectionOf.get(edge.from.toUpperCase());
96
+ const to = sectionOf.get(edge.to.toUpperCase());
97
+ if (from && to && from !== to) {
98
+ out.push({
99
+ rule: 'goto-crosses-section',
100
+ title: 'GO TO cruza de sección',
101
+ message: `GO TO ${edge.to} salta de la sección ${from} a ${to}: puede saltarse un cierre o una inicialización propia de ${from} que el mantenedor da por hecha.`,
102
+ line: edge.line,
103
+ paragraph: edge.from,
104
+ });
105
+ }
106
+ }
107
+ return out;
108
+ }
109
+ const ALTER_RE = /(?<![\w-])ALTER\s+([\w-]+)\s+TO\s+(?:PROCEED\s+TO\s+)?([\w-]+)/i;
110
+ /**
111
+ * ALTER cambia en tiempo de ejecución el destino de un GO TO (`ALTER X TO
112
+ * PROCEED TO Y`): el mismo párrafo salta a sitios distintos según lo que se
113
+ * haya ALTERado antes. Es de las construcciones más traicioneras que quedan
114
+ * en COBOL legacy —el diagrama de flujo NO puede mostrar el destino real,
115
+ * porque depende de la ejecución— así que se marca como aviso en vez de
116
+ * fingir una arista que el fuente no fija (ADR-0003). Deprecada desde el 85;
117
+ * su sola presencia ya es una señal para quien mantiene.
118
+ */
119
+ function alterStatements(source, flow) {
120
+ const declared = flow.paragraphs
121
+ .filter((p) => !p.implicit && p.line !== undefined)
122
+ .sort((a, b) => a.line - b.line);
123
+ // Párrafo que contiene una línea dada: el último cuya cabecera está en o
124
+ // antes de esa línea.
125
+ const paragraphAt = (line) => {
126
+ let name;
127
+ for (const p of declared) {
128
+ if (p.line <= line)
129
+ name = p.name;
130
+ else
131
+ break;
132
+ }
133
+ return name;
134
+ };
135
+ const out = [];
136
+ for (const { masked, line } of cleanLines(source)) {
137
+ const m = ALTER_RE.exec(masked);
138
+ if (!m)
139
+ continue;
140
+ const paragraph = paragraphAt(line);
141
+ out.push({
142
+ rule: 'alter-statement',
143
+ title: 'ALTER cambia un GO TO en ejecución',
144
+ message: `ALTER ${m[1]} TO ${m[2]}: cambia en ejecución el destino del GO TO de ${m[1]}, así que el flujo real depende de qué se haya ALTERado antes — el diagrama no puede mostrarlo. ` +
145
+ 'ALTER está deprecado; considera reescribir la lógica con EVALUATE/PERFORM.',
146
+ line,
147
+ ...(paragraph ? { paragraph } : {}),
148
+ });
149
+ }
150
+ return out;
151
+ }
152
+ const WHERE_RE = /(?<![\w-])WHERE(?![\w-])/i;
153
+ /**
154
+ * UPDATE/DELETE sin WHERE visible afecta a TODA la tabla, no a una fila —
155
+ * el error clásico de un SQL embebido mal probado. Si el recurso ya es
156
+ * dinámico, el motor lo marca aparte (no se conoce ni la tabla): no
157
+ * duplicamos el aviso para no ensuciar con dos mensajes la misma duda.
158
+ */
159
+ function sqlWriteWithoutWhere(inventory) {
160
+ const out = [];
161
+ for (const exec of inventory.execs) {
162
+ if (exec.kind !== 'sql' || exec.dynamic)
163
+ continue;
164
+ const verb = exec.verb.toUpperCase();
165
+ if (verb !== 'UPDATE' && verb !== 'DELETE')
166
+ continue;
167
+ if (WHERE_RE.test(exec.text))
168
+ continue;
169
+ out.push({
170
+ rule: 'sql-write-without-where',
171
+ title: `${verb} sin WHERE`,
172
+ message: `${verb} sin cláusula WHERE visible en el bloque: afecta a TODAS las filas de la tabla, no a una — confirma si es intencional.`,
173
+ line: exec.line,
174
+ paragraph: exec.paragraph,
175
+ });
176
+ }
177
+ return out;
178
+ }
179
+ // Modos de OPEN que escriben: si uno de estos queda sin CLOSE, hay buffers de
180
+ // salida que pueden perderse. Un OPEN INPUT sin CLOSE es mucho menos grave
181
+ // —COBOL cierra los ficheros implícitamente al STOP RUN, y un lector no tiene
182
+ // nada que volcar— así que avisar de él es casi siempre ruido.
183
+ const WRITE_OPEN_MODES = new Set(['OUTPUT', 'I-O', 'EXTEND']);
184
+ /**
185
+ * Un fichero abierto para ESCRITURA (OUTPUT/I-O/EXTEND) y nunca cerrado en el
186
+ * fuente aportado puede dejar buffers sin volcar o el dataset inconsistente si
187
+ * el programa termina sin pasar por el CLOSE. Se restringe a los modos de
188
+ * escritura para no inundar con avisos de lectores sin CLOSE, que COBOL cierra
189
+ * de todos modos al terminar. Se ancla al OPEN que abre la duda.
190
+ */
191
+ function fileOpenedNotClosed(inventory) {
192
+ const out = [];
193
+ for (const file of inventory.files) {
194
+ const writeOpen = file.operations.find(op => op.verb === 'OPEN' && op.mode !== undefined && WRITE_OPEN_MODES.has(op.mode));
195
+ const closed = file.operations.some(op => op.verb === 'CLOSE');
196
+ if (writeOpen && !closed) {
197
+ out.push({
198
+ rule: 'file-opened-not-closed',
199
+ title: `${file.name} sin CLOSE`,
200
+ message: `${file.name} se abre para escritura (OPEN ${writeOpen.mode}) pero no aparece un CLOSE en el fuente aportado. Si el programa termina sin cerrarlo, puede dejar buffers sin volcar.`,
201
+ line: writeOpen.line,
202
+ paragraph: writeOpen.paragraphImplicit ? undefined : writeOpen.paragraph,
203
+ });
204
+ }
205
+ }
206
+ return out;
207
+ }
208
+ /**
209
+ * Mismo riesgo que un fichero sin CLOSE, pero para cursores DB2 — deja el
210
+ * cursor ocupando recursos hasta el fin de la unidad de trabajo. Y un
211
+ * FETCH sin OPEN previo (con el cursor declarado en el fuente aportado,
212
+ * para no acusar un OPEN que en realidad vive en un copybook ausente)
213
+ * fallaría en ejecución. La línea de anclaje sale del bloque EXEC que
214
+ * disparó cada operación — `CursorUsage` es un agregado sin línea propia.
215
+ */
216
+ function cursorAdvisories(inventory) {
217
+ const out = [];
218
+ for (const cursor of inventory.cursors) {
219
+ const execFor = (verb) => inventory.execs.find(e => e.cursor === cursor.name && e.verb === verb);
220
+ if (cursor.opened && !cursor.closed) {
221
+ const open = execFor('OPEN');
222
+ out.push({
223
+ rule: 'cursor-opened-not-closed',
224
+ title: `Cursor ${cursor.name} sin CLOSE`,
225
+ message: `El cursor ${cursor.name} se abre (OPEN) pero no se cierra (CLOSE) en el fuente aportado: queda ocupando recursos en DB2 hasta el fin de la unidad de trabajo.`,
226
+ line: open?.line ?? 0,
227
+ paragraph: open?.paragraphImplicit ? undefined : open?.paragraph,
228
+ });
229
+ }
230
+ if (cursor.fetched && !cursor.opened && cursor.declared) {
231
+ const fetch = execFor('FETCH');
232
+ out.push({
233
+ rule: 'cursor-fetched-without-open',
234
+ title: `Cursor ${cursor.name}: FETCH sin OPEN`,
235
+ message: `El cursor ${cursor.name} tiene FETCH pero no OPEN en el fuente aportado — si el OPEN no está en un copybook ausente, el FETCH fallaría en ejecución.`,
236
+ line: fetch?.line ?? 0,
237
+ paragraph: fetch?.paragraphImplicit ? undefined : fetch?.paragraph,
238
+ });
239
+ }
240
+ }
241
+ return out;
242
+ }
243
+ // COBOL es case-insensitive: los nombres de párrafo se comparan en mayúsculas.
244
+ const upper = (name) => name.toUpperCase();
245
+ /** ¿La PROCEDURE DIVISION contiene un COPY? Un COPY puede inyectar PERFORMs
246
+ * que el parser de flujo no ve (no expande copybooks), así que la
247
+ * alcanzabilidad deja de ser fiable. */
248
+ function procedureHasCopy(source) {
249
+ let inProcedure = false;
250
+ for (const { masked } of cleanLines(source)) {
251
+ if (/^\s*PROCEDURE\s+DIVISION/i.test(masked)) {
252
+ inProcedure = true;
253
+ continue;
254
+ }
255
+ if (inProcedure && /(?<![\w-])COPY\s+[A-Za-z0-9]/i.test(masked))
256
+ return true;
257
+ }
258
+ return false;
259
+ }
260
+ /** ¿Hay algún ALTER? ALTER cambia el destino de un GO TO en ejecución, así
261
+ * que un párrafo podría alcanzarse por una vía que el grafo no modela. */
262
+ function sourceHasAlter(source) {
263
+ return cleanLines(source).some(l => /(?<![\w-])ALTER\s+[A-Za-z0-9]/i.test(l.masked));
264
+ }
265
+ /**
266
+ * Párrafos que ningún camino de ejecución alcanza: código muerto. Se hace un
267
+ * recorrido desde las entradas (el primer párrafo, el nodo de entrada
268
+ * implícito y los párrafos de DECLARATIVES, que invoca el runtime) siguiendo
269
+ * PERFORM/GO TO/caída natural/SORT — las CALL no cuentan (van a otro
270
+ * programa). Un párrafo declarado que no se alcanza parece eliminable.
271
+ *
272
+ * Honestidad (ADR-0003): si el flujo puede estar incompleto —un COPY en la
273
+ * PROCEDURE que inyecte PERFORMs no vistos, o un ALTER que redirija un GO TO—
274
+ * NO se acusa a nadie: prefiere no avisar a un falso positivo.
275
+ */
276
+ function unreachableParagraphs(source, flow) {
277
+ if (procedureHasCopy(source) || sourceHasAlter(source))
278
+ return [];
279
+ if (flow.paragraphs.length === 0)
280
+ return [];
281
+ // Adyacencia por nombre (mayúsculas): destino de cada arista a un párrafo.
282
+ const adj = new Map();
283
+ for (const edge of flow.edges) {
284
+ if (edge.kind === 'call')
285
+ continue;
286
+ const from = upper(edge.from);
287
+ if (!adj.has(from))
288
+ adj.set(from, []);
289
+ adj.get(from).push(upper(edge.to));
290
+ }
291
+ // Entradas del programa.
292
+ const entries = new Set();
293
+ entries.add(upper(flow.paragraphs[0].name));
294
+ for (const p of flow.paragraphs) {
295
+ if (p.implicit || p.inDeclaratives)
296
+ entries.add(upper(p.name));
297
+ }
298
+ const reachable = new Set(entries);
299
+ const stack = [...entries];
300
+ while (stack.length > 0) {
301
+ const cur = stack.pop();
302
+ for (const next of adj.get(cur) ?? []) {
303
+ if (!reachable.has(next)) {
304
+ reachable.add(next);
305
+ stack.push(next);
306
+ }
307
+ }
308
+ }
309
+ const out = [];
310
+ for (const para of flow.paragraphs) {
311
+ if (para.implicit || para.inDeclaratives || para.line === undefined)
312
+ continue;
313
+ if (reachable.has(upper(para.name)))
314
+ continue;
315
+ out.push({
316
+ rule: 'unreachable-paragraph',
317
+ title: `${para.name} inalcanzable`,
318
+ message: `Ningún PERFORM, GO TO ni caída natural llega a ${para.name} en el fuente aportado: parece código muerto. Confirma que no lo referencia un copybook no aportado antes de eliminarlo.`,
319
+ line: para.line,
320
+ paragraph: para.name,
321
+ });
322
+ }
323
+ return out;
324
+ }
325
+ /**
326
+ * Cursor DB2 declarado y sin usar: un DECLARE sin OPEN/FETCH/CLOSE en el
327
+ * fuente aportado. O sobra, o su uso vive en un copybook ausente.
328
+ */
329
+ function unusedCursors(inventory) {
330
+ const out = [];
331
+ for (const cursor of inventory.cursors) {
332
+ if (cursor.declared && !cursor.opened && !cursor.fetched && !cursor.closed) {
333
+ const declare = inventory.execs.find(e => e.cursor === cursor.name && e.verb === 'DECLARE');
334
+ out.push({
335
+ rule: 'unused-cursor',
336
+ title: `Cursor ${cursor.name} sin usar`,
337
+ message: `El cursor ${cursor.name} se declara (DECLARE) pero no se abre, lee ni cierra en el fuente aportado: parece declarado y sin uso.`,
338
+ line: declare?.line ?? 0,
339
+ ...(declare && !declare.paragraphImplicit && declare.paragraph ? { paragraph: declare.paragraph } : {}),
340
+ });
341
+ }
342
+ }
343
+ return out;
344
+ }
345
+ /**
346
+ * Fichero declarado en FILE-CONTROL (SELECT) y sin ninguna operación de E/S
347
+ * en el fuente aportado: o sobra el SELECT, o el uso está en un copybook
348
+ * ausente. No lleva línea propia (el SELECT no se ancla a una).
349
+ */
350
+ function unusedFiles(inventory) {
351
+ const out = [];
352
+ for (const file of inventory.files) {
353
+ if (file.operations.length === 0) {
354
+ out.push({
355
+ rule: 'unused-file',
356
+ title: `${file.name} declarado y sin usar`,
357
+ message: `El fichero ${file.name} se declara en FILE-CONTROL (SELECT) pero no aparece ninguna operación (OPEN/READ/WRITE…) sobre él en el fuente aportado.`,
358
+ line: 0,
359
+ });
360
+ }
361
+ }
362
+ return out;
363
+ }
364
+ //# sourceMappingURL=advisories.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"advisories.js","sourceRoot":"","sources":["../src/advisories.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+ // Punto de entrada `npx knowflow`: sirve la GUI ya compilada (gui/dist) en
3
+ // localhost y abre el navegador. Sin dependencias de servidor — un archivo
4
+ // estático servido a mano es toda la superficie que necesita esta app (no
5
+ // hay backend propio, ADR-0002). Local-first: nada de lo servido sale de
6
+ // esta máquina; la única llamada de red la hace el navegador, directa al
7
+ // proveedor de IA que el usuario configure en la GUI.
8
+ import { exec } from 'node:child_process';
9
+ import { existsSync } from 'node:fs';
10
+ import { readFile } from 'node:fs/promises';
11
+ import { createServer } from 'node:http';
12
+ import { extname, join, resolve } from 'node:path';
13
+ import { fileURLToPath } from 'node:url';
14
+ const here = fileURLToPath(new URL('.', import.meta.url));
15
+ // Publicado: dist/cli.js junto a gui/dist (ver "files" en package.json).
16
+ const GUI_DIST = resolve(here, '..', 'gui', 'dist');
17
+ const INDEX_HTML = join(GUI_DIST, 'index.html');
18
+ const MIME = {
19
+ '.html': 'text/html; charset=utf-8',
20
+ '.js': 'text/javascript; charset=utf-8',
21
+ '.css': 'text/css; charset=utf-8',
22
+ '.json': 'application/json; charset=utf-8',
23
+ '.svg': 'image/svg+xml',
24
+ '.png': 'image/png',
25
+ '.woff': 'font/woff',
26
+ '.woff2': 'font/woff2',
27
+ '.ico': 'image/x-icon',
28
+ };
29
+ function openBrowser(url) {
30
+ const cmd = process.platform === 'win32' ? `start "" "${url}"` : process.platform === 'darwin' ? `open "${url}"` : `xdg-open "${url}"`;
31
+ exec(cmd, () => {
32
+ // Si falla (entorno sin GUI, contenedor…), el usuario ya tiene la URL
33
+ // impresa en consola — no es un error que deba cortar el arranque.
34
+ });
35
+ }
36
+ async function serveFile(path) {
37
+ try {
38
+ const body = await readFile(path);
39
+ return { body, type: MIME[extname(path)] ?? 'application/octet-stream' };
40
+ }
41
+ catch {
42
+ return undefined;
43
+ }
44
+ }
45
+ // Versión mínima de Node (coincide con "engines" en package.json). Este
46
+ // aviso solo puede saltar si Node EXISTE pero es viejo — sin Node instalado
47
+ // no hay intérprete que lo muestre; para ese caso, el README indica cómo
48
+ // instalarlo. Aquí se convierte un fallo por sintaxis/API moderna en un
49
+ // mensaje claro con el comando para actualizar.
50
+ const MIN_NODE = 18;
51
+ function checkNodeVersion() {
52
+ const major = Number(process.versions.node.split('.')[0]);
53
+ if (major >= MIN_NODE)
54
+ return true;
55
+ console.error(`\nKnowFlow necesita Node ${MIN_NODE} o superior. Estás usando Node ${process.versions.node}.\n\n` +
56
+ 'Actualiza Node (elige uno):\n' +
57
+ ' • Instalador LTS: https://nodejs.org\n' +
58
+ ' • Windows (winget): winget install OpenJS.NodeJS.LTS\n' +
59
+ ' • macOS (brew): brew install node\n' +
60
+ ' • Con nvm: nvm install --lts\n\n' +
61
+ "Luego vuelve a ejecutar 'npx knowflow'.\n");
62
+ return false;
63
+ }
64
+ async function main() {
65
+ if (!checkNodeVersion()) {
66
+ process.exitCode = 1;
67
+ return;
68
+ }
69
+ if (!existsSync(INDEX_HTML)) {
70
+ console.error('No se encuentra la GUI compilada (gui/dist/index.html).\n' +
71
+ 'Si trabajas desde el repo de desarrollo: npm run build\n' +
72
+ 'Si instalaste el paquete publicado, esto es un bug — abre un issue.');
73
+ process.exitCode = 1;
74
+ return;
75
+ }
76
+ const port = Number(process.env.PORT) || Number(process.argv[2]) || 4173;
77
+ const server = createServer((req, res) => {
78
+ const urlPath = decodeURIComponent((req.url ?? '/').split('?')[0]);
79
+ const requested = resolve(GUI_DIST, '.' + (urlPath === '/' ? '/index.html' : urlPath));
80
+ // Guarda contra path traversal: cualquier ruta resuelta debe seguir
81
+ // dentro de GUI_DIST.
82
+ const safe = requested === GUI_DIST || requested.startsWith(GUI_DIST + '\\') || requested.startsWith(GUI_DIST + '/');
83
+ const target = safe ? requested : INDEX_HTML;
84
+ void serveFile(target).then(async (hit) => {
85
+ // SPA fallback: cualquier ruta no encontrada (recarga en una vista
86
+ // que no es un fichero real) sirve index.html en vez de 404.
87
+ const resolved = hit ?? (await serveFile(INDEX_HTML));
88
+ if (!resolved) {
89
+ res.writeHead(404).end('No encontrado');
90
+ return;
91
+ }
92
+ res.writeHead(200, { 'Content-Type': resolved.type });
93
+ res.end(resolved.body);
94
+ });
95
+ });
96
+ server.listen(port, () => {
97
+ const url = `http://localhost:${port}`;
98
+ console.log(`KnowFlow corriendo en ${url}`);
99
+ console.log('Local-first: el código que analices no sale de esta máquina, salvo la llamada al proveedor de IA que tú configures dentro de la app.');
100
+ openBrowser(url);
101
+ });
102
+ }
103
+ void main();
104
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export type ResolvedStatement = {
2
+ kind: 'text';
3
+ statement: string;
4
+ } | {
5
+ kind: 'unresolved-copy';
6
+ member: string;
7
+ };
8
+ export interface CopyResolutionResult {
9
+ statements: ResolvedStatement[];
10
+ /** Members de COPY/EXEC SQL INCLUDE no encontrados en el conjunto aportado */
11
+ missingCopybooks: string[];
12
+ }
13
+ /**
14
+ * Resuelve COPY y EXEC SQL INCLUDE contra el conjunto de copybooks
15
+ * aportado, recursivamente (un member puede a su vez tener COPY).
16
+ *
17
+ * Un member no encontrado se marca como `{ kind: 'unresolved-copy' }` en
18
+ * el flujo de sentencias — nunca se inventa contenido para él (ADR-0003).
19
+ * Un COPY circular (member A copia a B que copia a A) se trata igual que
20
+ * un member ausente, para no expandir indefinidamente.
21
+ */
22
+ export declare function resolveCopies(statements: string[], copybooks: Map<string, string>, missing?: string[], seen?: ReadonlySet<string>): CopyResolutionResult;
@@ -0,0 +1,74 @@
1
+ import { joinContinuations } from './lines.js';
2
+ // `COPY member [OF|IN library] [REPLACING ...].` La biblioteca (OF/IN) se
3
+ // reconoce pero se descarta: KnowFlow identifica los copybooks por nombre de
4
+ // member, no por biblioteca. Sin admitir OF/IN, un `COPY CUSTREC OF MYLIB.`
5
+ // no casaba con COPY_RE y se perdía en silencio — ni resuelto ni marcado
6
+ // como hueco, violando el contrato de fidelidad (ADR-0003).
7
+ const COPY_RE = /^COPY\s+([\w-]+)(?:\s+(?:OF|IN)\s+[\w-]+)?(?:\s+REPLACING\s+(.+?))?\s*\.\s*$/i;
8
+ const EXEC_SQL_INCLUDE_RE = /^EXEC\s+SQL\s+INCLUDE\s+([\w-]+)\s+END-EXEC\s*\.?\s*$/i;
9
+ /** Extrae pares FROM/BY de una cláusula REPLACING — con o sin pseudo-texto ==...== */
10
+ function parseReplacingClause(clause) {
11
+ const pairs = [];
12
+ const re = /(?:==(.*?)==|(\S+))\s+BY\s+(?:==(.*?)==|(\S+))/gi;
13
+ let m;
14
+ while ((m = re.exec(clause))) {
15
+ const from = (m[1] ?? m[2] ?? '').trim();
16
+ const to = (m[3] ?? m[4] ?? '').trim();
17
+ if (from)
18
+ pairs.push({ from, to });
19
+ }
20
+ return pairs;
21
+ }
22
+ function applyReplacing(text, replacements) {
23
+ let result = text;
24
+ for (const { from, to } of replacements) {
25
+ const escaped = from.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
26
+ // El límite de palabra de COBOL no es \b: un identificador con guiones
27
+ // ("ITEM-CODE") es UNA sola palabra léxica, distinta de "ITEM". \b trata
28
+ // el guion como frontera, así que confundiría ambas — el límite real
29
+ // exige que ni antes ni después del token haya letra, dígito o guion.
30
+ result = result.replace(new RegExp(`(?<![A-Za-z0-9-])${escaped}(?![A-Za-z0-9-])`, 'gi'), to);
31
+ }
32
+ return result;
33
+ }
34
+ /**
35
+ * Resuelve COPY y EXEC SQL INCLUDE contra el conjunto de copybooks
36
+ * aportado, recursivamente (un member puede a su vez tener COPY).
37
+ *
38
+ * Un member no encontrado se marca como `{ kind: 'unresolved-copy' }` en
39
+ * el flujo de sentencias — nunca se inventa contenido para él (ADR-0003).
40
+ * Un COPY circular (member A copia a B que copia a A) se trata igual que
41
+ * un member ausente, para no expandir indefinidamente.
42
+ */
43
+ export function resolveCopies(statements, copybooks, missing = [], seen = new Set()) {
44
+ const resolved = [];
45
+ for (const stmt of statements) {
46
+ const copyMatch = COPY_RE.exec(stmt);
47
+ const execMatch = !copyMatch ? EXEC_SQL_INCLUDE_RE.exec(stmt) : null;
48
+ const match = copyMatch ?? execMatch;
49
+ if (!match) {
50
+ resolved.push({ kind: 'text', statement: stmt });
51
+ continue;
52
+ }
53
+ // COBOL es case-insensitive: COPY Customer y COPY CUSTOMER son el
54
+ // mismo member. Todo el lookup se normaliza a mayúsculas.
55
+ const memberName = match[1].toUpperCase();
56
+ const replacingClause = copyMatch?.[2];
57
+ const memberSource = seen.has(memberName) ? undefined : copybooks.get(memberName);
58
+ if (memberSource === undefined) {
59
+ if (!missing.includes(memberName))
60
+ missing.push(memberName);
61
+ resolved.push({ kind: 'unresolved-copy', member: memberName });
62
+ continue;
63
+ }
64
+ const replacements = replacingClause ? parseReplacingClause(replacingClause) : [];
65
+ const expandedText = replacements.length > 0 ? applyReplacing(memberSource, replacements) : memberSource;
66
+ const memberStatements = joinContinuations(expandedText.split(/\r?\n/));
67
+ const nestedSeen = new Set(seen);
68
+ nestedSeen.add(memberName);
69
+ const nested = resolveCopies(memberStatements, copybooks, missing, nestedSeen);
70
+ resolved.push(...nested.statements);
71
+ }
72
+ return { statements: resolved, missingCopybooks: missing };
73
+ }
74
+ //# sourceMappingURL=copy-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy-resolver.js","sourceRoot":"","sources":["../src/copy-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { ReferenceResult, TraceResult } from './types.js';
2
+ export declare function traceField(references: ReferenceResult, name: string, direction: 'upstream' | 'downstream'): TraceResult;