effect-start 0.22.0 → 0.23.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 (313) hide show
  1. package/dist/BlobStore.d.ts +80 -0
  2. package/dist/BlobStore.js +19 -0
  3. package/dist/ChildProcess.d.ts +60 -0
  4. package/dist/ChildProcess.js +30 -0
  5. package/dist/Commander.d.ts +3 -6
  6. package/dist/Commander.js +6 -13
  7. package/dist/ContentNegotiation.d.ts +8 -9
  8. package/dist/ContentNegotiation.js +32 -37
  9. package/dist/Cookies.d.ts +47 -0
  10. package/dist/Cookies.js +273 -363
  11. package/dist/Development.d.ts +2 -2
  12. package/dist/Development.js +3 -4
  13. package/dist/Effectify.d.ts +1 -4
  14. package/dist/FilePathPattern.d.ts +3 -3
  15. package/dist/FileRouter.d.ts +5 -8
  16. package/dist/FileRouter.js +9 -10
  17. package/dist/FileRouterCodegen.d.ts +1 -1
  18. package/dist/FileRouterCodegen.js +33 -13
  19. package/dist/FileSystem.d.ts +158 -0
  20. package/dist/FileSystem.js +64 -125
  21. package/dist/Http.js +2 -6
  22. package/dist/PathPattern.d.ts +7 -7
  23. package/dist/PathPattern.js +1 -3
  24. package/dist/PlatformError.d.ts +24 -32
  25. package/dist/PlatformError.js +3 -21
  26. package/dist/PlatformRuntime.js +5 -10
  27. package/dist/Route.d.ts +14 -19
  28. package/dist/Route.js +8 -11
  29. package/dist/RouteBody.d.ts +6 -12
  30. package/dist/RouteBody.js +2 -2
  31. package/dist/RouteError.d.ts +98 -0
  32. package/dist/RouteError.js +55 -0
  33. package/dist/RouteHook.js +6 -11
  34. package/dist/RouteHttp.d.ts +3 -3
  35. package/dist/RouteHttp.js +27 -22
  36. package/dist/RouteMount.d.ts +16 -50
  37. package/dist/RouteMount.js +6 -20
  38. package/dist/RouteSchema.d.ts +22 -1
  39. package/dist/RouteSchema.js +33 -0
  40. package/dist/RouteSse.js +4 -10
  41. package/dist/RouteTree.d.ts +2 -1
  42. package/dist/RouteTree.js +17 -15
  43. package/dist/RouteTrie.d.ts +2 -2
  44. package/dist/RouteTrie.js +4 -9
  45. package/dist/SchemaExtra.d.ts +1 -1
  46. package/dist/Socket.d.ts +27 -0
  47. package/dist/Socket.js +20 -28
  48. package/dist/Sql.d.ts +34 -0
  49. package/dist/Sql.js +5 -0
  50. package/dist/SqlIntrospect.d.ts +91 -0
  51. package/dist/SqlIntrospect.js +466 -0
  52. package/dist/Start.d.ts +4 -6
  53. package/dist/Start.js +10 -2
  54. package/dist/StreamExtra.d.ts +1 -1
  55. package/dist/StreamExtra.js +9 -9
  56. package/dist/System.d.ts +7 -0
  57. package/dist/System.js +22 -0
  58. package/dist/TuplePathPattern.js +55 -50
  59. package/dist/Unique.js +7 -7
  60. package/dist/Values.d.ts +2 -1
  61. package/dist/Values.js +19 -13
  62. package/dist/bun/BunBlobStoreDisk.d.ts +6 -0
  63. package/dist/bun/BunBlobStoreDisk.js +116 -0
  64. package/dist/bun/BunBlobStoreS3.d.ts +11 -0
  65. package/dist/bun/BunBlobStoreS3.js +89 -0
  66. package/dist/bun/BunBlobWatcherDisk.d.ts +6 -0
  67. package/dist/bun/BunBlobWatcherDisk.js +60 -0
  68. package/dist/bun/BunBlobWatcherQueue.d.ts +6 -0
  69. package/dist/bun/BunBlobWatcherQueue.js +17 -0
  70. package/dist/bun/BunBundle.d.ts +5 -6
  71. package/dist/bun/BunBundle.js +7 -15
  72. package/dist/bun/BunChildProcessSpawner.d.ts +3 -0
  73. package/dist/bun/BunChildProcessSpawner.js +103 -0
  74. package/dist/bun/BunImportTrackerPlugin.d.ts +1 -1
  75. package/dist/bun/BunImportTrackerPlugin.js +3 -5
  76. package/dist/bun/BunRoute.d.ts +3 -2
  77. package/dist/bun/BunRoute.js +5 -7
  78. package/dist/bun/BunRuntime.js +1 -1
  79. package/dist/bun/BunServer.d.ts +11 -4
  80. package/dist/bun/BunServer.js +35 -11
  81. package/dist/bun/BunSql.d.ts +4 -0
  82. package/dist/bun/BunSql.js +81 -0
  83. package/dist/bun/_BunEnhancedResolve.d.ts +3 -3
  84. package/dist/bun/_BunEnhancedResolve.js +2 -4
  85. package/dist/bun/index.d.ts +1 -0
  86. package/dist/bun/index.js +1 -0
  87. package/dist/bundler/Bundle.d.ts +2 -1
  88. package/dist/bundler/Bundle.js +1 -1
  89. package/dist/bundler/BundleFiles.d.ts +5 -5
  90. package/dist/bundler/BundleFiles.js +10 -8
  91. package/dist/bundler/BundleRoute.d.ts +27 -0
  92. package/dist/bundler/BundleRoute.js +51 -0
  93. package/dist/client/ScrollState.js +2 -6
  94. package/dist/client/index.js +6 -8
  95. package/dist/console/Console.d.ts +6 -0
  96. package/dist/console/Console.js +26 -0
  97. package/dist/console/ConsoleErrors.d.ts +3 -0
  98. package/dist/console/ConsoleErrors.js +200 -0
  99. package/dist/console/ConsoleLogger.d.ts +3 -0
  100. package/dist/console/ConsoleLogger.js +47 -0
  101. package/dist/console/ConsoleMetrics.d.ts +3 -0
  102. package/dist/console/ConsoleMetrics.js +61 -0
  103. package/dist/console/ConsoleProcess.d.ts +3 -0
  104. package/dist/console/ConsoleProcess.js +49 -0
  105. package/dist/console/ConsoleStore.d.ts +144 -0
  106. package/dist/console/ConsoleStore.js +61 -0
  107. package/dist/console/ConsoleTracer.d.ts +3 -0
  108. package/dist/console/ConsoleTracer.js +94 -0
  109. package/dist/console/Simulation.d.ts +2 -0
  110. package/dist/console/Simulation.js +633 -0
  111. package/dist/console/index.d.ts +3 -0
  112. package/dist/console/index.js +3 -0
  113. package/dist/console/routes/errors/route.d.ts +10 -0
  114. package/dist/console/routes/errors/route.js +47 -0
  115. package/dist/console/routes/fiberDetail.d.ts +16 -0
  116. package/dist/console/routes/fiberDetail.js +38 -0
  117. package/dist/console/routes/fibers/route.d.ts +10 -0
  118. package/dist/console/routes/fibers/route.js +19 -0
  119. package/dist/console/routes/git/route.d.ts +11 -0
  120. package/dist/console/routes/git/route.js +33 -0
  121. package/dist/console/routes/layout.d.ts +9 -0
  122. package/dist/console/routes/layout.js +3 -0
  123. package/dist/console/routes/logs/route.d.ts +10 -0
  124. package/dist/console/routes/logs/route.js +32 -0
  125. package/dist/console/routes/metrics/route.d.ts +10 -0
  126. package/dist/console/routes/metrics/route.js +17 -0
  127. package/dist/console/routes/route.d.ts +6 -0
  128. package/dist/console/routes/route.js +5 -0
  129. package/dist/console/routes/routes/route.d.ts +6 -0
  130. package/dist/console/routes/routes/route.js +20 -0
  131. package/dist/console/routes/services/route.d.ts +6 -0
  132. package/dist/console/routes/services/route.js +12 -0
  133. package/dist/console/routes/system/route.d.ts +10 -0
  134. package/dist/console/routes/system/route.js +18 -0
  135. package/dist/console/routes/traceDetail.d.ts +16 -0
  136. package/dist/console/routes/traceDetail.js +14 -0
  137. package/dist/console/routes/traces/route.d.ts +10 -0
  138. package/dist/console/routes/traces/route.js +39 -0
  139. package/dist/console/routes/tree.d.ts +153 -0
  140. package/dist/console/routes/tree.js +29 -0
  141. package/dist/console/ui/Errors.d.ts +4 -0
  142. package/dist/console/ui/Errors.js +15 -0
  143. package/dist/console/ui/Fibers.d.ts +24 -0
  144. package/dist/console/ui/Fibers.js +121 -0
  145. package/dist/console/ui/Git.d.ts +20 -0
  146. package/dist/console/ui/Git.js +95 -0
  147. package/dist/console/ui/Logs.d.ts +4 -0
  148. package/dist/console/ui/Logs.js +25 -0
  149. package/dist/console/ui/Metrics.d.ts +4 -0
  150. package/dist/console/ui/Metrics.js +26 -0
  151. package/dist/console/ui/Routes.d.ts +8 -0
  152. package/dist/console/ui/Routes.js +70 -0
  153. package/dist/console/ui/Services.d.ts +10 -0
  154. package/dist/console/ui/Services.js +246 -0
  155. package/dist/console/ui/Shell.d.ts +10 -0
  156. package/dist/console/ui/Shell.js +7 -0
  157. package/dist/console/ui/System.d.ts +4 -0
  158. package/dist/console/ui/System.js +35 -0
  159. package/dist/console/ui/Traces.d.ts +12 -0
  160. package/dist/console/ui/Traces.js +179 -0
  161. package/dist/datastar/actions/fetch.d.ts +1 -1
  162. package/dist/datastar/actions/fetch.js +10 -18
  163. package/dist/datastar/actions/peek.js +1 -2
  164. package/dist/datastar/actions/setAll.js +1 -2
  165. package/dist/datastar/actions/toggleAll.js +1 -2
  166. package/dist/datastar/attributes/attr.js +1 -2
  167. package/dist/datastar/attributes/bind.js +10 -18
  168. package/dist/datastar/attributes/class.js +2 -5
  169. package/dist/datastar/attributes/computed.js +2 -3
  170. package/dist/datastar/attributes/effect.js +1 -2
  171. package/dist/datastar/attributes/indicator.js +2 -4
  172. package/dist/datastar/attributes/init.js +2 -3
  173. package/dist/datastar/attributes/jsonSignals.js +1 -2
  174. package/dist/datastar/attributes/on.js +41 -22
  175. package/dist/datastar/attributes/onIntersect.js +2 -3
  176. package/dist/datastar/attributes/onInterval.js +2 -3
  177. package/dist/datastar/attributes/onSignalPatch.js +2 -4
  178. package/dist/datastar/attributes/ref.js +1 -2
  179. package/dist/datastar/attributes/show.js +1 -2
  180. package/dist/datastar/attributes/signals.js +1 -2
  181. package/dist/datastar/attributes/style.js +6 -12
  182. package/dist/datastar/attributes/text.js +1 -2
  183. package/dist/datastar/engine.d.ts +13 -7
  184. package/dist/datastar/engine.js +76 -48
  185. package/dist/datastar/happydom.d.ts +1 -0
  186. package/dist/datastar/happydom.js +8 -0
  187. package/dist/datastar/index.d.ts +1 -1
  188. package/dist/datastar/index.js +1 -1
  189. package/dist/datastar/utils.js +4 -7
  190. package/dist/datastar/watchers/patchElements.js +24 -45
  191. package/dist/datastar/watchers/patchSignals.js +1 -2
  192. package/dist/experimental/EncryptedCookies.d.ts +2 -5
  193. package/dist/experimental/EncryptedCookies.js +17 -48
  194. package/dist/experimental/index.d.ts +0 -1
  195. package/dist/experimental/index.js +0 -1
  196. package/dist/hyper/Hyper.d.ts +2 -9
  197. package/dist/hyper/Hyper.js +1 -12
  198. package/dist/hyper/HyperHtml.d.ts +1 -1
  199. package/dist/hyper/HyperHtml.js +18 -12
  200. package/dist/hyper/HyperHtml.test.d.ts +1 -0
  201. package/dist/hyper/HyperHtml.test.js +197 -0
  202. package/dist/hyper/HyperRoute.test.js +14 -3
  203. package/dist/hyper/html.d.ts +11 -0
  204. package/dist/hyper/html.js +30 -0
  205. package/dist/hyper/index.d.ts +2 -0
  206. package/dist/hyper/index.js +1 -0
  207. package/dist/hyper/jsx-runtime.d.ts +1 -1
  208. package/dist/hyper/jsx-runtime.js +1 -1
  209. package/dist/index.d.ts +1 -0
  210. package/dist/index.js +1 -0
  211. package/dist/lint/plugin.d.ts +86 -0
  212. package/dist/lint/plugin.js +341 -0
  213. package/dist/node/NodeFileSystem.d.ts +2 -2
  214. package/dist/node/NodeFileSystem.js +4 -14
  215. package/dist/sql/bun/index.d.ts +3 -0
  216. package/dist/sql/bun/index.js +75 -0
  217. package/dist/sql/mssql/docker.d.ts +2 -0
  218. package/dist/sql/mssql/docker.js +67 -0
  219. package/dist/sql/mssql/index.d.ts +21 -0
  220. package/dist/sql/mssql/index.js +113 -0
  221. package/dist/testing/TestLogger.js +4 -1
  222. package/dist/testing/index.d.ts +0 -1
  223. package/dist/testing/index.js +0 -1
  224. package/dist/testing/utils.d.ts +3 -3
  225. package/dist/testing/utils.js +4 -4
  226. package/dist/x/cloudflare/CloudflareTunnel.d.ts +2 -5
  227. package/dist/x/cloudflare/CloudflareTunnel.js +14 -27
  228. package/dist/x/datastar/Datastar.d.ts +1 -1
  229. package/dist/x/datastar/Datastar.js +13 -12
  230. package/dist/x/datastar/index.d.ts +1 -2
  231. package/dist/x/datastar/index.js +1 -2
  232. package/dist/x/tailscale/TailscaleTunnel.d.ts +15 -0
  233. package/dist/x/tailscale/TailscaleTunnel.js +68 -0
  234. package/dist/x/tailscale/index.d.ts +1 -0
  235. package/dist/x/tailscale/index.js +1 -0
  236. package/dist/x/tailwind/TailwindPlugin.js +19 -19
  237. package/dist/x/tailwind/compile.d.ts +2 -2
  238. package/dist/x/tailwind/compile.js +2 -4
  239. package/package.json +22 -10
  240. package/src/ChildProcess.ts +145 -0
  241. package/src/PlatformError.ts +27 -50
  242. package/src/Route.ts +2 -2
  243. package/src/RouteError.ts +76 -0
  244. package/src/RouteHttp.ts +13 -5
  245. package/src/RouteSchema.ts +96 -1
  246. package/src/RouteTree.ts +12 -0
  247. package/src/Sql.ts +51 -0
  248. package/src/SqlIntrospect.ts +620 -0
  249. package/src/Start.ts +15 -3
  250. package/src/System.ts +43 -0
  251. package/src/Values.ts +7 -0
  252. package/src/bun/BunChildProcessSpawner.ts +143 -0
  253. package/src/bun/BunRoute.ts +5 -2
  254. package/src/bun/BunServer.ts +22 -1
  255. package/src/bun/index.ts +1 -0
  256. package/src/bundler/BundleRoute.ts +66 -0
  257. package/src/console/Console.ts +42 -0
  258. package/src/console/ConsoleErrors.ts +213 -0
  259. package/src/console/ConsoleLogger.ts +56 -0
  260. package/src/console/ConsoleMetrics.ts +72 -0
  261. package/src/console/ConsoleProcess.ts +59 -0
  262. package/src/console/ConsoleStore.ts +187 -0
  263. package/src/console/ConsoleTracer.ts +107 -0
  264. package/src/console/Simulation.ts +814 -0
  265. package/src/console/console.html +340 -0
  266. package/src/console/index.ts +3 -0
  267. package/src/console/routes/errors/route.tsx +97 -0
  268. package/src/console/routes/fiberDetail.tsx +54 -0
  269. package/src/console/routes/fibers/route.tsx +45 -0
  270. package/src/console/routes/git/route.tsx +64 -0
  271. package/src/console/routes/layout.tsx +4 -0
  272. package/src/console/routes/logs/route.tsx +77 -0
  273. package/src/console/routes/metrics/route.tsx +36 -0
  274. package/src/console/routes/route.tsx +8 -0
  275. package/src/console/routes/routes/route.tsx +30 -0
  276. package/src/console/routes/services/route.tsx +21 -0
  277. package/src/console/routes/system/route.tsx +43 -0
  278. package/src/console/routes/traceDetail.tsx +22 -0
  279. package/src/console/routes/traces/route.tsx +81 -0
  280. package/src/console/routes/tree.ts +30 -0
  281. package/src/console/ui/Errors.tsx +76 -0
  282. package/src/console/ui/Fibers.tsx +321 -0
  283. package/src/console/ui/Git.tsx +182 -0
  284. package/src/console/ui/Logs.tsx +46 -0
  285. package/src/console/ui/Metrics.tsx +78 -0
  286. package/src/console/ui/Routes.tsx +125 -0
  287. package/src/console/ui/Services.tsx +273 -0
  288. package/src/console/ui/Shell.tsx +62 -0
  289. package/src/console/ui/System.tsx +131 -0
  290. package/src/console/ui/Traces.tsx +426 -0
  291. package/src/datastar/README.md +6 -1
  292. package/src/datastar/actions/fetch.ts +0 -1
  293. package/src/datastar/attributes/on.ts +40 -20
  294. package/src/datastar/engine.ts +51 -0
  295. package/src/datastar/jsx.d.ts +79 -0
  296. package/src/hyper/Hyper.ts +1 -16
  297. package/src/hyper/HyperHtml.ts +6 -4
  298. package/src/hyper/HyperRoute.ts +2 -1
  299. package/src/hyper/html.ts +47 -0
  300. package/src/hyper/index.ts +2 -0
  301. package/src/hyper/jsx.d.ts +5 -3
  302. package/src/index.ts +1 -0
  303. package/src/lint/plugin.js +129 -0
  304. package/src/sql/bun/index.ts +147 -0
  305. package/src/sql/mssql/docker.ts +117 -0
  306. package/src/sql/mssql/index.ts +223 -0
  307. package/src/sql/mssql/mssql.d.ts +41 -0
  308. package/src/x/cloudflare/CloudflareTunnel.ts +8 -36
  309. package/src/x/tailscale/TailscaleTunnel.ts +113 -0
  310. package/src/x/tailscale/index.ts +1 -0
  311. package/src/x/datastar/Datastar.ts +0 -61
  312. package/src/x/datastar/index.ts +0 -2
  313. package/src/x/datastar/jsx-datastar.d.ts +0 -60
@@ -1,6 +1,5 @@
1
- import { attribute } from "../engine.js";
2
- import { effect, getPath, mergePaths, } from "../engine.js";
3
- import { aliasify, modifyCasing, } from "../utils.js";
1
+ import { attribute, effect, getPath, mergePaths } from "../engine.js";
2
+ import { aliasify, modifyCasing } from "../utils.js";
4
3
  const dataURIRegex = /^data:(?<mime>[^;]+);base64,(?<contents>.*)$/;
5
4
  const empty = Symbol("empty");
6
5
  const aliasedBind = aliasify("bind");
@@ -9,7 +8,7 @@ attribute({
9
8
  requirement: "exclusive",
10
9
  apply({ el, key, mods, value, error }) {
11
10
  const signalName = key != null ? modifyCasing(key, mods) : value;
12
- let get = (el, type) => type === "number" ? +el.value : el.value;
11
+ let get = (el, type) => (type === "number" ? +el.value : el.value);
13
12
  let set = (value) => {
14
13
  ;
15
14
  el.value = `${value}`;
@@ -18,7 +17,7 @@ attribute({
18
17
  switch (el.type) {
19
18
  case "range":
20
19
  case "number":
21
- get = (el, type) => type === "string" ? el.value : +el.value;
20
+ get = (el, type) => (type === "string" ? el.value : +el.value);
22
21
  break;
23
22
  case "checkbox":
24
23
  get = (el, type) => {
@@ -49,17 +48,14 @@ attribute({
49
48
  }
50
49
  get = (el, type) => el.checked ? (type === "number" ? +el.value : el.value) : empty;
51
50
  set = (value) => {
52
- el.checked = value === (typeof value === "number"
53
- ? +el.value
54
- : el.value);
51
+ el.checked = value === (typeof value === "number" ? +el.value : el.value);
55
52
  };
56
53
  break;
57
54
  case "file": {
58
55
  const syncSignal = () => {
59
56
  const files = [...(el.files || [])];
60
57
  const signalFiles = [];
61
- Promise
62
- .all(files.map((f) => new Promise((resolve) => {
58
+ Promise.all(files.map((f) => new Promise((resolve) => {
63
59
  const reader = new FileReader();
64
60
  reader.onload = () => {
65
61
  if (typeof reader.result !== "string") {
@@ -81,8 +77,7 @@ attribute({
81
77
  };
82
78
  reader.onloadend = () => resolve();
83
79
  reader.readAsDataURL(f);
84
- })))
85
- .then(() => {
80
+ }))).then(() => {
86
81
  mergePaths([[signalName, signalFiles]]);
87
82
  });
88
83
  };
@@ -100,9 +95,7 @@ attribute({
100
95
  const typeMap = new Map();
101
96
  get = (el) => [...el.selectedOptions].map((option) => {
102
97
  const type = typeMap.get(option.value);
103
- return type === "string" || type == null
104
- ? option.value
105
- : +option.value;
98
+ return type === "string" || type == null ? option.value : +option.value;
106
99
  });
107
100
  set = (value) => {
108
101
  for (const option of el.options) {
@@ -126,7 +119,7 @@ attribute({
126
119
  }
127
120
  else {
128
121
  // web component
129
- get = (el) => "value" in el ? el.value : el.getAttribute("value");
122
+ get = (el) => ("value" in el ? el.value : el.getAttribute("value"));
130
123
  set = (value) => {
131
124
  if ("value" in el) {
132
125
  el.value = value;
@@ -139,8 +132,7 @@ attribute({
139
132
  const initialValue = getPath(signalName);
140
133
  const type = typeof initialValue;
141
134
  let path = signalName;
142
- if (Array.isArray(initialValue)
143
- && !(el instanceof HTMLSelectElement && el.multiple)) {
135
+ if (Array.isArray(initialValue) && !(el instanceof HTMLSelectElement && el.multiple)) {
144
136
  const signalNameKebab = key ? key : value;
145
137
  const inputs = document.querySelectorAll(`[${aliasedBind}\\:${CSS.escape(signalNameKebab)}],[${aliasedBind}="${CSS.escape(signalNameKebab)}"]`);
146
138
  const paths = [];
@@ -1,5 +1,4 @@
1
- import { attribute } from "../engine.js";
2
- import { effect } from "../engine.js";
1
+ import { attribute, effect } from "../engine.js";
3
2
  import { modifyCasing } from "../utils.js";
4
3
  attribute({
5
4
  name: "class",
@@ -12,9 +11,7 @@ attribute({
12
11
  let classes;
13
12
  const callback = () => {
14
13
  observer.disconnect();
15
- classes = key
16
- ? { [key]: rx() }
17
- : rx();
14
+ classes = key ? { [key]: rx() } : rx();
18
15
  for (const k in classes) {
19
16
  const classNames = k.split(/\s+/).filter((cn) => cn.length > 0);
20
17
  if (classes[k]) {
@@ -1,6 +1,5 @@
1
- import { attribute } from "../engine.js";
2
- import { computed, mergePatch, mergePaths, } from "../engine.js";
3
- import { modifyCasing, updateLeaves, } from "../utils.js";
1
+ import { attribute, computed, mergePatch, mergePaths } from "../engine.js";
2
+ import { modifyCasing, updateLeaves } from "../utils.js";
4
3
  attribute({
5
4
  name: "computed",
6
5
  requirement: {
@@ -1,5 +1,4 @@
1
- import { attribute } from "../engine.js";
2
- import { effect } from "../engine.js";
1
+ import { attribute, effect } from "../engine.js";
3
2
  attribute({
4
3
  name: "effect",
5
4
  requirement: {
@@ -1,8 +1,6 @@
1
- import { DATASTAR_FETCH_EVENT } from "../engine.js";
2
- import { attribute } from "../engine.js";
3
- import { mergePaths } from "../engine.js";
1
+ import { attribute, DATASTAR_FETCH_EVENT, mergePaths } from "../engine.js";
4
2
  import { modifyCasing } from "../utils.js";
5
- import { FINISHED, STARTED, } from "../actions/fetch.js";
3
+ import { FINISHED, STARTED } from "../actions/fetch.js";
6
4
  attribute({
7
5
  name: "indicator",
8
6
  requirement: "exclusive",
@@ -1,6 +1,5 @@
1
- import { attribute } from "../engine.js";
2
- import { beginBatch, endBatch, } from "../engine.js";
3
- import { delay, modifyViewTransition, tagToMs, } from "../utils.js";
1
+ import { attribute, beginBatch, endBatch } from "../engine.js";
2
+ import { delay, modifyViewTransition, tagToMs } from "../utils.js";
4
3
  attribute({
5
4
  name: "init",
6
5
  requirement: {
@@ -1,5 +1,4 @@
1
- import { attribute } from "../engine.js";
2
- import { effect, filtered, } from "../engine.js";
1
+ import { attribute, effect, filtered } from "../engine.js";
3
2
  import { jsStrToObject } from "../utils.js";
4
3
  attribute({
5
4
  name: "json-signals",
@@ -1,47 +1,66 @@
1
- import { DATASTAR_FETCH_EVENT, DATASTAR_SIGNAL_PATCH_EVENT, } from "../engine.js";
2
- import { attribute } from "../engine.js";
3
- import { beginBatch, endBatch, } from "../engine.js";
4
- import { modifyCasing, modifyTiming, modifyViewTransition, } from "../utils.js";
1
+ import { attribute, beginBatch, DATASTAR_FETCH_EVENT, DATASTAR_SIGNAL_PATCH_EVENT, endBatch, } from "../engine.js";
2
+ import { modifyTiming, modifyViewTransition } from "../utils.js";
3
+ // TODO: support leading/trailing options for debounce/throttle
4
+ // e.g. { debounce: { ms: 500, leading: true, noTrailing: true } }
5
+ const configToMods = (config) => {
6
+ const mods = new Map();
7
+ for (const [k, v] of Object.entries(config)) {
8
+ if (v === true) {
9
+ mods.set(k, new Set());
10
+ }
11
+ else if (typeof v === "number") {
12
+ mods.set(k, new Set([`${v}ms`]));
13
+ }
14
+ }
15
+ return mods;
16
+ };
5
17
  attribute({
6
18
  name: "on",
7
19
  requirement: "must",
8
20
  argNames: ["evt"],
9
- apply({ el, key, mods, rx }) {
21
+ apply({ el, key, mods, rx, value }) {
22
+ let userFn;
23
+ let effectiveMods = mods;
24
+ try {
25
+ const parts = Function(`return [${value}]`)();
26
+ if (typeof parts[0] === "function") {
27
+ userFn = parts[0];
28
+ if (parts[1])
29
+ effectiveMods = configToMods(parts[1]);
30
+ }
31
+ }
32
+ catch { }
10
33
  let target = el;
11
- if (mods.has("window"))
34
+ if (effectiveMods.has("window"))
12
35
  target = window;
13
36
  let callback = (evt) => {
14
37
  if (evt) {
15
- if (mods.has("prevent")) {
38
+ if (effectiveMods.has("prevent"))
16
39
  evt.preventDefault();
17
- }
18
- if (mods.has("stop")) {
40
+ if (effectiveMods.has("stop"))
19
41
  evt.stopPropagation();
20
- }
21
42
  }
22
43
  beginBatch();
23
- rx(evt);
44
+ userFn ? userFn(evt) : rx(evt);
24
45
  endBatch();
25
46
  };
26
- callback = modifyViewTransition(callback, mods);
27
- callback = modifyTiming(callback, mods);
47
+ callback = modifyViewTransition(callback, effectiveMods);
48
+ callback = modifyTiming(callback, effectiveMods);
28
49
  const evtListOpts = {
29
- capture: mods.has("capture"),
30
- passive: mods.has("passive"),
31
- once: mods.has("once"),
50
+ capture: effectiveMods.has("capture"),
51
+ passive: effectiveMods.has("passive"),
52
+ once: effectiveMods.has("once"),
32
53
  };
33
- if (mods.has("outside")) {
54
+ if (effectiveMods.has("outside")) {
34
55
  target = document;
35
56
  const cb = callback;
36
57
  callback = (evt) => {
37
- if (!el.contains(evt?.target)) {
58
+ if (!el.contains(evt?.target))
38
59
  cb(evt);
39
- }
40
60
  };
41
61
  }
42
- const eventName = modifyCasing(key, mods, "kebab");
43
- if (eventName === DATASTAR_FETCH_EVENT
44
- || eventName === DATASTAR_SIGNAL_PATCH_EVENT) {
62
+ const eventName = key;
63
+ if (eventName === DATASTAR_FETCH_EVENT || eventName === DATASTAR_SIGNAL_PATCH_EVENT) {
45
64
  target = document;
46
65
  }
47
66
  if (el instanceof HTMLFormElement && eventName === "submit") {
@@ -1,6 +1,5 @@
1
- import { attribute } from "../engine.js";
2
- import { beginBatch, endBatch, } from "../engine.js";
3
- import { clamp, modifyTiming, modifyViewTransition, } from "../utils.js";
1
+ import { attribute, beginBatch, endBatch } from "../engine.js";
2
+ import { clamp, modifyTiming, modifyViewTransition } from "../utils.js";
4
3
  const once = new WeakSet();
5
4
  attribute({
6
5
  name: "on-intersect",
@@ -1,6 +1,5 @@
1
- import { attribute } from "../engine.js";
2
- import { beginBatch, endBatch, } from "../engine.js";
3
- import { modifyViewTransition, tagHas, tagToMs, } from "../utils.js";
1
+ import { attribute, beginBatch, endBatch } from "../engine.js";
2
+ import { modifyViewTransition, tagHas, tagToMs } from "../utils.js";
4
3
  attribute({
5
4
  name: "on-interval",
6
5
  requirement: {
@@ -1,7 +1,5 @@
1
- import { DATASTAR_SIGNAL_PATCH_EVENT } from "../engine.js";
2
- import { attribute } from "../engine.js";
3
- import { beginBatch, endBatch, filtered, } from "../engine.js";
4
- import { aliasify, isEmpty, jsStrToObject, modifyTiming, } from "../utils.js";
1
+ import { attribute, beginBatch, DATASTAR_SIGNAL_PATCH_EVENT, endBatch, filtered, } from "../engine.js";
2
+ import { aliasify, isEmpty, jsStrToObject, modifyTiming } from "../utils.js";
5
3
  attribute({
6
4
  name: "on-signal-patch",
7
5
  requirement: {
@@ -1,5 +1,4 @@
1
- import { attribute } from "../engine.js";
2
- import { mergePaths } from "../engine.js";
1
+ import { attribute, mergePaths } from "../engine.js";
3
2
  import { modifyCasing } from "../utils.js";
4
3
  attribute({
5
4
  name: "ref",
@@ -1,5 +1,4 @@
1
- import { attribute } from "../engine.js";
2
- import { effect } from "../engine.js";
1
+ import { attribute, effect } from "../engine.js";
3
2
  const NONE = "none";
4
3
  const DISPLAY = "display";
5
4
  attribute({
@@ -1,5 +1,4 @@
1
- import { attribute } from "../engine.js";
2
- import { mergePatch, mergePaths, } from "../engine.js";
1
+ import { attribute, mergePatch, mergePaths } from "../engine.js";
3
2
  import { modifyCasing } from "../utils.js";
4
3
  attribute({
5
4
  name: "signals",
@@ -1,5 +1,4 @@
1
- import { attribute } from "../engine.js";
2
- import { effect } from "../engine.js";
1
+ import { attribute, effect } from "../engine.js";
3
2
  import { kebab } from "../utils.js";
4
3
  attribute({
5
4
  name: "style",
@@ -13,14 +12,11 @@ attribute({
13
12
  const apply = (prop, value) => {
14
13
  const initial = initialStyles.get(prop);
15
14
  if (!value && value !== 0) {
16
- initial !== undefined
17
- && (initial
18
- ? style.setProperty(prop, initial)
19
- : style.removeProperty(prop));
15
+ initial !== undefined &&
16
+ (initial ? style.setProperty(prop, initial) : style.removeProperty(prop));
20
17
  }
21
18
  else {
22
- initial === undefined
23
- && initialStyles.set(prop, style.getPropertyValue(prop));
19
+ initial === undefined && initialStyles.set(prop, style.getPropertyValue(prop));
24
20
  style.setProperty(prop, String(value));
25
21
  }
26
22
  };
@@ -32,10 +28,8 @@ attribute({
32
28
  else {
33
29
  const styles = rx();
34
30
  for (const [prop, initial] of initialStyles) {
35
- prop in styles
36
- || (initial
37
- ? style.setProperty(prop, initial)
38
- : style.removeProperty(prop));
31
+ prop in styles ||
32
+ (initial ? style.setProperty(prop, initial) : style.removeProperty(prop));
39
33
  }
40
34
  for (const prop in styles) {
41
35
  apply(kebab(prop), styles[prop]);
@@ -1,5 +1,4 @@
1
- import { attribute } from "../engine.js";
2
- import { effect } from "../engine.js";
1
+ import { attribute, effect } from "../engine.js";
3
2
  attribute({
4
3
  name: "text",
5
4
  requirement: {
@@ -8,7 +8,7 @@ export declare const DATASTAR_SIGNAL_PATCH_EVENT = "datastar-signal-patch";
8
8
  export type JSONPatch = Record<string, any> & {
9
9
  length?: never;
10
10
  };
11
- export type Paths = [string, any][];
11
+ export type Paths = Array<[string, any]>;
12
12
  export type DatastarFetchEvent = {
13
13
  type: string;
14
14
  el: HTMLOrSVG;
@@ -33,7 +33,7 @@ export type Requirement = RequirementType | {
33
33
  key?: Exclude<RequirementType, "exclusive">;
34
34
  value: Exclude<RequirementType, "exclusive">;
35
35
  };
36
- type Rx<B extends boolean> = (...args: any[]) => B extends true ? unknown : void;
36
+ type Rx<B extends boolean> = (...args: Array<any>) => B extends true ? unknown : void;
37
37
  type ReqField<R, K extends "key" | "value", Return> = R extends "must" | {
38
38
  [P in K]: "must";
39
39
  } ? Return : R extends "denied" | {
@@ -70,7 +70,7 @@ export type AttributePlugin<R extends Requirement = Requirement, RxReturn extend
70
70
  apply: (ctx: AttributeContext<R, RxReturn>) => void | (() => void);
71
71
  requirement?: R;
72
72
  returnsValue?: RxReturn;
73
- argNames?: string[];
73
+ argNames?: Array<string>;
74
74
  };
75
75
  export type WatcherContext = {
76
76
  error: ErrorFn;
@@ -82,14 +82,20 @@ export type WatcherPlugin = {
82
82
  export type ActionPlugins = Record<string, ActionPlugin>;
83
83
  export type ActionPlugin<T = any> = {
84
84
  name: string;
85
- apply: (ctx: ActionContext, ...args: any[]) => T;
85
+ apply: (ctx: ActionContext, ...args: Array<any>) => T;
86
86
  };
87
87
  export type MergePatchArgs = {
88
88
  ifMissing?: boolean;
89
89
  };
90
90
  export type HTMLOrSVG = HTMLElement | SVGElement | MathMLElement;
91
+ export type DataEvent = Event & {
92
+ signals: Record<string, any>;
93
+ actions: Record<string, (...args: Array<any>) => any>;
94
+ target: HTMLOrSVG;
95
+ window: Window & typeof globalThis;
96
+ };
91
97
  export type Modifiers = Map<string, Set<string>>;
92
- export type EventCallbackHandler = (...args: any[]) => void;
98
+ export type EventCallbackHandler = (...args: Array<any>) => void;
93
99
  export type SignalFilter = RegExp;
94
100
  export type SignalFilterOptions = {
95
101
  include?: RegExp | string;
@@ -129,7 +135,7 @@ declare const ReactiveFlags: {
129
135
  readonly Dirty: number;
130
136
  readonly Pending: number;
131
137
  };
132
- type ReactiveFlags = typeof ReactiveFlags[keyof typeof ReactiveFlags];
138
+ type ReactiveFlags = (typeof ReactiveFlags)[keyof typeof ReactiveFlags];
133
139
  export declare const beginBatch: () => void;
134
140
  export declare const endBatch: () => void;
135
141
  export declare const startPeeking: (sub?: ReactiveNode) => void;
@@ -142,7 +148,7 @@ export declare const mergePatch: (patch: JSONPatch, { ifMissing }?: MergePatchAr
142
148
  export declare const mergePaths: (paths: Paths, options?: MergePatchArgs) => void;
143
149
  export declare const filtered: ({ include, exclude }?: SignalFilterOptions, obj?: JSONPatch) => Record<string, any>;
144
150
  export declare const root: Record<string, any>;
145
- export declare const actions: Record<string, (ctx: ActionContext, ...args: any[]) => any>;
151
+ export declare const actions: Record<string, (ctx: ActionContext, ...args: Array<any>) => any>;
146
152
  export declare const attribute: <R extends Requirement, B extends boolean>(plugin: AttributePlugin<R, B>) => void;
147
153
  export declare const action: <T>(plugin: ActionPlugin<T>) => void;
148
154
  export declare const watcher: (plugin: WatcherPlugin) => void;
@@ -1,4 +1,4 @@
1
- import { aliasify, hasOwn, isHTMLOrSVG, isPojo, pathToObj, snake, } from "./utils.js";
1
+ import { aliasify, hasOwn, isHTMLOrSVG, isPojo, pathToObj, snake } from "./utils.js";
2
2
  /*********
3
3
  * consts.ts
4
4
  *********/
@@ -84,7 +84,7 @@ const flush = () => {
84
84
  while (notifyIndex < queuedEffectsLength) {
85
85
  const effect = queuedEffects[notifyIndex];
86
86
  queuedEffects[notifyIndex++] = undefined;
87
- run(effect, effect.flags_ &= ~EffectFlags.Queued);
87
+ run(effect, (effect.flags_ &= ~EffectFlags.Queued));
88
88
  }
89
89
  notifyIndex = 0;
90
90
  queuedEffectsLength = 0;
@@ -125,8 +125,8 @@ const notify = (e) => {
125
125
  }
126
126
  };
127
127
  const run = (e, flags) => {
128
- if (flags & 16
129
- || (flags & 32 && checkDirty(e.deps_, e))) {
128
+ if (flags & 16 ||
129
+ (flags & 32 && checkDirty(e.deps_, e))) {
130
130
  startPeeking(e);
131
131
  startTracking(e);
132
132
  beginBatch();
@@ -148,7 +148,7 @@ const run = (e, flags) => {
148
148
  const dep = link.dep_;
149
149
  const depFlags = dep.flags_;
150
150
  if (depFlags & EffectFlags.Queued) {
151
- run(dep, dep.flags_ = depFlags & ~EffectFlags.Queued);
151
+ run(dep, (dep.flags_ = depFlags & ~EffectFlags.Queued));
152
152
  }
153
153
  link = link.nextDep_;
154
154
  }
@@ -184,8 +184,8 @@ const signalOper = (s, ...value) => {
184
184
  };
185
185
  const computedOper = (c) => {
186
186
  const flags = c.flags_;
187
- if (flags & 16
188
- || (flags & 32 && checkDirty(c.deps_, c))) {
187
+ if (flags & 16 ||
188
+ (flags & 32 && checkDirty(c.deps_, c))) {
189
189
  if (updateComputed(c)) {
190
190
  const subs = c.subs_;
191
191
  if (subs) {
@@ -302,21 +302,20 @@ const propagate = (link) => {
302
302
  top: while (true) {
303
303
  const sub = link.sub_;
304
304
  let flags = sub.flags_;
305
- if (!(flags
306
- & 60)) {
305
+ if (!(flags &
306
+ 60)) {
307
307
  sub.flags_ = flags | 32;
308
308
  }
309
309
  else if (!(flags & 12)) {
310
310
  flags = 0;
311
311
  }
312
312
  else if (!(flags & 4)) {
313
- sub.flags_ = (flags & ~8)
314
- | 32;
313
+ sub.flags_ =
314
+ (flags & ~8) | 32;
315
315
  }
316
- else if (!(flags & 48)
317
- && isValidLink(link, sub)) {
318
- sub.flags_ = flags
319
- | 40;
316
+ else if (!(flags & 48) &&
317
+ isValidLink(link, sub)) {
318
+ sub.flags_ = flags | 40;
320
319
  flags &= 1;
321
320
  }
322
321
  else {
@@ -354,9 +353,9 @@ const propagate = (link) => {
354
353
  const startTracking = (sub) => {
355
354
  version++;
356
355
  sub.depsTail_ = undefined;
357
- sub.flags_ = (sub.flags_
358
- & ~56)
359
- | 4;
356
+ sub.flags_ =
357
+ (sub.flags_ & ~56) |
358
+ 4;
360
359
  };
361
360
  const endTracking = (sub) => {
362
361
  const depsTail_ = sub.depsTail_;
@@ -376,8 +375,8 @@ const checkDirty = (link, sub) => {
376
375
  if (sub.flags_ & 16) {
377
376
  dirty = true;
378
377
  }
379
- else if ((flags & 17)
380
- === 17) {
378
+ else if ((flags & 17) ===
379
+ 17) {
381
380
  if (update(dep)) {
382
381
  const subs = dep.subs_;
383
382
  if (subs.nextSub_) {
@@ -386,8 +385,8 @@ const checkDirty = (link, sub) => {
386
385
  dirty = true;
387
386
  }
388
387
  }
389
- else if ((flags & 33)
390
- === 33) {
388
+ else if ((flags & 33) ===
389
+ 33) {
391
390
  if (link.nextSub_ || link.prevSub_) {
392
391
  stack = { value_: link, prev_: stack };
393
392
  }
@@ -439,8 +438,8 @@ const shallowPropagate = (link) => {
439
438
  do {
440
439
  const sub = link.sub_;
441
440
  const flags = sub.flags_;
442
- if ((flags & 48)
443
- === 32) {
441
+ if ((flags & 48) ===
442
+ 32) {
444
443
  sub.flags_ = flags | 16;
445
444
  if (flags & 2) {
446
445
  notify(sub);
@@ -598,8 +597,8 @@ export const mergePatch = (patch, { ifMissing } = {}) => {
598
597
  export const mergePaths = (paths, options) => mergePatch(pathToObj(paths), options);
599
598
  const mergeInner = (patch, target, targetParent, prefix, ifMissing) => {
600
599
  if (isPojo(patch)) {
601
- if (!(hasOwn(targetParent, target)
602
- && (isPojo(targetParent[target]) || Array.isArray(targetParent[target])))) {
600
+ if (!(hasOwn(targetParent, target) &&
601
+ (isPojo(targetParent[target]) || Array.isArray(targetParent[target])))) {
603
602
  targetParent[target] = {};
604
603
  }
605
604
  for (const key in patch) {
@@ -648,8 +647,7 @@ const error = (ctx, reason, metadata = {}) => {
648
647
  const r = snake(reason);
649
648
  const q = new URLSearchParams({
650
649
  metadata: JSON.stringify(metadata),
651
- })
652
- .toString();
650
+ }).toString();
653
651
  const c = JSON.stringify(metadata, null, 2);
654
652
  e.message = `${reason}\nMore info: ${url}/${r}?${q}\nContext: ${c}`;
655
653
  return e;
@@ -727,7 +725,7 @@ const applyEls = (els, onlyNew) => {
727
725
  }
728
726
  };
729
727
  const observe = (mutations) => {
730
- for (const { target, type, attributeName, addedNodes, removedNodes, } of mutations) {
728
+ for (const { target, type, attributeName, addedNodes, removedNodes } of mutations) {
731
729
  if (type === "childList") {
732
730
  for (const node of removedNodes) {
733
731
  if (isHTMLOrSVG(node)) {
@@ -742,10 +740,10 @@ const observe = (mutations) => {
742
740
  }
743
741
  }
744
742
  }
745
- else if (type === "attributes"
746
- && attributeName.startsWith("data-")
747
- && isHTMLOrSVG(target)
748
- && !shouldIgnore(target)) {
743
+ else if (type === "attributes" &&
744
+ attributeName.startsWith("data-") &&
745
+ isHTMLOrSVG(target) &&
746
+ !shouldIgnore(target)) {
749
747
  const key = attributeName.slice(5);
750
748
  const value = target.getAttribute(attributeName);
751
749
  if (value === null) {
@@ -814,16 +812,12 @@ const applyAttributePlugin = (el, attrKey, value, onlyNew) => {
814
812
  },
815
813
  rx: undefined,
816
814
  };
817
- const keyReq = (plugin.requirement
818
- && (typeof plugin.requirement === "string"
819
- ? plugin.requirement
820
- : plugin.requirement.key))
821
- || "allowed";
822
- const valueReq = (plugin.requirement
823
- && (typeof plugin.requirement === "string"
824
- ? plugin.requirement
825
- : plugin.requirement.value))
826
- || "allowed";
815
+ const keyReq = (plugin.requirement &&
816
+ (typeof plugin.requirement === "string" ? plugin.requirement : plugin.requirement.key)) ||
817
+ "allowed";
818
+ const valueReq = (plugin.requirement &&
819
+ (typeof plugin.requirement === "string" ? plugin.requirement : plugin.requirement.value)) ||
820
+ "allowed";
827
821
  const keyProvided = key !== undefined && key !== null && key !== "";
828
822
  const valueProvided = value !== undefined && value !== null && value !== "";
829
823
  if (keyProvided) {
@@ -884,7 +878,43 @@ const applyAttributePlugin = (el, attrKey, value, onlyNew) => {
884
878
  elCleanups.set(rawKey, cleanups);
885
879
  }
886
880
  };
887
- const genRx = (value, { returnsValue = false, argNames = [], cleanups = new Map(), } = {}) => {
881
+ const genRx = (value, { returnsValue = false, argNames = [], cleanups = new Map() } = {}) => {
882
+ if (/^\s*(?:async\s+)?(?:\(.*?\)\s*=>|[\w$]+\s*=>|function\s*[\w$]*\s*\()/.test(value)) {
883
+ const userFn = Function(`return (${value.trim()})`)();
884
+ return (el, ...args) => {
885
+ const actionsProxy = new Proxy({}, {
886
+ get: (_, name) => (...actionArgs) => {
887
+ const err = error.bind(0, {
888
+ plugin: { type: "action", name },
889
+ element: { id: el.id, tag: el.tagName },
890
+ expression: { fnContent: value, value },
891
+ });
892
+ const fn = actions[name];
893
+ if (fn)
894
+ return fn({ el, evt: undefined, error: err, cleanups }, ...actionArgs);
895
+ throw err("UndefinedAction");
896
+ },
897
+ });
898
+ const dataEvt = args[0] instanceof Event ? args[0] : new Event("datastar:expression");
899
+ Object.defineProperties(dataEvt, {
900
+ target: { value: el },
901
+ signals: { value: root },
902
+ actions: { value: actionsProxy },
903
+ window: { value: window },
904
+ });
905
+ try {
906
+ return userFn(dataEvt);
907
+ }
908
+ catch (e) {
909
+ console.error(e);
910
+ throw error({
911
+ element: { id: el.id, tag: el.tagName },
912
+ expression: { fnContent: value, value },
913
+ error: e.message,
914
+ }, "ExecuteExpression");
915
+ }
916
+ };
917
+ }
888
918
  let expr = "";
889
919
  if (returnsValue) {
890
920
  const statementRe = /(\/(\\\/|[^/])*\/|"(\\"|[^"])*"|'(\\'|[^'])*'|`(\\`|[^`])*`|\(\s*((function)\s*\(\s*\)|(\(\s*\))\s*=>)\s*(?:\{[\s\S]*?\}|[^;){]*)\s*\)\s*\(\s*\)|[^;])+/gm;
@@ -912,10 +942,8 @@ const genRx = (value, { returnsValue = false, argNames = [], cleanups = new Map(
912
942
  }
913
943
  expr = expr
914
944
  .replace(/\$\['([a-zA-Z_$\d][\w$]*)'\]/g, "$$$1")
915
- .replace(/\$([a-zA-Z_\d]\w*(?:[.-]\w+)*)/g, (_, signalName) => signalName
916
- .split(".")
917
- .reduce((acc, part) => `${acc}['${part}']`, "$"));
918
- expr = expr.replaceAll(/@([A-Za-z_$][\w$]*)\(/g, "__action(\"$1\",evt,");
945
+ .replace(/\$([a-zA-Z_\d]\w*(?:[.-]\w+)*)/g, (_, signalName) => signalName.split(".").reduce((acc, part) => `${acc}['${part}']`, "$"));
946
+ expr = expr.replaceAll(/@([A-Za-z_$][\w$]*)\(/g, '__action("$1",evt,');
919
947
  for (const [k, v] of escaped) {
920
948
  expr = expr.replace(k, v);
921
949
  }
@@ -0,0 +1 @@
1
+ export {};