@virune/compiler 1.1.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +2 -0
  3. package/dist/src/analysis/control-flow.d.ts +9 -0
  4. package/dist/src/analysis/control-flow.d.ts.map +1 -0
  5. package/dist/src/analysis/control-flow.js +47 -0
  6. package/dist/src/analysis/control-flow.js.map +1 -0
  7. package/dist/src/ast/nodes.d.ts +495 -0
  8. package/dist/src/ast/nodes.d.ts.map +1 -0
  9. package/dist/src/ast/nodes.js +2 -0
  10. package/dist/src/ast/nodes.js.map +1 -0
  11. package/dist/src/binder/symbols.d.ts +36 -0
  12. package/dist/src/binder/symbols.d.ts.map +1 -0
  13. package/dist/src/binder/symbols.js +30 -0
  14. package/dist/src/binder/symbols.js.map +1 -0
  15. package/dist/src/checker/builtin-members.d.ts +4 -0
  16. package/dist/src/checker/builtin-members.d.ts.map +1 -0
  17. package/dist/src/checker/builtin-members.js +175 -0
  18. package/dist/src/checker/builtin-members.js.map +1 -0
  19. package/dist/src/checker/checker.d.ts +148 -0
  20. package/dist/src/checker/checker.d.ts.map +1 -0
  21. package/dist/src/checker/checker.js +2985 -0
  22. package/dist/src/checker/checker.js.map +1 -0
  23. package/dist/src/checker/effect-registry.d.ts +14 -0
  24. package/dist/src/checker/effect-registry.d.ts.map +1 -0
  25. package/dist/src/checker/effect-registry.js +11 -0
  26. package/dist/src/checker/effect-registry.js.map +1 -0
  27. package/dist/src/checker/type-operations.d.ts +27 -0
  28. package/dist/src/checker/type-operations.d.ts.map +1 -0
  29. package/dist/src/checker/type-operations.js +268 -0
  30. package/dist/src/checker/type-operations.js.map +1 -0
  31. package/dist/src/codegen/emitter.d.ts +83 -0
  32. package/dist/src/codegen/emitter.d.ts.map +1 -0
  33. package/dist/src/codegen/emitter.js +1029 -0
  34. package/dist/src/codegen/emitter.js.map +1 -0
  35. package/dist/src/codegen/helpers.d.ts +7 -0
  36. package/dist/src/codegen/helpers.d.ts.map +1 -0
  37. package/dist/src/codegen/helpers.js +48 -0
  38. package/dist/src/codegen/helpers.js.map +1 -0
  39. package/dist/src/codegen/runtime-imports.d.ts +6 -0
  40. package/dist/src/codegen/runtime-imports.d.ts.map +1 -0
  41. package/dist/src/codegen/runtime-imports.js +45 -0
  42. package/dist/src/codegen/runtime-imports.js.map +1 -0
  43. package/dist/src/codegen/writer.d.ts +14 -0
  44. package/dist/src/codegen/writer.d.ts.map +1 -0
  45. package/dist/src/codegen/writer.js +56 -0
  46. package/dist/src/codegen/writer.js.map +1 -0
  47. package/dist/src/compiler.d.ts +24 -0
  48. package/dist/src/compiler.d.ts.map +1 -0
  49. package/dist/src/compiler.js +97 -0
  50. package/dist/src/compiler.js.map +1 -0
  51. package/dist/src/diagnostics/codes.d.ts +18 -0
  52. package/dist/src/diagnostics/codes.d.ts.map +1 -0
  53. package/dist/src/diagnostics/codes.js +43 -0
  54. package/dist/src/diagnostics/codes.js.map +1 -0
  55. package/dist/src/diagnostics/diagnostic.d.ts +41 -0
  56. package/dist/src/diagnostics/diagnostic.d.ts.map +1 -0
  57. package/dist/src/diagnostics/diagnostic.js +50 -0
  58. package/dist/src/diagnostics/diagnostic.js.map +1 -0
  59. package/dist/src/diagnostics/render.d.ts +44 -0
  60. package/dist/src/diagnostics/render.d.ts.map +1 -0
  61. package/dist/src/diagnostics/render.js +44 -0
  62. package/dist/src/diagnostics/render.js.map +1 -0
  63. package/dist/src/experimental-api.d.ts +19 -0
  64. package/dist/src/experimental-api.d.ts.map +1 -0
  65. package/dist/src/experimental-api.js +17 -0
  66. package/dist/src/experimental-api.js.map +1 -0
  67. package/dist/src/hir/lower.d.ts +6 -0
  68. package/dist/src/hir/lower.d.ts.map +1 -0
  69. package/dist/src/hir/lower.js +124 -0
  70. package/dist/src/hir/lower.js.map +1 -0
  71. package/dist/src/hir/nodes.d.ts +12 -0
  72. package/dist/src/hir/nodes.d.ts.map +1 -0
  73. package/dist/src/hir/nodes.js +2 -0
  74. package/dist/src/hir/nodes.js.map +1 -0
  75. package/dist/src/index.d.ts +2 -0
  76. package/dist/src/index.d.ts.map +1 -0
  77. package/dist/src/index.js +2 -0
  78. package/dist/src/index.js.map +1 -0
  79. package/dist/src/interop/checked-api.d.ts +21 -0
  80. package/dist/src/interop/checked-api.d.ts.map +1 -0
  81. package/dist/src/interop/checked-api.js +46 -0
  82. package/dist/src/interop/checked-api.js.map +1 -0
  83. package/dist/src/interop/decision.d.ts +24 -0
  84. package/dist/src/interop/decision.d.ts.map +1 -0
  85. package/dist/src/interop/decision.js +96 -0
  86. package/dist/src/interop/decision.js.map +1 -0
  87. package/dist/src/interop/frontend-component-emission.d.ts +17 -0
  88. package/dist/src/interop/frontend-component-emission.d.ts.map +1 -0
  89. package/dist/src/interop/frontend-component-emission.js +271 -0
  90. package/dist/src/interop/frontend-component-emission.js.map +1 -0
  91. package/dist/src/interop/jsx-view-validation.d.ts +20 -0
  92. package/dist/src/interop/jsx-view-validation.d.ts.map +1 -0
  93. package/dist/src/interop/jsx-view-validation.js +847 -0
  94. package/dist/src/interop/jsx-view-validation.js.map +1 -0
  95. package/dist/src/interop/operation-api.d.ts +32 -0
  96. package/dist/src/interop/operation-api.d.ts.map +1 -0
  97. package/dist/src/interop/operation-api.js +61 -0
  98. package/dist/src/interop/operation-api.js.map +1 -0
  99. package/dist/src/interop/operation.d.ts +136 -0
  100. package/dist/src/interop/operation.d.ts.map +1 -0
  101. package/dist/src/interop/operation.js +575 -0
  102. package/dist/src/interop/operation.js.map +1 -0
  103. package/dist/src/interop/repetition-host-locator.d.ts +25 -0
  104. package/dist/src/interop/repetition-host-locator.d.ts.map +1 -0
  105. package/dist/src/interop/repetition-host-locator.js +61 -0
  106. package/dist/src/interop/repetition-host-locator.js.map +1 -0
  107. package/dist/src/interop/repetition-host-usage-validation.d.ts +11 -0
  108. package/dist/src/interop/repetition-host-usage-validation.d.ts.map +1 -0
  109. package/dist/src/interop/repetition-host-usage-validation.js +89 -0
  110. package/dist/src/interop/repetition-host-usage-validation.js.map +1 -0
  111. package/dist/src/interop/types.d.ts +365 -0
  112. package/dist/src/interop/types.d.ts.map +1 -0
  113. package/dist/src/interop/types.js +2 -0
  114. package/dist/src/interop/types.js.map +1 -0
  115. package/dist/src/mir/lower.d.ts +4 -0
  116. package/dist/src/mir/lower.d.ts.map +1 -0
  117. package/dist/src/mir/lower.js +131 -0
  118. package/dist/src/mir/lower.js.map +1 -0
  119. package/dist/src/mir/nodes.d.ts +36 -0
  120. package/dist/src/mir/nodes.d.ts.map +1 -0
  121. package/dist/src/mir/nodes.js +2 -0
  122. package/dist/src/mir/nodes.js.map +1 -0
  123. package/dist/src/project/incremental.d.ts +9 -0
  124. package/dist/src/project/incremental.d.ts.map +1 -0
  125. package/dist/src/project/incremental.js +15 -0
  126. package/dist/src/project/incremental.js.map +1 -0
  127. package/dist/src/project/project.d.ts +98 -0
  128. package/dist/src/project/project.d.ts.map +1 -0
  129. package/dist/src/project/project.js +884 -0
  130. package/dist/src/project/project.js.map +1 -0
  131. package/dist/src/public-api.d.ts +45 -0
  132. package/dist/src/public-api.d.ts.map +1 -0
  133. package/dist/src/public-api.js +37 -0
  134. package/dist/src/public-api.js.map +1 -0
  135. package/dist/src/reference/evaluator.d.ts +13 -0
  136. package/dist/src/reference/evaluator.d.ts.map +1 -0
  137. package/dist/src/reference/evaluator.js +304 -0
  138. package/dist/src/reference/evaluator.js.map +1 -0
  139. package/dist/src/selfhost/bootstrap-artifact-normalizer.d.ts +65 -0
  140. package/dist/src/selfhost/bootstrap-artifact-normalizer.d.ts.map +1 -0
  141. package/dist/src/selfhost/bootstrap-artifact-normalizer.js +226 -0
  142. package/dist/src/selfhost/bootstrap-artifact-normalizer.js.map +1 -0
  143. package/dist/src/selfhost/bootstrap-artifact-snapshot.d.ts +23 -0
  144. package/dist/src/selfhost/bootstrap-artifact-snapshot.d.ts.map +1 -0
  145. package/dist/src/selfhost/bootstrap-artifact-snapshot.js +122 -0
  146. package/dist/src/selfhost/bootstrap-artifact-snapshot.js.map +1 -0
  147. package/dist/src/selfhost/bootstrap-compiler-selection.d.ts +36 -0
  148. package/dist/src/selfhost/bootstrap-compiler-selection.d.ts.map +1 -0
  149. package/dist/src/selfhost/bootstrap-compiler-selection.js +52 -0
  150. package/dist/src/selfhost/bootstrap-compiler-selection.js.map +1 -0
  151. package/dist/src/selfhost/bootstrap-execution-probe.d.ts +42 -0
  152. package/dist/src/selfhost/bootstrap-execution-probe.d.ts.map +1 -0
  153. package/dist/src/selfhost/bootstrap-execution-probe.js +115 -0
  154. package/dist/src/selfhost/bootstrap-execution-probe.js.map +1 -0
  155. package/dist/src/selfhost/bootstrap-rollback-decision.d.ts +40 -0
  156. package/dist/src/selfhost/bootstrap-rollback-decision.d.ts.map +1 -0
  157. package/dist/src/selfhost/bootstrap-rollback-decision.js +144 -0
  158. package/dist/src/selfhost/bootstrap-rollback-decision.js.map +1 -0
  159. package/dist/src/selfhost/bootstrap-shadow-history.d.ts +49 -0
  160. package/dist/src/selfhost/bootstrap-shadow-history.d.ts.map +1 -0
  161. package/dist/src/selfhost/bootstrap-shadow-history.js +348 -0
  162. package/dist/src/selfhost/bootstrap-shadow-history.js.map +1 -0
  163. package/dist/src/selfhost/bootstrap-shadow-report.d.ts +43 -0
  164. package/dist/src/selfhost/bootstrap-shadow-report.d.ts.map +1 -0
  165. package/dist/src/selfhost/bootstrap-shadow-report.js +94 -0
  166. package/dist/src/selfhost/bootstrap-shadow-report.js.map +1 -0
  167. package/dist/src/selfhost/bootstrap-stage-executor.d.ts +53 -0
  168. package/dist/src/selfhost/bootstrap-stage-executor.d.ts.map +1 -0
  169. package/dist/src/selfhost/bootstrap-stage-executor.js +159 -0
  170. package/dist/src/selfhost/bootstrap-stage-executor.js.map +1 -0
  171. package/dist/src/selfhost/bootstrap-stage-loader.d.ts +14 -0
  172. package/dist/src/selfhost/bootstrap-stage-loader.d.ts.map +1 -0
  173. package/dist/src/selfhost/bootstrap-stage-loader.js +112 -0
  174. package/dist/src/selfhost/bootstrap-stage-loader.js.map +1 -0
  175. package/dist/src/selfhost/bootstrap-stage-pipeline.d.ts +8 -0
  176. package/dist/src/selfhost/bootstrap-stage-pipeline.d.ts.map +1 -0
  177. package/dist/src/selfhost/bootstrap-stage-pipeline.js +85 -0
  178. package/dist/src/selfhost/bootstrap-stage-pipeline.js.map +1 -0
  179. package/dist/src/selfhost/bootstrap-stage-runner.d.ts +47 -0
  180. package/dist/src/selfhost/bootstrap-stage-runner.d.ts.map +1 -0
  181. package/dist/src/selfhost/bootstrap-stage-runner.js +106 -0
  182. package/dist/src/selfhost/bootstrap-stage-runner.js.map +1 -0
  183. package/dist/src/selfhost/clean-bootstrap-evidence.d.ts +83 -0
  184. package/dist/src/selfhost/clean-bootstrap-evidence.d.ts.map +1 -0
  185. package/dist/src/selfhost/clean-bootstrap-evidence.js +233 -0
  186. package/dist/src/selfhost/clean-bootstrap-evidence.js.map +1 -0
  187. package/dist/src/selfhost/compiler-facade.d.ts +33 -0
  188. package/dist/src/selfhost/compiler-facade.d.ts.map +1 -0
  189. package/dist/src/selfhost/compiler-facade.js +65 -0
  190. package/dist/src/selfhost/compiler-facade.js.map +1 -0
  191. package/dist/src/selfhost/contract.d.ts +151 -0
  192. package/dist/src/selfhost/contract.d.ts.map +1 -0
  193. package/dist/src/selfhost/contract.js +335 -0
  194. package/dist/src/selfhost/contract.js.map +1 -0
  195. package/dist/src/selfhost/differential-artifacts.d.ts +8 -0
  196. package/dist/src/selfhost/differential-artifacts.d.ts.map +1 -0
  197. package/dist/src/selfhost/differential-artifacts.js +50 -0
  198. package/dist/src/selfhost/differential-artifacts.js.map +1 -0
  199. package/dist/src/selfhost/differential-harness.d.ts +91 -0
  200. package/dist/src/selfhost/differential-harness.d.ts.map +1 -0
  201. package/dist/src/selfhost/differential-harness.js +246 -0
  202. package/dist/src/selfhost/differential-harness.js.map +1 -0
  203. package/dist/src/selfhost/full-language-inventory-runner.d.ts +49 -0
  204. package/dist/src/selfhost/full-language-inventory-runner.d.ts.map +1 -0
  205. package/dist/src/selfhost/full-language-inventory-runner.js +225 -0
  206. package/dist/src/selfhost/full-language-inventory-runner.js.map +1 -0
  207. package/dist/src/selfhost/full-language-inventory.d.ts +42 -0
  208. package/dist/src/selfhost/full-language-inventory.d.ts.map +1 -0
  209. package/dist/src/selfhost/full-language-inventory.js +163 -0
  210. package/dist/src/selfhost/full-language-inventory.js.map +1 -0
  211. package/dist/src/selfhost/interop-resolution-witness.d.ts +35 -0
  212. package/dist/src/selfhost/interop-resolution-witness.d.ts.map +1 -0
  213. package/dist/src/selfhost/interop-resolution-witness.js +186 -0
  214. package/dist/src/selfhost/interop-resolution-witness.js.map +1 -0
  215. package/dist/src/selfhost/kernel-model-host-adapter.d.ts +28 -0
  216. package/dist/src/selfhost/kernel-model-host-adapter.d.ts.map +1 -0
  217. package/dist/src/selfhost/kernel-model-host-adapter.js +36 -0
  218. package/dist/src/selfhost/kernel-model-host-adapter.js.map +1 -0
  219. package/dist/src/selfhost/legacy-adapter.d.ts +8 -0
  220. package/dist/src/selfhost/legacy-adapter.d.ts.map +1 -0
  221. package/dist/src/selfhost/legacy-adapter.js +186 -0
  222. package/dist/src/selfhost/legacy-adapter.js.map +1 -0
  223. package/dist/src/selfhost/module-graph.d.ts +57 -0
  224. package/dist/src/selfhost/module-graph.d.ts.map +1 -0
  225. package/dist/src/selfhost/module-graph.js +267 -0
  226. package/dist/src/selfhost/module-graph.js.map +1 -0
  227. package/dist/src/selfhost/mvp-adapter.d.ts +19 -0
  228. package/dist/src/selfhost/mvp-adapter.d.ts.map +1 -0
  229. package/dist/src/selfhost/mvp-adapter.js +186 -0
  230. package/dist/src/selfhost/mvp-adapter.js.map +1 -0
  231. package/dist/src/selfhost/node-executor.d.ts +6 -0
  232. package/dist/src/selfhost/node-executor.d.ts.map +1 -0
  233. package/dist/src/selfhost/node-executor.js +138 -0
  234. package/dist/src/selfhost/node-executor.js.map +1 -0
  235. package/dist/src/selfhost/project-compiler-adapter.d.ts +77 -0
  236. package/dist/src/selfhost/project-compiler-adapter.d.ts.map +1 -0
  237. package/dist/src/selfhost/project-compiler-adapter.js +358 -0
  238. package/dist/src/selfhost/project-compiler-adapter.js.map +1 -0
  239. package/dist/src/selfhost/project-differential-adapter.d.ts +15 -0
  240. package/dist/src/selfhost/project-differential-adapter.d.ts.map +1 -0
  241. package/dist/src/selfhost/project-differential-adapter.js +65 -0
  242. package/dist/src/selfhost/project-differential-adapter.js.map +1 -0
  243. package/dist/src/selfhost/promotion-evidence.d.ts +62 -0
  244. package/dist/src/selfhost/promotion-evidence.d.ts.map +1 -0
  245. package/dist/src/selfhost/promotion-evidence.js +332 -0
  246. package/dist/src/selfhost/promotion-evidence.js.map +1 -0
  247. package/dist/src/selfhost/promotion-policy-replay-v2.d.ts +54 -0
  248. package/dist/src/selfhost/promotion-policy-replay-v2.d.ts.map +1 -0
  249. package/dist/src/selfhost/promotion-policy-replay-v2.js +343 -0
  250. package/dist/src/selfhost/promotion-policy-replay-v2.js.map +1 -0
  251. package/dist/src/selfhost/promotion-shadow-history-v2.d.ts +55 -0
  252. package/dist/src/selfhost/promotion-shadow-history-v2.d.ts.map +1 -0
  253. package/dist/src/selfhost/promotion-shadow-history-v2.js +227 -0
  254. package/dist/src/selfhost/promotion-shadow-history-v2.js.map +1 -0
  255. package/dist/src/selfhost/promotion-subject.d.ts +34 -0
  256. package/dist/src/selfhost/promotion-subject.d.ts.map +1 -0
  257. package/dist/src/selfhost/promotion-subject.js +141 -0
  258. package/dist/src/selfhost/promotion-subject.js.map +1 -0
  259. package/dist/src/selfhost/source-manifest.d.ts +31 -0
  260. package/dist/src/selfhost/source-manifest.d.ts.map +1 -0
  261. package/dist/src/selfhost/source-manifest.js +194 -0
  262. package/dist/src/selfhost/source-manifest.js.map +1 -0
  263. package/dist/src/selfhost/stage-compiler-facade.d.ts +25 -0
  264. package/dist/src/selfhost/stage-compiler-facade.d.ts.map +1 -0
  265. package/dist/src/selfhost/stage-compiler-facade.js +100 -0
  266. package/dist/src/selfhost/stage-compiler-facade.js.map +1 -0
  267. package/dist/src/semantic-evidence/snapshot.d.ts +114 -0
  268. package/dist/src/semantic-evidence/snapshot.d.ts.map +1 -0
  269. package/dist/src/semantic-evidence/snapshot.js +336 -0
  270. package/dist/src/semantic-evidence/snapshot.js.map +1 -0
  271. package/dist/src/source.d.ts +25 -0
  272. package/dist/src/source.d.ts.map +1 -0
  273. package/dist/src/source.js +10 -0
  274. package/dist/src/source.js.map +1 -0
  275. package/dist/src/syntax/cst-to-ast.d.ts +108 -0
  276. package/dist/src/syntax/cst-to-ast.d.ts.map +1 -0
  277. package/dist/src/syntax/cst-to-ast.js +383 -0
  278. package/dist/src/syntax/cst-to-ast.js.map +1 -0
  279. package/dist/src/syntax/documentation.d.ts +11 -0
  280. package/dist/src/syntax/documentation.d.ts.map +1 -0
  281. package/dist/src/syntax/documentation.js +261 -0
  282. package/dist/src/syntax/documentation.js.map +1 -0
  283. package/dist/src/syntax/parser.d.ts +114 -0
  284. package/dist/src/syntax/parser.d.ts.map +1 -0
  285. package/dist/src/syntax/parser.js +970 -0
  286. package/dist/src/syntax/parser.js.map +1 -0
  287. package/dist/src/syntax/syntax-metadata.d.ts +8 -0
  288. package/dist/src/syntax/syntax-metadata.d.ts.map +1 -0
  289. package/dist/src/syntax/syntax-metadata.js +14 -0
  290. package/dist/src/syntax/syntax-metadata.js.map +1 -0
  291. package/dist/src/syntax/tokens.d.ts +96 -0
  292. package/dist/src/syntax/tokens.d.ts.map +1 -0
  293. package/dist/src/syntax/tokens.js +260 -0
  294. package/dist/src/syntax/tokens.js.map +1 -0
  295. package/dist/src/types/types.d.ts +97 -0
  296. package/dist/src/types/types.d.ts.map +1 -0
  297. package/dist/src/types/types.js +105 -0
  298. package/dist/src/types/types.js.map +1 -0
  299. package/package.json +47 -0
  300. package/schema/diagnostics-v1.schema.json +75 -0
@@ -0,0 +1,884 @@
1
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
+ import { createHash } from 'node:crypto';
3
+ import { dirname, extname, isAbsolute, join, relative, resolve } from 'node:path';
4
+ import { checkModule } from '../checker/checker.js';
5
+ import { emitJavaScript } from '../codegen/emitter.js';
6
+ import { DiagnosticBag } from '../diagnostics/diagnostic.js';
7
+ import { lowerToHir } from '../hir/lower.js';
8
+ import { validateFrontendComponentEmissionBoundary } from '../interop/frontend-component-emission.js';
9
+ import { validateFrontendJsxUsage } from '../interop/jsx-view-validation.js';
10
+ import { collectIdentityViewRepetitions, discoverRepetitionHostLocator } from '../interop/repetition-host-locator.js';
11
+ import { validateRepetitionHostTypeScriptUsage } from '../interop/repetition-host-usage-validation.js';
12
+ import { buildAst } from '../syntax/cst-to-ast.js';
13
+ import { attachDocumentation } from '../syntax/documentation.js';
14
+ import { parse } from '../syntax/parser.js';
15
+ import { lex } from '../syntax/tokens.js';
16
+ const runtimeDependencies = new WeakMap();
17
+ /**
18
+ * Return the exact modules that can be loaded from the supplied roots by emitted
19
+ * Virune-to-Virune runtime imports in this ProjectBuildResult. The dependency
20
+ * sidecar is attached to the same BuiltModule objects that own emitted output,
21
+ * so execution checks do not need to rebuild or re-read project state.
22
+ */
23
+ export function projectRuntimeModuleClosure(result, rootPaths) {
24
+ const modulesByPath = new Map(result.modules.map(module => [resolve(module.source.path), module]));
25
+ const reachable = new Set();
26
+ const visit = (path) => {
27
+ const normalized = resolve(path);
28
+ if (reachable.has(normalized))
29
+ return;
30
+ const module = modulesByPath.get(normalized);
31
+ if (module === undefined)
32
+ throw new Error(`Project runtime dependency ${normalized} is unavailable in this build result`);
33
+ const dependencies = runtimeDependencies.get(module);
34
+ if (dependencies === undefined)
35
+ throw new Error(`Project runtime dependency evidence is unavailable for ${normalized}`);
36
+ reachable.add(normalized);
37
+ for (const dependency of dependencies)
38
+ visit(dependency);
39
+ };
40
+ for (const rootPath of rootPaths)
41
+ visit(isAbsolute(rootPath) ? rootPath : resolve(result.root, rootPath));
42
+ return Object.freeze(result.modules.filter(module => reachable.has(resolve(module.source.path))));
43
+ }
44
+ /**
45
+ * Reusable state for incremental project builds. The cache is intentionally
46
+ * explicit so one-shot CLI builds remain deterministic and side-effect free.
47
+ */
48
+ export class ProjectBuildCache {
49
+ #entries = new Map();
50
+ #fileIds = new Map();
51
+ #nextFileId = 1;
52
+ clear() {
53
+ this.#entries.clear();
54
+ }
55
+ invalidate(path) {
56
+ if (path === undefined)
57
+ this.clear();
58
+ else
59
+ this.#entries.delete(resolve(path));
60
+ }
61
+ fileId(path) {
62
+ const normalized = resolve(path);
63
+ const existing = this.#fileIds.get(normalized);
64
+ if (existing !== undefined)
65
+ return existing;
66
+ const id = this.#nextFileId++;
67
+ this.#fileIds.set(normalized, id);
68
+ return id;
69
+ }
70
+ get(path) { return this.#entries.get(resolve(path)); }
71
+ set(path, value) { this.#entries.set(resolve(path), value); }
72
+ prune(paths) {
73
+ let removed = 0;
74
+ for (const path of this.#entries.keys()) {
75
+ if (paths.has(path))
76
+ continue;
77
+ this.#entries.delete(path);
78
+ removed++;
79
+ }
80
+ return removed;
81
+ }
82
+ }
83
+ const nodeProjectHost = {
84
+ readFile: path => readFile(path, 'utf8'),
85
+ };
86
+ const defaultConfig = {
87
+ languageVersion: '1.0', platform: 'node', sourceDir: 'src', outDir: 'dist', entry: 'src/main.virune', target: 'es2022', sourceMap: true, sourcesContent: true,
88
+ };
89
+ export async function loadConfig(root, host = nodeProjectHost) {
90
+ let value;
91
+ try {
92
+ value = JSON.parse(await host.readFile(join(root, 'virune.json')));
93
+ }
94
+ catch (error) {
95
+ if (error.code === 'ENOENT')
96
+ return defaultConfig;
97
+ throw new Error(`Invalid virune.json: ${error instanceof Error ? error.message : String(error)}`);
98
+ }
99
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
100
+ throw new Error('Invalid virune.json: root value must be an object');
101
+ const raw = value;
102
+ const merged = { ...defaultConfig, ...raw };
103
+ if (merged.languageVersion !== '1.0')
104
+ throw new Error('Invalid virune.json: languageVersion must be "1.0"');
105
+ if (!['node', 'browser', 'neutral'].includes(String(merged.platform)))
106
+ throw new Error('Invalid virune.json: platform must be node, browser, or neutral');
107
+ if (merged.target !== 'es2022')
108
+ throw new Error('Invalid virune.json: target must be "es2022"');
109
+ for (const key of ['sourceDir', 'outDir', 'entry'])
110
+ if (typeof merged[key] !== 'string' || merged[key].length === 0)
111
+ throw new Error(`Invalid virune.json: ${key} must be a non-empty string`);
112
+ for (const key of ['sourceMap', 'sourcesContent'])
113
+ if (typeof merged[key] !== 'boolean')
114
+ throw new Error(`Invalid virune.json: ${key} must be boolean`);
115
+ return merged;
116
+ }
117
+ export function parseSource(source) {
118
+ const diagnostics = new DiagnosticBag();
119
+ const lexed = lex(source.text);
120
+ for (const error of lexed.errors)
121
+ diagnostics.error('L0001', error.message, spanAt(source.id, error.offset, error.length, error.line ?? 1, error.column ?? 1));
122
+ const parsed = parse(lexed.tokens);
123
+ for (const error of parsed.errors) {
124
+ const token = error.token;
125
+ const offset = finitePosition(token.startOffset, source.text.length);
126
+ const endOffset = Math.min(source.text.length, Math.max(offset, finitePosition(token.endOffset, offset)));
127
+ const line = finitePosition(token.startLine, lineAt(source.text, offset));
128
+ const column = finitePosition(token.startColumn, columnAt(source.text, offset));
129
+ diagnostics.error('L0002', error.message, spanAt(source.id, offset, endOffset - offset, line, column));
130
+ }
131
+ if (diagnostics.hasErrors)
132
+ return { source, diagnostics: diagnostics.items };
133
+ try {
134
+ const ast = attachDocumentation(buildAst(source.id, parsed.cst), source, lexed.comments, lexed.tokens, diagnostics);
135
+ return { source, ast, diagnostics: diagnostics.items };
136
+ }
137
+ catch (error) {
138
+ diagnostics.error('L9001', `AST construction failed: ${error instanceof Error ? error.message : String(error)}`, spanAt(source.id, 0, 1, 1, 1));
139
+ return { source, diagnostics: diagnostics.items };
140
+ }
141
+ }
142
+ export async function buildProject(rootDirectory, optionsOrWrite = true, legacyAdditionalEntries = []) {
143
+ const options = typeof optionsOrWrite === 'boolean'
144
+ ? { write: optionsOrWrite, additionalEntries: legacyAdditionalEntries }
145
+ : optionsOrWrite;
146
+ const write = options.write ?? true;
147
+ const additionalEntries = options.additionalEntries ?? [];
148
+ const host = options.host ?? nodeProjectHost;
149
+ const includeConfigEntry = options.includeConfigEntry ?? true;
150
+ const root = resolve(rootDirectory);
151
+ const projectDiagnostics = new DiagnosticBag();
152
+ const cache = options.incrementalCache;
153
+ const jsInteropProvider = options.jsInteropProvider;
154
+ const mutableStats = { parsedModules: 0, reusedParsedModules: 0, checkedModules: 0, reusedCheckedModules: 0, emittedModules: 0, reusedEmittedModules: 0, invalidatedModules: 0 };
155
+ let config;
156
+ try {
157
+ config = await loadConfig(root, host);
158
+ }
159
+ catch (error) {
160
+ config = defaultConfig;
161
+ projectDiagnostics.error('L5002', error instanceof Error ? error.message : String(error), spanAt(0, 0, 1, 1, 1));
162
+ return { root, config, modules: [], diagnostics: projectDiagnostics.items, stats: mutableStats };
163
+ }
164
+ const entry = resolve(root, config.entry);
165
+ const parsedByPath = new Map();
166
+ const sourceHashes = new Map();
167
+ const dependenciesByPath = new Map();
168
+ let nextFileId = 1;
169
+ const visiting = new Set();
170
+ const visited = new Set();
171
+ const order = [];
172
+ const visit = async (path, fromImport) => {
173
+ const normalized = resolve(path);
174
+ if (visiting.has(normalized)) {
175
+ projectDiagnostics.error('L4002', `Module cycle detected at ${normalized}`, fromImport?.span ?? spanAt(0, 0, 1, 1, 1));
176
+ return;
177
+ }
178
+ if (visited.has(normalized))
179
+ return;
180
+ visiting.add(normalized);
181
+ let text;
182
+ try {
183
+ text = await host.readFile(normalized);
184
+ }
185
+ catch (error) {
186
+ projectDiagnostics.error('L5001', `Cannot read module ${normalized}: ${error instanceof Error ? error.message : String(error)}`, fromImport?.span ?? spanAt(0, 0, 1, 1, 1));
187
+ visiting.delete(normalized);
188
+ return;
189
+ }
190
+ const sourceHash = contentHash(text);
191
+ sourceHashes.set(normalized, sourceHash);
192
+ const cached = cache?.get(normalized);
193
+ let parsed;
194
+ if (cached?.sourceHash === sourceHash) {
195
+ parsed = cached.parsed;
196
+ mutableStats.reusedParsedModules++;
197
+ }
198
+ else {
199
+ parsed = parseSource({ id: cache?.fileId(normalized) ?? nextFileId++, path: normalized, text });
200
+ mutableStats.parsedModules++;
201
+ }
202
+ parsedByPath.set(normalized, parsed);
203
+ const dependencies = [];
204
+ if (parsed.ast !== undefined) {
205
+ validateModulePolicy(root, config, normalized, parsed.ast, projectDiagnostics);
206
+ validateSignatureVisibility(parsed.ast, projectDiagnostics);
207
+ for (const declaration of parsed.ast.imports) {
208
+ if (declaration.sourceKind === 'javascript')
209
+ continue;
210
+ const dependency = await resolveImport(root, normalized, declaration.source, host);
211
+ if (dependency === undefined)
212
+ projectDiagnostics.error('L4003', `Cannot resolve import ${declaration.source}`, declaration.span);
213
+ else {
214
+ dependencies.push(resolve(dependency));
215
+ await visit(dependency, declaration);
216
+ }
217
+ }
218
+ }
219
+ dependenciesByPath.set(normalized, dependencies);
220
+ visiting.delete(normalized);
221
+ visited.add(normalized);
222
+ order.push(normalized);
223
+ };
224
+ if (includeConfigEntry)
225
+ await visit(entry);
226
+ for (const additionalEntry of additionalEntries)
227
+ await visit(isAbsolute(additionalEntry) ? additionalEntry : resolve(root, additionalEntry));
228
+ const repetitionHostLocator = discoverRepetitionHostLocator(order.flatMap(path => {
229
+ const ast = parsedByPath.get(path)?.ast;
230
+ return ast === undefined || modulePackageScope(root, path) !== 'project' ? [] : [{ path, ast }];
231
+ }));
232
+ const repetitionHostFingerprint = fingerprintRepetitionHostResolution(repetitionHostLocator);
233
+ const moduleInterfaces = await buildModuleInterfaces(root, order, parsedByPath, projectDiagnostics, host);
234
+ const interfaceHashes = new Map();
235
+ for (const path of order)
236
+ interfaceHashes.set(path, moduleInterfaceHash(moduleInterfaces.get(path)));
237
+ const configFingerprint = contentHash(JSON.stringify({ config, jsInterop: jsInteropProvider === undefined ? null : { id: jsInteropProvider.id, version: jsInteropProvider.version, generation: jsInteropProvider.generation } }));
238
+ const builtByPath = new Map();
239
+ let cloneId = -1;
240
+ for (const path of order) {
241
+ const parsed = parsedByPath.get(path);
242
+ const component = parsed.ast?.declarations.find(declaration => declaration.kind === 'ComponentDeclaration');
243
+ const identityRepetitions = parsed.ast === undefined ? [] : collectIdentityViewRepetitions(parsed.ast);
244
+ const dependencySignature = contentHash((dependenciesByPath.get(path) ?? []).map(dependency => `${dependency}:${interfaceHashes.get(dependency) ?? ''}:${parsedByPath.get(dependency)?.ast?.declarations.some(declaration => declaration.kind === 'ComponentDeclaration') === true ? 'jsx' : 'js'}`).sort().join('|'));
245
+ const hostResolutionFingerprint = identityRepetitions.length === 0 ? '' : repetitionHostFingerprint;
246
+ const buildFingerprint = contentHash(`${sourceHashes.get(path) ?? ''}|${dependencySignature}|${configFingerprint}|${hostResolutionFingerprint}`);
247
+ const cached = cache?.get(path);
248
+ if (cached?.buildFingerprint === buildFingerprint) {
249
+ builtByPath.set(path, cached.built);
250
+ mutableStats.reusedCheckedModules++;
251
+ if (cached.built.output !== undefined) {
252
+ mutableStats.reusedEmittedModules++;
253
+ if (write && cached.built.outputPath !== undefined)
254
+ await writeEmitOutput(cached.built.outputPath, cached.built.output, config.sourceMap);
255
+ }
256
+ continue;
257
+ }
258
+ let built;
259
+ let moduleRuntimeDependencies = Object.freeze([]);
260
+ if (parsed.ast === undefined || parsed.diagnostics.some(item => item.severity === 'error')) {
261
+ built = parsed;
262
+ }
263
+ else {
264
+ const importModel = await buildImportModel(root, path, parsed.ast, parsedByPath, moduleInterfaces, projectDiagnostics, cloneId, host);
265
+ cloneId = importModel.nextId;
266
+ const { signatureOnly, typeOnlyNodeIds, importedDeclarations, emissionImports } = importModel;
267
+ moduleRuntimeDependencies = importModel.runtimeDependencies;
268
+ const synthetic = { ...parsed.ast, imports: parsed.ast.imports.filter(item => item.sourceKind === 'javascript'), declarations: [...importedDeclarations, ...parsed.ast.declarations] };
269
+ const semantic = checkModule(synthetic, { signatureOnlyNodeIds: signatureOnly, typeOnlyNodeIds, platform: config.platform, moduleId: moduleIdentity(root, path), containingFile: path, ...(jsInteropProvider === undefined ? {} : { jsInteropProvider }) });
270
+ mutableStats.checkedModules++;
271
+ const inSourceDirectory = isWithin(resolve(root, config.sourceDir), path);
272
+ if (!semantic.diagnostics.hasErrors && component !== undefined && inSourceDirectory) {
273
+ validateFrontendComponentEmissionBoundary(parsed.ast, semantic, semantic.diagnostics);
274
+ }
275
+ if (!semantic.diagnostics.hasErrors && identityRepetitions.length > 0 && inSourceDirectory && repetitionHostLocator.status !== 'ready') {
276
+ const message = repetitionHostLocator.status === 'none'
277
+ ? 'Identity-bearing View repetition requires exactly one project @repetitionHost locator'
278
+ : 'Identity-bearing View repetition cannot emit while the project @repetitionHost locator is ambiguous';
279
+ for (const repetition of identityRepetitions)
280
+ semantic.diagnostics.error('L2135', message, repetition.span);
281
+ }
282
+ const repetitionHostValidation = identityRepetitions.length > 0 && inSourceDirectory && repetitionHostLocator.status === 'ready'
283
+ ? {
284
+ moduleSpecifier: rebaseRepetitionHostModuleSpecifierForValidation(repetitionHostLocator.locator, path),
285
+ exportName: repetitionHostLocator.locator.exportName,
286
+ }
287
+ : undefined;
288
+ if (!semantic.diagnostics.hasErrors && repetitionHostValidation !== undefined) {
289
+ const accepted = validateRepetitionHostTypeScriptUsage({
290
+ containingFile: path,
291
+ platform: config.platform,
292
+ ...repetitionHostValidation,
293
+ ...(jsInteropProvider === undefined ? {} : { jsInteropProvider }),
294
+ });
295
+ if (!accepted) {
296
+ for (const repetition of identityRepetitions)
297
+ semantic.diagnostics.error('L2136', 'TypeScript whole-usage validation rejected the project @repetitionHost export', repetition.span);
298
+ }
299
+ }
300
+ if (!semantic.diagnostics.hasErrors) {
301
+ validateFrontendJsxUsage(parsed.ast, semantic, {
302
+ containingFile: path,
303
+ platform: config.platform,
304
+ ...(jsInteropProvider === undefined ? {} : { jsInteropProvider }),
305
+ ...(repetitionHostValidation === undefined ? {} : { repetitionHost: repetitionHostValidation }),
306
+ });
307
+ }
308
+ const diagnostics = [...parsed.diagnostics, ...semantic.diagnostics.items];
309
+ let output;
310
+ let outputPath;
311
+ if (!diagnostics.some(item => item.severity === 'error') && inSourceDirectory) {
312
+ const relativePath = relative(resolve(root, config.sourceDir), path);
313
+ outputPath = resolve(root, config.outDir, relativePath.replace(/\.virune$/u, component === undefined ? '.js' : '.jsx'));
314
+ const emissionModule = { ...parsed.ast, imports: emissionImports };
315
+ const repetitionHost = identityRepetitions.length > 0 && repetitionHostLocator.status === 'ready'
316
+ ? { moduleSpecifier: rebaseRepetitionHostModuleSpecifier(repetitionHostLocator.locator, outputPath, root, config), exportName: repetitionHostLocator.locator.exportName }
317
+ : undefined;
318
+ output = emitJavaScript(lowerToHir(emissionModule, semantic), parsed.source, outputPath, {
319
+ sourceMap: config.sourceMap,
320
+ sourcesContent: config.sourcesContent,
321
+ sourcePath: relative(root, path).replaceAll('\\', '/'),
322
+ ...(repetitionHost === undefined ? {} : { repetitionHost }),
323
+ });
324
+ mutableStats.emittedModules++;
325
+ if (write)
326
+ await writeEmitOutput(outputPath, output, config.sourceMap);
327
+ }
328
+ built = { ...parsed, semantic, ...(output === undefined ? {} : { output }), ...(outputPath === undefined ? {} : { outputPath }), diagnostics };
329
+ }
330
+ runtimeDependencies.set(built, moduleRuntimeDependencies);
331
+ builtByPath.set(path, built);
332
+ cache?.set(path, { sourceHash: sourceHashes.get(path), parsed, interfaceHash: interfaceHashes.get(path) ?? '', buildFingerprint, built });
333
+ }
334
+ const modules = order.map(path => builtByPath.get(path) ?? parsedByPath.get(path)).filter((item) => item !== undefined);
335
+ const diagnostics = [...projectDiagnostics.items, ...modules.flatMap(item => item.diagnostics)];
336
+ mutableStats.invalidatedModules = cache?.prune(new Set(order)) ?? 0;
337
+ return { root, config, modules, diagnostics, stats: mutableStats };
338
+ }
339
+ function contentHash(value) {
340
+ return createHash('sha256').update(value).digest('hex');
341
+ }
342
+ function fingerprintRepetitionHostResolution(resolution) {
343
+ if (resolution.status === 'none')
344
+ return contentHash('none');
345
+ const locatorKey = (locator) => `${locator.declarationFile}\u0000${locator.module}\u0000${locator.exportName}\u0000${locator.protocolVersion}`;
346
+ if (resolution.status === 'ready')
347
+ return contentHash(`ready\u0000${locatorKey(resolution.locator)}`);
348
+ return contentHash(`ambiguous\u0000${resolution.locators.map(locatorKey).sort().join('\u0001')}`);
349
+ }
350
+ function rebaseRepetitionHostModuleSpecifier(locator, outputPath, root, config) {
351
+ if (!locator.module.startsWith('.'))
352
+ return locator.module;
353
+ const absoluteTarget = resolve(dirname(locator.declarationFile), locator.module);
354
+ const sourceRoot = resolve(root, config.sourceDir);
355
+ const emittedTarget = isWithin(sourceRoot, absoluteTarget)
356
+ ? resolve(root, config.outDir, relative(sourceRoot, absoluteTarget))
357
+ : absoluteTarget;
358
+ const rebased = relative(dirname(outputPath), emittedTarget).replaceAll('\\', '/');
359
+ return rebased.startsWith('.') ? rebased : `./${rebased}`;
360
+ }
361
+ function rebaseRepetitionHostModuleSpecifierForValidation(locator, containingFile) {
362
+ if (!locator.module.startsWith('.'))
363
+ return locator.module;
364
+ const absoluteTarget = resolve(dirname(locator.declarationFile), locator.module);
365
+ const rebased = relative(dirname(containingFile), absoluteTarget).replaceAll('\\', '/');
366
+ return rebased.startsWith('.') ? rebased : `./${rebased}`;
367
+ }
368
+ function moduleInterfaceHash(moduleInterface) {
369
+ if (moduleInterface === undefined)
370
+ return contentHash('missing');
371
+ const entries = [...moduleInterface.exports.entries()]
372
+ .sort(([left], [right]) => left.localeCompare(right))
373
+ .map(([name, entry]) => ({ name, visibility: entry.visibility, originPath: entry.originPath, declaration: canonicalAst(publicSignatureAst(entry.declaration)) }));
374
+ return contentHash(JSON.stringify(entries));
375
+ }
376
+ function publicSignatureAst(declaration) {
377
+ switch (declaration.kind) {
378
+ case 'FunctionDeclaration': {
379
+ const { body: _body, expressionBody: _expressionBody, attributes, ...signature } = declaration;
380
+ return attributes.some(attribute => attribute.name === 'jsExport') ? { ...signature, jsExport: true } : signature;
381
+ }
382
+ case 'ComponentDeclaration': {
383
+ const { body: _body, attributes: _attributes, ...signature } = declaration;
384
+ return signature;
385
+ }
386
+ case 'TopLevelLetDeclaration': {
387
+ const { value: _value, attributes: _attributes, ...signature } = declaration;
388
+ return signature;
389
+ }
390
+ case 'RecordDeclaration':
391
+ case 'NewtypeDeclaration':
392
+ return declaration;
393
+ default: {
394
+ const { attributes: _attributes, ...signature } = declaration;
395
+ return signature;
396
+ }
397
+ }
398
+ }
399
+ function canonicalAst(value) {
400
+ if (Array.isArray(value))
401
+ return value.map(canonicalAst);
402
+ if (value === null || typeof value !== 'object')
403
+ return value;
404
+ const result = {};
405
+ for (const [key, child] of Object.entries(value).sort(([left], [right]) => left.localeCompare(right))) {
406
+ if (['id', 'span', 'documentation', 'symbolId', 'inferredTypeId', 'resolvedTypeId'].includes(key))
407
+ continue;
408
+ result[key] = canonicalAst(child);
409
+ }
410
+ return result;
411
+ }
412
+ async function writeEmitOutput(outputPath, output, sourceMap) {
413
+ await mkdir(dirname(outputPath), { recursive: true });
414
+ await writeFile(outputPath, output.code, 'utf8');
415
+ if (sourceMap)
416
+ await writeFile(`${outputPath}.map`, output.map, 'utf8');
417
+ }
418
+ /**
419
+ * Validate the executable entry point without making library builds depend on
420
+ * the presence of `main`. The CLI invokes this only for `virune run`.
421
+ */
422
+ export function validateEntryPoint(module) {
423
+ const diagnostics = new DiagnosticBag();
424
+ const moduleSpan = module.ast?.span ?? spanAt(module.source.id, 0, 1, 1, 1);
425
+ if (module.ast === undefined || module.semantic === undefined) {
426
+ diagnostics.error('L5010', 'Entry module could not be analyzed', moduleSpan);
427
+ return { diagnostics: diagnostics.items };
428
+ }
429
+ const namedMain = module.ast.declarations.find(declaration => 'name' in declaration && declaration.name === 'main');
430
+ if (namedMain === undefined || namedMain.kind !== 'FunctionDeclaration') {
431
+ diagnostics.error('L5011', 'Entry module must declare pub fn main', namedMain?.span ?? moduleSpan);
432
+ return { diagnostics: diagnostics.items };
433
+ }
434
+ if (!namedMain.public)
435
+ diagnostics.error('L5012', 'Entry function main must be public', namedMain.span);
436
+ if (namedMain.typeParameters.length > 0)
437
+ diagnostics.error('L5013', 'Entry function main cannot be generic', namedMain.span);
438
+ if (namedMain.parameters.length > 1) {
439
+ diagnostics.error('L5014', 'Entry function main accepts zero parameters or one List<String> parameter', namedMain.span);
440
+ }
441
+ else if (namedMain.parameters.length === 1) {
442
+ const parameter = namedMain.parameters[0];
443
+ const typeId = parameter.type.resolvedTypeId;
444
+ const type = typeId === undefined ? undefined : module.semantic.arena.get(typeId);
445
+ const valid = type?.kind === 'list' && module.semantic.arena.equals(type.element, module.semantic.arena.string);
446
+ if (!valid)
447
+ diagnostics.error('L5015', 'Entry function main parameter must be List<String>', parameter.span);
448
+ }
449
+ const returnTypeId = namedMain.inferredTypeId;
450
+ const returnType = returnTypeId === undefined ? undefined : module.semantic.arena.get(returnTypeId);
451
+ const validReturn = returnTypeId !== undefined && (module.semantic.arena.equals(returnTypeId, module.semantic.arena.unit)
452
+ || (returnType?.kind === 'result' && module.semantic.arena.equals(returnType.value, module.semantic.arena.unit)));
453
+ if (!validReturn)
454
+ diagnostics.error('L5016', 'Entry function main must return Unit or Result<Unit, E>', namedMain.returnType?.span ?? namedMain.span);
455
+ return diagnostics.hasErrors ? { diagnostics: diagnostics.items } : { main: namedMain, diagnostics: diagnostics.items };
456
+ }
457
+ async function resolveImport(projectRoot, importer, specifier, host) {
458
+ if (specifier.startsWith('.')) {
459
+ if (extname(specifier) !== '.virune')
460
+ return undefined;
461
+ return resolve(dirname(importer), specifier);
462
+ }
463
+ const segments = specifier.split('/');
464
+ const packageName = specifier.startsWith('@') ? segments.slice(0, 2).join('/') : segments[0];
465
+ const subpathSegments = specifier.startsWith('@') ? segments.slice(2) : segments.slice(1);
466
+ const exportKey = subpathSegments.length === 0 ? '.' : `./${subpathSegments.join('/')}`;
467
+ const packageRoot = join(projectRoot, 'node_modules', packageName);
468
+ try {
469
+ const packageJson = JSON.parse(await host.readFile(join(packageRoot, 'package.json')));
470
+ if (exportKey === '.' && typeof packageJson.virune === 'string')
471
+ return resolve(packageRoot, packageJson.virune);
472
+ const target = resolveViruneExport(packageJson.exports, exportKey);
473
+ return target === undefined ? undefined : resolve(packageRoot, target);
474
+ }
475
+ catch {
476
+ return undefined;
477
+ }
478
+ }
479
+ function resolveViruneExport(exportsValue, key) {
480
+ if (typeof exportsValue === 'string')
481
+ return key === '.' ? undefined : undefined;
482
+ if (exportsValue === null || typeof exportsValue !== 'object' || Array.isArray(exportsValue))
483
+ return undefined;
484
+ const record = exportsValue;
485
+ const selected = Object.keys(record).some(item => item.startsWith('.')) ? record[key] : key === '.' ? exportsValue : undefined;
486
+ if (typeof selected === 'string')
487
+ return undefined;
488
+ if (selected === null || typeof selected !== 'object' || Array.isArray(selected))
489
+ return undefined;
490
+ const virune = selected.virune;
491
+ return typeof virune === 'string' ? virune : undefined;
492
+ }
493
+ function isWithin(parent, child) {
494
+ const value = relative(parent, child);
495
+ return value === '' || (!value.startsWith('..') && !isAbsolute(value));
496
+ }
497
+ function modulePackageScope(root, path) {
498
+ const normalizedRoot = resolve(root);
499
+ const normalizedPath = resolve(path);
500
+ if (!isWithin(normalizedRoot, normalizedPath))
501
+ return undefined;
502
+ const segments = relative(normalizedRoot, normalizedPath).replaceAll('\\', '/').split('/');
503
+ const nodeModulesIndex = segments.lastIndexOf('node_modules');
504
+ if (nodeModulesIndex < 0)
505
+ return 'project';
506
+ const first = segments[nodeModulesIndex + 1];
507
+ if (first === undefined || first.length === 0)
508
+ return undefined;
509
+ const packageEnd = first.startsWith('@') ? nodeModulesIndex + 3 : nodeModulesIndex + 2;
510
+ if (first.startsWith('@') && (segments[nodeModulesIndex + 2]?.length ?? 0) === 0)
511
+ return undefined;
512
+ return `package:${segments.slice(0, packageEnd).join('/')}`;
513
+ }
514
+ function samePackageScope(root, left, right) {
515
+ const leftScope = modulePackageScope(root, left);
516
+ return leftScope !== undefined && leftScope === modulePackageScope(root, right);
517
+ }
518
+ function validateModulePolicy(root, config, path, module, diagnostics) {
519
+ const sourceRelative = relative(resolve(root, config.sourceDir), path).replaceAll('\\', '/');
520
+ const inFfiDirectory = sourceRelative === 'ffi' || sourceRelative.startsWith('ffi/');
521
+ for (const declaration of module.imports) {
522
+ if (declaration.internal === true)
523
+ diagnostics.error('L4019', '`internal` is a declaration visibility modifier and cannot be applied to imports', declaration.span);
524
+ }
525
+ for (const declaration of module.declarations) {
526
+ if (declaration.kind !== 'ExternDeclaration')
527
+ continue;
528
+ if (declaration.module.startsWith('node:') && config.platform !== 'node')
529
+ diagnostics.error('L4006', `Node.js module ${declaration.module} is not available for platform ${config.platform}`, declaration.span);
530
+ if (declaration.unsafe && !module.unsafe)
531
+ diagnostics.error('L4007', 'unsafe extern requires an unsafe module declaration', declaration.span);
532
+ if (declaration.unsafe && !inFfiDirectory)
533
+ diagnostics.error('L4008', 'unsafe extern is allowed only under the source ffi/ directory', declaration.span);
534
+ }
535
+ if (module.unsafe && !inFfiDirectory)
536
+ diagnostics.error('L4009', 'unsafe module is allowed only under the source ffi/ directory', module.span);
537
+ }
538
+ function declarationHasRuntimeExport(declaration) {
539
+ return declaration.kind === 'FunctionDeclaration' || declaration.kind === 'ComponentDeclaration' || declaration.kind === 'RecordDeclaration' || declaration.kind === 'EnumDeclaration' || declaration.kind === 'NewtypeDeclaration' || (declaration.kind === 'TopLevelLetDeclaration' && (declaration.public || declaration.internal === true));
540
+ }
541
+ function exportVisibleTo(root, importerPath, entry) {
542
+ return entry.visibility === 'public' || samePackageScope(root, importerPath, entry.originPath);
543
+ }
544
+ async function buildModuleInterfaces(root, order, parsedByPath, diagnostics, host) {
545
+ const interfaces = new Map();
546
+ for (const path of order) {
547
+ const module = parsedByPath.get(path)?.ast;
548
+ if (module === undefined)
549
+ continue;
550
+ const exports = new Map();
551
+ for (const declaration of module.declarations) {
552
+ if (!('name' in declaration) || !('public' in declaration))
553
+ continue;
554
+ const visibility = declaration.public ? 'public' : declaration.internal === true ? 'internal' : undefined;
555
+ if (visibility === undefined)
556
+ continue;
557
+ exports.set(declaration.name, { declaration, originPath: path, originModule: module, visibility });
558
+ }
559
+ const importedTypeVisibilities = new Map();
560
+ for (const importDeclaration of module.imports.filter(item => item.sourceKind === 'virune' && item.internal !== true)) {
561
+ const dependencyPath = await resolveImport(root, path, importDeclaration.source, host);
562
+ const dependencyInterface = dependencyPath === undefined ? undefined : interfaces.get(dependencyPath);
563
+ if (dependencyInterface === undefined)
564
+ continue;
565
+ for (const item of importDeclaration.items) {
566
+ const exported = dependencyInterface.exports.get(item.imported);
567
+ const visible = exported !== undefined && exportVisibleTo(root, path, exported);
568
+ if (visible && exported !== undefined && isTypeDeclaration(exported.declaration)) {
569
+ const previous = importedTypeVisibilities.get(item.local);
570
+ if (previous === undefined || exported.visibility === 'internal')
571
+ importedTypeVisibilities.set(item.local, exported.visibility);
572
+ }
573
+ if (!importDeclaration.public)
574
+ continue;
575
+ if (!visible || exported === undefined) {
576
+ diagnostics.error('L4004', `Module ${importDeclaration.source} does not export ${item.imported}`, item.span);
577
+ continue;
578
+ }
579
+ if (exported.visibility === 'internal') {
580
+ diagnostics.error('L4018', `Public import cannot re-export internal declaration ${item.imported}`, item.span);
581
+ continue;
582
+ }
583
+ if (importDeclaration.typeOnly && !isTypeDeclaration(exported.declaration)) {
584
+ diagnostics.error('L4015', `Type-only re-export ${item.local} must refer to a type`, item.span);
585
+ continue;
586
+ }
587
+ if (exports.has(item.local)) {
588
+ diagnostics.error('L4016', `Duplicate public export ${item.local}`, item.span);
589
+ continue;
590
+ }
591
+ exports.set(item.local, exported);
592
+ }
593
+ }
594
+ validateImportedSignatureVisibility(module, importedTypeVisibilities, diagnostics);
595
+ interfaces.set(path, { exports });
596
+ }
597
+ return interfaces;
598
+ }
599
+ const builtinTypeNames = new Set([
600
+ 'Bool', 'Int', 'Float', 'BigInt', 'String', 'Unit', 'Unknown', 'Never', 'Option', 'Result', 'List', 'Map', 'Set', 'Stream',
601
+ 'JsError', 'JsonError', 'Duration', 'TaskTimeoutError', 'SupervisorRestartLimitError', 'HttpResponse', 'HttpBody', 'FileHandle', 'Bytes', 'MutableBytes', 'ByteOrder', 'BytesError', 'IntegerRangeError', 'Byte', 'Int8', 'UInt8', 'Int16', 'UInt16', 'Int32', 'UInt32', 'Int64', 'UInt64',
602
+ ]);
603
+ async function buildImportModel(root, importerPath, module, parsedByPath, moduleInterfaces, diagnostics, initialId, host) {
604
+ let nextId = initialId;
605
+ const next = () => nextId--;
606
+ const signatureOnly = new Set();
607
+ const typeOnlyNodeIds = new Set();
608
+ const importedDeclarations = [];
609
+ const emissionImports = [];
610
+ const runtimeDependencyPaths = [];
611
+ const emittedTypeDefinitions = new Set();
612
+ for (const importDeclaration of module.imports) {
613
+ if (importDeclaration.internal === true)
614
+ continue;
615
+ if (importDeclaration.sourceKind === 'javascript') {
616
+ emissionImports.push(importDeclaration);
617
+ continue;
618
+ }
619
+ const dependencyPath = await resolveImport(root, importerPath, importDeclaration.source, host);
620
+ const dependencyInterface = dependencyPath === undefined ? undefined : moduleInterfaces.get(dependencyPath);
621
+ if (dependencyPath === undefined || dependencyInterface === undefined)
622
+ continue;
623
+ const runtimeItems = [];
624
+ const groups = new Map();
625
+ for (const item of importDeclaration.items) {
626
+ const exported = dependencyInterface.exports.get(item.imported);
627
+ if (exported === undefined || !exportVisibleTo(root, importerPath, exported)) {
628
+ diagnostics.error('L4004', `Module ${importDeclaration.source} does not export ${item.imported}`, item.span);
629
+ continue;
630
+ }
631
+ if (importDeclaration.public && exported.visibility === 'internal')
632
+ continue;
633
+ const group = groups.get(exported.originPath) ?? { module: exported.originModule, entries: [] };
634
+ group.entries.push({ item, exported });
635
+ groups.set(exported.originPath, group);
636
+ if (!importDeclaration.typeOnly && declarationHasRuntimeExport(exported.declaration))
637
+ runtimeItems.push(item);
638
+ }
639
+ for (const [originPath, group] of groups) {
640
+ const explicitAliases = new Map();
641
+ const roots = new Set();
642
+ const valueImports = [];
643
+ for (const entry of group.entries) {
644
+ const declaration = entry.exported.declaration;
645
+ if (isTypeDeclaration(declaration)) {
646
+ const previous = explicitAliases.get(declaration.name);
647
+ if (previous !== undefined && previous !== entry.item.local)
648
+ diagnostics.error('L4012', `Type ${declaration.name} cannot be imported under multiple local names`, entry.item.span);
649
+ else
650
+ explicitAliases.set(declaration.name, entry.item.local);
651
+ roots.add(declaration.name);
652
+ }
653
+ else
654
+ valueImports.push({ declaration, localName: entry.item.local });
655
+ for (const name of referencedTypeNames(declaration))
656
+ if (!builtinTypeNames.has(name))
657
+ roots.add(name);
658
+ }
659
+ const requiredTypes = collectTypeClosure(group.module, roots, diagnostics, importDeclaration.span);
660
+ const rename = new Map();
661
+ for (const name of requiredTypes)
662
+ rename.set(name, explicitAliases.get(name) ?? hiddenImportName(root, originPath, name));
663
+ for (const name of requiredTypes) {
664
+ const declaration = group.module.declarations.find(candidate => isTypeDeclaration(candidate) && candidate.name === name);
665
+ if (declaration === undefined || !isTypeDeclaration(declaration))
666
+ continue;
667
+ const definitionId = `${moduleIdentity(root, originPath)}#${name}`;
668
+ const emittedKey = `${definitionId}:${rename.get(name)}`;
669
+ if (emittedTypeDefinitions.has(emittedKey))
670
+ continue;
671
+ emittedTypeDefinitions.add(emittedKey);
672
+ const clone = cloneTypeSignature(declaration, rename.get(name), definitionId, rename, next);
673
+ signatureOnly.add(clone.id);
674
+ if (!explicitAliases.has(name) || importDeclaration.typeOnly)
675
+ typeOnlyNodeIds.add(clone.id);
676
+ importedDeclarations.push(clone);
677
+ }
678
+ for (const valueImport of valueImports) {
679
+ const clone = cloneValueSignature(valueImport.declaration, valueImport.localName, rename, next);
680
+ signatureOnly.add(clone.id);
681
+ if (importDeclaration.typeOnly)
682
+ typeOnlyNodeIds.add(clone.id);
683
+ importedDeclarations.push(clone);
684
+ }
685
+ }
686
+ if (runtimeItems.length > 0) {
687
+ const componentDependency = parsedByPath.get(dependencyPath)?.ast?.declarations.some(declaration => declaration.kind === 'ComponentDeclaration') === true;
688
+ const source = componentDependency && importDeclaration.source.endsWith('.virune') ? `${importDeclaration.source.slice(0, -7)}.jsx` : importDeclaration.source;
689
+ emissionImports.push({ ...importDeclaration, source, items: runtimeItems });
690
+ if (importDeclaration.source.endsWith('.virune') && !runtimeDependencyPaths.includes(dependencyPath))
691
+ runtimeDependencyPaths.push(dependencyPath);
692
+ }
693
+ }
694
+ return { signatureOnly, typeOnlyNodeIds, importedDeclarations, emissionImports, runtimeDependencies: Object.freeze(runtimeDependencyPaths), nextId };
695
+ }
696
+ function isTypeDeclaration(declaration) {
697
+ return declaration.kind === 'RecordDeclaration' || declaration.kind === 'EnumDeclaration' || declaration.kind === 'NewtypeDeclaration' || declaration.kind === 'TypeAliasDeclaration';
698
+ }
699
+ function collectTypeClosure(module, roots, diagnostics, span) {
700
+ const declarations = new Map(module.declarations.filter(isTypeDeclaration).map(declaration => [declaration.name, declaration]));
701
+ const result = new Set();
702
+ const visit = (name) => {
703
+ if (builtinTypeNames.has(name) || result.has(name))
704
+ return;
705
+ const declaration = declarations.get(name);
706
+ if (declaration === undefined) {
707
+ diagnostics.error('L4011', `Public signature refers to imported or unavailable type ${name}; re-exported signature types are not supported in Virune 1.0`, span);
708
+ return;
709
+ }
710
+ result.add(name);
711
+ for (const dependency of referencedTypeNames(declaration))
712
+ visit(dependency);
713
+ };
714
+ for (const root of roots)
715
+ visit(root);
716
+ return result;
717
+ }
718
+ function referencedTypeNames(declaration) {
719
+ const result = new Set();
720
+ const addReference = (reference, typeParameters) => {
721
+ if (reference.functionType !== undefined) {
722
+ for (const parameter of reference.functionType.parameters)
723
+ addReference(parameter, typeParameters);
724
+ addReference(reference.functionType.result, typeParameters);
725
+ return;
726
+ }
727
+ if (!typeParameters.has(reference.name))
728
+ result.add(reference.name);
729
+ for (const argument of reference.arguments)
730
+ addReference(argument, typeParameters);
731
+ };
732
+ if (declaration.kind === 'FunctionDeclaration') {
733
+ const parameters = new Set(declaration.typeParameters.map(item => item.name));
734
+ for (const parameter of declaration.parameters)
735
+ addReference(parameter.type, parameters);
736
+ if (declaration.returnType !== undefined)
737
+ addReference(declaration.returnType, parameters);
738
+ }
739
+ else if (declaration.kind === 'ComponentDeclaration') {
740
+ for (const parameter of declaration.parameters)
741
+ addReference(parameter.type, new Set());
742
+ }
743
+ else if (declaration.kind === 'RecordDeclaration') {
744
+ const parameters = new Set(declaration.typeParameters.map(item => item.name));
745
+ for (const field of declaration.fields)
746
+ addReference(field.type, parameters);
747
+ }
748
+ else if (declaration.kind === 'EnumDeclaration') {
749
+ const parameters = new Set(declaration.typeParameters.map(item => item.name));
750
+ for (const variant of declaration.variants)
751
+ for (const value of variant.values)
752
+ addReference(value, parameters);
753
+ }
754
+ else if (declaration.kind === 'NewtypeDeclaration')
755
+ addReference(declaration.underlying, new Set());
756
+ else if (declaration.kind === 'TypeAliasDeclaration')
757
+ addReference(declaration.target, new Set(declaration.typeParameters.map(item => item.name)));
758
+ else if (declaration.kind === 'TopLevelLetDeclaration' && declaration.annotation !== undefined)
759
+ addReference(declaration.annotation, new Set());
760
+ return result;
761
+ }
762
+ function cloneValueSignature(declaration, localName, rename, next) {
763
+ if (declaration.kind === 'TopLevelLetDeclaration') {
764
+ const id = next();
765
+ return {
766
+ ...declaration,
767
+ id,
768
+ name: localName,
769
+ public: false,
770
+ attributes: [],
771
+ ...(declaration.annotation === undefined ? {} : { annotation: cloneTypeReference(declaration.annotation, rename, next) }),
772
+ value: { id: next(), kind: 'LiteralExpression', span: declaration.span, literalKind: 'Bool', value: false },
773
+ };
774
+ }
775
+ if (declaration.kind === 'ComponentDeclaration') {
776
+ return {
777
+ ...declaration,
778
+ id: next(),
779
+ name: localName,
780
+ public: false,
781
+ attributes: [],
782
+ parameters: declaration.parameters.map(parameter => ({ ...parameter, type: cloneTypeReference(parameter.type, rename, next) })),
783
+ effects: declaration.effects,
784
+ body: { id: next(), kind: 'BlockStatement', span: declaration.span, statements: [] },
785
+ };
786
+ }
787
+ if (declaration.kind !== 'FunctionDeclaration')
788
+ throw new Error(`Declaration ${declaration.kind} cannot be imported as a value signature`);
789
+ const id = next();
790
+ return {
791
+ ...declaration,
792
+ id,
793
+ name: localName,
794
+ public: false,
795
+ attributes: declaration.attributes.filter(attribute => attribute.name === 'jsExport'),
796
+ parameters: declaration.parameters.map(parameter => ({ ...parameter, type: cloneTypeReference(parameter.type, rename, next) })),
797
+ ...(declaration.returnType === undefined ? {} : { returnType: cloneTypeReference(declaration.returnType, rename, next) }),
798
+ effects: declaration.effects,
799
+ body: { id: next(), kind: 'LiteralExpression', span: declaration.span, literalKind: 'Bool', value: false },
800
+ expressionBody: true,
801
+ };
802
+ }
803
+ function cloneTypeSignature(declaration, localName, definitionId, rename, next) {
804
+ const id = next();
805
+ switch (declaration.kind) {
806
+ case 'RecordDeclaration': return { ...declaration, id, name: localName, definitionId, public: false, attributes: declaration.attributes, fields: declaration.fields.map(field => ({ ...field, type: cloneTypeReference(field.type, rename, next), attributes: field.attributes })) };
807
+ case 'EnumDeclaration': return { ...declaration, id, name: localName, definitionId, public: false, attributes: [], variants: declaration.variants.map(variant => ({ ...variant, values: variant.values.map(value => cloneTypeReference(value, rename, next)) })) };
808
+ case 'NewtypeDeclaration': return { ...declaration, id, name: localName, definitionId, public: false, attributes: declaration.attributes, underlying: cloneTypeReference(declaration.underlying, rename, next) };
809
+ case 'TypeAliasDeclaration': return { ...declaration, id, name: localName, definitionId, public: false, attributes: [], target: cloneTypeReference(declaration.target, rename, next) };
810
+ }
811
+ }
812
+ function cloneTypeReference(reference, rename, next) {
813
+ return {
814
+ id: next(), kind: 'TypeReference', span: reference.span, name: rename.get(reference.name) ?? reference.name,
815
+ arguments: reference.arguments.map(argument => cloneTypeReference(argument, rename, next)), optional: reference.optional,
816
+ ...(reference.functionType === undefined ? {} : { functionType: {
817
+ async: reference.functionType.async,
818
+ parameters: reference.functionType.parameters.map(parameter => cloneTypeReference(parameter, rename, next)),
819
+ result: cloneTypeReference(reference.functionType.result, rename, next),
820
+ effects: reference.functionType.effects,
821
+ } }),
822
+ };
823
+ }
824
+ function hiddenImportName(root, dependencyPath, name) {
825
+ const hash = createHash('sha256').update(moduleIdentity(root, dependencyPath)).digest('hex').slice(0, 10);
826
+ return `$import_${hash}_${name}`;
827
+ }
828
+ function moduleIdentity(root, path) {
829
+ const relativePath = relative(root, path).replaceAll('\\', '/');
830
+ return relativePath.startsWith('../') ? `external:${createHash('sha256').update(path).digest('hex').slice(0, 16)}` : `project:${relativePath}`;
831
+ }
832
+ function declarationVisibilityRank(declaration) {
833
+ return 'public' in declaration && declaration.public ? 2 : 'internal' in declaration && declaration.internal === true ? 1 : 0;
834
+ }
835
+ function validateSignatureVisibility(module, diagnostics) {
836
+ const localTypes = new Map(module.declarations.filter(isTypeDeclaration).map(declaration => [declaration.name, declaration]));
837
+ for (const declaration of module.declarations) {
838
+ const rank = declarationVisibilityRank(declaration);
839
+ if (rank === 0 || declaration.kind === 'NewtypeDeclaration' || !('name' in declaration))
840
+ continue;
841
+ for (const name of referencedTypeNames(declaration)) {
842
+ const local = localTypes.get(name);
843
+ if (local === undefined || declarationVisibilityRank(local) >= rank)
844
+ continue;
845
+ const owner = rank === 2 ? 'Public' : 'Internal';
846
+ const exposed = local.internal === true ? 'internal' : 'private';
847
+ diagnostics.error('L4010', `${owner} declaration ${declaration.name} exposes ${exposed} type ${name}`, declaration.span);
848
+ }
849
+ }
850
+ }
851
+ function validateImportedSignatureVisibility(module, importedTypes, diagnostics) {
852
+ for (const declaration of module.declarations) {
853
+ const rank = declarationVisibilityRank(declaration);
854
+ if (rank === 0 || declaration.kind === 'NewtypeDeclaration' || !('name' in declaration))
855
+ continue;
856
+ for (const name of referencedTypeNames(declaration)) {
857
+ const importedVisibility = importedTypes.get(name);
858
+ if (importedVisibility === undefined)
859
+ continue;
860
+ const importedRank = importedVisibility === 'public' ? 2 : 1;
861
+ if (importedRank >= rank)
862
+ continue;
863
+ const owner = rank === 2 ? 'Public' : 'Internal';
864
+ diagnostics.error('L4010', `${owner} declaration ${declaration.name} exposes internal type ${name}`, declaration.span);
865
+ }
866
+ }
867
+ }
868
+ function finitePosition(value, fallback) {
869
+ return value !== undefined && Number.isFinite(value) ? value : fallback;
870
+ }
871
+ function lineAt(text, offset) {
872
+ let line = 1;
873
+ for (let index = 0; index < offset; index++)
874
+ if (text[index] === '\n')
875
+ line++;
876
+ return line;
877
+ }
878
+ function columnAt(text, offset) {
879
+ return offset - text.lastIndexOf('\n', Math.max(0, offset - 1));
880
+ }
881
+ function spanAt(fileId, offset, length, line, column) {
882
+ return { fileId, start: { offset, line, column }, end: { offset: offset + length, line, column: column + length } };
883
+ }
884
+ //# sourceMappingURL=project.js.map