@rocicorp/zero 0.26.0-canary.7 → 0.26.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 (276) hide show
  1. package/out/ast-to-zql/src/ast-to-zql.d.ts.map +1 -1
  2. package/out/ast-to-zql/src/ast-to-zql.js +16 -27
  3. package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
  4. package/out/otel/src/log-options.d.ts +2 -2
  5. package/out/replicache/src/bg-interval.d.ts.map +1 -1
  6. package/out/replicache/src/bg-interval.js +3 -0
  7. package/out/replicache/src/bg-interval.js.map +1 -1
  8. package/out/shared/src/arrays.js +1 -1
  9. package/out/shared/src/arrays.js.map +1 -1
  10. package/out/shared/src/browser-env.js +0 -4
  11. package/out/shared/src/browser-env.js.map +1 -1
  12. package/out/shared/src/btree-set.js +4 -1
  13. package/out/shared/src/btree-set.js.map +1 -1
  14. package/out/shared/src/options.js +1 -1
  15. package/out/shared/src/options.js.map +1 -1
  16. package/out/shared/src/queue.js +1 -1
  17. package/out/shared/src/queue.js.map +1 -1
  18. package/out/z2s/src/compiler.d.ts.map +1 -1
  19. package/out/z2s/src/compiler.js +13 -11
  20. package/out/z2s/src/compiler.js.map +1 -1
  21. package/out/zero/package.json.js +1 -1
  22. package/out/zero/src/react.js +1 -3
  23. package/out/zero/src/react.js.map +1 -1
  24. package/out/zero-cache/src/auth/read-authorizer.js +0 -7
  25. package/out/zero-cache/src/auth/read-authorizer.js.map +1 -1
  26. package/out/zero-cache/src/config/network.d.ts +3 -2
  27. package/out/zero-cache/src/config/network.d.ts.map +1 -1
  28. package/out/zero-cache/src/config/network.js +9 -2
  29. package/out/zero-cache/src/config/network.js.map +1 -1
  30. package/out/zero-cache/src/config/server-context.d.ts +16 -0
  31. package/out/zero-cache/src/config/server-context.d.ts.map +1 -0
  32. package/out/zero-cache/src/config/server-context.js +32 -0
  33. package/out/zero-cache/src/config/server-context.js.map +1 -0
  34. package/out/zero-cache/src/config/zero-config.d.ts +3 -3
  35. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  36. package/out/zero-cache/src/config/zero-config.js +2 -6
  37. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  38. package/out/zero-cache/src/db/migration.d.ts.map +1 -1
  39. package/out/zero-cache/src/db/migration.js +40 -51
  40. package/out/zero-cache/src/db/migration.js.map +1 -1
  41. package/out/zero-cache/src/db/run-transaction.d.ts +17 -0
  42. package/out/zero-cache/src/db/run-transaction.d.ts.map +1 -0
  43. package/out/zero-cache/src/db/run-transaction.js +24 -0
  44. package/out/zero-cache/src/db/run-transaction.js.map +1 -0
  45. package/out/zero-cache/src/db/transaction-pool.d.ts.map +1 -1
  46. package/out/zero-cache/src/db/transaction-pool.js +3 -3
  47. package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
  48. package/out/zero-cache/src/scripts/decommission.d.ts +1 -1
  49. package/out/zero-cache/src/scripts/deploy-permissions.js +2 -1
  50. package/out/zero-cache/src/scripts/deploy-permissions.js.map +1 -1
  51. package/out/zero-cache/src/scripts/permissions.d.ts +1 -1
  52. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  53. package/out/zero-cache/src/server/change-streamer.js +6 -2
  54. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  55. package/out/zero-cache/src/server/main.js +1 -1
  56. package/out/zero-cache/src/server/main.js.map +1 -1
  57. package/out/zero-cache/src/server/runner/run-worker.d.ts.map +1 -1
  58. package/out/zero-cache/src/server/runner/run-worker.js +7 -3
  59. package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
  60. package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts +1 -1
  61. package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts.map +1 -1
  62. package/out/zero-cache/src/services/change-source/common/backfill-manager.js +11 -9
  63. package/out/zero-cache/src/services/change-source/common/backfill-manager.js.map +1 -1
  64. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts.map +1 -1
  65. package/out/zero-cache/src/services/change-source/common/replica-schema.js +11 -0
  66. package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
  67. package/out/zero-cache/src/services/change-source/custom/change-source.d.ts +5 -2
  68. package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +1 -1
  69. package/out/zero-cache/src/services/change-source/custom/change-source.js +6 -6
  70. package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
  71. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +6 -4
  72. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
  73. package/out/zero-cache/src/services/change-source/pg/change-source.js +148 -54
  74. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  75. package/out/zero-cache/src/services/change-source/pg/decommission.d.ts.map +1 -1
  76. package/out/zero-cache/src/services/change-source/pg/decommission.js +2 -1
  77. package/out/zero-cache/src/services/change-source/pg/decommission.js.map +1 -1
  78. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +4 -1
  79. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
  80. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +35 -10
  81. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  82. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +1 -1
  83. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js.map +1 -1
  84. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
  85. package/out/zero-cache/src/services/change-source/pg/schema/init.js +10 -0
  86. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  87. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +6 -3
  88. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
  89. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +19 -10
  90. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  91. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts +1 -0
  92. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts.map +1 -1
  93. package/out/zero-cache/src/services/change-source/protocol/current/data.js +4 -2
  94. package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
  95. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +3 -0
  96. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
  97. package/out/zero-cache/src/services/change-source/protocol/current/status.d.ts +6 -4
  98. package/out/zero-cache/src/services/change-source/protocol/current/status.d.ts.map +1 -1
  99. package/out/zero-cache/src/services/change-source/protocol/current/status.js.map +1 -1
  100. package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts +2 -2
  101. package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts.map +1 -1
  102. package/out/zero-cache/src/services/change-streamer/backup-monitor.js +30 -12
  103. package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -1
  104. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +23 -3
  105. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  106. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +1 -0
  107. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
  108. package/out/zero-cache/src/services/change-streamer/forwarder.js +1 -1
  109. package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
  110. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +1 -1
  111. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts.map +1 -1
  112. package/out/zero-cache/src/services/change-streamer/schema/tables.js +12 -4
  113. package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
  114. package/out/zero-cache/src/services/change-streamer/storer.d.ts +11 -2
  115. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
  116. package/out/zero-cache/src/services/change-streamer/storer.js +80 -42
  117. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  118. package/out/zero-cache/src/services/litestream/commands.d.ts +1 -1
  119. package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
  120. package/out/zero-cache/src/services/litestream/commands.js +2 -1
  121. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  122. package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
  123. package/out/zero-cache/src/services/mutagen/mutagen.js +22 -17
  124. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  125. package/out/zero-cache/src/services/replicator/schema/replication-state.d.ts +10 -1
  126. package/out/zero-cache/src/services/replicator/schema/replication-state.d.ts.map +1 -1
  127. package/out/zero-cache/src/services/replicator/schema/replication-state.js +49 -9
  128. package/out/zero-cache/src/services/replicator/schema/replication-state.js.map +1 -1
  129. package/out/zero-cache/src/services/running-state.d.ts +1 -0
  130. package/out/zero-cache/src/services/running-state.d.ts.map +1 -1
  131. package/out/zero-cache/src/services/running-state.js +3 -0
  132. package/out/zero-cache/src/services/running-state.js.map +1 -1
  133. package/out/zero-cache/src/services/view-syncer/cvr-purger.d.ts.map +1 -1
  134. package/out/zero-cache/src/services/view-syncer/cvr-purger.js +32 -28
  135. package/out/zero-cache/src/services/view-syncer/cvr-purger.js.map +1 -1
  136. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
  137. package/out/zero-cache/src/services/view-syncer/cvr-store.js +329 -155
  138. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  139. package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
  140. package/out/zero-cache/src/services/view-syncer/cvr.js +387 -345
  141. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  142. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  143. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +68 -16
  144. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  145. package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts.map +1 -1
  146. package/out/zero-cache/src/services/view-syncer/row-record-cache.js +13 -8
  147. package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
  148. package/out/zero-cache/src/services/view-syncer/tracer.d.ts +2 -0
  149. package/out/zero-cache/src/services/view-syncer/tracer.d.ts.map +1 -0
  150. package/out/zero-cache/src/services/view-syncer/tracer.js +7 -0
  151. package/out/zero-cache/src/services/view-syncer/tracer.js.map +1 -0
  152. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  153. package/out/zero-cache/src/services/view-syncer/view-syncer.js +58 -43
  154. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  155. package/out/zero-cache/src/types/pg.js +0 -4
  156. package/out/zero-cache/src/types/pg.js.map +1 -1
  157. package/out/zero-cache/src/types/streams.d.ts +3 -1
  158. package/out/zero-cache/src/types/streams.d.ts.map +1 -1
  159. package/out/zero-cache/src/types/streams.js +1 -1
  160. package/out/zero-cache/src/types/streams.js.map +1 -1
  161. package/out/zero-cache/src/types/subscription.d.ts +7 -1
  162. package/out/zero-cache/src/types/subscription.d.ts.map +1 -1
  163. package/out/zero-cache/src/types/subscription.js +8 -2
  164. package/out/zero-cache/src/types/subscription.js.map +1 -1
  165. package/out/zero-client/src/client/options.d.ts +7 -7
  166. package/out/zero-client/src/client/options.d.ts.map +1 -1
  167. package/out/zero-client/src/client/options.js.map +1 -1
  168. package/out/zero-client/src/client/query-manager.js +1 -1
  169. package/out/zero-client/src/client/query-manager.js.map +1 -1
  170. package/out/zero-client/src/client/version.js +1 -1
  171. package/out/zero-client/src/client/zero-poke-handler.d.ts +5 -5
  172. package/out/zero-client/src/client/zero-poke-handler.d.ts.map +1 -1
  173. package/out/zero-client/src/client/zero-poke-handler.js +15 -17
  174. package/out/zero-client/src/client/zero-poke-handler.js.map +1 -1
  175. package/out/zero-client/src/client/zero.d.ts +6 -2
  176. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  177. package/out/zero-client/src/client/zero.js +44 -8
  178. package/out/zero-client/src/client/zero.js.map +1 -1
  179. package/out/zero-client/src/mod.d.ts +1 -1
  180. package/out/zero-client/src/mod.d.ts.map +1 -1
  181. package/out/zero-protocol/src/ast.d.ts +2 -9
  182. package/out/zero-protocol/src/ast.d.ts.map +1 -1
  183. package/out/zero-protocol/src/ast.js +15 -32
  184. package/out/zero-protocol/src/ast.js.map +1 -1
  185. package/out/zero-protocol/src/protocol-version.d.ts +1 -1
  186. package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
  187. package/out/zero-protocol/src/protocol-version.js +5 -2
  188. package/out/zero-protocol/src/protocol-version.js.map +1 -1
  189. package/out/zero-react/src/mod.d.ts +0 -2
  190. package/out/zero-react/src/mod.d.ts.map +1 -1
  191. package/out/zero-react/src/use-query.d.ts +6 -6
  192. package/out/zero-react/src/use-query.d.ts.map +1 -1
  193. package/out/zero-react/src/use-query.js +9 -2
  194. package/out/zero-react/src/use-query.js.map +1 -1
  195. package/out/zero-react/src/zero-provider.d.ts +5 -5
  196. package/out/zero-react/src/zero-provider.d.ts.map +1 -1
  197. package/out/zero-react/src/zero-provider.js.map +1 -1
  198. package/out/zero-solid/src/solid-view.d.ts +0 -42
  199. package/out/zero-solid/src/solid-view.d.ts.map +1 -1
  200. package/out/zero-solid/src/solid-view.js +1 -1
  201. package/out/zero-solid/src/solid-view.js.map +1 -1
  202. package/out/zero-solid/src/use-query.d.ts +4 -4
  203. package/out/zero-solid/src/use-query.d.ts.map +1 -1
  204. package/out/zero-solid/src/use-query.js.map +1 -1
  205. package/out/zero-solid/src/use-zero.d.ts +5 -5
  206. package/out/zero-solid/src/use-zero.d.ts.map +1 -1
  207. package/out/zero-solid/src/use-zero.js.map +1 -1
  208. package/out/zero-types/src/default-types.d.ts +2 -0
  209. package/out/zero-types/src/default-types.d.ts.map +1 -1
  210. package/out/zql/src/builder/builder.d.ts.map +1 -1
  211. package/out/zql/src/builder/builder.js +6 -48
  212. package/out/zql/src/builder/builder.js.map +1 -1
  213. package/out/zql/src/builder/filter.d.ts.map +1 -1
  214. package/out/zql/src/builder/filter.js +0 -1
  215. package/out/zql/src/builder/filter.js.map +1 -1
  216. package/out/zql/src/ivm/array-view.d.ts.map +1 -1
  217. package/out/zql/src/ivm/array-view.js +6 -57
  218. package/out/zql/src/ivm/array-view.js.map +1 -1
  219. package/out/zql/src/ivm/view-apply-change.d.ts +3 -50
  220. package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
  221. package/out/zql/src/ivm/view-apply-change.js +105 -358
  222. package/out/zql/src/ivm/view-apply-change.js.map +1 -1
  223. package/out/zql/src/mutate/mutator-registry.d.ts +3 -3
  224. package/out/zql/src/mutate/mutator-registry.d.ts.map +1 -1
  225. package/out/zql/src/mutate/mutator-registry.js.map +1 -1
  226. package/out/zql/src/planner/planner-builder.d.ts.map +1 -1
  227. package/out/zql/src/planner/planner-builder.js +1 -2
  228. package/out/zql/src/planner/planner-builder.js.map +1 -1
  229. package/out/zql/src/query/complete-ordering.js +0 -6
  230. package/out/zql/src/query/complete-ordering.js.map +1 -1
  231. package/out/zql/src/query/expression.d.ts +2 -19
  232. package/out/zql/src/query/expression.d.ts.map +1 -1
  233. package/out/zql/src/query/expression.js +6 -50
  234. package/out/zql/src/query/expression.js.map +1 -1
  235. package/out/zql/src/query/query-delegate-base.js +3 -1
  236. package/out/zql/src/query/query-delegate-base.js.map +1 -1
  237. package/out/zql/src/query/query-impl.d.ts.map +1 -1
  238. package/out/zql/src/query/query-impl.js +8 -12
  239. package/out/zql/src/query/query-impl.js.map +1 -1
  240. package/out/zql/src/query/query-internals.js.map +1 -1
  241. package/out/zql/src/query/query-registry.d.ts +3 -3
  242. package/out/zql/src/query/query-registry.d.ts.map +1 -1
  243. package/out/zql/src/query/query-registry.js.map +1 -1
  244. package/out/zql/src/query/query.d.ts +28 -5
  245. package/out/zql/src/query/query.d.ts.map +1 -1
  246. package/out/zqlite/src/query-builder.d.ts +0 -2
  247. package/out/zqlite/src/query-builder.d.ts.map +1 -1
  248. package/out/zqlite/src/query-builder.js.map +1 -1
  249. package/out/zqlite/src/resolve-scalar-subqueries.d.ts +10 -2
  250. package/out/zqlite/src/resolve-scalar-subqueries.d.ts.map +1 -1
  251. package/out/zqlite/src/resolve-scalar-subqueries.js +41 -9
  252. package/out/zqlite/src/resolve-scalar-subqueries.js.map +1 -1
  253. package/out/zqlite/src/sqlite-cost-model.d.ts.map +1 -1
  254. package/out/zqlite/src/sqlite-cost-model.js +0 -1
  255. package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
  256. package/package.json +3 -5
  257. package/out/zero-cache/src/services/change-source/custom/sync-schema.d.ts +0 -4
  258. package/out/zero-cache/src/services/change-source/custom/sync-schema.d.ts.map +0 -1
  259. package/out/zero-cache/src/services/change-source/custom/sync-schema.js +0 -14
  260. package/out/zero-cache/src/services/change-source/custom/sync-schema.js.map +0 -1
  261. package/out/zero-cache/src/services/change-source/pg/sync-schema.d.ts +0 -5
  262. package/out/zero-cache/src/services/change-source/pg/sync-schema.d.ts.map +0 -1
  263. package/out/zero-cache/src/services/change-source/pg/sync-schema.js +0 -14
  264. package/out/zero-cache/src/services/change-source/pg/sync-schema.js.map +0 -1
  265. package/out/zero-react/src/paging-reducer.d.ts +0 -61
  266. package/out/zero-react/src/paging-reducer.d.ts.map +0 -1
  267. package/out/zero-react/src/paging-reducer.js +0 -77
  268. package/out/zero-react/src/paging-reducer.js.map +0 -1
  269. package/out/zero-react/src/use-rows.d.ts +0 -39
  270. package/out/zero-react/src/use-rows.d.ts.map +0 -1
  271. package/out/zero-react/src/use-rows.js +0 -130
  272. package/out/zero-react/src/use-rows.js.map +0 -1
  273. package/out/zero-react/src/use-zero-virtualizer.d.ts +0 -122
  274. package/out/zero-react/src/use-zero-virtualizer.d.ts.map +0 -1
  275. package/out/zero-react/src/use-zero-virtualizer.js +0 -342
  276. package/out/zero-react/src/use-zero-virtualizer.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ast-to-zql.d.ts","sourceRoot":"","sources":["../../../../ast-to-zql/src/ast-to-zql.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,GAAG,EAYJ,MAAM,gCAAgC,CAAC;AAGxC;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAyCzC"}
1
+ {"version":3,"file":"ast-to-zql.d.ts","sourceRoot":"","sources":["../../../../ast-to-zql/src/ast-to-zql.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,GAAG,EAWJ,MAAM,gCAAgC,CAAC;AAGxC;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAyCzC"}
@@ -39,8 +39,6 @@ function transformCondition(condition, prefix, args) {
39
39
  return transformLogicalCondition(condition, prefix, args);
40
40
  case "correlatedSubquery":
41
41
  return transformExistsCondition(condition, prefix, args);
42
- case "scalarSubquery":
43
- return transformScalarSubqueryCondition(condition, prefix, args);
44
42
  default:
45
43
  unreachable();
46
44
  }
@@ -79,53 +77,44 @@ function transformExistsCondition(condition, prefix, args) {
79
77
  const relationship = extractRelationshipName(related);
80
78
  const nextSubquery = getNextExistsSubquery(related);
81
79
  const hasSubQueryProps = nextSubquery.where || nextSubquery.related && nextSubquery.related.length > 0 || nextSubquery.orderBy || nextSubquery.limit;
80
+ const optionParts = [];
81
+ if (condition.flip !== void 0) {
82
+ optionParts.push(`flip: ${condition.flip}`);
83
+ }
84
+ if (condition.scalar !== void 0) {
85
+ optionParts.push(`scalar: ${condition.scalar}`);
86
+ }
87
+ const optionsStr = optionParts.length > 0 ? `, {${optionParts.join(", ")}}` : "";
82
88
  if (op === "EXISTS") {
83
- const flipped = condition.flip ? ", {flip: true}" : "";
84
89
  if (!hasSubQueryProps) {
85
90
  if (prefix === ".where") {
86
- return `.whereExists('${relationship}'${flipped})`;
91
+ return `.whereExists('${relationship}'${optionsStr})`;
87
92
  }
88
93
  args.add("exists");
89
- return `exists('${relationship}'${flipped})`;
94
+ return `exists('${relationship}'${optionsStr})`;
90
95
  }
91
96
  if (prefix === ".where") {
92
- return `.whereExists('${relationship}', q => q${astToZQL(nextSubquery)}${flipped})`;
97
+ return `.whereExists('${relationship}', q => q${astToZQL(nextSubquery)}${optionsStr})`;
93
98
  }
94
99
  args.add("exists");
95
- return `exists('${relationship}', q => q${astToZQL(nextSubquery)}${flipped})`;
100
+ return `exists('${relationship}', q => q${astToZQL(nextSubquery)}${optionsStr})`;
96
101
  }
97
102
  if (hasSubQueryProps) {
98
103
  if (prefix === ".where") {
99
104
  return `.where(({exists, not}) => not(exists('${relationship}', q => q${astToZQL(
100
105
  nextSubquery
101
- )})))`;
106
+ )}${optionsStr})))`;
102
107
  }
103
108
  args.add("not");
104
109
  args.add("exists");
105
- return `not(exists('${relationship}', q => q${astToZQL(nextSubquery)}))`;
110
+ return `not(exists('${relationship}', q => q${astToZQL(nextSubquery)}${optionsStr}))`;
106
111
  }
107
112
  if (prefix === ".where") {
108
- return `.where(({exists, not}) => not(exists('${relationship}')))`;
113
+ return `.where(({exists, not}) => not(exists('${relationship}'${optionsStr})))`;
109
114
  }
110
115
  args.add("not");
111
116
  args.add("exists");
112
- return `not(exists('${relationship}')))`;
113
- }
114
- function transformScalarSubqueryCondition(condition, prefix, args) {
115
- const subqueryCode = astToZQL(condition.subquery);
116
- const scalarExpr = `scalar(q => q${subqueryCode}, '${condition.childField}')`;
117
- let cmpExpr;
118
- if (condition.op === "=") {
119
- cmpExpr = `cmp('${condition.parentField}', ${scalarExpr})`;
120
- } else {
121
- cmpExpr = `cmp('${condition.parentField}', '${condition.op}', ${scalarExpr})`;
122
- }
123
- if (prefix === ".where") {
124
- return `.where(({cmp, scalar}) => ${cmpExpr})`;
125
- }
126
- args.add("cmp");
127
- args.add("scalar");
128
- return cmpExpr;
117
+ return `not(exists('${relationship}'${optionsStr})))`;
129
118
  }
130
119
  function getNextExistsSubquery(related) {
131
120
  if (related.subquery.where?.type === "correlatedSubquery" && related.subquery.where.related.subquery.alias?.includes(
@@ -1 +1 @@
1
- {"version":3,"file":"ast-to-zql.js","sources":["../../../../ast-to-zql/src/ast-to-zql.ts"],"sourcesContent":["import {unreachable} from '../../shared/src/asserts.ts';\nimport {must} from '../../shared/src/must.ts';\nimport type {\n AST,\n Condition,\n Conjunction,\n CorrelatedSubquery,\n CorrelatedSubqueryCondition,\n Disjunction,\n LiteralReference,\n Ordering,\n Parameter,\n ScalarSubqueryCondition,\n SimpleCondition,\n ValuePosition,\n} from '../../zero-protocol/src/ast.ts';\nimport {SUBQ_PREFIX} from '../../zero-protocol/src/ast.ts';\n\n/**\n * Converts an AST to the equivalent query builder code.\n * This is useful for debugging and understanding queries.\n *\n * @example\n * ```\n * const ast = query.issue.where('id', '=', 123)[astSymbol];\n * console.log(astToZQL(ast)); // outputs: .where('id', '=', 123)\n * ```\n */\nexport function astToZQL(ast: AST): string {\n let code = '';\n\n // Handle where conditions\n if (ast.where) {\n code += transformCondition(ast.where, '.where', new Set());\n }\n\n // Handle related subqueries\n if (ast.related && ast.related.length > 0) {\n for (const related of ast.related) {\n if (related.hidden) {\n const nestedRelated = related.subquery.related?.[0];\n if (nestedRelated) {\n code += transformRelated(nestedRelated);\n }\n } else {\n code += transformRelated(related);\n }\n }\n }\n\n // Handle orderBy\n if (ast.orderBy && ast.orderBy.length > 0) {\n code += transformOrder(ast.orderBy);\n }\n\n // Handle limit\n if (ast.limit !== undefined) {\n code += `.limit(${ast.limit})`;\n }\n\n // Handle start\n if (ast.start) {\n const {row, exclusive} = ast.start;\n code += `.start(${JSON.stringify(row)}${\n exclusive ? '' : ', { inclusive: true }'\n })`;\n }\n\n return code;\n}\n\ntype Args = Set<string>;\n\ntype Prefix = '.where' | 'cmp';\n\nfunction transformCondition(\n condition: Condition,\n prefix: Prefix,\n args: Args,\n): string {\n switch (condition.type) {\n case 'simple':\n return transformSimpleCondition(condition, prefix);\n case 'and':\n case 'or':\n return transformLogicalCondition(condition, prefix, args);\n case 'correlatedSubquery':\n return transformExistsCondition(condition, prefix, args);\n case 'scalarSubquery':\n return transformScalarSubqueryCondition(condition, prefix, args);\n default:\n unreachable(condition);\n }\n}\n\nfunction transformSimpleCondition(\n condition: SimpleCondition,\n prefix: Prefix,\n): string {\n const {left, op, right} = condition;\n\n const leftCode = transformValuePosition(left);\n const rightCode = transformValuePosition(right);\n\n // Handle the shorthand form for equals\n if (op === '=') {\n return `${prefix}(${leftCode}, ${rightCode})`;\n }\n\n return `${prefix}(${leftCode}, '${op}', ${rightCode})`;\n}\n\nfunction transformLogicalCondition(\n condition: Conjunction | Disjunction,\n prefix: Prefix,\n args: Args,\n): string {\n const {type, conditions} = condition;\n\n // For single condition, no need for logical operator\n if (conditions.length === 1) {\n return transformCondition(conditions[0], prefix, args);\n }\n\n // Generate multiple where calls for top-level AND conditions\n if (type === 'and') {\n const parts = conditions.map(c => transformCondition(c, prefix, args));\n // Simply concatenate the where conditions\n if (prefix === '.where') {\n return parts.join('');\n }\n args.add('and');\n return 'and(' + parts.join(', ') + ')';\n }\n\n args = new Set<string>();\n\n // Handle nested conditions with a callback for OR conditions and nested ANDs/ORs\n const conditionsCode = conditions\n .map(c => transformCondition(c, 'cmp', args))\n .join(', ');\n\n args.add('cmp');\n args.add(type);\n const argsCode = [...args].sort().join(', ');\n\n return `.where(({${argsCode}}) => ${type}(${conditionsCode}))`;\n}\n\nfunction transformExistsCondition(\n condition: CorrelatedSubqueryCondition,\n prefix: '.where' | 'cmp',\n args: Set<string>,\n): string {\n const {related, op} = condition;\n const relationship = extractRelationshipName(related);\n\n const nextSubquery = getNextExistsSubquery(related);\n\n // Check if subquery has additional properties\n const hasSubQueryProps =\n nextSubquery.where ||\n (nextSubquery.related && nextSubquery.related.length > 0) ||\n nextSubquery.orderBy ||\n nextSubquery.limit;\n\n if (op === 'EXISTS') {\n const flipped = condition.flip ? ', {flip: true}' : '';\n if (!hasSubQueryProps) {\n if (prefix === '.where') {\n return `.whereExists('${relationship}'${flipped})`;\n }\n args.add('exists');\n return `exists('${relationship}'${flipped})`;\n }\n\n if (prefix === '.where') {\n return `.whereExists('${relationship}', q => q${astToZQL(nextSubquery)}${flipped})`;\n }\n prefix satisfies 'cmp';\n args.add('exists');\n return `exists('${relationship}', q => q${astToZQL(nextSubquery)}${flipped})`;\n }\n\n op satisfies 'NOT EXISTS';\n\n if (hasSubQueryProps) {\n if (prefix === '.where') {\n return `.where(({exists, not}) => not(exists('${relationship}', q => q${astToZQL(\n nextSubquery,\n )})))`;\n }\n prefix satisfies 'cmp';\n args.add('not');\n args.add('exists');\n return `not(exists('${relationship}', q => q${astToZQL(nextSubquery)}))`;\n }\n\n if (prefix === '.where') {\n return `.where(({exists, not}) => not(exists('${relationship}')))`;\n }\n args.add('not');\n args.add('exists');\n\n return `not(exists('${relationship}')))`;\n}\n\nfunction transformScalarSubqueryCondition(\n condition: ScalarSubqueryCondition,\n prefix: Prefix,\n args: Args,\n): string {\n const subqueryCode = astToZQL(condition.subquery);\n const scalarExpr = `scalar(q => q${subqueryCode}, '${condition.childField}')`;\n\n let cmpExpr: string;\n if (condition.op === '=') {\n cmpExpr = `cmp('${condition.parentField}', ${scalarExpr})`;\n } else {\n cmpExpr = `cmp('${condition.parentField}', '${condition.op}', ${scalarExpr})`;\n }\n\n if (prefix === '.where') {\n return `.where(({cmp, scalar}) => ${cmpExpr})`;\n }\n args.add('cmp');\n args.add('scalar');\n return cmpExpr;\n}\n\n// If the `exists` is applied against a junction edge, both hops will have the same alias and both hops will be exists conditions.\nfunction getNextExistsSubquery(related: CorrelatedSubquery): AST {\n if (\n related.subquery.where?.type === 'correlatedSubquery' &&\n related.subquery.where.related.subquery.alias?.includes(\n SUBQ_PREFIX + 'zhidden_',\n )\n ) {\n return getNextExistsSubquery(related.subquery.where.related);\n }\n\n return related.subquery;\n}\n\nfunction extractRelationshipName(related: CorrelatedSubquery): string {\n const alias = must(related.subquery.alias);\n return alias.startsWith(SUBQ_PREFIX)\n ? alias.substring(SUBQ_PREFIX.length)\n : alias;\n}\n\nfunction transformRelated(related: CorrelatedSubquery): string {\n const {alias} = related.subquery;\n if (!alias) return '';\n\n const relationship = alias;\n let code = `.related('${relationship}'`;\n\n // If the subquery has additional filters or configurations\n if (\n related.subquery.where ||\n (related.subquery.related && related.subquery.related.length > 0) ||\n related.subquery.orderBy ||\n related.subquery.limit\n ) {\n code += ', q => q' + astToZQL(related.subquery);\n }\n\n code += ')';\n return code;\n}\n\nfunction transformOrder(orderBy: Ordering): string {\n let code = '';\n for (const [field, direction] of orderBy) {\n code += `.orderBy('${field}', '${direction}')`;\n }\n return code;\n}\n\nfunction transformValuePosition(value: ValuePosition): string {\n switch (value.type) {\n case 'literal':\n return transformLiteral(value);\n case 'column':\n return `'${value.name}'`;\n case 'static':\n return transformParameter(value);\n default:\n unreachable(value);\n }\n}\n\nfunction transformLiteral(literal: LiteralReference): string {\n if (literal.value === null) {\n return 'null';\n }\n if (Array.isArray(literal.value)) {\n return JSON.stringify(literal.value);\n }\n if (typeof literal.value === 'string') {\n return `'${literal.value.replace(/'/g, \"\\\\'\")}'`;\n }\n return String(literal.value);\n}\n\nfunction transformParameter(param: Parameter): string {\n const fieldStr = Array.isArray(param.field)\n ? `[${param.field.map(f => `'${f}'`).join(', ')}]`\n : `'${param.field}'`;\n\n return `authParam(${fieldStr})`;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ast-to-zql.js","sources":["../../../../ast-to-zql/src/ast-to-zql.ts"],"sourcesContent":["import {unreachable} from '../../shared/src/asserts.ts';\nimport {must} from '../../shared/src/must.ts';\nimport type {\n AST,\n Condition,\n Conjunction,\n CorrelatedSubquery,\n CorrelatedSubqueryCondition,\n Disjunction,\n LiteralReference,\n Ordering,\n Parameter,\n SimpleCondition,\n ValuePosition,\n} from '../../zero-protocol/src/ast.ts';\nimport {SUBQ_PREFIX} from '../../zero-protocol/src/ast.ts';\n\n/**\n * Converts an AST to the equivalent query builder code.\n * This is useful for debugging and understanding queries.\n *\n * @example\n * ```\n * const ast = query.issue.where('id', '=', 123)[astSymbol];\n * console.log(astToZQL(ast)); // outputs: .where('id', '=', 123)\n * ```\n */\nexport function astToZQL(ast: AST): string {\n let code = '';\n\n // Handle where conditions\n if (ast.where) {\n code += transformCondition(ast.where, '.where', new Set());\n }\n\n // Handle related subqueries\n if (ast.related && ast.related.length > 0) {\n for (const related of ast.related) {\n if (related.hidden) {\n const nestedRelated = related.subquery.related?.[0];\n if (nestedRelated) {\n code += transformRelated(nestedRelated);\n }\n } else {\n code += transformRelated(related);\n }\n }\n }\n\n // Handle orderBy\n if (ast.orderBy && ast.orderBy.length > 0) {\n code += transformOrder(ast.orderBy);\n }\n\n // Handle limit\n if (ast.limit !== undefined) {\n code += `.limit(${ast.limit})`;\n }\n\n // Handle start\n if (ast.start) {\n const {row, exclusive} = ast.start;\n code += `.start(${JSON.stringify(row)}${\n exclusive ? '' : ', { inclusive: true }'\n })`;\n }\n\n return code;\n}\n\ntype Args = Set<string>;\n\ntype Prefix = '.where' | 'cmp';\n\nfunction transformCondition(\n condition: Condition,\n prefix: Prefix,\n args: Args,\n): string {\n switch (condition.type) {\n case 'simple':\n return transformSimpleCondition(condition, prefix);\n case 'and':\n case 'or':\n return transformLogicalCondition(condition, prefix, args);\n case 'correlatedSubquery':\n return transformExistsCondition(condition, prefix, args);\n default:\n unreachable(condition);\n }\n}\n\nfunction transformSimpleCondition(\n condition: SimpleCondition,\n prefix: Prefix,\n): string {\n const {left, op, right} = condition;\n\n const leftCode = transformValuePosition(left);\n const rightCode = transformValuePosition(right);\n\n // Handle the shorthand form for equals\n if (op === '=') {\n return `${prefix}(${leftCode}, ${rightCode})`;\n }\n\n return `${prefix}(${leftCode}, '${op}', ${rightCode})`;\n}\n\nfunction transformLogicalCondition(\n condition: Conjunction | Disjunction,\n prefix: Prefix,\n args: Args,\n): string {\n const {type, conditions} = condition;\n\n // For single condition, no need for logical operator\n if (conditions.length === 1) {\n return transformCondition(conditions[0], prefix, args);\n }\n\n // Generate multiple where calls for top-level AND conditions\n if (type === 'and') {\n const parts = conditions.map(c => transformCondition(c, prefix, args));\n // Simply concatenate the where conditions\n if (prefix === '.where') {\n return parts.join('');\n }\n args.add('and');\n return 'and(' + parts.join(', ') + ')';\n }\n\n args = new Set<string>();\n\n // Handle nested conditions with a callback for OR conditions and nested ANDs/ORs\n const conditionsCode = conditions\n .map(c => transformCondition(c, 'cmp', args))\n .join(', ');\n\n args.add('cmp');\n args.add(type);\n const argsCode = [...args].sort().join(', ');\n\n return `.where(({${argsCode}}) => ${type}(${conditionsCode}))`;\n}\n\nfunction transformExistsCondition(\n condition: CorrelatedSubqueryCondition,\n prefix: '.where' | 'cmp',\n args: Set<string>,\n): string {\n const {related, op} = condition;\n const relationship = extractRelationshipName(related);\n\n const nextSubquery = getNextExistsSubquery(related);\n\n // Check if subquery has additional properties\n const hasSubQueryProps =\n nextSubquery.where ||\n (nextSubquery.related && nextSubquery.related.length > 0) ||\n nextSubquery.orderBy ||\n nextSubquery.limit;\n\n // Build options string for flip and scalar\n const optionParts: string[] = [];\n if (condition.flip !== undefined) {\n optionParts.push(`flip: ${condition.flip}`);\n }\n if (condition.scalar !== undefined) {\n optionParts.push(`scalar: ${condition.scalar}`);\n }\n const optionsStr =\n optionParts.length > 0 ? `, {${optionParts.join(', ')}}` : '';\n\n if (op === 'EXISTS') {\n if (!hasSubQueryProps) {\n if (prefix === '.where') {\n return `.whereExists('${relationship}'${optionsStr})`;\n }\n args.add('exists');\n return `exists('${relationship}'${optionsStr})`;\n }\n\n if (prefix === '.where') {\n return `.whereExists('${relationship}', q => q${astToZQL(nextSubquery)}${optionsStr})`;\n }\n prefix satisfies 'cmp';\n args.add('exists');\n return `exists('${relationship}', q => q${astToZQL(nextSubquery)}${optionsStr})`;\n }\n\n op satisfies 'NOT EXISTS';\n\n if (hasSubQueryProps) {\n if (prefix === '.where') {\n return `.where(({exists, not}) => not(exists('${relationship}', q => q${astToZQL(\n nextSubquery,\n )}${optionsStr})))`;\n }\n prefix satisfies 'cmp';\n args.add('not');\n args.add('exists');\n return `not(exists('${relationship}', q => q${astToZQL(nextSubquery)}${optionsStr}))`;\n }\n\n if (prefix === '.where') {\n return `.where(({exists, not}) => not(exists('${relationship}'${optionsStr})))`;\n }\n args.add('not');\n args.add('exists');\n\n return `not(exists('${relationship}'${optionsStr})))`;\n}\n\n// If the `exists` is applied against a junction edge, both hops will have the same alias and both hops will be exists conditions.\nfunction getNextExistsSubquery(related: CorrelatedSubquery): AST {\n if (\n related.subquery.where?.type === 'correlatedSubquery' &&\n related.subquery.where.related.subquery.alias?.includes(\n SUBQ_PREFIX + 'zhidden_',\n )\n ) {\n return getNextExistsSubquery(related.subquery.where.related);\n }\n\n return related.subquery;\n}\n\nfunction extractRelationshipName(related: CorrelatedSubquery): string {\n const alias = must(related.subquery.alias);\n return alias.startsWith(SUBQ_PREFIX)\n ? alias.substring(SUBQ_PREFIX.length)\n : alias;\n}\n\nfunction transformRelated(related: CorrelatedSubquery): string {\n const {alias} = related.subquery;\n if (!alias) return '';\n\n const relationship = alias;\n let code = `.related('${relationship}'`;\n\n // If the subquery has additional filters or configurations\n if (\n related.subquery.where ||\n (related.subquery.related && related.subquery.related.length > 0) ||\n related.subquery.orderBy ||\n related.subquery.limit\n ) {\n code += ', q => q' + astToZQL(related.subquery);\n }\n\n code += ')';\n return code;\n}\n\nfunction transformOrder(orderBy: Ordering): string {\n let code = '';\n for (const [field, direction] of orderBy) {\n code += `.orderBy('${field}', '${direction}')`;\n }\n return code;\n}\n\nfunction transformValuePosition(value: ValuePosition): string {\n switch (value.type) {\n case 'literal':\n return transformLiteral(value);\n case 'column':\n return `'${value.name}'`;\n case 'static':\n return transformParameter(value);\n default:\n unreachable(value);\n }\n}\n\nfunction transformLiteral(literal: LiteralReference): string {\n if (literal.value === null) {\n return 'null';\n }\n if (Array.isArray(literal.value)) {\n return JSON.stringify(literal.value);\n }\n if (typeof literal.value === 'string') {\n return `'${literal.value.replace(/'/g, \"\\\\'\")}'`;\n }\n return String(literal.value);\n}\n\nfunction transformParameter(param: Parameter): string {\n const fieldStr = Array.isArray(param.field)\n ? `[${param.field.map(f => `'${f}'`).join(', ')}]`\n : `'${param.field}'`;\n\n return `authParam(${fieldStr})`;\n}\n"],"names":[],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { type Config } from '../../shared/src/options-types.ts';
2
2
  import * as v from '../../shared/src/valita.ts';
3
- export declare const logLevel: v.Type<"error" | "debug" | "info" | "warn">;
3
+ export declare const logLevel: v.Type<"info" | "error" | "debug" | "warn">;
4
4
  export declare const logOptions: {
5
- level: v.Type<"error" | "debug" | "info" | "warn">;
5
+ level: v.Type<"info" | "error" | "debug" | "warn">;
6
6
  format: {
7
7
  type: v.Type<"text" | "json">;
8
8
  desc: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"bg-interval.d.ts","sourceRoot":"","sources":["../../../../replicache/src/bg-interval.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAIjD,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAC/B,OAAO,EAAE,MAAM,MAAM,EACrB,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,WAAW,GAClB,IAAI,CAEN"}
1
+ {"version":3,"file":"bg-interval.d.ts","sourceRoot":"","sources":["../../../../replicache/src/bg-interval.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAKjD,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAC/B,OAAO,EAAE,MAAM,MAAM,EACrB,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,WAAW,GAClB,IAAI,CAEN"}
@@ -1,5 +1,6 @@
1
1
  import { AbortError } from "../../shared/src/abort-error.js";
2
2
  import { sleep } from "../../shared/src/sleep.js";
3
+ import { IDBNotFoundError } from "./kv/idb-store.js";
3
4
  function initBgIntervalProcess(processName, process, delayMs, lc, signal) {
4
5
  void runBgIntervalProcess(processName, process, delayMs, lc, signal);
5
6
  }
@@ -24,6 +25,8 @@ async function runBgIntervalProcess(processName, process, delayMs, lc, signal) {
24
25
  } catch (e) {
25
26
  if (signal.aborted) {
26
27
  lc.debug?.("Error running most likely due to close.", e);
28
+ } else if (e instanceof IDBNotFoundError) {
29
+ lc.info?.("IndexedDB was deleted externally.", e);
27
30
  } else {
28
31
  lc.error?.("Error running.", e);
29
32
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bg-interval.js","sources":["../../../../replicache/src/bg-interval.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {AbortError} from '../../shared/src/abort-error.ts';\nimport {sleep} from '../../shared/src/sleep.ts';\n\nexport function initBgIntervalProcess(\n processName: string,\n process: () => Promise<unknown>,\n delayMs: () => number,\n lc: LogContext,\n signal: AbortSignal,\n): void {\n void runBgIntervalProcess(processName, process, delayMs, lc, signal);\n}\n\nasync function runBgIntervalProcess(\n processName: string,\n process: () => Promise<unknown>,\n delayMs: () => number,\n lc: LogContext,\n signal: AbortSignal,\n): Promise<void> {\n if (signal.aborted) {\n return;\n }\n lc = lc.withContext('bgIntervalProcess', processName);\n lc.debug?.('Starting');\n while (!signal.aborted) {\n try {\n await sleep(delayMs(), signal);\n } catch (e) {\n if (!(e instanceof AbortError)) {\n throw e;\n }\n }\n if (!signal.aborted) {\n lc.debug?.('Running');\n try {\n await process();\n } catch (e) {\n if (signal.aborted) {\n lc.debug?.('Error running most likely due to close.', e);\n } else {\n lc.error?.('Error running.', e);\n }\n }\n }\n }\n lc.debug?.('Stopping');\n}\n"],"names":[],"mappings":";;AAIO,SAAS,sBACd,aACA,SACA,SACA,IACA,QACM;AACN,OAAK,qBAAqB,aAAa,SAAS,SAAS,IAAI,MAAM;AACrE;AAEA,eAAe,qBACb,aACA,SACA,SACA,IACA,QACe;AACf,MAAI,OAAO,SAAS;AAClB;AAAA,EACF;AACA,OAAK,GAAG,YAAY,qBAAqB,WAAW;AACpD,KAAG,QAAQ,UAAU;AACrB,SAAO,CAAC,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,MAAM,QAAA,GAAW,MAAM;AAAA,IAC/B,SAAS,GAAG;AACV,UAAI,EAAE,aAAa,aAAa;AAC9B,cAAM;AAAA,MACR;AAAA,IACF;AACA,QAAI,CAAC,OAAO,SAAS;AACnB,SAAG,QAAQ,SAAS;AACpB,UAAI;AACF,cAAM,QAAA;AAAA,MACR,SAAS,GAAG;AACV,YAAI,OAAO,SAAS;AAClB,aAAG,QAAQ,2CAA2C,CAAC;AAAA,QACzD,OAAO;AACL,aAAG,QAAQ,kBAAkB,CAAC;AAAA,QAChC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,KAAG,QAAQ,UAAU;AACvB;"}
1
+ {"version":3,"file":"bg-interval.js","sources":["../../../../replicache/src/bg-interval.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {AbortError} from '../../shared/src/abort-error.ts';\nimport {sleep} from '../../shared/src/sleep.ts';\nimport {IDBNotFoundError} from './kv/idb-store.ts';\n\nexport function initBgIntervalProcess(\n processName: string,\n process: () => Promise<unknown>,\n delayMs: () => number,\n lc: LogContext,\n signal: AbortSignal,\n): void {\n void runBgIntervalProcess(processName, process, delayMs, lc, signal);\n}\n\nasync function runBgIntervalProcess(\n processName: string,\n process: () => Promise<unknown>,\n delayMs: () => number,\n lc: LogContext,\n signal: AbortSignal,\n): Promise<void> {\n if (signal.aborted) {\n return;\n }\n lc = lc.withContext('bgIntervalProcess', processName);\n lc.debug?.('Starting');\n while (!signal.aborted) {\n try {\n await sleep(delayMs(), signal);\n } catch (e) {\n if (!(e instanceof AbortError)) {\n throw e;\n }\n }\n if (!signal.aborted) {\n lc.debug?.('Running');\n try {\n await process();\n } catch (e) {\n if (signal.aborted) {\n lc.debug?.('Error running most likely due to close.', e);\n } else if (e instanceof IDBNotFoundError) {\n lc.info?.('IndexedDB was deleted externally.', e);\n } else {\n lc.error?.('Error running.', e);\n }\n }\n }\n }\n lc.debug?.('Stopping');\n}\n"],"names":[],"mappings":";;;AAKO,SAAS,sBACd,aACA,SACA,SACA,IACA,QACM;AACN,OAAK,qBAAqB,aAAa,SAAS,SAAS,IAAI,MAAM;AACrE;AAEA,eAAe,qBACb,aACA,SACA,SACA,IACA,QACe;AACf,MAAI,OAAO,SAAS;AAClB;AAAA,EACF;AACA,OAAK,GAAG,YAAY,qBAAqB,WAAW;AACpD,KAAG,QAAQ,UAAU;AACrB,SAAO,CAAC,OAAO,SAAS;AACtB,QAAI;AACF,YAAM,MAAM,QAAA,GAAW,MAAM;AAAA,IAC/B,SAAS,GAAG;AACV,UAAI,EAAE,aAAa,aAAa;AAC9B,cAAM;AAAA,MACR;AAAA,IACF;AACA,QAAI,CAAC,OAAO,SAAS;AACnB,SAAG,QAAQ,SAAS;AACpB,UAAI;AACF,cAAM,QAAA;AAAA,MACR,SAAS,GAAG;AACV,YAAI,OAAO,SAAS;AAClB,aAAG,QAAQ,2CAA2C,CAAC;AAAA,QACzD,WAAW,aAAa,kBAAkB;AACxC,aAAG,OAAO,qCAAqC,CAAC;AAAA,QAClD,OAAO;AACL,aAAG,QAAQ,kBAAkB,CAAC;AAAA,QAChC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,KAAG,QAAQ,UAAU;AACvB;"}
@@ -17,7 +17,7 @@ function areEqual(arr1, arr2) {
17
17
  return arr1.length === arr2.length && arr1.every((e, i) => e === arr2[i]);
18
18
  }
19
19
  function zip(a1, a2) {
20
- assert(a1.length === a2.length);
20
+ assert(a1.length === a2.length, "zip: arrays must have equal length");
21
21
  const result = [];
22
22
  for (let i = 0; i < a1.length; i++) {
23
23
  result.push([a1[i], a2[i]]);
@@ -1 +1 @@
1
- {"version":3,"file":"arrays.js","sources":["../../../../shared/src/arrays.ts"],"sourcesContent":["import {assert} from './asserts.ts';\n\n/**\n * Returns `arr` as is if none of the elements are `undefined`.\n * Otherwise returns a new array with only defined elements in `arr`.\n */\nexport function defined<T>(arr: (T | undefined)[]): T[] {\n // avoid an array copy if possible\n let i = arr.findIndex(x => x === undefined);\n if (i < 0) {\n return arr as T[];\n }\n const defined: T[] = arr.slice(0, i) as T[];\n for (i++; i < arr.length; i++) {\n const x = arr[i];\n if (x !== undefined) {\n defined.push(x);\n }\n }\n return defined;\n}\n\nexport function areEqual<T>(arr1: readonly T[], arr2: readonly T[]): boolean {\n return arr1.length === arr2.length && arr1.every((e, i) => e === arr2[i]);\n}\n\nexport function zip<T1, T2>(a1: readonly T1[], a2: readonly T2[]): [T1, T2][] {\n assert(a1.length === a2.length);\n const result: [T1, T2][] = [];\n for (let i = 0; i < a1.length; i++) {\n result.push([a1[i], a2[i]]);\n }\n return result;\n}\n\nexport function last<T>(arr: T[]): T | undefined {\n if (arr.length === 0) {\n return undefined;\n }\n return arr[arr.length - 1];\n}\n\nexport function groupBy<T, K>(\n arr: readonly T[],\n keyFn: (el: T) => K,\n): Map<K, T[]> {\n const groups = new Map<K, T[]>();\n for (const el of arr) {\n const key = keyFn(el);\n let group = groups.get(key);\n if (group === undefined) {\n group = [];\n groups.set(key, group);\n }\n group.push(el);\n }\n return groups;\n}\n"],"names":["defined"],"mappings":";AAMO,SAAS,QAAW,KAA6B;AAEtD,MAAI,IAAI,IAAI,UAAU,CAAA,MAAK,MAAM,MAAS;AAC1C,MAAI,IAAI,GAAG;AACT,WAAO;AAAA,EACT;AACA,QAAMA,WAAe,IAAI,MAAM,GAAG,CAAC;AACnC,OAAK,KAAK,IAAI,IAAI,QAAQ,KAAK;AAC7B,UAAM,IAAI,IAAI,CAAC;AACf,QAAI,MAAM,QAAW;AACnBA,eAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AACA,SAAOA;AACT;AAEO,SAAS,SAAY,MAAoB,MAA6B;AAC3E,SAAO,KAAK,WAAW,KAAK,UAAU,KAAK,MAAM,CAAC,GAAG,MAAM,MAAM,KAAK,CAAC,CAAC;AAC1E;AAEO,SAAS,IAAY,IAAmB,IAA+B;AAC5E,SAAO,GAAG,WAAW,GAAG,MAAM;AAC9B,QAAM,SAAqB,CAAA;AAC3B,WAAS,IAAI,GAAG,IAAI,GAAG,QAAQ,KAAK;AAClC,WAAO,KAAK,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;AAAA,EAC5B;AACA,SAAO;AACT;AAEO,SAAS,KAAQ,KAAyB;AAC/C,MAAI,IAAI,WAAW,GAAG;AACpB,WAAO;AAAA,EACT;AACA,SAAO,IAAI,IAAI,SAAS,CAAC;AAC3B;AAEO,SAAS,QACd,KACA,OACa;AACb,QAAM,6BAAa,IAAA;AACnB,aAAW,MAAM,KAAK;AACpB,UAAM,MAAM,MAAM,EAAE;AACpB,QAAI,QAAQ,OAAO,IAAI,GAAG;AAC1B,QAAI,UAAU,QAAW;AACvB,cAAQ,CAAA;AACR,aAAO,IAAI,KAAK,KAAK;AAAA,IACvB;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AACA,SAAO;AACT;"}
1
+ {"version":3,"file":"arrays.js","sources":["../../../../shared/src/arrays.ts"],"sourcesContent":["import {assert} from './asserts.ts';\n\n/**\n * Returns `arr` as is if none of the elements are `undefined`.\n * Otherwise returns a new array with only defined elements in `arr`.\n */\nexport function defined<T>(arr: (T | undefined)[]): T[] {\n // avoid an array copy if possible\n let i = arr.findIndex(x => x === undefined);\n if (i < 0) {\n return arr as T[];\n }\n const defined: T[] = arr.slice(0, i) as T[];\n for (i++; i < arr.length; i++) {\n const x = arr[i];\n if (x !== undefined) {\n defined.push(x);\n }\n }\n return defined;\n}\n\nexport function areEqual<T>(arr1: readonly T[], arr2: readonly T[]): boolean {\n return arr1.length === arr2.length && arr1.every((e, i) => e === arr2[i]);\n}\n\nexport function zip<T1, T2>(a1: readonly T1[], a2: readonly T2[]): [T1, T2][] {\n assert(a1.length === a2.length, 'zip: arrays must have equal length');\n const result: [T1, T2][] = [];\n for (let i = 0; i < a1.length; i++) {\n result.push([a1[i], a2[i]]);\n }\n return result;\n}\n\nexport function last<T>(arr: T[]): T | undefined {\n if (arr.length === 0) {\n return undefined;\n }\n return arr[arr.length - 1];\n}\n\nexport function groupBy<T, K>(\n arr: readonly T[],\n keyFn: (el: T) => K,\n): Map<K, T[]> {\n const groups = new Map<K, T[]>();\n for (const el of arr) {\n const key = keyFn(el);\n let group = groups.get(key);\n if (group === undefined) {\n group = [];\n groups.set(key, group);\n }\n group.push(el);\n }\n return groups;\n}\n"],"names":["defined"],"mappings":";AAMO,SAAS,QAAW,KAA6B;AAEtD,MAAI,IAAI,IAAI,UAAU,CAAA,MAAK,MAAM,MAAS;AAC1C,MAAI,IAAI,GAAG;AACT,WAAO;AAAA,EACT;AACA,QAAMA,WAAe,IAAI,MAAM,GAAG,CAAC;AACnC,OAAK,KAAK,IAAI,IAAI,QAAQ,KAAK;AAC7B,UAAM,IAAI,IAAI,CAAC;AACf,QAAI,MAAM,QAAW;AACnBA,eAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AACA,SAAOA;AACT;AAEO,SAAS,SAAY,MAAoB,MAA6B;AAC3E,SAAO,KAAK,WAAW,KAAK,UAAU,KAAK,MAAM,CAAC,GAAG,MAAM,MAAM,KAAK,CAAC,CAAC;AAC1E;AAEO,SAAS,IAAY,IAAmB,IAA+B;AAC5E,SAAO,GAAG,WAAW,GAAG,QAAQ,oCAAoC;AACpE,QAAM,SAAqB,CAAA;AAC3B,WAAS,IAAI,GAAG,IAAI,GAAG,QAAQ,KAAK;AAClC,WAAO,KAAK,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;AAAA,EAC5B;AACA,SAAO;AACT;AAEO,SAAS,KAAQ,KAAyB;AAC/C,MAAI,IAAI,WAAW,GAAG;AACpB,WAAO;AAAA,EACT;AACA,SAAO,IAAI,IAAI,SAAS,CAAC;AAC3B;AAEO,SAAS,QACd,KACA,OACa;AACb,QAAM,6BAAa,IAAA;AACnB,aAAW,MAAM,KAAK;AACpB,UAAM,MAAM,MAAM,EAAE;AACpB,QAAI,QAAQ,OAAO,IAAI,GAAG;AAC1B,QAAI,UAAU,QAAW;AACvB,cAAQ,CAAA;AACR,aAAO,IAAI,KAAK,KAAK;AAAA,IACvB;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AACA,SAAO;AACT;"}
@@ -5,9 +5,6 @@ function getBrowserGlobal(name) {
5
5
  }
6
6
  return globalThis[name];
7
7
  }
8
- function getBrowserGlobalMethod(name) {
9
- return getBrowserGlobal(name)?.bind(globalThis);
10
- }
11
8
  function mustGetBrowserGlobal(name) {
12
9
  const r = getBrowserGlobal(name);
13
10
  if (r === void 0) {
@@ -19,7 +16,6 @@ function mustGetBrowserGlobal(name) {
19
16
  }
20
17
  export {
21
18
  getBrowserGlobal,
22
- getBrowserGlobalMethod,
23
19
  mustGetBrowserGlobal
24
20
  };
25
21
  //# sourceMappingURL=browser-env.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"browser-env.js","sources":["../../../../shared/src/browser-env.ts"],"sourcesContent":["// Helpers for some objects from the browser environment. These are wrapped in\n// functions because Replicache runs in environments that do not have these\n// objects (such as Web Workers, Deno etc).\n\ntype GlobalThis = typeof globalThis;\n\nconst overrides = new Map<keyof GlobalThis, GlobalThis[keyof GlobalThis]>();\n\nexport function overrideBrowserGlobal<T extends keyof GlobalThis>(\n name: T,\n value: GlobalThis[T],\n) {\n overrides.set(name, value);\n}\n\nexport function clearBrowserOverrides() {\n overrides.clear();\n}\n\nexport function getBrowserGlobal<T extends keyof GlobalThis>(\n name: T,\n): GlobalThis[T] | undefined {\n if (overrides.has(name)) {\n return overrides.get(name);\n }\n return globalThis[name];\n}\n\n/**\n * Returns the global method with the given name, bound to the global object.\n * This is important because some methods (e.g. `requestAnimationFrame`) are not\n * bound to the global object by default.\n *\n * If you end up using {@linkcode getBrowserGlobal} instead in a case like this:\n *\n * ```js\n * this.#raf = getBrowserGlobal('requestAnimationFrame') ?? rafFallback;\n * ...\n * this.#raf(() => ...);\n * ```\n *\n * You will end up with `Uncaught TypeError: Illegal invocation` because `this`\n * is not bound to the global object\n */\nexport function getBrowserGlobalMethod<T extends keyof GlobalThis>(\n name: T,\n): GlobalThis[T] | undefined {\n return getBrowserGlobal(name)?.bind(globalThis);\n}\n\nexport function mustGetBrowserGlobal<T extends keyof GlobalThis>(\n name: T,\n): GlobalThis[T] {\n const r = getBrowserGlobal(name);\n if (r === undefined) {\n throw new Error(\n `Unsupported JavaScript environment: Could not find ${name}.`,\n );\n }\n return r;\n}\n"],"names":[],"mappings":"AAMA,MAAM,gCAAgB,IAAA;AAaf,SAAS,iBACd,MAC2B;AAC3B,MAAI,UAAU,IAAI,IAAI,GAAG;AACvB,WAAO,UAAU,IAAI,IAAI;AAAA,EAC3B;AACA,SAAO,WAAW,IAAI;AACxB;AAkBO,SAAS,uBACd,MAC2B;AAC3B,SAAO,iBAAiB,IAAI,GAAG,KAAK,UAAU;AAChD;AAEO,SAAS,qBACd,MACe;AACf,QAAM,IAAI,iBAAiB,IAAI;AAC/B,MAAI,MAAM,QAAW;AACnB,UAAM,IAAI;AAAA,MACR,sDAAsD,IAAI;AAAA,IAAA;AAAA,EAE9D;AACA,SAAO;AACT;"}
1
+ {"version":3,"file":"browser-env.js","sources":["../../../../shared/src/browser-env.ts"],"sourcesContent":["// Helpers for some objects from the browser environment. These are wrapped in\n// functions because Replicache runs in environments that do not have these\n// objects (such as Web Workers, Deno etc).\n\ntype GlobalThis = typeof globalThis;\n\nconst overrides = new Map<keyof GlobalThis, GlobalThis[keyof GlobalThis]>();\n\nexport function overrideBrowserGlobal<T extends keyof GlobalThis>(\n name: T,\n value: GlobalThis[T],\n) {\n overrides.set(name, value);\n}\n\nexport function clearBrowserOverrides() {\n overrides.clear();\n}\n\nexport function getBrowserGlobal<T extends keyof GlobalThis>(\n name: T,\n): GlobalThis[T] | undefined {\n if (overrides.has(name)) {\n return overrides.get(name);\n }\n return globalThis[name];\n}\n\n/**\n * Returns the global method with the given name, bound to the global object.\n * This is important because some methods (e.g. `requestAnimationFrame`) are not\n * bound to the global object by default.\n *\n * If you end up using {@linkcode getBrowserGlobal} instead in a case like this:\n *\n * ```js\n * this.#raf = getBrowserGlobal('requestAnimationFrame') ?? rafFallback;\n * ...\n * this.#raf(() => ...);\n * ```\n *\n * You will end up with `Uncaught TypeError: Illegal invocation` because `this`\n * is not bound to the global object\n */\nexport function getBrowserGlobalMethod<T extends keyof GlobalThis>(\n name: T,\n): GlobalThis[T] | undefined {\n return getBrowserGlobal(name)?.bind(globalThis);\n}\n\nexport function mustGetBrowserGlobal<T extends keyof GlobalThis>(\n name: T,\n): GlobalThis[T] {\n const r = getBrowserGlobal(name);\n if (r === undefined) {\n throw new Error(\n `Unsupported JavaScript environment: Could not find ${name}.`,\n );\n }\n return r;\n}\n"],"names":[],"mappings":"AAMA,MAAM,gCAAgB,IAAA;AAaf,SAAS,iBACd,MAC2B;AAC3B,MAAI,UAAU,IAAI,IAAI,GAAG;AACvB,WAAO,UAAU,IAAI,IAAI;AAAA,EAC3B;AACA,SAAO,WAAW,IAAI;AACxB;AAwBO,SAAS,qBACd,MACe;AACf,QAAM,IAAI,iBAAiB,IAAI;AAC/B,MAAI,MAAM,QAAW;AACnB,UAAM,IAAI;AAAA,MACR,sDAAsD,IAAI;AAAA,IAAA;AAAA,EAE9D;AACA,SAAO;AACT;"}
@@ -147,7 +147,10 @@ function valuesFromReversed(maxKey, root, comparator, highestKey, inclusive) {
147
147
  return iterator(() => ({ done: true, value: void 0 }));
148
148
  }
149
149
  let [nodeQueue, nodeIndex, leaf] = findPath(highestKey, root, comparator) || findPath(maxKey, root, comparator);
150
- assert(!nodeQueue[0] || leaf === nodeQueue[0][nodeIndex[0]]);
150
+ assert(
151
+ !nodeQueue[0] || leaf === nodeQueue[0][nodeIndex[0]],
152
+ "BTreeSet: leaf node mismatch in iteration"
153
+ );
151
154
  let i = indexOf(highestKey, leaf.keys, 0, comparator);
152
155
  if (inclusive && i < leaf.keys.length && comparator(leaf.keys[i], highestKey) <= 0) {
153
156
  i++;
@@ -1 +1 @@
1
- {"version":3,"file":"btree-set.js","sources":["../../../../shared/src/btree-set.ts"],"sourcesContent":["import {assert} from './asserts.ts';\n\nconst MAX_NODE_SIZE = 32;\n\ntype Comparator<K> = (a: K, b: K) => number;\nexport class BTreeSet<K> {\n #root: BNode<K> = emptyLeaf as BNode<K>;\n size: number = 0;\n\n readonly comparator: Comparator<K>;\n\n constructor(comparator: Comparator<K>, entries?: IterableIterator<K>) {\n this.comparator = comparator;\n if (entries) {\n for (const key of entries) {\n this.add(key);\n }\n }\n }\n\n /** Releases the tree so that its size is 0. */\n clear() {\n this.#root = emptyLeaf as BNode<K>;\n this.size = 0;\n }\n\n clone() {\n this.#root.isShared = true;\n const ret = new BTreeSet<K>(this.comparator);\n ret.#root = this.#root;\n ret.size = this.size;\n return ret;\n }\n\n get(key: K): K | undefined {\n return this.#root.get(key, this);\n }\n\n add(key: K): this {\n if (this.#root.isShared) this.#root = this.#root.clone();\n const result = this.#root.set(key, this);\n if (result === null) return this;\n // Root node has split, so create a new root node.\n this.#root = new BNodeInternal<K>([this.#root, result]);\n return this;\n }\n\n /**\n * Returns true if the key exists in the B+ tree, false if not.\n * Use get() for best performance; use has() if you need to\n * distinguish between \"undefined value\" and \"key not present\".\n * @param key Key to detect\n * @description Computational complexity: O(log size)\n */\n has(key: K): boolean {\n return this.#root.has(key, this);\n }\n\n /**\n * Removes a single key-value pair from the B+ tree.\n * @param key Key to find\n * @returns true if a pair was found and removed, false otherwise.\n * @description Computational complexity: O(log size)\n */\n delete(key: K): boolean {\n return this.#delete(key);\n }\n\n #delete(key: K): boolean {\n let root = this.#root;\n if (root.isShared) {\n this.#root = root = root.clone();\n }\n try {\n return root.delete(key, this);\n } finally {\n let isShared;\n while (root.keys.length <= 1 && root.isInternal()) {\n isShared ||= root.isShared;\n this.#root = root =\n root.keys.length === 0 ? emptyLeaf : root.children[0];\n }\n // If any ancestor of the new root was shared, the new root must also be shared\n if (isShared) {\n root.isShared = true;\n }\n }\n }\n\n keys(): IterableIterator<K> {\n return valuesFrom(this.#root, this.comparator, undefined, true);\n }\n\n values(): IterableIterator<K> {\n return valuesFrom(this.#root, this.comparator, undefined, true);\n }\n\n valuesFrom(lowestKey?: K, inclusive: boolean = true): IterableIterator<K> {\n return valuesFrom(this.#root, this.comparator, lowestKey, inclusive);\n }\n\n valuesReversed(): IterableIterator<K> {\n return valuesFromReversed(\n this.#maxKey(),\n this.#root,\n this.comparator,\n undefined,\n true,\n );\n }\n\n valuesFromReversed(\n highestKey?: K,\n inclusive: boolean = true,\n ): IterableIterator<K> {\n return valuesFromReversed(\n this.#maxKey(),\n this.#root,\n this.comparator,\n highestKey,\n inclusive,\n );\n }\n\n /** Gets the highest key in the tree. Complexity: O(1) */\n #maxKey(): K | undefined {\n return this.#root.maxKey();\n }\n\n [Symbol.iterator](): IterableIterator<K> {\n return this.keys();\n }\n}\n\nfunction valuesFrom<K>(\n root: BNode<K>,\n comparator: Comparator<K>,\n lowestKey: K | undefined,\n inclusive: boolean,\n): IterableIterator<K> {\n const info = findPath(lowestKey, root, comparator);\n if (info === undefined) {\n return iterator<K>(() => ({done: true, value: undefined}));\n }\n\n let [nodeQueue, nodeIndex, leaf] = info;\n let i =\n lowestKey === undefined\n ? -1\n : indexOf(lowestKey, leaf.keys, 0, comparator) - 1;\n\n if (\n !inclusive &&\n i < leaf.keys.length &&\n // +1 because we did -1 above.\n comparator(leaf.keys[i + 1], lowestKey!) === 0\n ) {\n i++;\n }\n\n return iterator<K>(() => {\n for (;;) {\n if (++i < leaf.keys.length) {\n return {done: false, value: leaf.keys[i]};\n }\n\n let level = -1;\n for (;;) {\n if (++level >= nodeQueue.length) {\n return {done: true, value: undefined};\n }\n if (++nodeIndex[level] < nodeQueue[level].length) {\n break;\n }\n }\n for (; level > 0; level--) {\n nodeQueue[level - 1] = (\n nodeQueue[level][nodeIndex[level]] as BNodeInternal<K>\n ).children;\n nodeIndex[level - 1] = 0;\n }\n leaf = nodeQueue[0][nodeIndex[0]];\n i = -1;\n }\n });\n}\n\nfunction valuesFromReversed<K>(\n maxKey: K | undefined,\n root: BNode<K>,\n comparator: Comparator<K>,\n highestKey: K | undefined,\n inclusive: boolean,\n): IterableIterator<K> {\n if (highestKey === undefined) {\n highestKey = maxKey;\n if (highestKey === undefined)\n return iterator<K>(() => ({done: true, value: undefined})); // collection is empty\n }\n let [nodeQueue, nodeIndex, leaf] =\n findPath(highestKey, root, comparator) ||\n findPath(maxKey, root, comparator)!;\n assert(!nodeQueue[0] || leaf === nodeQueue[0][nodeIndex[0]]);\n let i = indexOf(highestKey, leaf.keys, 0, comparator);\n if (\n inclusive &&\n i < leaf.keys.length &&\n comparator(leaf.keys[i], highestKey) <= 0\n ) {\n i++;\n }\n\n return iterator<K>(() => {\n for (;;) {\n if (--i >= 0) {\n return {done: false, value: leaf.keys[i]};\n }\n\n let level;\n // Advance to the next leaf node\n for (level = -1; ; ) {\n if (++level >= nodeQueue.length) {\n return {done: true, value: undefined};\n }\n if (--nodeIndex[level] >= 0) {\n break;\n }\n }\n for (; level > 0; level--) {\n nodeQueue[level - 1] = (\n nodeQueue[level][nodeIndex[level]] as BNodeInternal<K>\n ).children;\n nodeIndex[level - 1] = nodeQueue[level - 1].length - 1;\n }\n leaf = nodeQueue[0][nodeIndex[0]];\n i = leaf.keys.length;\n }\n });\n}\n\nfunction findPath<K>(\n key: K | undefined,\n root: BNode<K>,\n comparator: Comparator<K>,\n): [nodeQueue: BNode<K>[][], nodeIndex: number[], leaf: BNode<K>] | undefined {\n let nextNode = root;\n const nodeQueue: BNode<K>[][] = [];\n const nodeIndex: number[] = [];\n\n if (nextNode.isInternal()) {\n for (let d = 0; nextNode.isInternal(); d++) {\n nodeQueue[d] = nextNode.children;\n nodeIndex[d] =\n key === undefined ? 0 : indexOf(key, nextNode.keys, 0, comparator);\n if (nodeIndex[d] >= nodeQueue[d].length) return; // first key > maxKey()\n nextNode = nodeQueue[d][nodeIndex[d]];\n }\n nodeQueue.reverse();\n nodeIndex.reverse();\n }\n return [nodeQueue, nodeIndex, nextNode];\n}\n\nfunction iterator<T>(next: () => IteratorResult<T>): IterableIterator<T> {\n return {\n next,\n [Symbol.iterator]() {\n return this;\n },\n };\n}\n\n/** Leaf node / base class. **************************************************/\nclass BNode<K> {\n // If this is an internal node, _keys[i] is the highest key in children[i].\n keys: K[];\n // True if this node might be within multiple `BTree`s (or have multiple parents).\n // If so, it must be cloned before being mutated to avoid changing an unrelated tree.\n // This is transitive: if it's true, children are also shared even if `isShared!=true`\n // in those children. (Certain operations will propagate isShared=true to children.)\n isShared: true | undefined;\n\n constructor(keys: K[]) {\n this.keys = keys;\n this.isShared = undefined;\n }\n\n isInternal(): this is BNodeInternal<K> {\n return false;\n }\n\n maxKey() {\n return this.keys[this.keys.length - 1];\n }\n\n minKey(): K | undefined {\n return this.keys[0];\n }\n\n clone(): BNode<K> {\n return new BNode<K>(this.keys.slice(0));\n }\n\n get(key: K, tree: BTreeSet<K>): K | undefined {\n const i = indexOf(key, this.keys, -1, tree.comparator);\n return i < 0 ? undefined : this.keys[i];\n }\n\n has(key: K, tree: BTreeSet<K>): boolean {\n const i = indexOf(key, this.keys, -1, tree.comparator);\n return i >= 0 && i < this.keys.length;\n }\n\n set(key: K, tree: BTreeSet<K>): null | BNode<K> {\n let i = indexOf(key, this.keys, -1, tree.comparator);\n if (i < 0) {\n // key does not exist yet\n i = ~i;\n tree.size++;\n\n if (this.keys.length < MAX_NODE_SIZE) {\n this.keys.splice(i, 0, key);\n return null;\n }\n // This leaf node is full and must split\n const newRightSibling = this.splitOffRightSide();\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n let target: BNode<K> = this;\n if (i > this.keys.length) {\n i -= this.keys.length;\n target = newRightSibling;\n }\n // target.#insertInLeaf(i, key);\n target.keys.splice(i, 0, key);\n\n return newRightSibling;\n }\n\n // usually this is a no-op, but some users may wish to edit the key\n this.keys[i] = key;\n return null;\n }\n\n takeFromRight(rhs: BNode<K>) {\n this.keys.push(rhs.keys.shift()!);\n }\n\n takeFromLeft(lhs: BNode<K>) {\n this.keys.unshift(lhs.keys.pop()!);\n }\n\n splitOffRightSide(): BNode<K> {\n const half = this.keys.length >> 1;\n const keys = this.keys.splice(half);\n return new BNode<K>(keys);\n }\n\n delete(key: K, tree: BTreeSet<K>): boolean {\n const cmp = tree.comparator;\n const iLow = indexOf(key, this.keys, -1, cmp);\n const iHigh = iLow + 1;\n\n if (iLow < 0) {\n return false;\n }\n\n const {keys} = this;\n for (let i = iLow; i < iHigh; i++) {\n const key = keys[i];\n\n if (key !== keys[i] || this.isShared === true) {\n throw new Error('BTree illegally changed or cloned in delete');\n }\n\n this.keys.splice(i, 1);\n tree.size--;\n return true;\n }\n\n return false;\n }\n\n mergeSibling(rhs: BNode<K>, _: number) {\n this.keys.push(...rhs.keys);\n }\n}\n\n/** Internal node (non-leaf node) ********************************************/\nclass BNodeInternal<K> extends BNode<K> {\n // Note: conventionally B+ trees have one fewer key than the number of\n // children, but I find it easier to keep the array lengths equal: each\n // keys[i] caches the value of children[i].maxKey().\n children: BNode<K>[];\n\n /**\n * This does not mark `children` as shared, so it is the responsibility of the caller\n * to ensure children are either marked shared, or aren't included in another tree.\n */\n constructor(children: BNode<K>[], keys?: K[]) {\n if (!keys) {\n keys = [];\n for (let i = 0; i < children.length; i++) {\n keys[i] = children[i].maxKey();\n }\n }\n super(keys);\n this.children = children;\n }\n\n isInternal(): this is BNodeInternal<K> {\n return true;\n }\n\n clone(): BNode<K> {\n const children = this.children.slice(0);\n for (let i = 0; i < children.length; i++) {\n children[i].isShared = true;\n }\n return new BNodeInternal<K>(children, this.keys.slice(0));\n }\n\n minKey() {\n return this.children[0].minKey();\n }\n\n get(key: K, tree: BTreeSet<K>): K | undefined {\n const i = indexOf(key, this.keys, 0, tree.comparator);\n const {children} = this;\n return i < children.length ? children[i].get(key, tree) : undefined;\n }\n\n has(key: K, tree: BTreeSet<K>): boolean {\n const i = indexOf(key, this.keys, 0, tree.comparator);\n const {children} = this;\n return i < children.length ? children[i].has(key, tree) : false;\n }\n\n set(key: K, tree: BTreeSet<K>): null | BNode<K> {\n const c = this.children;\n const cmp = tree.comparator;\n let i = Math.min(indexOf(key, this.keys, 0, cmp), c.length - 1);\n let child = c[i];\n\n if (child.isShared) {\n c[i] = child = child.clone();\n }\n if (child.keys.length >= MAX_NODE_SIZE) {\n // child is full; inserting anything else will cause a split.\n // Shifting an item to the left or right sibling may avoid a split.\n // We can do a shift if the adjacent node is not full and if the\n // current key can still be placed in the same node after the shift.\n let other: BNode<K>;\n if (\n i > 0 &&\n (other = c[i - 1]).keys.length < MAX_NODE_SIZE &&\n cmp(child.keys[0], key) < 0\n ) {\n if (other.isShared) {\n c[i - 1] = other = other.clone();\n }\n other.takeFromRight(child);\n this.keys[i - 1] = other.maxKey();\n } else if (\n (other = c[i + 1]) !== undefined &&\n other.keys.length < MAX_NODE_SIZE &&\n cmp(child.maxKey(), key) < 0\n ) {\n if (other.isShared) c[i + 1] = other = other.clone();\n other.takeFromLeft(child);\n this.keys[i] = c[i].maxKey();\n }\n }\n\n const result = child.set(key, tree);\n this.keys[i] = child.maxKey();\n if (result === null) return null;\n\n // The child has split and `result` is a new right child... does it fit?\n if (this.keys.length < MAX_NODE_SIZE) {\n // yes\n this.insert(i + 1, result);\n return null;\n }\n // no, we must split also\n const newRightSibling = this.splitOffRightSide();\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n let target: BNodeInternal<K> = this;\n if (cmp(result.maxKey(), this.maxKey()) > 0) {\n target = newRightSibling;\n i -= this.keys.length;\n }\n target.insert(i + 1, result);\n return newRightSibling;\n }\n\n /**\n * Inserts `child` at index `i`.\n * This does not mark `child` as shared, so it is the responsibility of the caller\n * to ensure that either child is marked shared, or it is not included in another tree.\n */\n insert(i: number, child: BNode<K>) {\n this.children.splice(i, 0, child);\n this.keys.splice(i, 0, child.maxKey());\n }\n\n /**\n * Split this node.\n * Modifies this to remove the second half of the items, returning a separate node containing them.\n */\n splitOffRightSide() {\n const half = this.children.length >> 1;\n return new BNodeInternal<K>(\n this.children.splice(half),\n this.keys.splice(half),\n );\n }\n\n takeFromRight(rhs: BNode<K>) {\n this.keys.push(rhs.keys.shift()!);\n this.children.push((rhs as BNodeInternal<K>).children.shift()!);\n }\n\n takeFromLeft(lhs: BNode<K>) {\n this.keys.unshift(lhs.keys.pop()!);\n this.children.unshift((lhs as BNodeInternal<K>).children.pop()!);\n }\n\n delete(key: K, tree: BTreeSet<K>): boolean {\n const cmp = tree.comparator;\n const {keys} = this;\n const {children} = this;\n let iLow = indexOf(key, this.keys, 0, cmp);\n let i = iLow;\n const iHigh = Math.min(iLow, keys.length - 1);\n if (i <= iHigh) {\n try {\n if (children[i].isShared) {\n children[i] = children[i].clone();\n }\n const result = children[i].delete(key, tree);\n // Note: if children[i] is empty then keys[i]=undefined.\n // This is an invalid state, but it is fixed below.\n keys[i] = children[i].maxKey();\n return result;\n } finally {\n // Deletions may have occurred, so look for opportunities to merge nodes.\n const half = MAX_NODE_SIZE >> 1;\n if (iLow > 0) iLow--;\n for (i = iHigh; i >= iLow; i--) {\n if (children[i].keys.length <= half) {\n if (children[i].keys.length !== 0) {\n this.tryMerge(i, MAX_NODE_SIZE);\n } else {\n // child is empty! delete it!\n keys.splice(i, 1);\n children.splice(i, 1);\n }\n }\n }\n }\n }\n return false;\n }\n\n /** Merges child i with child i+1 if their combined size is not too large */\n tryMerge(i: number, maxSize: number): boolean {\n const {children} = this;\n if (i >= 0 && i + 1 < children.length) {\n if (children[i].keys.length + children[i + 1].keys.length <= maxSize) {\n if (children[i].isShared)\n // cloned already UNLESS i is outside scan range\n children[i] = children[i].clone();\n children[i].mergeSibling(children[i + 1], maxSize);\n children.splice(i + 1, 1);\n this.keys.splice(i + 1, 1);\n this.keys[i] = children[i].maxKey();\n return true;\n }\n }\n return false;\n }\n\n /**\n * Move children from `rhs` into this.\n * `rhs` must be part of this tree, and be removed from it after this call\n * (otherwise isShared for its children could be incorrect).\n */\n mergeSibling(rhs: BNode<K>, maxNodeSize: number) {\n // assert !this.isShared;\n const oldLength = this.keys.length;\n this.keys.push(...rhs.keys);\n const rhsChildren = (rhs as unknown as BNodeInternal<K>).children;\n this.children.push(...rhsChildren);\n\n if (rhs.isShared && !this.isShared) {\n // All children of a shared node are implicitly shared, and since their new\n // parent is not shared, they must now be explicitly marked as shared.\n for (let i = 0; i < rhsChildren.length; i++) {\n rhsChildren[i].isShared = true;\n }\n }\n\n // If our children are themselves almost empty due to a mass-delete,\n // they may need to be merged too (but only the oldLength-1 and its\n // right sibling should need this).\n this.tryMerge(oldLength - 1, maxNodeSize);\n }\n}\n\n// If key not found, returns i^failXor where i is the insertion index.\n// Callers that don't care whether there was a match will set failXor=0.\nfunction indexOf<K>(\n key: K,\n keys: K[],\n failXor: number,\n comparator: Comparator<K>,\n): number {\n let lo = 0;\n let hi = keys.length;\n let mid = hi >> 1;\n while (lo < hi) {\n const c = comparator(keys[mid], key);\n if (c < 0) {\n lo = mid + 1;\n } else if (c > 0) {\n // key < keys[mid]\n hi = mid;\n } else if (c === 0) {\n return mid;\n } else {\n // c is NaN or otherwise invalid\n if (key === key) {\n // at least the search key is not NaN\n return keys.length;\n }\n throw new Error('NaN was used as a key');\n }\n mid = (lo + hi) >> 1;\n }\n return mid ^ failXor;\n}\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\nconst emptyLeaf = new BNode<any>([]);\nemptyLeaf.isShared = true;\n"],"names":["key"],"mappings":"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"}
1
+ {"version":3,"file":"btree-set.js","sources":["../../../../shared/src/btree-set.ts"],"sourcesContent":["import {assert} from './asserts.ts';\n\nconst MAX_NODE_SIZE = 32;\n\ntype Comparator<K> = (a: K, b: K) => number;\nexport class BTreeSet<K> {\n #root: BNode<K> = emptyLeaf as BNode<K>;\n size: number = 0;\n\n readonly comparator: Comparator<K>;\n\n constructor(comparator: Comparator<K>, entries?: IterableIterator<K>) {\n this.comparator = comparator;\n if (entries) {\n for (const key of entries) {\n this.add(key);\n }\n }\n }\n\n /** Releases the tree so that its size is 0. */\n clear() {\n this.#root = emptyLeaf as BNode<K>;\n this.size = 0;\n }\n\n clone() {\n this.#root.isShared = true;\n const ret = new BTreeSet<K>(this.comparator);\n ret.#root = this.#root;\n ret.size = this.size;\n return ret;\n }\n\n get(key: K): K | undefined {\n return this.#root.get(key, this);\n }\n\n add(key: K): this {\n if (this.#root.isShared) this.#root = this.#root.clone();\n const result = this.#root.set(key, this);\n if (result === null) return this;\n // Root node has split, so create a new root node.\n this.#root = new BNodeInternal<K>([this.#root, result]);\n return this;\n }\n\n /**\n * Returns true if the key exists in the B+ tree, false if not.\n * Use get() for best performance; use has() if you need to\n * distinguish between \"undefined value\" and \"key not present\".\n * @param key Key to detect\n * @description Computational complexity: O(log size)\n */\n has(key: K): boolean {\n return this.#root.has(key, this);\n }\n\n /**\n * Removes a single key-value pair from the B+ tree.\n * @param key Key to find\n * @returns true if a pair was found and removed, false otherwise.\n * @description Computational complexity: O(log size)\n */\n delete(key: K): boolean {\n return this.#delete(key);\n }\n\n #delete(key: K): boolean {\n let root = this.#root;\n if (root.isShared) {\n this.#root = root = root.clone();\n }\n try {\n return root.delete(key, this);\n } finally {\n let isShared;\n while (root.keys.length <= 1 && root.isInternal()) {\n isShared ||= root.isShared;\n this.#root = root =\n root.keys.length === 0 ? emptyLeaf : root.children[0];\n }\n // If any ancestor of the new root was shared, the new root must also be shared\n if (isShared) {\n root.isShared = true;\n }\n }\n }\n\n keys(): IterableIterator<K> {\n return valuesFrom(this.#root, this.comparator, undefined, true);\n }\n\n values(): IterableIterator<K> {\n return valuesFrom(this.#root, this.comparator, undefined, true);\n }\n\n valuesFrom(lowestKey?: K, inclusive: boolean = true): IterableIterator<K> {\n return valuesFrom(this.#root, this.comparator, lowestKey, inclusive);\n }\n\n valuesReversed(): IterableIterator<K> {\n return valuesFromReversed(\n this.#maxKey(),\n this.#root,\n this.comparator,\n undefined,\n true,\n );\n }\n\n valuesFromReversed(\n highestKey?: K,\n inclusive: boolean = true,\n ): IterableIterator<K> {\n return valuesFromReversed(\n this.#maxKey(),\n this.#root,\n this.comparator,\n highestKey,\n inclusive,\n );\n }\n\n /** Gets the highest key in the tree. Complexity: O(1) */\n #maxKey(): K | undefined {\n return this.#root.maxKey();\n }\n\n [Symbol.iterator](): IterableIterator<K> {\n return this.keys();\n }\n}\n\nfunction valuesFrom<K>(\n root: BNode<K>,\n comparator: Comparator<K>,\n lowestKey: K | undefined,\n inclusive: boolean,\n): IterableIterator<K> {\n const info = findPath(lowestKey, root, comparator);\n if (info === undefined) {\n return iterator<K>(() => ({done: true, value: undefined}));\n }\n\n let [nodeQueue, nodeIndex, leaf] = info;\n let i =\n lowestKey === undefined\n ? -1\n : indexOf(lowestKey, leaf.keys, 0, comparator) - 1;\n\n if (\n !inclusive &&\n i < leaf.keys.length &&\n // +1 because we did -1 above.\n comparator(leaf.keys[i + 1], lowestKey!) === 0\n ) {\n i++;\n }\n\n return iterator<K>(() => {\n for (;;) {\n if (++i < leaf.keys.length) {\n return {done: false, value: leaf.keys[i]};\n }\n\n let level = -1;\n for (;;) {\n if (++level >= nodeQueue.length) {\n return {done: true, value: undefined};\n }\n if (++nodeIndex[level] < nodeQueue[level].length) {\n break;\n }\n }\n for (; level > 0; level--) {\n nodeQueue[level - 1] = (\n nodeQueue[level][nodeIndex[level]] as BNodeInternal<K>\n ).children;\n nodeIndex[level - 1] = 0;\n }\n leaf = nodeQueue[0][nodeIndex[0]];\n i = -1;\n }\n });\n}\n\nfunction valuesFromReversed<K>(\n maxKey: K | undefined,\n root: BNode<K>,\n comparator: Comparator<K>,\n highestKey: K | undefined,\n inclusive: boolean,\n): IterableIterator<K> {\n if (highestKey === undefined) {\n highestKey = maxKey;\n if (highestKey === undefined)\n return iterator<K>(() => ({done: true, value: undefined})); // collection is empty\n }\n let [nodeQueue, nodeIndex, leaf] =\n findPath(highestKey, root, comparator) ||\n findPath(maxKey, root, comparator)!;\n assert(\n !nodeQueue[0] || leaf === nodeQueue[0][nodeIndex[0]],\n 'BTreeSet: leaf node mismatch in iteration',\n );\n let i = indexOf(highestKey, leaf.keys, 0, comparator);\n if (\n inclusive &&\n i < leaf.keys.length &&\n comparator(leaf.keys[i], highestKey) <= 0\n ) {\n i++;\n }\n\n return iterator<K>(() => {\n for (;;) {\n if (--i >= 0) {\n return {done: false, value: leaf.keys[i]};\n }\n\n let level;\n // Advance to the next leaf node\n for (level = -1; ; ) {\n if (++level >= nodeQueue.length) {\n return {done: true, value: undefined};\n }\n if (--nodeIndex[level] >= 0) {\n break;\n }\n }\n for (; level > 0; level--) {\n nodeQueue[level - 1] = (\n nodeQueue[level][nodeIndex[level]] as BNodeInternal<K>\n ).children;\n nodeIndex[level - 1] = nodeQueue[level - 1].length - 1;\n }\n leaf = nodeQueue[0][nodeIndex[0]];\n i = leaf.keys.length;\n }\n });\n}\n\nfunction findPath<K>(\n key: K | undefined,\n root: BNode<K>,\n comparator: Comparator<K>,\n): [nodeQueue: BNode<K>[][], nodeIndex: number[], leaf: BNode<K>] | undefined {\n let nextNode = root;\n const nodeQueue: BNode<K>[][] = [];\n const nodeIndex: number[] = [];\n\n if (nextNode.isInternal()) {\n for (let d = 0; nextNode.isInternal(); d++) {\n nodeQueue[d] = nextNode.children;\n nodeIndex[d] =\n key === undefined ? 0 : indexOf(key, nextNode.keys, 0, comparator);\n if (nodeIndex[d] >= nodeQueue[d].length) return; // first key > maxKey()\n nextNode = nodeQueue[d][nodeIndex[d]];\n }\n nodeQueue.reverse();\n nodeIndex.reverse();\n }\n return [nodeQueue, nodeIndex, nextNode];\n}\n\nfunction iterator<T>(next: () => IteratorResult<T>): IterableIterator<T> {\n return {\n next,\n [Symbol.iterator]() {\n return this;\n },\n };\n}\n\n/** Leaf node / base class. **************************************************/\nclass BNode<K> {\n // If this is an internal node, _keys[i] is the highest key in children[i].\n keys: K[];\n // True if this node might be within multiple `BTree`s (or have multiple parents).\n // If so, it must be cloned before being mutated to avoid changing an unrelated tree.\n // This is transitive: if it's true, children are also shared even if `isShared!=true`\n // in those children. (Certain operations will propagate isShared=true to children.)\n isShared: true | undefined;\n\n constructor(keys: K[]) {\n this.keys = keys;\n this.isShared = undefined;\n }\n\n isInternal(): this is BNodeInternal<K> {\n return false;\n }\n\n maxKey() {\n return this.keys[this.keys.length - 1];\n }\n\n minKey(): K | undefined {\n return this.keys[0];\n }\n\n clone(): BNode<K> {\n return new BNode<K>(this.keys.slice(0));\n }\n\n get(key: K, tree: BTreeSet<K>): K | undefined {\n const i = indexOf(key, this.keys, -1, tree.comparator);\n return i < 0 ? undefined : this.keys[i];\n }\n\n has(key: K, tree: BTreeSet<K>): boolean {\n const i = indexOf(key, this.keys, -1, tree.comparator);\n return i >= 0 && i < this.keys.length;\n }\n\n set(key: K, tree: BTreeSet<K>): null | BNode<K> {\n let i = indexOf(key, this.keys, -1, tree.comparator);\n if (i < 0) {\n // key does not exist yet\n i = ~i;\n tree.size++;\n\n if (this.keys.length < MAX_NODE_SIZE) {\n this.keys.splice(i, 0, key);\n return null;\n }\n // This leaf node is full and must split\n const newRightSibling = this.splitOffRightSide();\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n let target: BNode<K> = this;\n if (i > this.keys.length) {\n i -= this.keys.length;\n target = newRightSibling;\n }\n // target.#insertInLeaf(i, key);\n target.keys.splice(i, 0, key);\n\n return newRightSibling;\n }\n\n // usually this is a no-op, but some users may wish to edit the key\n this.keys[i] = key;\n return null;\n }\n\n takeFromRight(rhs: BNode<K>) {\n this.keys.push(rhs.keys.shift()!);\n }\n\n takeFromLeft(lhs: BNode<K>) {\n this.keys.unshift(lhs.keys.pop()!);\n }\n\n splitOffRightSide(): BNode<K> {\n const half = this.keys.length >> 1;\n const keys = this.keys.splice(half);\n return new BNode<K>(keys);\n }\n\n delete(key: K, tree: BTreeSet<K>): boolean {\n const cmp = tree.comparator;\n const iLow = indexOf(key, this.keys, -1, cmp);\n const iHigh = iLow + 1;\n\n if (iLow < 0) {\n return false;\n }\n\n const {keys} = this;\n for (let i = iLow; i < iHigh; i++) {\n const key = keys[i];\n\n if (key !== keys[i] || this.isShared === true) {\n throw new Error('BTree illegally changed or cloned in delete');\n }\n\n this.keys.splice(i, 1);\n tree.size--;\n return true;\n }\n\n return false;\n }\n\n mergeSibling(rhs: BNode<K>, _: number) {\n this.keys.push(...rhs.keys);\n }\n}\n\n/** Internal node (non-leaf node) ********************************************/\nclass BNodeInternal<K> extends BNode<K> {\n // Note: conventionally B+ trees have one fewer key than the number of\n // children, but I find it easier to keep the array lengths equal: each\n // keys[i] caches the value of children[i].maxKey().\n children: BNode<K>[];\n\n /**\n * This does not mark `children` as shared, so it is the responsibility of the caller\n * to ensure children are either marked shared, or aren't included in another tree.\n */\n constructor(children: BNode<K>[], keys?: K[]) {\n if (!keys) {\n keys = [];\n for (let i = 0; i < children.length; i++) {\n keys[i] = children[i].maxKey();\n }\n }\n super(keys);\n this.children = children;\n }\n\n isInternal(): this is BNodeInternal<K> {\n return true;\n }\n\n clone(): BNode<K> {\n const children = this.children.slice(0);\n for (let i = 0; i < children.length; i++) {\n children[i].isShared = true;\n }\n return new BNodeInternal<K>(children, this.keys.slice(0));\n }\n\n minKey() {\n return this.children[0].minKey();\n }\n\n get(key: K, tree: BTreeSet<K>): K | undefined {\n const i = indexOf(key, this.keys, 0, tree.comparator);\n const {children} = this;\n return i < children.length ? children[i].get(key, tree) : undefined;\n }\n\n has(key: K, tree: BTreeSet<K>): boolean {\n const i = indexOf(key, this.keys, 0, tree.comparator);\n const {children} = this;\n return i < children.length ? children[i].has(key, tree) : false;\n }\n\n set(key: K, tree: BTreeSet<K>): null | BNode<K> {\n const c = this.children;\n const cmp = tree.comparator;\n let i = Math.min(indexOf(key, this.keys, 0, cmp), c.length - 1);\n let child = c[i];\n\n if (child.isShared) {\n c[i] = child = child.clone();\n }\n if (child.keys.length >= MAX_NODE_SIZE) {\n // child is full; inserting anything else will cause a split.\n // Shifting an item to the left or right sibling may avoid a split.\n // We can do a shift if the adjacent node is not full and if the\n // current key can still be placed in the same node after the shift.\n let other: BNode<K>;\n if (\n i > 0 &&\n (other = c[i - 1]).keys.length < MAX_NODE_SIZE &&\n cmp(child.keys[0], key) < 0\n ) {\n if (other.isShared) {\n c[i - 1] = other = other.clone();\n }\n other.takeFromRight(child);\n this.keys[i - 1] = other.maxKey();\n } else if (\n (other = c[i + 1]) !== undefined &&\n other.keys.length < MAX_NODE_SIZE &&\n cmp(child.maxKey(), key) < 0\n ) {\n if (other.isShared) c[i + 1] = other = other.clone();\n other.takeFromLeft(child);\n this.keys[i] = c[i].maxKey();\n }\n }\n\n const result = child.set(key, tree);\n this.keys[i] = child.maxKey();\n if (result === null) return null;\n\n // The child has split and `result` is a new right child... does it fit?\n if (this.keys.length < MAX_NODE_SIZE) {\n // yes\n this.insert(i + 1, result);\n return null;\n }\n // no, we must split also\n const newRightSibling = this.splitOffRightSide();\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n let target: BNodeInternal<K> = this;\n if (cmp(result.maxKey(), this.maxKey()) > 0) {\n target = newRightSibling;\n i -= this.keys.length;\n }\n target.insert(i + 1, result);\n return newRightSibling;\n }\n\n /**\n * Inserts `child` at index `i`.\n * This does not mark `child` as shared, so it is the responsibility of the caller\n * to ensure that either child is marked shared, or it is not included in another tree.\n */\n insert(i: number, child: BNode<K>) {\n this.children.splice(i, 0, child);\n this.keys.splice(i, 0, child.maxKey());\n }\n\n /**\n * Split this node.\n * Modifies this to remove the second half of the items, returning a separate node containing them.\n */\n splitOffRightSide() {\n const half = this.children.length >> 1;\n return new BNodeInternal<K>(\n this.children.splice(half),\n this.keys.splice(half),\n );\n }\n\n takeFromRight(rhs: BNode<K>) {\n this.keys.push(rhs.keys.shift()!);\n this.children.push((rhs as BNodeInternal<K>).children.shift()!);\n }\n\n takeFromLeft(lhs: BNode<K>) {\n this.keys.unshift(lhs.keys.pop()!);\n this.children.unshift((lhs as BNodeInternal<K>).children.pop()!);\n }\n\n delete(key: K, tree: BTreeSet<K>): boolean {\n const cmp = tree.comparator;\n const {keys} = this;\n const {children} = this;\n let iLow = indexOf(key, this.keys, 0, cmp);\n let i = iLow;\n const iHigh = Math.min(iLow, keys.length - 1);\n if (i <= iHigh) {\n try {\n if (children[i].isShared) {\n children[i] = children[i].clone();\n }\n const result = children[i].delete(key, tree);\n // Note: if children[i] is empty then keys[i]=undefined.\n // This is an invalid state, but it is fixed below.\n keys[i] = children[i].maxKey();\n return result;\n } finally {\n // Deletions may have occurred, so look for opportunities to merge nodes.\n const half = MAX_NODE_SIZE >> 1;\n if (iLow > 0) iLow--;\n for (i = iHigh; i >= iLow; i--) {\n if (children[i].keys.length <= half) {\n if (children[i].keys.length !== 0) {\n this.tryMerge(i, MAX_NODE_SIZE);\n } else {\n // child is empty! delete it!\n keys.splice(i, 1);\n children.splice(i, 1);\n }\n }\n }\n }\n }\n return false;\n }\n\n /** Merges child i with child i+1 if their combined size is not too large */\n tryMerge(i: number, maxSize: number): boolean {\n const {children} = this;\n if (i >= 0 && i + 1 < children.length) {\n if (children[i].keys.length + children[i + 1].keys.length <= maxSize) {\n if (children[i].isShared)\n // cloned already UNLESS i is outside scan range\n children[i] = children[i].clone();\n children[i].mergeSibling(children[i + 1], maxSize);\n children.splice(i + 1, 1);\n this.keys.splice(i + 1, 1);\n this.keys[i] = children[i].maxKey();\n return true;\n }\n }\n return false;\n }\n\n /**\n * Move children from `rhs` into this.\n * `rhs` must be part of this tree, and be removed from it after this call\n * (otherwise isShared for its children could be incorrect).\n */\n mergeSibling(rhs: BNode<K>, maxNodeSize: number) {\n // assert !this.isShared;\n const oldLength = this.keys.length;\n this.keys.push(...rhs.keys);\n const rhsChildren = (rhs as unknown as BNodeInternal<K>).children;\n this.children.push(...rhsChildren);\n\n if (rhs.isShared && !this.isShared) {\n // All children of a shared node are implicitly shared, and since their new\n // parent is not shared, they must now be explicitly marked as shared.\n for (let i = 0; i < rhsChildren.length; i++) {\n rhsChildren[i].isShared = true;\n }\n }\n\n // If our children are themselves almost empty due to a mass-delete,\n // they may need to be merged too (but only the oldLength-1 and its\n // right sibling should need this).\n this.tryMerge(oldLength - 1, maxNodeSize);\n }\n}\n\n// If key not found, returns i^failXor where i is the insertion index.\n// Callers that don't care whether there was a match will set failXor=0.\nfunction indexOf<K>(\n key: K,\n keys: K[],\n failXor: number,\n comparator: Comparator<K>,\n): number {\n let lo = 0;\n let hi = keys.length;\n let mid = hi >> 1;\n while (lo < hi) {\n const c = comparator(keys[mid], key);\n if (c < 0) {\n lo = mid + 1;\n } else if (c > 0) {\n // key < keys[mid]\n hi = mid;\n } else if (c === 0) {\n return mid;\n } else {\n // c is NaN or otherwise invalid\n if (key === key) {\n // at least the search key is not NaN\n return keys.length;\n }\n throw new Error('NaN was used as a key');\n }\n mid = (lo + hi) >> 1;\n }\n return mid ^ failXor;\n}\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\nconst emptyLeaf = new BNode<any>([]);\nemptyLeaf.isShared = true;\n"],"names":["key"],"mappings":"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"}
@@ -103,7 +103,7 @@ function parseOptionsAdvanced(appOptions, opts = {}) {
103
103
  if (terminalTypes.size > 1) {
104
104
  throw new TypeError(`${env} has mixed types ${[...terminalTypes]}`);
105
105
  }
106
- assert(terminalTypes.size === 1);
106
+ assert(terminalTypes.size === 1, "Expected exactly one terminal type");
107
107
  const terminalType = [...terminalTypes][0];
108
108
  if (processEnv[env]) {
109
109
  if (multiple) {
@@ -1 +1 @@
1
- {"version":3,"file":"options.js","sources":["../../../../shared/src/options.ts"],"sourcesContent":["import type {OptionalLogger} from '@rocicorp/logger';\nimport {template} from 'chalk-template';\nimport type {OptionDefinition} from 'command-line-args';\nimport commandLineArgs from 'command-line-args';\nimport commandLineUsage, {type Section} from 'command-line-usage';\nimport {createDefu} from 'defu';\nimport {toKebabCase, toSnakeCase} from 'kasi';\nimport {stripVTControlCharacters as stripAnsi} from 'node:util';\nimport {assert} from './asserts.ts';\nimport {must} from './must.ts';\nimport type {\n Config,\n Group,\n Option,\n Options,\n WrappedOptionType,\n} from './options-types.ts';\nimport * as v from './valita.ts';\n\nexport type {Config, Group, Option, Options, WrappedOptionType};\n\ntype Primitive = number | string | boolean;\ntype Value = Primitive | Array<Primitive>;\n\ntype RequiredOptionType =\n | v.Type<string>\n | v.Type<number>\n | v.Type<boolean>\n | v.Type<string[]>\n | v.Type<number[]>\n | v.Type<boolean[]>;\n\ntype OptionalOptionType =\n | v.Optional<string>\n | v.Optional<number>\n | v.Optional<boolean>\n | v.Optional<string[]>\n | v.Optional<number[]>\n | v.Optional<boolean[]>;\n\ntype OptionType = RequiredOptionType | OptionalOptionType;\n\n/**\n * Creates a defu instance that overrides arrays instead of merging them.\n */\nconst defu = createDefu((obj, key, value) => {\n if (!Array.isArray(value)) return;\n\n obj[key] = value;\n return true;\n});\n\n/**\n * Converts an Options instance into its corresponding {@link Config} schema.\n */\nfunction configSchema<T extends Options>(\n options: T,\n envNamePrefix: string,\n): v.Type<Config<T>> {\n function makeObjectType(options: Options | Group, group?: string) {\n return v.object(\n Object.fromEntries(\n Object.entries(options).map(\n ([name, value]): [string, OptionType | v.Type] => {\n const addErrorMessage = (t: OptionType) => {\n const {required} = getRequiredOrDefault(t);\n if (required) {\n // Adds an error message for required options that includes the\n // actual name of the option.\n const optionName = toSnakeCase(\n `${envNamePrefix}${group ? group + '_' : ''}${name}`,\n ).toUpperCase();\n return (t as v.Type<string>)\n .optional()\n .assert(\n val => val !== undefined,\n `Missing required option ${optionName}`,\n );\n }\n return t;\n };\n // OptionType\n if (v.instanceOfAbstractType(value)) {\n return [name, addErrorMessage(value)];\n }\n // WrappedOptionType\n const {type} = value;\n if (v.instanceOfAbstractType(type)) {\n return [name, addErrorMessage(type)];\n }\n // OptionGroup\n return [name, makeObjectType(value as Group, name)];\n },\n ),\n ),\n );\n }\n return makeObjectType(options) as v.Type<Config<T>>;\n}\n\n/**\n * Converts an Options instance into an \"env schema\", which is an object with\n * ENV names as its keys, mapped to optional or required string values\n * (corresponding to the optionality of the corresponding options).\n *\n * This is used as a format for encoding options for a multi-tenant version\n * of an app, with an envSchema for each tenant.\n */\nexport function envSchema<T extends Options>(options: T, envNamePrefix = '') {\n const fields: [string, v.Type<string> | v.Optional<string>][] = [];\n\n function addField(name: string, type: OptionType, group?: string) {\n const flag = group ? `${group}_${name}` : name;\n const env = toSnakeCase(`${envNamePrefix}${flag}`).toUpperCase();\n\n const {required} = getRequiredOrDefault(type);\n fields.push([env, required ? v.string() : v.string().optional()]);\n }\n\n function addFields(o: Options | Group, group?: string) {\n Object.entries(o).forEach(([name, value]) => {\n // OptionType\n if (v.instanceOfAbstractType(value)) {\n addField(name, value, group);\n return;\n }\n // WrappedOptionType\n const {type} = value;\n if (v.instanceOfAbstractType(type)) {\n addField(name, type, group);\n return;\n }\n // OptionGroup\n addFields(value as Group, name);\n });\n }\n\n addFields(options);\n\n return v.object(Object.fromEntries(fields));\n}\n\n// type TerminalType is not exported from badrap/valita\ntype TerminalType = Parameters<\n Parameters<v.Type<unknown>['toTerminals']>[0]\n>[0];\n\nfunction getRequiredOrDefault(type: OptionType) {\n const defaultResult = v.testOptional<Value>(undefined, type);\n return {\n required: !defaultResult.ok,\n defaultValue: defaultResult.ok ? defaultResult.value : undefined,\n };\n}\n\nexport type ParseOptions = {\n /** Defaults to process.argv.slice(2) */\n argv?: string[];\n\n envNamePrefix?: string;\n\n description?: {header: string; content: string}[];\n\n /** Defaults to `false` */\n allowUnknown?: boolean;\n\n /** Defaults to `false` */\n allowPartial?: boolean;\n\n /** Defaults to `process.env`. */\n env?: NodeJS.ProcessEnv;\n\n /** Defaults to `true`. */\n emitDeprecationWarnings?: boolean;\n\n /** Defaults to `true`. When false, excludes default values from both config and env return values. */\n includeDefaults?: boolean;\n\n /** Defaults to `console` */\n logger?: OptionalLogger;\n\n /** Defaults to `process.exit` */\n exit?: (code?: number | string | null) => never;\n};\n\nexport function parseOptions<T extends Options>(\n appOptions: T,\n opts: ParseOptions = {},\n): Config<T> {\n return parseOptionsAdvanced(appOptions, opts).config;\n}\n\nexport function parseOptionsAdvanced<T extends Options>(\n appOptions: T,\n opts: ParseOptions = {},\n): {config: Config<T>; env: Record<string, string>; unknown?: string[]} {\n const {\n argv = process.argv.slice(2),\n envNamePrefix = '',\n description = [],\n allowUnknown = false,\n allowPartial = false,\n env: processEnv = process.env,\n emitDeprecationWarnings = true,\n includeDefaults = true,\n logger = console,\n exit = process.exit,\n } = opts;\n // The main logic for converting a valita Type spec to an Option (i.e. flag) spec.\n function addOption(field: string, option: WrappedOptionType, group?: string) {\n const {type, desc = [], deprecated, alias, hidden} = option;\n\n // The group name is prepended to the flag name.\n const flag = group ? toKebabCase(`${group}-${field}`) : toKebabCase(field);\n\n const {required, defaultValue} = getRequiredOrDefault(type);\n let multiple = type.name === 'array';\n const literals = new Set<string>();\n const terminalTypes = new Set<string>();\n\n type.toTerminals(getTerminalTypes);\n\n function getTerminalTypes(t: TerminalType) {\n switch (t.name) {\n case 'undefined':\n case 'optional':\n break;\n case 'array': {\n multiple = true;\n t.prefix.forEach(t => t.toTerminals(getTerminalTypes));\n t.rest?.toTerminals(getTerminalTypes);\n t.suffix.forEach(t => t.toTerminals(getTerminalTypes));\n break;\n }\n case 'literal':\n literals.add(String(t.value));\n terminalTypes.add(typeof t.value);\n break;\n default:\n terminalTypes.add(t.name);\n break;\n }\n }\n const env = toSnakeCase(`${envNamePrefix}${flag}`).toUpperCase();\n if (terminalTypes.size > 1) {\n throw new TypeError(`${env} has mixed types ${[...terminalTypes]}`);\n }\n assert(terminalTypes.size === 1);\n const terminalType = [...terminalTypes][0];\n\n if (processEnv[env]) {\n if (multiple) {\n // Technically not water-tight; assumes values for the string[] flag don't contain commas.\n envArgv.push(`--${flag}`, ...processEnv[env].split(','));\n } else {\n envArgv.push(`--${flag}`, processEnv[env]);\n }\n }\n names.set(flag, {field, env});\n\n const spec = [\n (required\n ? '{italic required}'\n : defaultValue !== undefined\n ? `default: ${JSON.stringify(defaultValue)}`\n : 'optional') + '\\n',\n ];\n if (desc) {\n spec.push(...desc);\n }\n\n const typeLabel = [\n literals.size\n ? String([...literals].map(l => `{underline ${l}}`))\n : multiple\n ? `{underline ${terminalType}[]}`\n : `{underline ${terminalType}}`,\n ` ${env} env`,\n ];\n\n const opt = {\n name: flag,\n alias,\n type: valueParser(\n env,\n terminalType,\n logger,\n emitDeprecationWarnings ? deprecated : undefined,\n ),\n multiple,\n group,\n description: spec.join('\\n') + '\\n',\n typeLabel: typeLabel.join('\\n') + '\\n',\n hidden: hidden === undefined ? deprecated !== undefined : hidden,\n };\n optsWithoutDefaults.push(opt);\n optsWithDefaults.push({...opt, defaultValue});\n }\n\n const names = new Map<string, {field: string; env: string}>();\n const optsWithDefaults: DescribedOptionDefinition[] = [];\n const optsWithoutDefaults: DescribedOptionDefinition[] = [];\n const envArgv: string[] = [];\n\n try {\n for (const [name, val] of Object.entries(appOptions)) {\n const {type} = val as {type: unknown};\n if (v.instanceOfAbstractType(val)) {\n addOption(name, {type: val});\n } else if (v.instanceOfAbstractType(type)) {\n addOption(name, val as WrappedOptionType);\n } else {\n const group = name;\n for (const [name, option] of Object.entries(val as Group)) {\n const wrapped = v.instanceOfAbstractType(option)\n ? {type: option}\n : option;\n addOption(name, wrapped, group);\n }\n }\n }\n\n const [defaults, env1, unknown] = parseArgs(optsWithDefaults, argv, names);\n const [fromEnv, env2] = parseArgs(optsWithoutDefaults, envArgv, names);\n const [withoutDefaults, env3] = parseArgs(optsWithoutDefaults, argv, names);\n\n switch (unknown?.[0]) {\n case undefined:\n break;\n case '--help':\n case '-h':\n showUsage(optsWithDefaults, description, logger);\n exit(0);\n break;\n default:\n if (!allowUnknown) {\n logger.error?.('Invalid arguments:', unknown);\n showUsage(optsWithDefaults, description, logger);\n exit(0);\n }\n break;\n }\n\n const parsedArgs = includeDefaults\n ? defu(withoutDefaults, fromEnv, defaults)\n : defu(withoutDefaults, fromEnv);\n const env = includeDefaults\n ? {...env1, ...env2, ...env3}\n : {...env2, ...env3};\n\n let schema = configSchema(appOptions, envNamePrefix);\n if (allowPartial || !includeDefaults) {\n // TODO: Type configSchema() to return a v.ObjectType<...>\n schema = v.deepPartial(schema as v.ObjectType) as v.Type<Config<T>>;\n }\n return {\n config: v.parse(parsedArgs, schema),\n env,\n ...(unknown ? {unknown} : {}),\n };\n } catch (e) {\n logger.error?.(String(e));\n showUsage(optsWithDefaults, description, logger);\n throw e;\n }\n}\n\nfunction valueParser(\n optionName: string,\n typeName: string,\n logger: OptionalLogger,\n deprecated: string[] | undefined,\n) {\n return (input: string) => {\n if (deprecated) {\n logger.warn?.(\n template(\n `\\n${optionName} is deprecated:\\n` + deprecated.join('\\n') + '\\n',\n ),\n );\n }\n switch (typeName) {\n case 'string':\n return input;\n case 'boolean':\n return parseBoolean(optionName, input);\n case 'number': {\n const val = Number(input);\n if (Number.isNaN(val)) {\n throw new TypeError(`Invalid input for ${optionName}: \"${input}\"`);\n }\n return val;\n }\n default:\n // Should be impossible given the constraints of `Option`\n throw new TypeError(\n `${optionName} option has unsupported type ${typeName}`,\n );\n }\n };\n}\n\nfunction parseArgs(\n optionDefs: DescribedOptionDefinition[],\n argv: string[],\n names: Map<string, {field: string; env: string}>,\n) {\n function normalizeFlagValue(value: unknown) {\n // A --flag without value is parsed by commandLineArgs() to `null`,\n // but this is a common convention to set a boolean flag to true.\n return value === null ? true : value;\n }\n\n const {\n _all,\n _none: ungrouped,\n _unknown: unknown,\n ...config\n } = commandLineArgs(optionDefs, {\n argv,\n partial: true,\n });\n\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n const result: Record<string, any> = {};\n const envObj: Record<string, string> = {};\n\n function addFlag(flagName: string, value: unknown, group?: string) {\n const {field, env} = must(names.get(flagName));\n const normalized = normalizeFlagValue(value);\n if (group) {\n result[group][field] = normalized;\n } else {\n result[field] = normalized;\n }\n envObj[env] = String(normalized);\n }\n\n for (const [flagName, value] of Object.entries(ungrouped ?? {})) {\n addFlag(flagName, value);\n }\n\n // Then handle (potentially) grouped flags\n for (const [name, value] of Object.entries(config)) {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n addFlag(name, value); // Flag, not a group\n } else {\n const group = name;\n result[group] = {};\n for (const [flagName, flagValue] of Object.entries(value)) {\n addFlag(flagName, flagValue, group);\n }\n }\n }\n\n return [result, envObj, unknown] as const;\n}\n\nexport function flagToEnv(prefix: string, flag: string): string {\n return toSnakeCase(prefix + flag).toUpperCase();\n}\n\nexport function parseBoolean(optionName: string, input: string) {\n const bool = input.toLowerCase();\n if (['true', '1'].includes(bool)) {\n return true;\n } else if (['false', '0'].includes(bool)) {\n return false;\n }\n throw new TypeError(`Invalid input for ${optionName}: \"${input}\"`);\n}\n\nfunction showUsage(\n optionList: DescribedOptionDefinition[],\n description: {header: string; content: string}[] = [],\n logger: OptionalLogger = console,\n) {\n const hide: string[] = [];\n let leftWidth = 35;\n let rightWidth = 70;\n optionList.forEach(({name, typeLabel, description, hidden}) => {\n if (hidden) {\n hide.push(name);\n }\n const text = template(`${name} ${typeLabel ?? ''}`);\n const lines = stripAnsi(text).split('\\n');\n for (const l of lines) {\n leftWidth = Math.max(leftWidth, l.length + 2);\n }\n const desc = stripAnsi(template(description ?? '')).split('\\n');\n for (const l of desc) {\n rightWidth = Math.max(rightWidth, l.length + 2);\n }\n });\n\n const sections: Section[] = [\n {\n optionList,\n reverseNameOrder: true, // Display --flag-name before -alias\n hide,\n tableOptions: {\n columns: [\n {name: 'option', width: leftWidth},\n {name: 'description', width: rightWidth},\n ],\n noTrim: true,\n },\n },\n ];\n\n if (description) {\n sections.unshift(...description);\n }\n\n logger.info?.(commandLineUsage(sections));\n}\n\ntype DescribedOptionDefinition = OptionDefinition & {\n // Additional fields recognized by command-line-usage\n description?: string;\n typeLabel?: string | undefined;\n hidden?: boolean | undefined;\n};\n"],"names":["options","v.object","v.instanceOfAbstractType","v.testOptional","t","name","v.deepPartial","v.parse","description","stripAnsi"],"mappings":"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"}
1
+ {"version":3,"file":"options.js","sources":["../../../../shared/src/options.ts"],"sourcesContent":["import type {OptionalLogger} from '@rocicorp/logger';\nimport {template} from 'chalk-template';\nimport type {OptionDefinition} from 'command-line-args';\nimport commandLineArgs from 'command-line-args';\nimport commandLineUsage, {type Section} from 'command-line-usage';\nimport {createDefu} from 'defu';\nimport {toKebabCase, toSnakeCase} from 'kasi';\nimport {stripVTControlCharacters as stripAnsi} from 'node:util';\nimport {assert} from './asserts.ts';\nimport {must} from './must.ts';\nimport type {\n Config,\n Group,\n Option,\n Options,\n WrappedOptionType,\n} from './options-types.ts';\nimport * as v from './valita.ts';\n\nexport type {Config, Group, Option, Options, WrappedOptionType};\n\ntype Primitive = number | string | boolean;\ntype Value = Primitive | Array<Primitive>;\n\ntype RequiredOptionType =\n | v.Type<string>\n | v.Type<number>\n | v.Type<boolean>\n | v.Type<string[]>\n | v.Type<number[]>\n | v.Type<boolean[]>;\n\ntype OptionalOptionType =\n | v.Optional<string>\n | v.Optional<number>\n | v.Optional<boolean>\n | v.Optional<string[]>\n | v.Optional<number[]>\n | v.Optional<boolean[]>;\n\ntype OptionType = RequiredOptionType | OptionalOptionType;\n\n/**\n * Creates a defu instance that overrides arrays instead of merging them.\n */\nconst defu = createDefu((obj, key, value) => {\n if (!Array.isArray(value)) return;\n\n obj[key] = value;\n return true;\n});\n\n/**\n * Converts an Options instance into its corresponding {@link Config} schema.\n */\nfunction configSchema<T extends Options>(\n options: T,\n envNamePrefix: string,\n): v.Type<Config<T>> {\n function makeObjectType(options: Options | Group, group?: string) {\n return v.object(\n Object.fromEntries(\n Object.entries(options).map(\n ([name, value]): [string, OptionType | v.Type] => {\n const addErrorMessage = (t: OptionType) => {\n const {required} = getRequiredOrDefault(t);\n if (required) {\n // Adds an error message for required options that includes the\n // actual name of the option.\n const optionName = toSnakeCase(\n `${envNamePrefix}${group ? group + '_' : ''}${name}`,\n ).toUpperCase();\n return (t as v.Type<string>)\n .optional()\n .assert(\n val => val !== undefined,\n `Missing required option ${optionName}`,\n );\n }\n return t;\n };\n // OptionType\n if (v.instanceOfAbstractType(value)) {\n return [name, addErrorMessage(value)];\n }\n // WrappedOptionType\n const {type} = value;\n if (v.instanceOfAbstractType(type)) {\n return [name, addErrorMessage(type)];\n }\n // OptionGroup\n return [name, makeObjectType(value as Group, name)];\n },\n ),\n ),\n );\n }\n return makeObjectType(options) as v.Type<Config<T>>;\n}\n\n/**\n * Converts an Options instance into an \"env schema\", which is an object with\n * ENV names as its keys, mapped to optional or required string values\n * (corresponding to the optionality of the corresponding options).\n *\n * This is used as a format for encoding options for a multi-tenant version\n * of an app, with an envSchema for each tenant.\n */\nexport function envSchema<T extends Options>(options: T, envNamePrefix = '') {\n const fields: [string, v.Type<string> | v.Optional<string>][] = [];\n\n function addField(name: string, type: OptionType, group?: string) {\n const flag = group ? `${group}_${name}` : name;\n const env = toSnakeCase(`${envNamePrefix}${flag}`).toUpperCase();\n\n const {required} = getRequiredOrDefault(type);\n fields.push([env, required ? v.string() : v.string().optional()]);\n }\n\n function addFields(o: Options | Group, group?: string) {\n Object.entries(o).forEach(([name, value]) => {\n // OptionType\n if (v.instanceOfAbstractType(value)) {\n addField(name, value, group);\n return;\n }\n // WrappedOptionType\n const {type} = value;\n if (v.instanceOfAbstractType(type)) {\n addField(name, type, group);\n return;\n }\n // OptionGroup\n addFields(value as Group, name);\n });\n }\n\n addFields(options);\n\n return v.object(Object.fromEntries(fields));\n}\n\n// type TerminalType is not exported from badrap/valita\ntype TerminalType = Parameters<\n Parameters<v.Type<unknown>['toTerminals']>[0]\n>[0];\n\nfunction getRequiredOrDefault(type: OptionType) {\n const defaultResult = v.testOptional<Value>(undefined, type);\n return {\n required: !defaultResult.ok,\n defaultValue: defaultResult.ok ? defaultResult.value : undefined,\n };\n}\n\nexport type ParseOptions = {\n /** Defaults to process.argv.slice(2) */\n argv?: string[];\n\n envNamePrefix?: string;\n\n description?: {header: string; content: string}[];\n\n /** Defaults to `false` */\n allowUnknown?: boolean;\n\n /** Defaults to `false` */\n allowPartial?: boolean;\n\n /** Defaults to `process.env`. */\n env?: NodeJS.ProcessEnv;\n\n /** Defaults to `true`. */\n emitDeprecationWarnings?: boolean;\n\n /** Defaults to `true`. When false, excludes default values from both config and env return values. */\n includeDefaults?: boolean;\n\n /** Defaults to `console` */\n logger?: OptionalLogger;\n\n /** Defaults to `process.exit` */\n exit?: (code?: number | string | null) => never;\n};\n\nexport function parseOptions<T extends Options>(\n appOptions: T,\n opts: ParseOptions = {},\n): Config<T> {\n return parseOptionsAdvanced(appOptions, opts).config;\n}\n\nexport function parseOptionsAdvanced<T extends Options>(\n appOptions: T,\n opts: ParseOptions = {},\n): {config: Config<T>; env: Record<string, string>; unknown?: string[]} {\n const {\n argv = process.argv.slice(2),\n envNamePrefix = '',\n description = [],\n allowUnknown = false,\n allowPartial = false,\n env: processEnv = process.env,\n emitDeprecationWarnings = true,\n includeDefaults = true,\n logger = console,\n exit = process.exit,\n } = opts;\n // The main logic for converting a valita Type spec to an Option (i.e. flag) spec.\n function addOption(field: string, option: WrappedOptionType, group?: string) {\n const {type, desc = [], deprecated, alias, hidden} = option;\n\n // The group name is prepended to the flag name.\n const flag = group ? toKebabCase(`${group}-${field}`) : toKebabCase(field);\n\n const {required, defaultValue} = getRequiredOrDefault(type);\n let multiple = type.name === 'array';\n const literals = new Set<string>();\n const terminalTypes = new Set<string>();\n\n type.toTerminals(getTerminalTypes);\n\n function getTerminalTypes(t: TerminalType) {\n switch (t.name) {\n case 'undefined':\n case 'optional':\n break;\n case 'array': {\n multiple = true;\n t.prefix.forEach(t => t.toTerminals(getTerminalTypes));\n t.rest?.toTerminals(getTerminalTypes);\n t.suffix.forEach(t => t.toTerminals(getTerminalTypes));\n break;\n }\n case 'literal':\n literals.add(String(t.value));\n terminalTypes.add(typeof t.value);\n break;\n default:\n terminalTypes.add(t.name);\n break;\n }\n }\n const env = toSnakeCase(`${envNamePrefix}${flag}`).toUpperCase();\n if (terminalTypes.size > 1) {\n throw new TypeError(`${env} has mixed types ${[...terminalTypes]}`);\n }\n assert(terminalTypes.size === 1, 'Expected exactly one terminal type');\n const terminalType = [...terminalTypes][0];\n\n if (processEnv[env]) {\n if (multiple) {\n // Technically not water-tight; assumes values for the string[] flag don't contain commas.\n envArgv.push(`--${flag}`, ...processEnv[env].split(','));\n } else {\n envArgv.push(`--${flag}`, processEnv[env]);\n }\n }\n names.set(flag, {field, env});\n\n const spec = [\n (required\n ? '{italic required}'\n : defaultValue !== undefined\n ? `default: ${JSON.stringify(defaultValue)}`\n : 'optional') + '\\n',\n ];\n if (desc) {\n spec.push(...desc);\n }\n\n const typeLabel = [\n literals.size\n ? String([...literals].map(l => `{underline ${l}}`))\n : multiple\n ? `{underline ${terminalType}[]}`\n : `{underline ${terminalType}}`,\n ` ${env} env`,\n ];\n\n const opt = {\n name: flag,\n alias,\n type: valueParser(\n env,\n terminalType,\n logger,\n emitDeprecationWarnings ? deprecated : undefined,\n ),\n multiple,\n group,\n description: spec.join('\\n') + '\\n',\n typeLabel: typeLabel.join('\\n') + '\\n',\n hidden: hidden === undefined ? deprecated !== undefined : hidden,\n };\n optsWithoutDefaults.push(opt);\n optsWithDefaults.push({...opt, defaultValue});\n }\n\n const names = new Map<string, {field: string; env: string}>();\n const optsWithDefaults: DescribedOptionDefinition[] = [];\n const optsWithoutDefaults: DescribedOptionDefinition[] = [];\n const envArgv: string[] = [];\n\n try {\n for (const [name, val] of Object.entries(appOptions)) {\n const {type} = val as {type: unknown};\n if (v.instanceOfAbstractType(val)) {\n addOption(name, {type: val});\n } else if (v.instanceOfAbstractType(type)) {\n addOption(name, val as WrappedOptionType);\n } else {\n const group = name;\n for (const [name, option] of Object.entries(val as Group)) {\n const wrapped = v.instanceOfAbstractType(option)\n ? {type: option}\n : option;\n addOption(name, wrapped, group);\n }\n }\n }\n\n const [defaults, env1, unknown] = parseArgs(optsWithDefaults, argv, names);\n const [fromEnv, env2] = parseArgs(optsWithoutDefaults, envArgv, names);\n const [withoutDefaults, env3] = parseArgs(optsWithoutDefaults, argv, names);\n\n switch (unknown?.[0]) {\n case undefined:\n break;\n case '--help':\n case '-h':\n showUsage(optsWithDefaults, description, logger);\n exit(0);\n break;\n default:\n if (!allowUnknown) {\n logger.error?.('Invalid arguments:', unknown);\n showUsage(optsWithDefaults, description, logger);\n exit(0);\n }\n break;\n }\n\n const parsedArgs = includeDefaults\n ? defu(withoutDefaults, fromEnv, defaults)\n : defu(withoutDefaults, fromEnv);\n const env = includeDefaults\n ? {...env1, ...env2, ...env3}\n : {...env2, ...env3};\n\n let schema = configSchema(appOptions, envNamePrefix);\n if (allowPartial || !includeDefaults) {\n // TODO: Type configSchema() to return a v.ObjectType<...>\n schema = v.deepPartial(schema as v.ObjectType) as v.Type<Config<T>>;\n }\n return {\n config: v.parse(parsedArgs, schema),\n env,\n ...(unknown ? {unknown} : {}),\n };\n } catch (e) {\n logger.error?.(String(e));\n showUsage(optsWithDefaults, description, logger);\n throw e;\n }\n}\n\nfunction valueParser(\n optionName: string,\n typeName: string,\n logger: OptionalLogger,\n deprecated: string[] | undefined,\n) {\n return (input: string) => {\n if (deprecated) {\n logger.warn?.(\n template(\n `\\n${optionName} is deprecated:\\n` + deprecated.join('\\n') + '\\n',\n ),\n );\n }\n switch (typeName) {\n case 'string':\n return input;\n case 'boolean':\n return parseBoolean(optionName, input);\n case 'number': {\n const val = Number(input);\n if (Number.isNaN(val)) {\n throw new TypeError(`Invalid input for ${optionName}: \"${input}\"`);\n }\n return val;\n }\n default:\n // Should be impossible given the constraints of `Option`\n throw new TypeError(\n `${optionName} option has unsupported type ${typeName}`,\n );\n }\n };\n}\n\nfunction parseArgs(\n optionDefs: DescribedOptionDefinition[],\n argv: string[],\n names: Map<string, {field: string; env: string}>,\n) {\n function normalizeFlagValue(value: unknown) {\n // A --flag without value is parsed by commandLineArgs() to `null`,\n // but this is a common convention to set a boolean flag to true.\n return value === null ? true : value;\n }\n\n const {\n _all,\n _none: ungrouped,\n _unknown: unknown,\n ...config\n } = commandLineArgs(optionDefs, {\n argv,\n partial: true,\n });\n\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n const result: Record<string, any> = {};\n const envObj: Record<string, string> = {};\n\n function addFlag(flagName: string, value: unknown, group?: string) {\n const {field, env} = must(names.get(flagName));\n const normalized = normalizeFlagValue(value);\n if (group) {\n result[group][field] = normalized;\n } else {\n result[field] = normalized;\n }\n envObj[env] = String(normalized);\n }\n\n for (const [flagName, value] of Object.entries(ungrouped ?? {})) {\n addFlag(flagName, value);\n }\n\n // Then handle (potentially) grouped flags\n for (const [name, value] of Object.entries(config)) {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n addFlag(name, value); // Flag, not a group\n } else {\n const group = name;\n result[group] = {};\n for (const [flagName, flagValue] of Object.entries(value)) {\n addFlag(flagName, flagValue, group);\n }\n }\n }\n\n return [result, envObj, unknown] as const;\n}\n\nexport function flagToEnv(prefix: string, flag: string): string {\n return toSnakeCase(prefix + flag).toUpperCase();\n}\n\nexport function parseBoolean(optionName: string, input: string) {\n const bool = input.toLowerCase();\n if (['true', '1'].includes(bool)) {\n return true;\n } else if (['false', '0'].includes(bool)) {\n return false;\n }\n throw new TypeError(`Invalid input for ${optionName}: \"${input}\"`);\n}\n\nfunction showUsage(\n optionList: DescribedOptionDefinition[],\n description: {header: string; content: string}[] = [],\n logger: OptionalLogger = console,\n) {\n const hide: string[] = [];\n let leftWidth = 35;\n let rightWidth = 70;\n optionList.forEach(({name, typeLabel, description, hidden}) => {\n if (hidden) {\n hide.push(name);\n }\n const text = template(`${name} ${typeLabel ?? ''}`);\n const lines = stripAnsi(text).split('\\n');\n for (const l of lines) {\n leftWidth = Math.max(leftWidth, l.length + 2);\n }\n const desc = stripAnsi(template(description ?? '')).split('\\n');\n for (const l of desc) {\n rightWidth = Math.max(rightWidth, l.length + 2);\n }\n });\n\n const sections: Section[] = [\n {\n optionList,\n reverseNameOrder: true, // Display --flag-name before -alias\n hide,\n tableOptions: {\n columns: [\n {name: 'option', width: leftWidth},\n {name: 'description', width: rightWidth},\n ],\n noTrim: true,\n },\n },\n ];\n\n if (description) {\n sections.unshift(...description);\n }\n\n logger.info?.(commandLineUsage(sections));\n}\n\ntype DescribedOptionDefinition = OptionDefinition & {\n // Additional fields recognized by command-line-usage\n description?: string;\n typeLabel?: string | undefined;\n hidden?: boolean | undefined;\n};\n"],"names":["options","v.object","v.instanceOfAbstractType","v.testOptional","t","name","v.deepPartial","v.parse","description","stripAnsi"],"mappings":"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"}
@@ -33,7 +33,7 @@ class Queue {
33
33
  * @returns The number of entries deleted.
34
34
  */
35
35
  delete(value) {
36
- assert(value !== void 0);
36
+ assert(value !== void 0, "Queue delete value must not be undefined");
37
37
  let count = 0;
38
38
  for (let i = this.#produced.length - 1; i >= 0; i--) {
39
39
  const p = this.#produced[i];
@@ -1 +1 @@
1
- {"version":3,"file":"queue.js","sources":["../../../../shared/src/queue.ts"],"sourcesContent":["import {resolver, type Resolver} from '@rocicorp/resolver';\nimport {assert} from './asserts.ts';\n\n/**\n * A Queue allows the consumers to await (possibly future) values,\n * and producers to await the consumption of their values.\n */\nexport class Queue<T> {\n // Consumers waiting for entries to be produced.\n readonly #consumers: Consumer<T>[] = [];\n // Produced entries waiting to be consumed.\n readonly #produced: Produced<T>[] = [];\n\n enqueue(value: T): void {\n const consumer = this.#consumers.shift();\n if (consumer) {\n consumer.resolver.resolve(value);\n clearTimeout(consumer.timeoutID);\n return;\n }\n this.#produced.push({value});\n }\n\n enqueueRejection(reason?: unknown): void {\n const consumer = this.#consumers.shift();\n if (consumer) {\n consumer.resolver.reject(reason);\n clearTimeout(consumer.timeoutID);\n return;\n }\n this.#produced.push({rejection: reason});\n }\n\n /**\n * Deletes all unconsumed entries matching the specified `value` based on identity equality.\n * The consumed callback(s) are resolved as if the values were dequeued.\n *\n * Note: deletion of `undefined` values is not supported. This method will assert\n * if `value` is undefined.\n *\n * @returns The number of entries deleted.\n */\n delete(value: T): number {\n assert(value !== undefined);\n\n let count = 0;\n for (let i = this.#produced.length - 1; i >= 0; i--) {\n const p = this.#produced[i];\n if (p.value === value) {\n this.#produced.splice(i, 1);\n count++;\n }\n }\n return count;\n }\n\n /**\n * @param timeoutValue An optional value to resolve if `timeoutMs` is reached.\n * @param timeoutMs The milliseconds after which the `timeoutValue` is resolved\n * if nothing is produced for the consumer.\n * @returns A Promise that resolves to the next enqueued value.\n */\n dequeue(timeoutValue?: T, timeoutMs: number = 0): Promise<T> | T {\n const produced = this.#produced.shift();\n if (produced) {\n return produced.value ?? Promise.reject(produced.rejection);\n }\n const r = resolver<T>();\n const timeoutID =\n timeoutValue === undefined\n ? undefined\n : setTimeout(() => {\n const i = this.#consumers.findIndex(c => c.resolver === r);\n if (i >= 0) {\n const [consumer] = this.#consumers.splice(i, 1);\n consumer.resolver.resolve(timeoutValue);\n }\n }, timeoutMs);\n this.#consumers.push({resolver: r, timeoutID});\n return r.promise;\n }\n\n /**\n * Drains the entire queue.\n *\n * Usage example:\n * ```ts\n * // A consumer that, when awoken, drains\n * // all entries in the queue in order to\n * // process them in a batch.\n * for (;;) {\n * const value = await queue.dequeue();\n * const rest = queue.drain();\n * }\n * ```\n */\n drain(): (T | undefined)[] {\n const ret: (T | undefined)[] = [];\n for (const p of this.#produced) {\n ret.push(p.value);\n }\n this.#produced.length = 0;\n\n return ret;\n }\n\n /**\n * @returns The instantaneous number of outstanding values waiting to be\n * dequeued. Note that if a value was enqueued while a consumer\n * was waiting (with `await dequeue()`), the value is immediately\n * handed to the consumer and the Queue's size remains 0.\n */\n size(): number {\n return this.#produced.length;\n }\n\n asAsyncIterable(cleanup = NOOP): AsyncIterable<T> {\n return {[Symbol.asyncIterator]: () => this.asAsyncIterator(cleanup)};\n }\n\n asAsyncIterator(cleanup = NOOP): AsyncIterator<T> {\n return {\n next: async () => {\n try {\n const value = await this.dequeue();\n return {value};\n } catch (e) {\n cleanup();\n throw e;\n }\n },\n return: value => {\n cleanup();\n return Promise.resolve({value, done: true});\n },\n };\n }\n}\n\nconst NOOP = () => {};\n\ntype Consumer<T> = {\n resolver: Resolver<T>;\n timeoutID: ReturnType<typeof setTimeout> | undefined;\n};\n\ntype Produced<T> =\n | {value: T; rejection?: undefined}\n | {value?: undefined; rejection: unknown};\n"],"names":[],"mappings":";;AAOO,MAAM,MAAS;AAAA;AAAA,EAEX,aAA4B,CAAA;AAAA;AAAA,EAE5B,YAA2B,CAAA;AAAA,EAEpC,QAAQ,OAAgB;AACtB,UAAM,WAAW,KAAK,WAAW,MAAA;AACjC,QAAI,UAAU;AACZ,eAAS,SAAS,QAAQ,KAAK;AAC/B,mBAAa,SAAS,SAAS;AAC/B;AAAA,IACF;AACA,SAAK,UAAU,KAAK,EAAC,MAAA,CAAM;AAAA,EAC7B;AAAA,EAEA,iBAAiB,QAAwB;AACvC,UAAM,WAAW,KAAK,WAAW,MAAA;AACjC,QAAI,UAAU;AACZ,eAAS,SAAS,OAAO,MAAM;AAC/B,mBAAa,SAAS,SAAS;AAC/B;AAAA,IACF;AACA,SAAK,UAAU,KAAK,EAAC,WAAW,QAAO;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAO,OAAkB;AACvB,WAAO,UAAU,MAAS;AAE1B,QAAI,QAAQ;AACZ,aAAS,IAAI,KAAK,UAAU,SAAS,GAAG,KAAK,GAAG,KAAK;AACnD,YAAM,IAAI,KAAK,UAAU,CAAC;AAC1B,UAAI,EAAE,UAAU,OAAO;AACrB,aAAK,UAAU,OAAO,GAAG,CAAC;AAC1B;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,QAAQ,cAAkB,YAAoB,GAAmB;AAC/D,UAAM,WAAW,KAAK,UAAU,MAAA;AAChC,QAAI,UAAU;AACZ,aAAO,SAAS,SAAS,QAAQ,OAAO,SAAS,SAAS;AAAA,IAC5D;AACA,UAAM,IAAI,SAAA;AACV,UAAM,YACJ,iBAAiB,SACb,SACA,WAAW,MAAM;AACf,YAAM,IAAI,KAAK,WAAW,UAAU,CAAA,MAAK,EAAE,aAAa,CAAC;AACzD,UAAI,KAAK,GAAG;AACV,cAAM,CAAC,QAAQ,IAAI,KAAK,WAAW,OAAO,GAAG,CAAC;AAC9C,iBAAS,SAAS,QAAQ,YAAY;AAAA,MACxC;AAAA,IACF,GAAG,SAAS;AAClB,SAAK,WAAW,KAAK,EAAC,UAAU,GAAG,WAAU;AAC7C,WAAO,EAAE;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,QAA2B;AACzB,UAAM,MAAyB,CAAA;AAC/B,eAAW,KAAK,KAAK,WAAW;AAC9B,UAAI,KAAK,EAAE,KAAK;AAAA,IAClB;AACA,SAAK,UAAU,SAAS;AAExB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAe;AACb,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA,EAEA,gBAAgB,UAAU,MAAwB;AAChD,WAAO,EAAC,CAAC,OAAO,aAAa,GAAG,MAAM,KAAK,gBAAgB,OAAO,EAAA;AAAA,EACpE;AAAA,EAEA,gBAAgB,UAAU,MAAwB;AAChD,WAAO;AAAA,MACL,MAAM,YAAY;AAChB,YAAI;AACF,gBAAM,QAAQ,MAAM,KAAK,QAAA;AACzB,iBAAO,EAAC,MAAA;AAAA,QACV,SAAS,GAAG;AACV,kBAAA;AACA,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,MACA,QAAQ,CAAA,UAAS;AACf,gBAAA;AACA,eAAO,QAAQ,QAAQ,EAAC,OAAO,MAAM,MAAK;AAAA,MAC5C;AAAA,IAAA;AAAA,EAEJ;AACF;AAEA,MAAM,OAAO,MAAM;AAAC;"}
1
+ {"version":3,"file":"queue.js","sources":["../../../../shared/src/queue.ts"],"sourcesContent":["import {resolver, type Resolver} from '@rocicorp/resolver';\nimport {assert} from './asserts.ts';\n\n/**\n * A Queue allows the consumers to await (possibly future) values,\n * and producers to await the consumption of their values.\n */\nexport class Queue<T> {\n // Consumers waiting for entries to be produced.\n readonly #consumers: Consumer<T>[] = [];\n // Produced entries waiting to be consumed.\n readonly #produced: Produced<T>[] = [];\n\n enqueue(value: T): void {\n const consumer = this.#consumers.shift();\n if (consumer) {\n consumer.resolver.resolve(value);\n clearTimeout(consumer.timeoutID);\n return;\n }\n this.#produced.push({value});\n }\n\n enqueueRejection(reason?: unknown): void {\n const consumer = this.#consumers.shift();\n if (consumer) {\n consumer.resolver.reject(reason);\n clearTimeout(consumer.timeoutID);\n return;\n }\n this.#produced.push({rejection: reason});\n }\n\n /**\n * Deletes all unconsumed entries matching the specified `value` based on identity equality.\n * The consumed callback(s) are resolved as if the values were dequeued.\n *\n * Note: deletion of `undefined` values is not supported. This method will assert\n * if `value` is undefined.\n *\n * @returns The number of entries deleted.\n */\n delete(value: T): number {\n assert(value !== undefined, 'Queue delete value must not be undefined');\n\n let count = 0;\n for (let i = this.#produced.length - 1; i >= 0; i--) {\n const p = this.#produced[i];\n if (p.value === value) {\n this.#produced.splice(i, 1);\n count++;\n }\n }\n return count;\n }\n\n /**\n * @param timeoutValue An optional value to resolve if `timeoutMs` is reached.\n * @param timeoutMs The milliseconds after which the `timeoutValue` is resolved\n * if nothing is produced for the consumer.\n * @returns A Promise that resolves to the next enqueued value.\n */\n dequeue(timeoutValue?: T, timeoutMs: number = 0): Promise<T> | T {\n const produced = this.#produced.shift();\n if (produced) {\n return produced.value ?? Promise.reject(produced.rejection);\n }\n const r = resolver<T>();\n const timeoutID =\n timeoutValue === undefined\n ? undefined\n : setTimeout(() => {\n const i = this.#consumers.findIndex(c => c.resolver === r);\n if (i >= 0) {\n const [consumer] = this.#consumers.splice(i, 1);\n consumer.resolver.resolve(timeoutValue);\n }\n }, timeoutMs);\n this.#consumers.push({resolver: r, timeoutID});\n return r.promise;\n }\n\n /**\n * Drains the entire queue.\n *\n * Usage example:\n * ```ts\n * // A consumer that, when awoken, drains\n * // all entries in the queue in order to\n * // process them in a batch.\n * for (;;) {\n * const value = await queue.dequeue();\n * const rest = queue.drain();\n * }\n * ```\n */\n drain(): (T | undefined)[] {\n const ret: (T | undefined)[] = [];\n for (const p of this.#produced) {\n ret.push(p.value);\n }\n this.#produced.length = 0;\n\n return ret;\n }\n\n /**\n * @returns The instantaneous number of outstanding values waiting to be\n * dequeued. Note that if a value was enqueued while a consumer\n * was waiting (with `await dequeue()`), the value is immediately\n * handed to the consumer and the Queue's size remains 0.\n */\n size(): number {\n return this.#produced.length;\n }\n\n asAsyncIterable(cleanup = NOOP): AsyncIterable<T> {\n return {[Symbol.asyncIterator]: () => this.asAsyncIterator(cleanup)};\n }\n\n asAsyncIterator(cleanup = NOOP): AsyncIterator<T> {\n return {\n next: async () => {\n try {\n const value = await this.dequeue();\n return {value};\n } catch (e) {\n cleanup();\n throw e;\n }\n },\n return: value => {\n cleanup();\n return Promise.resolve({value, done: true});\n },\n };\n }\n}\n\nconst NOOP = () => {};\n\ntype Consumer<T> = {\n resolver: Resolver<T>;\n timeoutID: ReturnType<typeof setTimeout> | undefined;\n};\n\ntype Produced<T> =\n | {value: T; rejection?: undefined}\n | {value?: undefined; rejection: unknown};\n"],"names":[],"mappings":";;AAOO,MAAM,MAAS;AAAA;AAAA,EAEX,aAA4B,CAAA;AAAA;AAAA,EAE5B,YAA2B,CAAA;AAAA,EAEpC,QAAQ,OAAgB;AACtB,UAAM,WAAW,KAAK,WAAW,MAAA;AACjC,QAAI,UAAU;AACZ,eAAS,SAAS,QAAQ,KAAK;AAC/B,mBAAa,SAAS,SAAS;AAC/B;AAAA,IACF;AACA,SAAK,UAAU,KAAK,EAAC,MAAA,CAAM;AAAA,EAC7B;AAAA,EAEA,iBAAiB,QAAwB;AACvC,UAAM,WAAW,KAAK,WAAW,MAAA;AACjC,QAAI,UAAU;AACZ,eAAS,SAAS,OAAO,MAAM;AAC/B,mBAAa,SAAS,SAAS;AAC/B;AAAA,IACF;AACA,SAAK,UAAU,KAAK,EAAC,WAAW,QAAO;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAO,OAAkB;AACvB,WAAO,UAAU,QAAW,0CAA0C;AAEtE,QAAI,QAAQ;AACZ,aAAS,IAAI,KAAK,UAAU,SAAS,GAAG,KAAK,GAAG,KAAK;AACnD,YAAM,IAAI,KAAK,UAAU,CAAC;AAC1B,UAAI,EAAE,UAAU,OAAO;AACrB,aAAK,UAAU,OAAO,GAAG,CAAC;AAC1B;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,QAAQ,cAAkB,YAAoB,GAAmB;AAC/D,UAAM,WAAW,KAAK,UAAU,MAAA;AAChC,QAAI,UAAU;AACZ,aAAO,SAAS,SAAS,QAAQ,OAAO,SAAS,SAAS;AAAA,IAC5D;AACA,UAAM,IAAI,SAAA;AACV,UAAM,YACJ,iBAAiB,SACb,SACA,WAAW,MAAM;AACf,YAAM,IAAI,KAAK,WAAW,UAAU,CAAA,MAAK,EAAE,aAAa,CAAC;AACzD,UAAI,KAAK,GAAG;AACV,cAAM,CAAC,QAAQ,IAAI,KAAK,WAAW,OAAO,GAAG,CAAC;AAC9C,iBAAS,SAAS,QAAQ,YAAY;AAAA,MACxC;AAAA,IACF,GAAG,SAAS;AAClB,SAAK,WAAW,KAAK,EAAC,UAAU,GAAG,WAAU;AAC7C,WAAO,EAAE;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,QAA2B;AACzB,UAAM,MAAyB,CAAA;AAC/B,eAAW,KAAK,KAAK,WAAW;AAC9B,UAAI,KAAK,EAAE,KAAK;AAAA,IAClB;AACA,SAAK,UAAU,SAAS;AAExB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAe;AACb,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA,EAEA,gBAAgB,UAAU,MAAwB;AAChD,WAAO,EAAC,CAAC,OAAO,aAAa,GAAG,MAAM,KAAK,gBAAgB,OAAO,EAAA;AAAA,EACpE;AAAA,EAEA,gBAAgB,UAAU,MAAwB;AAChD,WAAO;AAAA,MACL,MAAM,YAAY;AAChB,YAAI;AACF,gBAAM,QAAQ,MAAM,KAAK,QAAA;AACzB,iBAAO,EAAC,MAAA;AAAA,QACV,SAAS,GAAG;AACV,kBAAA;AACA,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,MACA,QAAQ,CAAA,UAAS;AACf,gBAAA;AACA,eAAO,QAAQ,QAAQ,EAAC,OAAO,MAAM,MAAK;AAAA,MAC5C;AAAA,IAAA;AAAA,EAEJ;AACF;AAEA,MAAM,OAAO,MAAM;AAAC;"}
@@ -1 +1 @@
1
- {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../../../z2s/src/compiler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAQ7C,OAAO,EAAC,KAAK,SAAS,EAAC,MAAM,0BAA0B,CAAC;AAGxD,OAAO,KAAK,EACV,GAAG,EAEH,kBAAkB,EAElB,WAAW,EAEX,QAAQ,EAER,eAAe,EAEhB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAEL,KAAK,UAAU,EAChB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,gCAAgC,CAAC;AAC3D,OAAO,KAAK,EAEV,YAAY,EACb,MAAM,uCAAuC,CAAC;AAC/C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,2BAA2B,CAAC;AAWtD,KAAK,KAAK,GAAG;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,KAAK,UAAU,GAAG;IAChB,MAAM,EAAE,YAAY,CAAC;IAErB,MAAM,EAAE,UAAU,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAQF,wBAAgB,OAAO,CACrB,YAAY,EAAE,YAAY,EAC1B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,GAAG,EACR,MAAM,CAAC,EAAE,MAAM,GACd,QAAQ,CAgBV;AA4CD,wBAAgB,KAAK,CACnB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,QAAQ,EAAE,OAAO,GAAG,SAAS,GAC5B,QAAQ,CAWV;AAUD,wBAAgB,OAAO,CACrB,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,QAAQ,GAAG,SAAS,EAC7B,KAAK,EAAE,KAAK,GACX,QAAQ,CAqBV;AAoMD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,SAAS,eAAe,EAAE,EACxC,cAAc,EAAE,SAAS,MAAM,EAAE,GAChC,CAAC,UAAU,EAAE,KAAK,KAAK,QAAQ,CAiBjC;AAED,wBAAgB,MAAM,CACpB,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,eAAe,EAC1B,KAAK,EAAE,KAAK,GACX,QAAQ,CAgCV;AAED,wBAAgB,GAAG,CACjB,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,eAAe,EAC1B,KAAK,EAAE,KAAK,GACX,QAAQ,CAMV;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,eAAe,EAC1B,KAAK,EAAE,KAAK,GACX,QAAQ,CAIV;AAwGD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,kBAAkB,GAC/B;IACD,IAAI,EAAE,QAAQ,CAAC;IACf,mBAAmB,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;CAC/D,CA2BA;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,kBAAkB,GAC/B;IACD;QACE,KAAK,EAAE,KAAK,CAAC;QACb,WAAW,EAAE,WAAW,CAAC;QACzB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;KAC3B;IACD;QAAC,KAAK,EAAE,KAAK,CAAC;QAAC,WAAW,EAAE,WAAW,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;KAAC;CACpE,CAmBA;AAiDD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAMhE"}
1
+ {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../../../z2s/src/compiler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAQ7C,OAAO,EAAC,KAAK,SAAS,EAAC,MAAM,0BAA0B,CAAC;AAGxD,OAAO,KAAK,EACV,GAAG,EAEH,kBAAkB,EAElB,WAAW,EAEX,QAAQ,EACR,eAAe,EAEhB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAEL,KAAK,UAAU,EAChB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,gCAAgC,CAAC;AAC3D,OAAO,KAAK,EAEV,YAAY,EACb,MAAM,uCAAuC,CAAC;AAC/C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,2BAA2B,CAAC;AAWtD,KAAK,KAAK,GAAG;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,KAAK,UAAU,GAAG;IAChB,MAAM,EAAE,YAAY,CAAC;IAErB,MAAM,EAAE,UAAU,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAQF,wBAAgB,OAAO,CACrB,YAAY,EAAE,YAAY,EAC1B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,GAAG,EACR,MAAM,CAAC,EAAE,MAAM,GACd,QAAQ,CAgBV;AA4CD,wBAAgB,KAAK,CACnB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,QAAQ,EAAE,OAAO,GAAG,SAAS,GAC5B,QAAQ,CAWV;AAUD,wBAAgB,OAAO,CACrB,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,QAAQ,GAAG,SAAS,EAC7B,KAAK,EAAE,KAAK,GACX,QAAQ,CAqBV;AAuMD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,SAAS,eAAe,EAAE,EACxC,cAAc,EAAE,SAAS,MAAM,EAAE,GAChC,CAAC,UAAU,EAAE,KAAK,KAAK,QAAQ,CAiBjC;AAED,wBAAgB,MAAM,CACpB,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,eAAe,EAC1B,KAAK,EAAE,KAAK,GACX,QAAQ,CAgCV;AAED,wBAAgB,GAAG,CACjB,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,eAAe,EAC1B,KAAK,EAAE,KAAK,GACX,QAAQ,CAMV;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,eAAe,EAC1B,KAAK,EAAE,KAAK,GACX,QAAQ,CAIV;AAwGD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,kBAAkB,GAC/B;IACD,IAAI,EAAE,QAAQ,CAAC;IACf,mBAAmB,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;CAC/D,CA2BA;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,kBAAkB,GAC/B;IACD;QACE,KAAK,EAAE,KAAK,CAAC;QACb,WAAW,EAAE,WAAW,CAAC;QACzB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;KAC3B;IACD;QAAC,KAAK,EAAE,KAAK,CAAC;QAAC,WAAW,EAAE,WAAW,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;KAAC;CACpE,CAmBA;AAiDD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAMhE"}