openalgo-script 0.2.0 → 0.5.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 (357) hide show
  1. package/CHANGELOG.md +1198 -0
  2. package/README.md +127 -40
  3. package/dist/adapters/charts/driving.d.ts +50 -0
  4. package/dist/adapters/charts/driving.d.ts.map +1 -0
  5. package/dist/adapters/charts/driving.js +57 -0
  6. package/dist/adapters/charts/driving.js.map +1 -0
  7. package/dist/adapters/charts/run.d.ts +20 -0
  8. package/dist/adapters/charts/run.d.ts.map +1 -1
  9. package/dist/adapters/charts/run.js +83 -16
  10. package/dist/adapters/charts/run.js.map +1 -1
  11. package/dist/adapters/charts/surfaces.d.ts +17 -0
  12. package/dist/adapters/charts/surfaces.d.ts.map +1 -1
  13. package/dist/adapters/charts/tables.js +82 -0
  14. package/dist/adapters/charts/tables.js.map +1 -1
  15. package/dist/adapters/charts/venue.d.ts +73 -0
  16. package/dist/adapters/charts/venue.d.ts.map +1 -0
  17. package/dist/adapters/charts/venue.js +104 -0
  18. package/dist/adapters/charts/venue.js.map +1 -0
  19. package/dist/adapters/codemirror/commands.d.ts +14 -0
  20. package/dist/adapters/codemirror/commands.d.ts.map +1 -0
  21. package/dist/adapters/codemirror/commands.js +52 -0
  22. package/dist/adapters/codemirror/commands.js.map +1 -0
  23. package/dist/adapters/codemirror/completion.d.ts +15 -0
  24. package/dist/adapters/codemirror/completion.d.ts.map +1 -0
  25. package/dist/adapters/codemirror/completion.js +64 -0
  26. package/dist/adapters/codemirror/completion.js.map +1 -0
  27. package/dist/adapters/codemirror/contract.d.ts +156 -0
  28. package/dist/adapters/codemirror/contract.d.ts.map +1 -0
  29. package/dist/adapters/codemirror/contract.js +42 -0
  30. package/dist/adapters/codemirror/contract.js.map +1 -0
  31. package/dist/adapters/codemirror/index.d.ts +43 -0
  32. package/dist/adapters/codemirror/index.d.ts.map +1 -0
  33. package/dist/adapters/codemirror/index.js +8 -0
  34. package/dist/adapters/codemirror/index.js.map +1 -0
  35. package/dist/adapters/codemirror/lint.d.ts +17 -0
  36. package/dist/adapters/codemirror/lint.d.ts.map +1 -0
  37. package/dist/adapters/codemirror/lint.js +62 -0
  38. package/dist/adapters/codemirror/lint.js.map +1 -0
  39. package/dist/adapters/codemirror/positions.d.ts +16 -0
  40. package/dist/adapters/codemirror/positions.d.ts.map +1 -0
  41. package/dist/adapters/codemirror/positions.js +65 -0
  42. package/dist/adapters/codemirror/positions.js.map +1 -0
  43. package/dist/adapters/codemirror/stream.d.ts +23 -0
  44. package/dist/adapters/codemirror/stream.d.ts.map +1 -0
  45. package/dist/adapters/codemirror/stream.js +70 -0
  46. package/dist/adapters/codemirror/stream.js.map +1 -0
  47. package/dist/adapters/codemirror/tokens.d.ts +44 -0
  48. package/dist/adapters/codemirror/tokens.d.ts.map +1 -0
  49. package/dist/adapters/codemirror/tokens.js +34 -0
  50. package/dist/adapters/codemirror/tokens.js.map +1 -0
  51. package/dist/adapters/codemirror/tooltips.d.ts +35 -0
  52. package/dist/adapters/codemirror/tooltips.d.ts.map +1 -0
  53. package/dist/adapters/codemirror/tooltips.js +108 -0
  54. package/dist/adapters/codemirror/tooltips.js.map +1 -0
  55. package/dist/core/accounting/analysis.d.ts +111 -0
  56. package/dist/core/accounting/analysis.d.ts.map +1 -0
  57. package/dist/core/accounting/analysis.js +123 -0
  58. package/dist/core/accounting/analysis.js.map +1 -0
  59. package/dist/core/accounting/charges.d.ts +136 -0
  60. package/dist/core/accounting/charges.d.ts.map +1 -0
  61. package/dist/core/accounting/charges.js +362 -0
  62. package/dist/core/accounting/charges.js.map +1 -0
  63. package/dist/core/accounting/equity.d.ts +191 -0
  64. package/dist/core/accounting/equity.d.ts.map +1 -0
  65. package/dist/core/accounting/equity.js +167 -0
  66. package/dist/core/accounting/equity.js.map +1 -0
  67. package/dist/core/accounting/index.d.ts +46 -0
  68. package/dist/core/accounting/index.d.ts.map +1 -0
  69. package/dist/core/accounting/index.js +37 -0
  70. package/dist/core/accounting/index.js.map +1 -0
  71. package/dist/core/accounting/markers.d.ts +43 -0
  72. package/dist/core/accounting/markers.d.ts.map +1 -0
  73. package/dist/core/accounting/markers.js +64 -0
  74. package/dist/core/accounting/markers.js.map +1 -0
  75. package/dist/core/accounting/monthly.d.ts +52 -0
  76. package/dist/core/accounting/monthly.d.ts.map +1 -0
  77. package/dist/core/accounting/monthly.js +99 -0
  78. package/dist/core/accounting/monthly.js.map +1 -0
  79. package/dist/core/accounting/report.d.ts +41 -0
  80. package/dist/core/accounting/report.d.ts.map +1 -0
  81. package/dist/core/accounting/report.js +65 -0
  82. package/dist/core/accounting/report.js.map +1 -0
  83. package/dist/core/accounting/shapes.d.ts +70 -0
  84. package/dist/core/accounting/shapes.d.ts.map +1 -0
  85. package/dist/core/accounting/shapes.js +21 -0
  86. package/dist/core/accounting/shapes.js.map +1 -0
  87. package/dist/core/accounting/statistics.d.ts +87 -0
  88. package/dist/core/accounting/statistics.d.ts.map +1 -0
  89. package/dist/core/accounting/statistics.js +268 -0
  90. package/dist/core/accounting/statistics.js.map +1 -0
  91. package/dist/core/accounting/trades.d.ts +118 -0
  92. package/dist/core/accounting/trades.d.ts.map +1 -0
  93. package/dist/core/accounting/trades.js +186 -0
  94. package/dist/core/accounting/trades.js.map +1 -0
  95. package/dist/core/backtest/case.d.ts +60 -0
  96. package/dist/core/backtest/case.d.ts.map +1 -0
  97. package/dist/core/backtest/case.js +319 -0
  98. package/dist/core/backtest/case.js.map +1 -0
  99. package/dist/core/backtest/compare.d.ts +38 -0
  100. package/dist/core/backtest/compare.d.ts.map +1 -0
  101. package/dist/core/backtest/compare.js +191 -0
  102. package/dist/core/backtest/compare.js.map +1 -0
  103. package/dist/core/backtest/declaration.d.ts +52 -0
  104. package/dist/core/backtest/declaration.d.ts.map +1 -0
  105. package/dist/core/backtest/declaration.js +48 -0
  106. package/dist/core/backtest/declaration.js.map +1 -0
  107. package/dist/core/backtest/deliver.d.ts +93 -0
  108. package/dist/core/backtest/deliver.d.ts.map +1 -0
  109. package/dist/core/backtest/deliver.js +94 -0
  110. package/dist/core/backtest/deliver.js.map +1 -0
  111. package/dist/core/backtest/drive.d.ts +87 -0
  112. package/dist/core/backtest/drive.d.ts.map +1 -0
  113. package/dist/core/backtest/drive.js +312 -0
  114. package/dist/core/backtest/drive.js.map +1 -0
  115. package/dist/core/backtest/index.d.ts +58 -0
  116. package/dist/core/backtest/index.d.ts.map +1 -0
  117. package/dist/core/backtest/index.js +47 -0
  118. package/dist/core/backtest/index.js.map +1 -0
  119. package/dist/core/backtest/range.d.ts +84 -0
  120. package/dist/core/backtest/range.d.ts.map +1 -0
  121. package/dist/core/backtest/range.js +90 -0
  122. package/dist/core/backtest/range.js.map +1 -0
  123. package/dist/core/backtest/record.d.ts +299 -0
  124. package/dist/core/backtest/record.d.ts.map +1 -0
  125. package/dist/core/backtest/record.js +243 -0
  126. package/dist/core/backtest/record.js.map +1 -0
  127. package/dist/core/backtest/replay.d.ts +48 -0
  128. package/dist/core/backtest/replay.d.ts.map +1 -0
  129. package/dist/core/backtest/replay.js +137 -0
  130. package/dist/core/backtest/replay.js.map +1 -0
  131. package/dist/core/backtest/resting.d.ts +62 -0
  132. package/dist/core/backtest/resting.d.ts.map +1 -0
  133. package/dist/core/backtest/resting.js +59 -0
  134. package/dist/core/backtest/resting.js.map +1 -0
  135. package/dist/core/backtest/settings.d.ts +117 -0
  136. package/dist/core/backtest/settings.d.ts.map +1 -0
  137. package/dist/core/backtest/settings.js +207 -0
  138. package/dist/core/backtest/settings.js.map +1 -0
  139. package/dist/core/backtest/simulate.d.ts +258 -0
  140. package/dist/core/backtest/simulate.d.ts.map +1 -0
  141. package/dist/core/backtest/simulate.js +335 -0
  142. package/dist/core/backtest/simulate.js.map +1 -0
  143. package/dist/core/catalogue/catalogue.generated.d.ts +66 -0
  144. package/dist/core/catalogue/catalogue.generated.d.ts.map +1 -1
  145. package/dist/core/catalogue/catalogue.generated.js +6 -0
  146. package/dist/core/catalogue/catalogue.generated.js.map +1 -1
  147. package/dist/core/catalogue/values.generated.d.ts +24 -0
  148. package/dist/core/catalogue/values.generated.d.ts.map +1 -1
  149. package/dist/core/check/index.d.ts +2 -1
  150. package/dist/core/check/index.d.ts.map +1 -1
  151. package/dist/core/check/index.js +1 -1
  152. package/dist/core/check/index.js.map +1 -1
  153. package/dist/core/check/library-orders.js +2 -2
  154. package/dist/core/check/library-orders.js.map +1 -1
  155. package/dist/core/check/library-prose.generated.d.ts +16 -0
  156. package/dist/core/check/library-prose.generated.d.ts.map +1 -0
  157. package/dist/core/check/library-prose.generated.js +353 -0
  158. package/dist/core/check/library-prose.generated.js.map +1 -0
  159. package/dist/core/check/surface.d.ts +24 -0
  160. package/dist/core/check/surface.d.ts.map +1 -1
  161. package/dist/core/check/surface.js +29 -0
  162. package/dist/core/check/surface.js.map +1 -1
  163. package/dist/core/emit/canonical.d.ts +22 -8
  164. package/dist/core/emit/canonical.d.ts.map +1 -1
  165. package/dist/core/emit/canonical.js +67 -6
  166. package/dist/core/emit/canonical.js.map +1 -1
  167. package/dist/core/emit/defaults.d.ts +35 -16
  168. package/dist/core/emit/defaults.d.ts.map +1 -1
  169. package/dist/core/emit/defaults.js +66 -0
  170. package/dist/core/emit/defaults.js.map +1 -1
  171. package/dist/core/emit/index.d.ts +2 -0
  172. package/dist/core/emit/index.d.ts.map +1 -1
  173. package/dist/core/emit/index.js +2 -0
  174. package/dist/core/emit/index.js.map +1 -1
  175. package/dist/core/engine/arithmetic.d.ts +6 -25
  176. package/dist/core/engine/arithmetic.d.ts.map +1 -1
  177. package/dist/core/engine/arithmetic.js +48 -3
  178. package/dist/core/engine/arithmetic.js.map +1 -1
  179. package/dist/core/engine/index.d.ts +2 -2
  180. package/dist/core/engine/index.d.ts.map +1 -1
  181. package/dist/core/engine/index.js +2 -2
  182. package/dist/core/engine/index.js.map +1 -1
  183. package/dist/core/engine/library/arrays.d.ts.map +1 -1
  184. package/dist/core/engine/library/arrays.js +8 -2
  185. package/dist/core/engine/library/arrays.js.map +1 -1
  186. package/dist/core/engine/library/code-points.d.ts +40 -0
  187. package/dist/core/engine/library/code-points.d.ts.map +1 -0
  188. package/dist/core/engine/library/code-points.js +74 -0
  189. package/dist/core/engine/library/code-points.js.map +1 -0
  190. package/dist/core/engine/library/index.d.ts +5 -0
  191. package/dist/core/engine/library/index.d.ts.map +1 -1
  192. package/dist/core/engine/library/index.js +5 -0
  193. package/dist/core/engine/library/index.js.map +1 -1
  194. package/dist/core/engine/library/text.d.ts.map +1 -1
  195. package/dist/core/engine/library/text.js +51 -34
  196. package/dist/core/engine/library/text.js.map +1 -1
  197. package/dist/core/engine/load.d.ts +35 -1
  198. package/dist/core/engine/load.d.ts.map +1 -1
  199. package/dist/core/engine/load.js +63 -0
  200. package/dist/core/engine/load.js.map +1 -1
  201. package/dist/core/engine/verify-tables.d.ts.map +1 -1
  202. package/dist/core/engine/verify-tables.js +41 -0
  203. package/dist/core/engine/verify-tables.js.map +1 -1
  204. package/dist/core/index.d.ts +43 -4
  205. package/dist/core/index.d.ts.map +1 -1
  206. package/dist/core/index.js +23 -2
  207. package/dist/core/index.js.map +1 -1
  208. package/dist/core/stdlib/index.d.ts +1 -1
  209. package/dist/core/stdlib/index.d.ts.map +1 -1
  210. package/dist/core/stdlib/index.js +1 -1
  211. package/dist/core/stdlib/index.js.map +1 -1
  212. package/dist/core/stdlib/maths/index.d.ts +1 -1
  213. package/dist/core/stdlib/maths/index.d.ts.map +1 -1
  214. package/dist/core/stdlib/maths/index.js +1 -1
  215. package/dist/core/stdlib/maths/index.js.map +1 -1
  216. package/dist/core/stdlib/maths/rounding.d.ts +5 -0
  217. package/dist/core/stdlib/maths/rounding.d.ts.map +1 -1
  218. package/dist/core/stdlib/maths/rounding.js +19 -1
  219. package/dist/core/stdlib/maths/rounding.js.map +1 -1
  220. package/dist/core/version/version.generated.d.ts +1 -1
  221. package/dist/core/version/version.generated.js +1 -1
  222. package/dist/editor/complete.d.ts +40 -0
  223. package/dist/editor/complete.d.ts.map +1 -0
  224. package/dist/editor/complete.js +206 -0
  225. package/dist/editor/complete.js.map +1 -0
  226. package/dist/editor/diagnose.d.ts +18 -0
  227. package/dist/editor/diagnose.d.ts.map +1 -0
  228. package/dist/editor/diagnose.js +70 -0
  229. package/dist/editor/diagnose.js.map +1 -0
  230. package/dist/editor/format.d.ts +11 -0
  231. package/dist/editor/format.d.ts.map +1 -0
  232. package/dist/editor/format.js +50 -0
  233. package/dist/editor/format.js.map +1 -0
  234. package/dist/editor/highlight.d.ts +28 -0
  235. package/dist/editor/highlight.d.ts.map +1 -0
  236. package/dist/editor/highlight.js +65 -0
  237. package/dist/editor/highlight.js.map +1 -0
  238. package/dist/editor/hover.d.ts +40 -0
  239. package/dist/editor/hover.d.ts.map +1 -0
  240. package/dist/editor/hover.js +147 -0
  241. package/dist/editor/hover.js.map +1 -0
  242. package/dist/editor/index.d.ts +60 -0
  243. package/dist/editor/index.d.ts.map +1 -0
  244. package/dist/editor/index.js +7 -0
  245. package/dist/editor/index.js.map +1 -0
  246. package/dist/editor/kinds.d.ts +27 -0
  247. package/dist/editor/kinds.d.ts.map +1 -0
  248. package/dist/editor/kinds.js +118 -0
  249. package/dist/editor/kinds.js.map +1 -0
  250. package/dist/editor/layout.d.ts +47 -0
  251. package/dist/editor/layout.d.ts.map +1 -0
  252. package/dist/editor/layout.js +135 -0
  253. package/dist/editor/layout.js.map +1 -0
  254. package/dist/editor/manifest.d.ts +47 -0
  255. package/dist/editor/manifest.d.ts.map +1 -0
  256. package/dist/editor/manifest.js +93 -0
  257. package/dist/editor/manifest.js.map +1 -0
  258. package/dist/editor/reading.d.ts +41 -0
  259. package/dist/editor/reading.d.ts.map +1 -0
  260. package/dist/editor/reading.js +51 -0
  261. package/dist/editor/reading.js.map +1 -0
  262. package/dist/editor/scan.d.ts +26 -0
  263. package/dist/editor/scan.d.ts.map +1 -0
  264. package/dist/editor/scan.js +139 -0
  265. package/dist/editor/scan.js.map +1 -0
  266. package/dist/editor/scope.d.ts +19 -0
  267. package/dist/editor/scope.d.ts.map +1 -0
  268. package/dist/editor/scope.js +99 -0
  269. package/dist/editor/scope.js.map +1 -0
  270. package/dist/editor/signature.d.ts +38 -0
  271. package/dist/editor/signature.d.ts.map +1 -0
  272. package/dist/editor/signature.js +112 -0
  273. package/dist/editor/signature.js.map +1 -0
  274. package/dist/editor/site.d.ts +46 -0
  275. package/dist/editor/site.d.ts.map +1 -0
  276. package/dist/editor/site.js +184 -0
  277. package/dist/editor/site.js.map +1 -0
  278. package/dist/editor/spacing.d.ts +29 -0
  279. package/dist/editor/spacing.d.ts.map +1 -0
  280. package/dist/editor/spacing.js +116 -0
  281. package/dist/editor/spacing.js.map +1 -0
  282. package/package.json +42 -3
  283. package/spec/README.md +2 -1
  284. package/spec/errors.json +141 -1
  285. package/src/adapters/charts/driving.ts +109 -0
  286. package/src/adapters/charts/run.ts +120 -28
  287. package/src/adapters/charts/surfaces.ts +17 -0
  288. package/src/adapters/charts/tables.ts +88 -0
  289. package/src/adapters/charts/venue.ts +132 -0
  290. package/src/adapters/codemirror/commands.ts +53 -0
  291. package/src/adapters/codemirror/completion.ts +74 -0
  292. package/src/adapters/codemirror/contract.ts +156 -0
  293. package/src/adapters/codemirror/index.ts +66 -0
  294. package/src/adapters/codemirror/lint.ts +66 -0
  295. package/src/adapters/codemirror/positions.ts +79 -0
  296. package/src/adapters/codemirror/stream.ts +87 -0
  297. package/src/adapters/codemirror/tokens.ts +64 -0
  298. package/src/adapters/codemirror/tooltips.ts +113 -0
  299. package/src/core/accounting/analysis.ts +188 -0
  300. package/src/core/accounting/charges.ts +452 -0
  301. package/src/core/accounting/equity.ts +314 -0
  302. package/src/core/accounting/index.ts +51 -0
  303. package/src/core/accounting/markers.ts +95 -0
  304. package/src/core/accounting/monthly.ts +137 -0
  305. package/src/core/accounting/report.ts +94 -0
  306. package/src/core/accounting/shapes.ts +73 -0
  307. package/src/core/accounting/statistics.ts +387 -0
  308. package/src/core/accounting/trades.ts +313 -0
  309. package/src/core/backtest/case.ts +395 -0
  310. package/src/core/backtest/compare.ts +246 -0
  311. package/src/core/backtest/declaration.ts +97 -0
  312. package/src/core/backtest/deliver.ts +161 -0
  313. package/src/core/backtest/drive.ts +468 -0
  314. package/src/core/backtest/index.ts +64 -0
  315. package/src/core/backtest/range.ts +137 -0
  316. package/src/core/backtest/record.ts +470 -0
  317. package/src/core/backtest/replay.ts +168 -0
  318. package/src/core/backtest/resting.ts +125 -0
  319. package/src/core/backtest/settings.ts +280 -0
  320. package/src/core/backtest/simulate.ts +499 -0
  321. package/src/core/catalogue/catalogue.generated.ts +6 -0
  322. package/src/core/catalogue/values.generated.ts +6 -0
  323. package/src/core/check/index.ts +3 -0
  324. package/src/core/check/library-orders.ts +2 -2
  325. package/src/core/check/library-prose.generated.ts +367 -0
  326. package/src/core/check/surface.ts +34 -0
  327. package/src/core/emit/canonical.ts +67 -9
  328. package/src/core/emit/defaults.ts +70 -0
  329. package/src/core/emit/index.ts +2 -0
  330. package/src/core/engine/arithmetic.ts +23 -3
  331. package/src/core/engine/index.ts +2 -2
  332. package/src/core/engine/library/arrays.ts +8 -2
  333. package/src/core/engine/library/code-points.ts +73 -0
  334. package/src/core/engine/library/index.ts +6 -0
  335. package/src/core/engine/library/text.ts +53 -35
  336. package/src/core/engine/load.ts +84 -2
  337. package/src/core/engine/verify-tables.ts +43 -0
  338. package/src/core/index.ts +100 -2
  339. package/src/core/stdlib/index.ts +1 -0
  340. package/src/core/stdlib/maths/index.ts +1 -0
  341. package/src/core/stdlib/maths/rounding.ts +23 -1
  342. package/src/core/version/version.generated.ts +1 -1
  343. package/src/editor/complete.ts +266 -0
  344. package/src/editor/diagnose.ts +71 -0
  345. package/src/editor/format.ts +85 -0
  346. package/src/editor/highlight.ts +110 -0
  347. package/src/editor/hover.ts +199 -0
  348. package/src/editor/index.ts +65 -0
  349. package/src/editor/kinds.ts +157 -0
  350. package/src/editor/layout.ts +189 -0
  351. package/src/editor/manifest.ts +119 -0
  352. package/src/editor/reading.ts +69 -0
  353. package/src/editor/scan.ts +162 -0
  354. package/src/editor/scope.ts +122 -0
  355. package/src/editor/signature.ts +150 -0
  356. package/src/editor/site.ts +233 -0
  357. package/src/editor/spacing.ts +132 -0
@@ -0,0 +1,199 @@
1
+ /**
2
+ * `hover`: what the thing under the pointer is.
3
+ *
4
+ * Three answers, and the difference between them is what the compiler says the
5
+ * word is rather than anything guessed from its spelling:
6
+ *
7
+ * a library name its signatures from the manifest, the line the
8
+ * specification gives it, the first bar its own row
9
+ * promises a value on, and the channels of a named colour
10
+ * a declared name the type the checker worked out, how it is held between
11
+ * bars, and where in the file it was declared
12
+ * a reserved word that it is one, and nothing else. See below
13
+ *
14
+ * ## What a hover wants and cannot have, said plainly
15
+ *
16
+ * **There is no per-word explanation of a keyword in a machine readable form.**
17
+ * `language.md` 3.4 reserves the words in one block and explains each one in the
18
+ * prose of the section that uses it, which is a page rather than a field. So a
19
+ * hover over `var` says it is a reserved word and stops. The alternative was to
20
+ * type thirty-five sentences into this file, and that is the copy that drifts:
21
+ * it would be right today, the specification would improve next month, and the
22
+ * only copy a writer ever reads would be the stale one. A host that wants more
23
+ * links the word to the specification, which is one page and stays current.
24
+ *
25
+ * **A name with several signatures has one description.** The specification
26
+ * gives every signature its own row, and the map read here is keyed by name, so
27
+ * `close` is described by its bar series row rather than by the order function's.
28
+ * Every signature is still listed: it is the sentence beside them that is the
29
+ * first row's.
30
+ *
31
+ * **A parameter has no description of its own anywhere.** `stdlib.md` describes
32
+ * a call in one line and names its parameters in the signature; only section
33
+ * 13's shared input arguments have a table with a meaning per argument. So
34
+ * `signature` shows a parameter's name, type, default and accepted values, which
35
+ * are facts, and no sentence, which would have to be invented.
36
+ *
37
+ * Each of those is recorded in `spec/editor-narrowings.json` beside what the
38
+ * adapter narrows, so a host reads them in one place rather than discovering
39
+ * them.
40
+ */
41
+ import {
42
+ endOffset,
43
+ entryFor,
44
+ fillTemplate,
45
+ isNamespace,
46
+ libraryEntries,
47
+ namedColour,
48
+ proseFor,
49
+ typeText,
50
+ } from '../core/index.js';
51
+ import type { Colour, SourceFile, Span, Token } from '../core/index.js';
52
+ import { isReserved } from './kinds.js';
53
+ import { signatureTextOf } from './manifest.js';
54
+ import { readChecked } from './reading.js';
55
+ import { bindingNamed } from './scope.js';
56
+ import { tokenOn } from './site.js';
57
+
58
+ export type HoverKind = 'library' | 'declared' | 'keyword';
59
+
60
+ export interface Hover {
61
+ readonly kind: HoverKind;
62
+ /** The word the pointer is over, which is what a host underlines. */
63
+ readonly span: Span;
64
+ /** The name as written, dotted where the word is half of a namespaced name. */
65
+ readonly name: string;
66
+ /**
67
+ * Every signature the name has, in the order the manifest holds them.
68
+ *
69
+ * More than one where the language gives the name more than one, which
70
+ * `stdlib.md` 2.2 allows: a hover has no arguments to choose between them
71
+ * with, so it shows both rather than picking.
72
+ */
73
+ readonly signatures: readonly string[];
74
+ /** The line the specification gives it, where it gives one. */
75
+ readonly summary: string | undefined;
76
+ /** The first bar it can produce a value for, as its own row states it. */
77
+ readonly warmup: string | undefined;
78
+ /** The type the checker gave a declared name. */
79
+ readonly type: string | undefined;
80
+ /** Where a declared name was declared, which is what a host jumps to. */
81
+ readonly declaredAt: Span | undefined;
82
+ /** The channels of a named colour, for a swatch. */
83
+ readonly colour: Colour | undefined;
84
+ /** Named in the library and not implemented in this version: OS2020. */
85
+ readonly planned: boolean;
86
+ /** The catalogue's OS2020 message for this name, on a planned name and no other. */
87
+ readonly refusal: string | undefined;
88
+ }
89
+
90
+ /**
91
+ * The name a word is part of, which is the dotted one when it is half of one.
92
+ *
93
+ * Pointing at `box` in `draw.box` is pointing at `draw.box`: the member on its
94
+ * own is an ordinary name the library does not have, and a hover that said so
95
+ * would be wrong about the word under the pointer.
96
+ */
97
+ function nameAt(
98
+ file: SourceFile,
99
+ tokens: readonly Token[],
100
+ token: Token,
101
+ ): { name: string; span: Span } {
102
+ const index = tokens.indexOf(token);
103
+ const dot = tokens[index - 1];
104
+ const namespace = tokens[index - 2];
105
+ if (dot?.kind === '.' && namespace?.kind === 'identifier' && isNamespace(namespace.text)) {
106
+ return {
107
+ name: `${namespace.text}.${token.text}`,
108
+ span: file.spanAt(namespace.span.offset, endOffset(token.span) - namespace.span.offset),
109
+ };
110
+ }
111
+ // A namespace with a member after it is pointed at as the whole name too, so
112
+ // that hovering either half of `draw.box` says the same thing.
113
+ const next = tokens[index + 1];
114
+ const member = tokens[index + 2];
115
+ if (
116
+ isNamespace(token.text) &&
117
+ next?.kind === '.' &&
118
+ member?.kind === 'identifier' &&
119
+ libraryEntries(`${token.text}.${member.text}`).length > 0
120
+ ) {
121
+ return {
122
+ name: `${token.text}.${member.text}`,
123
+ span: file.spanAt(token.span.offset, endOffset(member.span) - token.span.offset),
124
+ };
125
+ }
126
+ return { name: file.text.slice(token.span.offset, endOffset(token.span)), span: token.span };
127
+ }
128
+
129
+ const NOTHING = {
130
+ summary: undefined,
131
+ warmup: undefined,
132
+ type: undefined,
133
+ declaredAt: undefined,
134
+ colour: undefined,
135
+ planned: false,
136
+ refusal: undefined,
137
+ } as const;
138
+
139
+ /**
140
+ * What the word at an offset is, or nothing where the offset is not on a word.
141
+ *
142
+ * A pointer over a space, a bracket, a number or a string gets nothing: those
143
+ * are not names, and a tooltip that appeared over a comma would be in the way
144
+ * rather than useful. A host that wants a literal's value has it in the text.
145
+ */
146
+ export function hover(source: string, offset: number): Hover | undefined {
147
+ const { file, tokens, checked } = readChecked(source);
148
+ const token = tokenOn(tokens, offset);
149
+ if (token === undefined) return undefined;
150
+
151
+ if (isReserved(token.kind)) {
152
+ // A reserved word, and every one of them is also a word a script may not
153
+ // declare. What it means is the specification's, and there is no per-word
154
+ // field to read it from, which the file header states and the narrowings
155
+ // record.
156
+ return { kind: 'keyword', span: token.span, name: token.text, signatures: [], ...NOTHING };
157
+ }
158
+ if (token.kind !== 'identifier') return undefined;
159
+
160
+ const { name, span } = nameAt(file, tokens, token);
161
+
162
+ const binding = bindingNamed(checked, name, offset);
163
+ if (binding !== undefined) {
164
+ const persistence = binding.persistence === 'none' ? '' : `${binding.persistence} `;
165
+ return {
166
+ kind: 'declared',
167
+ span,
168
+ name,
169
+ signatures: [`${persistence}${name}: ${typeText(binding.type)}`],
170
+ summary: undefined,
171
+ warmup: undefined,
172
+ type: typeText(binding.type),
173
+ declaredAt: binding.declaredAt,
174
+ colour: undefined,
175
+ planned: false,
176
+ refusal: undefined,
177
+ };
178
+ }
179
+
180
+ const entries = libraryEntries(name);
181
+ const first = entries[0];
182
+ if (first === undefined) return undefined;
183
+
184
+ const prose = proseFor(name);
185
+ const planned = entries.every((one) => one.planned);
186
+ return {
187
+ kind: 'library',
188
+ span,
189
+ name,
190
+ signatures: entries.map(signatureTextOf),
191
+ summary: prose?.summary,
192
+ warmup: prose?.warmup,
193
+ type: typeText(first.returns),
194
+ declaredAt: undefined,
195
+ colour: namedColour(name),
196
+ planned,
197
+ refusal: planned ? fillTemplate(entryFor('OS2020').message, { name }) : undefined,
198
+ };
199
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * OpenScript, the language intelligence, headless.
3
+ *
4
+ * Six pure functions, text in and data out: highlight, complete, diagnose,
5
+ * hover, signature, format. Three of them are here. No DOM anywhere, no package,
6
+ * no browser global, and nothing on screen: a host supplies the text component,
7
+ * the panel, the apply button, saving and revisions, and keeps its own design
8
+ * system. `scripts/check-layering.mjs` fails the build if this tier so much as
9
+ * mentions a document object, because an editor half that reaches for one is the
10
+ * thing that stops a platform embedding it.
11
+ *
12
+ * **None of it is hand written.** That is the whole reason it is worth shipping
13
+ * rather than leaving to each host, and it is a property of how each function is
14
+ * built rather than an intention:
15
+ *
16
+ * highlight the real lexer, and the language's own tables of words and
17
+ * marks decide what each token is painted as
18
+ * diagnose the whole compiler, and every message and fix comes from the
19
+ * error catalogue the documentation is generated from
20
+ * format the real lexer for the tokens and the real parser for the
21
+ * three questions spacing cannot answer without a tree
22
+ *
23
+ * A hand written version of any of them drifts from the language and nobody
24
+ * notices for a release: a word is added and stays grey, a diagnostic's wording
25
+ * improves in one place. The editor is the compiler wearing a different hat, not
26
+ * a second implementation to keep in step.
27
+ *
28
+ * complete the standard library manifest, the checker's bindings for
29
+ * what the file itself declares, and the error catalogue for
30
+ * what a planned call would be refused with
31
+ * hover the manifest again, and the specification's own tables, read
32
+ * at build time rather than retyped here
33
+ * signature the manifest and the emitter, which between them are where
34
+ * every default the compiler applies lives
35
+ *
36
+ * All six exist, so `openalgo-script/editor` is an entry point in the package's
37
+ * export map. It was not one while three of them were missing, because an entry
38
+ * point that resolves to half a tier fails at a consumer's run time rather than
39
+ * honestly at install.
40
+ *
41
+ * What a host loses by taking the drop-in adapter beside this rather than
42
+ * calling these six itself, and the three places a hover has no sentence to show
43
+ * because none exists in a machine readable form, are recorded together in
44
+ * `spec/editor-narrowings.json`.
45
+ */
46
+ export type { Diagnostic, Span } from '../core/index.js';
47
+
48
+ export type { HighlightKind } from './kinds.js';
49
+ export type { Highlight } from './scan.js';
50
+ export type { HighlightedLine } from './highlight.js';
51
+ export { highlight, highlightLines } from './highlight.js';
52
+
53
+ export { diagnose } from './diagnose.js';
54
+
55
+ export { format } from './format.js';
56
+
57
+ export type { Completion, CompletionKind } from './complete.js';
58
+ export { complete } from './complete.js';
59
+
60
+ export type { Hover, HoverKind } from './hover.js';
61
+ export { hover } from './hover.js';
62
+
63
+ export type { Parameter } from './manifest.js';
64
+ export type { SignatureHelp } from './signature.js';
65
+ export { signature } from './signature.js';
@@ -0,0 +1,157 @@
1
+ /**
2
+ * What a host paints, and where each kind comes from.
3
+ *
4
+ * A highlighter is the one part of a language tool that is always written twice:
5
+ * once in the compiler, where the vocabulary is decided, and once in a theme
6
+ * file, where somebody types the words out again from memory. The second copy is
7
+ * wrong from the day a word is added to the language, and nobody notices, because
8
+ * an unpainted keyword still compiles.
9
+ *
10
+ * So nothing below is a list of words. Every kind is decided by asking the
11
+ * compiler a question it already answers:
12
+ *
13
+ * keyword the token's kind is in the language's reserved word table
14
+ * builtin the standard library manifest has an entry for the name
15
+ * operator the mark is in one of the language's operator tables
16
+ * punctuation a mark the grammar has that no operator table claims
17
+ *
18
+ * A word added to `RESERVED_WORDS`, a function added to the manifest and a mark
19
+ * added to `PUNCTUATORS` are each painted the day they lex, without this file
20
+ * being edited.
21
+ *
22
+ * ## Why `reserved` is a question and not a comparison
23
+ *
24
+ * A token's kind is its own text for a keyword and for a punctuation mark, which
25
+ * is what lets a parser read `token.kind === 'if'`. A consuming platform read
26
+ * that as "a reserved word is a token whose kind equals its text", which is true
27
+ * and is folklore: it is nowhere in the token vocabulary, it silently takes in
28
+ * every punctuation mark as well, and it would stop being true the first time a
29
+ * kind and a spelling came apart. `kindOf` answers the question instead, from
30
+ * the same table the lexer classifies with.
31
+ */
32
+ import { PUNCTUATORS, RESERVED_WORDS } from '../core/index.js';
33
+ import {
34
+ ARITHMETIC_OPERATORS,
35
+ ASSIGNMENT_OPERATORS,
36
+ COMPARISON_OPERATORS,
37
+ EQUALITY_OPERATORS,
38
+ isLibraryName,
39
+ isNamespace,
40
+ } from '../core/index.js';
41
+ import type { Token, TokenKind } from '../core/index.js';
42
+
43
+ /**
44
+ * What a span of source is, for the purpose of giving it a colour.
45
+ *
46
+ * Eleven kinds, and the set is closed: a host writes eleven theme rules once and
47
+ * never has to add a twelfth, because a new word in the language arrives as one
48
+ * of these rather than as a kind nobody has a colour for.
49
+ *
50
+ * `whitespace` and `unknown` exist because every character of the file is
51
+ * covered exactly once (see `scan.ts`), so the spaces between tokens have to be
52
+ * something. `unknown` is source the lexer took no token from and that is not a
53
+ * space or a comment: a character the language does not have, a region somebody
54
+ * meant as a block comment, or a line continuation backslash. It does not mean
55
+ * "wrong": `diagnose` says what is wrong, and a highlighter that had a second
56
+ * opinion about it would be a second opinion about the language.
57
+ */
58
+ export type HighlightKind =
59
+ | 'keyword'
60
+ | 'builtin'
61
+ | 'name'
62
+ | 'number'
63
+ | 'string'
64
+ | 'color'
65
+ | 'comment'
66
+ | 'operator'
67
+ | 'punctuation'
68
+ | 'whitespace'
69
+ | 'unknown';
70
+
71
+ const RESERVED: ReadonlySet<string> = new Set<string>(RESERVED_WORDS);
72
+
73
+ /**
74
+ * The marks that compute something, as against the marks that group and
75
+ * separate.
76
+ *
77
+ * Built from the language's own operator tables rather than by dividing the
78
+ * punctuation list by hand, so that an operator added to the language is painted
79
+ * as one. The tables of words, `and` and `or` and `not`, are reserved words and
80
+ * are painted as keywords, which is what they are to the lexer.
81
+ *
82
+ * What is left over is punctuation: the brackets, the comma, the dot, and the
83
+ * two marks of the ternary. They group and separate rather than compute, and a
84
+ * theme that wants them dimmer than the arithmetic can have that.
85
+ */
86
+ const OPERATORS: ReadonlySet<string> = new Set<string>([
87
+ ...ARITHMETIC_OPERATORS,
88
+ ...COMPARISON_OPERATORS,
89
+ ...EQUALITY_OPERATORS,
90
+ ...ASSIGNMENT_OPERATORS,
91
+ ]);
92
+
93
+ const PUNCTUATION: ReadonlySet<string> = new Set<string>(PUNCTUATORS);
94
+
95
+ /** Whether a token's kind is a reserved word of language.md 3.4. */
96
+ export function isReserved(kind: TokenKind): boolean {
97
+ return RESERVED.has(kind);
98
+ }
99
+
100
+ /**
101
+ * Whether a name is one the standard library already has.
102
+ *
103
+ * The manifest is the same index the checker resolves against and the same one
104
+ * the example check reads its globals from, so a function added to the library
105
+ * is painted as a built-in on the day it is added. A namespace is included
106
+ * because `draw` on its own is not a value a script can hold: it is half of a
107
+ * dotted name, and `dotted` below finishes the question for the other half.
108
+ */
109
+ function isBuiltin(name: string): boolean {
110
+ return isLibraryName(name) || isNamespace(name);
111
+ }
112
+
113
+ /**
114
+ * The member half of a namespaced name, which is only a built-in in company.
115
+ *
116
+ * `box` is an ordinary name, and `draw.box` is a library entry. The manifest is
117
+ * asked about the dotted spelling, so nothing here decides what a namespace
118
+ * holds: `language.md` 15.2 and the manifest do.
119
+ */
120
+ function dotted(before: readonly Token[], name: string): boolean {
121
+ const dot = before[before.length - 1];
122
+ const namespace = before[before.length - 2];
123
+ if (dot?.kind !== '.' || namespace?.kind !== 'identifier') return false;
124
+ return isNamespace(namespace.text) && isLibraryName(`${namespace.text}.${name}`);
125
+ }
126
+
127
+ /**
128
+ * The kind a token is painted as, given the tokens before it.
129
+ *
130
+ * The tokens before it are needed for exactly one question, the dotted name
131
+ * above. Everything else is decided by the token alone.
132
+ */
133
+ export function kindOf(token: Token, before: readonly Token[]): HighlightKind {
134
+ switch (token.kind) {
135
+ case 'numberLiteral':
136
+ return 'number';
137
+ case 'stringLiteral':
138
+ return 'string';
139
+ case 'hexColor':
140
+ // The language's own spelling of the type is `color`, so that is the kind
141
+ // a host matches on, whatever the prose around it calls the thing.
142
+ return 'color';
143
+ case 'identifier':
144
+ return isBuiltin(token.text) || dotted(before, token.text) ? 'builtin' : 'name';
145
+ case 'newline':
146
+ case 'indent':
147
+ case 'dedent':
148
+ case 'endOfFile':
149
+ // Layout is the file's shape rather than something to read, and an indent
150
+ // token's span is the leading spaces of its line, which are spaces.
151
+ return 'whitespace';
152
+ default:
153
+ if (isReserved(token.kind)) return 'keyword';
154
+ if (OPERATORS.has(token.kind)) return 'operator';
155
+ return PUNCTUATION.has(token.kind) ? 'punctuation' : 'unknown';
156
+ }
157
+ }
@@ -0,0 +1,189 @@
1
+ /**
2
+ * The canonical layout of a file, line by line.
3
+ *
4
+ * `language.md` 3.13 states the rules; this applies them. The two halves are
5
+ * separate because the specification is what another implementation writes a
6
+ * formatter from, and a rule that lived only here would be a rule only this
7
+ * formatter has.
8
+ *
9
+ * ## What is preserved, and why that is the safe direction
10
+ *
11
+ * The writer's line breaks are kept. A formatter that joined a call spanning
12
+ * four lines into one would be correct and unusable: it would take the layout
13
+ * somebody chose to make a long argument list readable and hand back a line
14
+ * nobody can read. So this decides indentation and spacing, which have one right
15
+ * answer, and leaves the choice of where to break a long statement to the person
16
+ * writing it, which does not.
17
+ *
18
+ * It is also the safe direction. A break that was there before is a break the
19
+ * lexer already accepted, so preserving them cannot turn a legal file into an
20
+ * illegal one, while inventing or removing one can: a statement continues onto
21
+ * the next line only under the three conditions of 3.11, and a formatter that
22
+ * moved a break would have to know them, which is the language's rule
23
+ * implemented twice.
24
+ *
25
+ * ## Comments
26
+ *
27
+ * A comment on a line of its own takes the indentation of the next line that
28
+ * carries a token, so a commented-out statement sits with the block it belongs
29
+ * to. This is safe for a reason worth stating: such a line produces no token at
30
+ * all, so its indentation says nothing about block structure and cannot open or
31
+ * close one (3.10). A comment after code stays where it is, two spaces clear of
32
+ * the code.
33
+ */
34
+ import type { SourceFile, Token } from '../core/index.js';
35
+ import type { Highlight } from './scan.js';
36
+ import { spaceBetween } from './spacing.js';
37
+ import type { Shapes } from './spacing.js';
38
+
39
+ /** One level of block, `language.md` 3.13. */
40
+ const INDENT = ' ';
41
+
42
+ /**
43
+ * What a continuation line is indented past the line that began its statement.
44
+ *
45
+ * Eight rather than four so that a continuation can never be read as the body of
46
+ * the header above it. `if crossUp(fast,` with its second half indented four
47
+ * would sit exactly where the block's first statement sits, which is legal and
48
+ * unreadable.
49
+ */
50
+ const CONTINUATION = ' ';
51
+
52
+ /** Two, so a trailing comment is visibly not part of the code it follows. */
53
+ const BEFORE_COMMENT = ' ';
54
+
55
+ const BACKSLASH = '\\';
56
+
57
+ interface CodeLine {
58
+ readonly tokens: Token[];
59
+ readonly indent: string;
60
+ }
61
+
62
+ /**
63
+ * The code lines of a file, each with the indentation the canonical layout gives
64
+ * it.
65
+ *
66
+ * Depth comes from the lexer's own indent and dedent tokens rather than from
67
+ * counting spaces, so the blocks this prints are the blocks the compiler read. A
68
+ * line that begins a statement is indented by its depth; a line that continues
69
+ * one is indented past the line that began it.
70
+ */
71
+ function codeLines(tokens: readonly Token[]): ReadonlyMap<number, CodeLine> {
72
+ const lines = new Map<number, CodeLine>();
73
+ let depth = 0;
74
+ let starting = true;
75
+
76
+ for (const token of tokens) {
77
+ switch (token.kind) {
78
+ case 'indent':
79
+ depth += 1;
80
+ continue;
81
+ case 'dedent':
82
+ depth -= 1;
83
+ continue;
84
+ case 'newline':
85
+ starting = true;
86
+ continue;
87
+ case 'endOfFile':
88
+ continue;
89
+ default:
90
+ break;
91
+ }
92
+
93
+ let line = lines.get(token.span.line);
94
+ if (line === undefined) {
95
+ const body = INDENT.repeat(Math.max(depth, 0));
96
+ line = { tokens: [], indent: starting ? body : body + CONTINUATION };
97
+ lines.set(token.span.line, line);
98
+ }
99
+ line.tokens.push(token);
100
+ starting = false;
101
+ }
102
+
103
+ return lines;
104
+ }
105
+
106
+ /** One code line as text: its indentation, then its tokens with their spacing. */
107
+ function printCode(file: SourceFile, line: CodeLine, shapes: Shapes): string {
108
+ let text = line.indent;
109
+ for (const [at, token] of line.tokens.entries()) {
110
+ const before = line.tokens[at - 1];
111
+ if (before !== undefined && spaceBetween(before, token, shapes)) text += ' ';
112
+ text += file.text.slice(token.span.offset, token.span.offset + token.span.length);
113
+ }
114
+ return text;
115
+ }
116
+
117
+ /** The indentation of the next line that carries a token, for a comment to take. */
118
+ function indentBelow(lines: ReadonlyMap<number, CodeLine>, from: number, last: number): string {
119
+ for (let line = from + 1; line <= last; line += 1) {
120
+ const found = lines.get(line);
121
+ if (found !== undefined) return found.indent;
122
+ }
123
+ return '';
124
+ }
125
+
126
+ /**
127
+ * Blank lines, as the canonical layout has them: never two in a row, never
128
+ * before the first line, and one line ending at the end of the file.
129
+ *
130
+ * A blank line between two paragraphs of a script is the writer's, and it is
131
+ * kept. A run of four is a file that has been edited for a year, and one of them
132
+ * says everything the four said.
133
+ */
134
+ function joinLines(printed: readonly (string | undefined)[]): string {
135
+ const kept: string[] = [];
136
+ for (const line of printed) {
137
+ if (line !== undefined) {
138
+ kept.push(line);
139
+ continue;
140
+ }
141
+ if (kept.length === 0 || kept[kept.length - 1] === '') continue;
142
+ kept.push('');
143
+ }
144
+ while (kept.length > 0 && kept[kept.length - 1] === '') kept.pop();
145
+ return kept.length === 0 ? '' : `${kept.join('\n')}\n`;
146
+ }
147
+
148
+ /**
149
+ * The whole file, laid out.
150
+ *
151
+ * The pieces are the covering scan, which is where the comments come from and
152
+ * where a line continuation backslash is found. A backslash is kept wherever it
153
+ * was written rather than worked out again: whether a statement needs one is the
154
+ * lexer's rule, and the file in front of this one has already been through the
155
+ * lexer with it in place.
156
+ */
157
+ export function layOut(
158
+ file: SourceFile,
159
+ tokens: readonly Token[],
160
+ pieces: readonly Highlight[],
161
+ shapes: Shapes,
162
+ ): string {
163
+ const lines = codeLines(tokens);
164
+ const comments = new Map<number, string>();
165
+ const continued = new Set<number>();
166
+
167
+ for (const piece of pieces) {
168
+ if (piece.kind === 'comment') comments.set(piece.span.line, piece.text.trimEnd());
169
+ else if (piece.kind === 'unknown' && piece.text === BACKSLASH) continued.add(piece.span.line);
170
+ }
171
+
172
+ const printed: (string | undefined)[] = [];
173
+ for (let line = 1; line <= file.lineCount; line += 1) {
174
+ const code = lines.get(line);
175
+ const comment = comments.get(line);
176
+
177
+ if (code === undefined) {
178
+ printed.push(comment === undefined ? undefined : indentBelow(lines, line, file.lineCount) + comment);
179
+ continue;
180
+ }
181
+
182
+ let text = printCode(file, code, shapes);
183
+ if (continued.has(line)) text += ` ${BACKSLASH}`;
184
+ if (comment !== undefined) text += BEFORE_COMMENT + comment;
185
+ printed.push(text);
186
+ }
187
+
188
+ return joinLines(printed);
189
+ }