firefly-compiler 0.5.47 → 0.5.49

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 (98) hide show
  1. package/.vscode/settings.json +1 -1
  2. package/bin/firefly.mjs +1 -1
  3. package/compiler/Builder.ff +9 -1
  4. package/compiler/Compiler.ff +1 -1
  5. package/compiler/Dependencies.ff +11 -7
  6. package/compiler/JsEmitter.ff +75 -58
  7. package/core/BrowserSystem.ff +5 -0
  8. package/core/Date.ff +623 -0
  9. package/core/Instant.ff +0 -24
  10. package/core/JsValue.ff +1 -1
  11. package/core/Map.ff +16 -0
  12. package/core/NodeSystem.ff +5 -0
  13. package/core/Path.ff +2 -2
  14. package/core/Random.ff +0 -4
  15. package/core/RbMap.ff +32 -0
  16. package/core/Set.ff +4 -0
  17. package/core/Task.ff +0 -4
  18. package/experimental/tests/TestDate.ff +10 -0
  19. package/experimental/tests/TestEmailAlertDateLogic.ff +84 -0
  20. package/firefly.sh +5 -5
  21. package/lsp/LanguageServer.ff +3 -0
  22. package/output/js/ff/compiler/Builder.mjs +46 -4
  23. package/output/js/ff/compiler/Compiler.mjs +3 -3
  24. package/output/js/ff/compiler/Dependencies.mjs +28 -14
  25. package/output/js/ff/compiler/DependencyLock.mjs +2 -2
  26. package/output/js/ff/compiler/Deriver.mjs +2 -2
  27. package/output/js/ff/compiler/Dictionaries.mjs +2 -2
  28. package/output/js/ff/compiler/Environment.mjs +2 -2
  29. package/output/js/ff/compiler/Inference.mjs +2 -2
  30. package/output/js/ff/compiler/JsEmitter.mjs +675 -575
  31. package/output/js/ff/compiler/JsImporter.mjs +2 -2
  32. package/output/js/ff/compiler/LspHook.mjs +2 -2
  33. package/output/js/ff/compiler/Main.mjs +2 -2
  34. package/output/js/ff/compiler/ModuleCache.mjs +2 -2
  35. package/output/js/ff/compiler/Parser.mjs +2 -2
  36. package/output/js/ff/compiler/Patterns.mjs +2 -2
  37. package/output/js/ff/compiler/Resolver.mjs +2 -2
  38. package/output/js/ff/compiler/Substitution.mjs +2 -2
  39. package/output/js/ff/compiler/Syntax.mjs +2 -2
  40. package/output/js/ff/compiler/Token.mjs +2 -2
  41. package/output/js/ff/compiler/Tokenizer.mjs +2 -2
  42. package/output/js/ff/compiler/Unification.mjs +2 -2
  43. package/output/js/ff/compiler/Wildcards.mjs +2 -2
  44. package/output/js/ff/compiler/Workspace.mjs +2 -2
  45. package/output/js/ff/core/Any.mjs +2 -2
  46. package/output/js/ff/core/Array.mjs +2 -2
  47. package/output/js/ff/core/AssetSystem.mjs +2 -2
  48. package/output/js/ff/core/Atomic.mjs +2 -2
  49. package/output/js/ff/core/Bool.mjs +2 -2
  50. package/output/js/ff/core/BrowserSystem.mjs +28 -2
  51. package/output/js/ff/core/Buffer.mjs +2 -2
  52. package/output/js/ff/core/BuildSystem.mjs +2 -2
  53. package/output/js/ff/core/Channel.mjs +2 -2
  54. package/output/js/ff/core/Char.mjs +2 -2
  55. package/output/js/ff/core/Core.mjs +2 -2
  56. package/output/js/ff/core/Crypto.mjs +2 -2
  57. package/output/js/ff/core/Date.mjs +1009 -0
  58. package/output/js/ff/core/Duration.mjs +2 -2
  59. package/output/js/ff/core/Equal.mjs +2 -2
  60. package/output/js/ff/core/Error.mjs +2 -2
  61. package/output/js/ff/core/FileHandle.mjs +2 -2
  62. package/output/js/ff/core/Float.mjs +2 -2
  63. package/output/js/ff/core/HttpClient.mjs +2 -2
  64. package/output/js/ff/core/Int.mjs +2 -2
  65. package/output/js/ff/core/IntMap.mjs +2 -2
  66. package/output/js/ff/core/Js.mjs +2 -2
  67. package/output/js/ff/core/JsSystem.mjs +2 -2
  68. package/output/js/ff/core/JsValue.mjs +3 -3
  69. package/output/js/ff/core/Json.mjs +2 -2
  70. package/output/js/ff/core/List.mjs +2 -2
  71. package/output/js/ff/core/Lock.mjs +2 -2
  72. package/output/js/ff/core/Log.mjs +2 -2
  73. package/output/js/ff/core/Map.mjs +34 -2
  74. package/output/js/ff/core/NodeSystem.mjs +28 -2
  75. package/output/js/ff/core/Nothing.mjs +2 -2
  76. package/output/js/ff/core/Option.mjs +2 -2
  77. package/output/js/ff/core/Ordering.mjs +2 -2
  78. package/output/js/ff/core/Pair.mjs +2 -2
  79. package/output/js/ff/core/Path.mjs +6 -12
  80. package/output/js/ff/core/Queue.mjs +2 -2
  81. package/output/js/ff/core/Random.mjs +2 -10
  82. package/output/js/ff/core/RbMap.mjs +186 -2
  83. package/output/js/ff/core/Serializable.mjs +2 -2
  84. package/output/js/ff/core/Set.mjs +50 -2
  85. package/output/js/ff/core/Show.mjs +2 -2
  86. package/output/js/ff/core/SourceLocation.mjs +2 -2
  87. package/output/js/ff/core/Stream.mjs +2 -2
  88. package/output/js/ff/core/String.mjs +2 -2
  89. package/output/js/ff/core/StringMap.mjs +2 -2
  90. package/output/js/ff/core/Task.mjs +2 -10
  91. package/output/js/ff/core/Try.mjs +2 -2
  92. package/output/js/ff/core/Unit.mjs +2 -2
  93. package/package.json +1 -1
  94. package/postgresql/Pg.ff +0 -40
  95. package/s3/S3.ff +4 -4
  96. package/vscode/package.json +1 -1
  97. package/output/js/ff/core/Instant.mjs +0 -149
  98. /package/fireflysite/assets/markdown/scratch/{Toc.md → toc.md} +0 -0
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "editor.suggest.showWords": false,
3
- "firefly.trace.server": "messages",
3
+ "firefly.trace.server": "verbose",
4
4
  "editor.trimAutoWhitespace": false
5
5
  }
package/bin/firefly.mjs CHANGED
@@ -1,2 +1,2 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node --harmony-temporal
2
2
  import * as firefly from '../output/js/ff/compiler/Main.mjs';
@@ -136,7 +136,15 @@ check(
136
136
 
137
137
  packages.filter {!_.files.isEmpty()}.each {package =>
138
138
  let firstFile = package.files.grabFirst()
139
- let resolvedDependencies = Dependencies.process(system.httpClient(), dependencyLock, firstFile)
139
+ try {
140
+ Some(Dependencies.process(system.httpClient(), dependencyLock, firstFile))
141
+ } tryCatch {| CompileError(_, _) @ c, error =>
142
+ errors.push(c)
143
+ None
144
+ } catch {| CompileErrors(compileErrors), error =>
145
+ errors.pushList(compileErrors)
146
+ None
147
+ }.each: resolvedDependencies =>
140
148
  let fixedPackagePaths = if(resolvedDependencies.packagePaths.contains(PackagePair("ff", "core"))) {
141
149
  resolvedDependencies.packagePaths
142
150
  } else {
@@ -67,13 +67,13 @@ coreImports: List[DImport] =
67
67
  "Char"
68
68
  "Core"
69
69
  "Crypto"
70
+ "Date"
70
71
  "Duration"
71
72
  "Equal"
72
73
  "Error"
73
74
  "FileHandle"
74
75
  "Float"
75
76
  "HttpClient"
76
- "Instant"
77
77
  "Int"
78
78
  "IntMap"
79
79
  "Json"
@@ -24,7 +24,7 @@ extend self: Dependencies {
24
24
  loadPackageInfo(
25
25
  packagePair: PackagePair
26
26
  path: Path
27
- ): PackageInfo {
27
+ ): Option[PackageInfo] {
28
28
  let packageDirectory = if(path.extension() == ".ff") {path.parent().grab()} else {path}
29
29
  let sharedPackageFile = packageDirectory.slash(".firefly").slash("package.ff")
30
30
  let packageFile = if(sharedPackageFile.exists()) {
@@ -33,8 +33,8 @@ extend self: Dependencies {
33
33
  self.singleFilePackages = self.singleFilePackages.add(packagePair)
34
34
  path
35
35
  }
36
- let code = packageFile.readText()
37
- self.parsePackageFile(packagePair, packageFile.relativeTo(path), code)
36
+ try {packageFile.readText()}.toOption().map: code =>
37
+ self.parsePackageFile(packagePair, packageFile.absolute(), code)
38
38
  }
39
39
 
40
40
  parsePackageFile(
@@ -93,7 +93,7 @@ extend self: Dependencies {
93
93
  Log.trace("Fetching " + location)
94
94
  let buffer = httpClient.get(location, []) {response =>
95
95
  if(!response.ok()) {
96
- panic("Could not download dependency: " + location)
96
+ throw(CompileError(dependency.at, "Could not download dependency: " + location))
97
97
  }
98
98
  response.readBuffer()
99
99
  }
@@ -109,7 +109,7 @@ extend self: Dependencies {
109
109
  }
110
110
  dependencyPath
111
111
  } else {
112
- panic("Loading packages by this protocol is not supported: " + location)
112
+ throw(CompileError(dependency.at, "Loading packages by this protocol is not supported: " + location))
113
113
  }
114
114
  } else {
115
115
  path.path(location)
@@ -126,7 +126,9 @@ extend self: Dependencies {
126
126
  let packageInfos = dependencies.map {dependency =>
127
127
  let dependencyPath = self.fetchDependency(path, httpClient, dependencyLock, dependency)
128
128
  self.packagePaths = self.packagePaths.add(dependency.packagePair, dependencyPath)
129
- let packageInfo = self.loadPackageInfo(dependency.packagePair, dependencyPath)
129
+ let packageInfo = self.loadPackageInfo(dependency.packagePair, dependencyPath).else {
130
+ throw(CompileError(dependency.at, "Dependency not found: " + dependencyPath.absolute()))
131
+ }
130
132
  checkPackagePairs(dependency.packagePair, packageInfo.package.packagePair)
131
133
  packageInfo
132
134
  }
@@ -141,7 +143,9 @@ extend self: Dependencies {
141
143
  process(fetch: HttpClient, dependencyLock: DependencyLock, path: Path): ResolvedDependencies {
142
144
  let workspace = Workspace.loadWorkspace(path)
143
145
  let self = Dependencies(workspace, [].toMap(), [].toMap(), [].toSet())
144
- let packageInfo = self.loadPackageInfo(PackagePair("script", "script"), path)
146
+ let packageInfo = self.loadPackageInfo(PackagePair("script", "script"), path).else {
147
+ panic("Not a main file: " + path.absolute())
148
+ }
145
149
  let newDependencies = self.processPackageInfo(packageInfo)
146
150
  self.processDependencies(path, fetch, dependencyLock, newDependencies)
147
151
  let packagePaths = self.packagePaths.add(packageInfo.package.packagePair, findScriptPackageLocation(path))
@@ -279,7 +279,7 @@ extend self: JsEmitter {
279
279
  }
280
280
  }
281
281
 
282
- emitTerm(term: Term, async: Bool): String {term.{
282
+ emitTerm(term: Term, async: Bool, ignored: Bool = False): String {term.{
283
283
  | EString(at, value) {value.startsWith("\"\"\"")} =>
284
284
  "`" + value.dropFirst(3).dropLast(3).replace("`", "\\`") + "`" // TODO: Fix escaping
285
285
  | EString(at, value) => value
@@ -347,6 +347,8 @@ extend self: JsEmitter {
347
347
  let c = if(await) {", $task"} else {""}
348
348
  let call = "(" + self.emitTerm(function, async) + ")(" + self.emitTerm(value, async) + c + ")"
349
349
  if(await) {"(await " + call + ")"} else {call}
350
+ | _ {self.emitAssignment(term, async) | Some(code)} =>
351
+ if(ignored) {code} else {"(" + code + ", void 0)"}
350
352
  | ECall(at, StaticCall(name, _, _), _, _, arguments, dictionaries) {
351
353
  self.emitSpecialCall(term, async, name, arguments.map {_.value}, dictionaries) | Some(code)
352
354
  } =>
@@ -379,14 +381,14 @@ extend self: JsEmitter {
379
381
  let call = functionCode + "(" + [...emittedArguments, ...ds, ...controller].join(", ") + ")"
380
382
  if(await) {"(await " + call + ")"} else {call}
381
383
  | [Pair(EVariant(_, "ff:core/Bool.True", _, _), elseBody), ...list] =>
382
- "(" + list.foldLeft(self.emitComma(elseBody, async)) {| otherwise, Pair(condition, body) =>
383
- self.emitComma(condition, async) +
384
- "\n? " + self.emitComma(body, async) + "\n: " + otherwise
384
+ "(" + list.foldLeft(self.emitTerm(elseBody, async)) {| otherwise, Pair(condition, body) =>
385
+ self.emitTerm(condition, async) +
386
+ "\n? " + self.emitTerm(body, async) + "\n: " + otherwise
385
387
  } + ")"
386
388
  | list =>
387
389
  "(" + list.foldLeft("ff_core_Option.None()") {| otherwise, Pair(condition, body) =>
388
- self.emitComma(condition, async) +
389
- "\n? ff_core_Option.Some(" + self.emitComma(body, async) + ")\n: " + otherwise
390
+ self.emitTerm(condition, async) +
391
+ "\n? ff_core_Option.Some(" + self.emitTerm(body, async) + ")\n: " + otherwise
390
392
  } + ")"
391
393
  }
392
394
  | ECall(at, DynamicCall(function, _), effect, typeArguments, arguments, dictionaries) =>
@@ -405,6 +407,24 @@ extend self: JsEmitter {
405
407
  | EWildcard(at, index) =>
406
408
  if(index == 0) {fail(at, "Unbound wildcard")}
407
409
  "_w" + index
410
+ | ESequential(_, ESequential(_, ESequential(_, before1, before2), before3), after) {
411
+ safeCommable(before1) && safeCommable(before2) && safeCommable(before3) && safeCommable(after)
412
+ } =>
413
+ "(" + self.emitTerm(before1, async, ignored = True) + ", " +
414
+ self.emitTerm(before2, async, ignored = True) + ", " +
415
+ self.emitTerm(before3, async, ignored = True) + ", " +
416
+ self.emitTerm(after, async, ignored) + ")"
417
+ | ESequential(_, ESequential(_, before1, before2), after) {
418
+ safeCommable(before1) && safeCommable(before2) && safeCommable(after)
419
+ } =>
420
+ "(" + self.emitTerm(before1, async, ignored = True) + ", " +
421
+ self.emitTerm(before2, async, ignored = True) + ", " +
422
+ self.emitTerm(after, async, ignored) + ")"
423
+ | ESequential(_, before, after) {
424
+ safeCommable(before) && safeCommable(after)
425
+ } =>
426
+ "(" + self.emitTerm(before, async, ignored = True) + ", " +
427
+ self.emitTerm(after, async, ignored) + ")"
408
428
  | _ {async} =>
409
429
  "(await (async function() {\n" + self.emitStatements(term, True, False, async) + "\n})())"
410
430
  | _ =>
@@ -450,11 +470,6 @@ extend self: JsEmitter {
450
470
  | ESequential(at, before, after) =>
451
471
  self.emitStatements(before, False, False, async) + ";\n" +
452
472
  self.emitStatements(after, last, break, async)
453
- | EAssign(at, operator, name, value) =>
454
- escapeKeyword(name) + " " + operator + "= " + self.emitTerm(value, async)
455
- | EAssignField(at, operator, record, field, value) =>
456
- self.emitTerm(record, async) + "." + escapeKeyword(field) + " " + operator + "= " +
457
- self.emitTerm(value, async)
458
473
  | ECall(at, StaticCall(name, True, instanceCall), effect, _, arguments, _) =>
459
474
  if(instanceCall) {throw(CompileError(at, "Not yet implemented: Tail calls on trait methods."))}
460
475
  self.tailCallUsed = True
@@ -478,15 +493,17 @@ extend self: JsEmitter {
478
493
  self.emitCase(["_1"], c, [], [], True, last, break, lastCase, async)
479
494
  }.join("\n") +
480
495
  "\n}" + if(!last && !break) {" while(false)"}.else {""}
496
+ | _ {self.emitAssignment(term, async) | Some(code)} =>
497
+ code
481
498
  | _ =>
482
499
  detectIfElse(term).{
483
500
  | [] =>
484
501
  if(break) {
485
- "if(!" + self.emitComma(term, async) + ") break"
502
+ "if(!" + self.emitTerm(term, async) + ") break"
486
503
  } elseIf {last} {
487
504
  "return " + self.emitTerm(term, async)
488
505
  } else {
489
- self.emitTerm(term, async)
506
+ self.emitTerm(term, async, ignored = True)
490
507
  }
491
508
  | [Pair(EVariant(_, "ff:core/Bool.True", _, _), elseBody), ...list] =>
492
509
  let initial = "{\n" + self.emitStatements(elseBody, last, break, async) + "\n}"
@@ -508,6 +525,49 @@ extend self: JsEmitter {
508
525
  }
509
526
  }
510
527
 
528
+ emitAssignment(
529
+ term: Term
530
+ async: Bool
531
+ ): Option[String] {
532
+ | ECall(at, StaticCall(name, _, _), _, _, arguments, dictionaries), _ =>
533
+ name.{
534
+ | "ff:core/JsValue.JsValue_set" {arguments.map {_.value} | [e1, e2, e3]} =>
535
+ Some(self.emitTerm(e1, async) + self.emitField(e2, async) + " = " + self.emitTerm(e3, async))
536
+ | "ff:core/JsValue.JsValue_increment" {arguments.map {_.value} | [e1, e2, e3]} =>
537
+ Some(self.emitTerm(e1, async) + self.emitField(e2, async) + " += " + self.emitTerm(e3, async))
538
+ | "ff:core/JsValue.JsValue_decrement" {arguments.map {_.value} | [e1, e2, e3]} =>
539
+ Some(self.emitTerm(e1, async) + self.emitField(e2, async) + " -= " + self.emitTerm(e3, async))
540
+ | "ff:core/JsSystem.JsSystem_set" {arguments.map {_.value} | [e1, EString(_, q), e3]} {
541
+ noSideEffects(e1)} {safeBare(q) | Some(s)
542
+ } =>
543
+ Some(s + " = " + self.emitTerm(e3, async))
544
+ | "ff:core/JsSystem.JsSystem_increment" {arguments.map {_.value} | [e1, EString(_, q), e3]} {
545
+ noSideEffects(e1)} {safeBare(q) | Some(s)
546
+ } =>
547
+ Some(s + " += " + self.emitTerm(e3, async))
548
+ | "ff:core/JsSystem.JsSystem_decrement" {arguments.map {_.value} | [e1, EString(_, q), e3]} {
549
+ noSideEffects(e1)} {safeBare(q) | Some(s)
550
+ } =>
551
+ Some(s + " -= " + self.emitTerm(e3, async))
552
+ | "ff:core/Js.set" {arguments.map {_.value} | [EString(_, q), e2]} {safeBare(q) | Some(s)} =>
553
+ Some(s + " = " + self.emitTerm(e2, async))
554
+ | "ff:core/Js.increment" {arguments.map {_.value} | [EString(_, q), e2]} {safeBare(q) | Some(s)} =>
555
+ Some(s + " += " + self.emitTerm(e2, async))
556
+ | "ff:core/Js.decrement" {arguments.map {_.value} | [EString(_, q), e2]} {safeBare(q) | Some(s)} =>
557
+ Some(s + " -= " + self.emitTerm(e2, async))
558
+ | _ => None
559
+ }
560
+ | EAssign(at, operator, name, value), _ =>
561
+ Some(escapeKeyword(name) + " " + operator + "= " + self.emitTerm(value, async))
562
+ | EAssignField(at, operator, record, field, value), _ =>
563
+ Some(
564
+ self.emitTerm(record, async) + "." + escapeKeyword(field) + " " + operator + "= " +
565
+ self.emitTerm(value, async)
566
+ )
567
+ | _, _ =>
568
+ None
569
+ }
570
+
511
571
  emitSpecialCall(
512
572
  term: Term
513
573
  async: Bool
@@ -794,7 +854,7 @@ extend self: JsEmitter {
794
854
  name.{
795
855
  | "ff:core/Core.while" {arguments | [condition, body]} =>
796
856
  Some(
797
- "while(" + self.emitComma(invokeImmediately(condition), async) + ") {\n" +
857
+ "while(" + self.emitTerm(invokeImmediately(condition), async) + ") {\n" +
798
858
  self.emitStatements(invokeImmediately(body), False, False, async) + "\n}"
799
859
  )
800
860
  | "ff:core/Core.doWhile" {arguments | [doWhileBody]} {
@@ -906,7 +966,7 @@ extend self: JsEmitter {
906
966
  Some(self.emitTerm(array, async) + ".array.push(" + self.emitTerm(value, async) + ")")
907
967
  | "ff:core/Core.if" {arguments | [condition, body]} =>
908
968
  Some(
909
- "if(" + self.emitComma(condition, async) + ") {\n" +
969
+ "if(" + self.emitTerm(condition, async) + ") {\n" +
910
970
  if(last) {
911
971
  "return ff_core_Option.Some(" + self.emitTerm(invokeImmediately(body), async) +
912
972
  ")\n} else return ff_core_Option.None()"
@@ -928,24 +988,6 @@ extend self: JsEmitter {
928
988
  Some(if(async) {"ff_core_Task.Task_throwIfAborted($task)"} else {""})
929
989
  | "ff:core/Js.throw" {term | ECall c} {c.arguments | [argument]} =>
930
990
  Some("throw " + self.emitTerm(argument.value, async))
931
- | "ff:core/JsValue.JsValue_set" {arguments | [e1, e2, e3]} =>
932
- Some(self.emitTerm(e1, async) + self.emitField(e2, async) + " = " + self.emitTerm(e3, async))
933
- | "ff:core/JsValue.JsValue_increment" {arguments | [e1, e2, e3]} =>
934
- Some(self.emitTerm(e1, async) + self.emitField(e2, async) + " += " + self.emitTerm(e3, async))
935
- | "ff:core/JsValue.JsValue_decrement" {arguments | [e1, e2, e3]} =>
936
- Some(self.emitTerm(e1, async) + self.emitField(e2, async) + " -= " + self.emitTerm(e3, async))
937
- | "ff:core/JsSystem.JsSystem_set" {arguments | [e1, EString(_, q), e3]} {noSideEffects(e1)} {safeBare(q) | Some(s)} =>
938
- Some(s + " = " + self.emitTerm(e3, async))
939
- | "ff:core/JsSystem.JsSystem_increment" {arguments | [e1, EString(_, q), e3]} {noSideEffects(e1)} {safeBare(q) | Some(s)} =>
940
- Some(s + " += " + self.emitTerm(e3, async))
941
- | "ff:core/JsSystem.JsSystem_decrement" {arguments | [e1, EString(_, q), e3]} {noSideEffects(e1)} {safeBare(q) | Some(s)} =>
942
- Some(s + " -= " + self.emitTerm(e3, async))
943
- | "ff:core/Js.set" {arguments | [EString(_, q), e2]} {safeBare(q) | Some(s)} =>
944
- Some(s + " = " + self.emitTerm(e2, async))
945
- | "ff:core/Js.increment" {arguments | [EString(_, q), e2]} {safeBare(q) | Some(s)} =>
946
- Some(s + " += " + self.emitTerm(e2, async))
947
- | "ff:core/Js.decrement" {arguments | [EString(_, q), e2]} {safeBare(q) | Some(s)} =>
948
- Some(s + " -= " + self.emitTerm(e2, async))
949
991
  | _ =>
950
992
  None
951
993
  }
@@ -1280,31 +1322,6 @@ extend self: JsEmitter {
1280
1322
  }
1281
1323
  }
1282
1324
 
1283
- emitComma(term: Term, async: Bool): String {
1284
- term.{
1285
- | ESequential(_, ESequential(_, ESequential(_, before1, before2), before3), after) {
1286
- safeCommable(before1) && safeCommable(before2) && safeCommable(before3) && safeCommable(after)
1287
- } =>
1288
- "(" + self.emitStatements(before1, False, False, async) + ", " +
1289
- self.emitStatements(before2, False, False, async) + ", " +
1290
- self.emitStatements(before3, False, False, async) + ", " +
1291
- self.emitTerm(after, async) + ")"
1292
- | ESequential(_, ESequential(_, before1, before2), after) {
1293
- safeCommable(before1) && safeCommable(before2) && safeCommable(after)
1294
- } =>
1295
- "(" + self.emitStatements(before1, False, False, async) + ", " +
1296
- self.emitStatements(before2, False, False, async) + ", " +
1297
- self.emitTerm(after, async) + ")"
1298
- | ESequential(_, before, after) {
1299
- safeCommable(before) && safeCommable(after)
1300
- } =>
1301
- "(" + self.emitStatements(before, False, False, async) + ", " +
1302
- self.emitTerm(after, async) + ")"
1303
- | _ =>
1304
- self.emitTerm(term, async)
1305
- }
1306
- }
1307
-
1308
1325
  }
1309
1326
 
1310
1327
  data ProcessedVariantCase(
@@ -18,6 +18,11 @@ extend self: BrowserSystem {
18
18
  Js.globalThis()?
19
19
  }
20
20
 
21
+ date(timeZoneId: Option[String] = None, calendarId: String = Date.isoCalendarId): Date {
22
+ let date = Date(Js->Temporal->Now->zonedDateTimeISO(timeZoneId.map {_!}.else {Js.undefined()}))
23
+ if(calendarId == Date.isoCalendarId) {date} else {date.withCalendar(calendarId)}
24
+ }
25
+
21
26
  url(): String {
22
27
  Js->location->href?
23
28
  }