firefly-compiler 0.4.77 → 0.4.79

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 (135) hide show
  1. package/.hintrc +4 -4
  2. package/.vscode/settings.json +4 -4
  3. package/bin/Release.ff +153 -153
  4. package/bin/firefly.mjs +1 -1
  5. package/compiler/Builder.ff +257 -257
  6. package/compiler/Compiler.ff +227 -227
  7. package/compiler/Dependencies.ff +187 -187
  8. package/compiler/DependencyLock.ff +17 -17
  9. package/compiler/JsEmitter.ff +946 -946
  10. package/compiler/LspHook.ff +202 -202
  11. package/compiler/ModuleCache.ff +178 -178
  12. package/compiler/Workspace.ff +88 -88
  13. package/core/.firefly/include/package-lock.json +564 -394
  14. package/core/.firefly/include/package.json +5 -5
  15. package/core/.firefly/include/prepare.sh +1 -1
  16. package/core/.firefly/package.ff +2 -2
  17. package/core/Array.ff +265 -265
  18. package/core/Atomic.ff +64 -64
  19. package/core/Box.ff +7 -7
  20. package/core/BrowserSystem.ff +40 -40
  21. package/core/BuildSystem.ff +148 -148
  22. package/core/Crypto.ff +96 -96
  23. package/core/Equal.ff +36 -36
  24. package/core/HttpClient.ff +148 -148
  25. package/core/JsSystem.ff +69 -69
  26. package/core/Json.ff +434 -434
  27. package/core/List.ff +486 -486
  28. package/core/Lock.ff +144 -144
  29. package/core/NodeSystem.ff +216 -216
  30. package/core/Ordering.ff +161 -161
  31. package/core/Path.ff +401 -401
  32. package/core/Random.ff +134 -134
  33. package/core/RbMap.ff +216 -216
  34. package/core/Show.ff +43 -43
  35. package/core/SourceLocation.ff +68 -68
  36. package/core/String.ff +16 -0
  37. package/core/Task.ff +141 -141
  38. package/experimental/benchmarks/ListGrab.ff +23 -23
  39. package/experimental/benchmarks/ListGrab.java +55 -55
  40. package/experimental/benchmarks/Pyrotek45.ff +30 -30
  41. package/experimental/benchmarks/Pyrotek45.java +64 -64
  42. package/experimental/bidirectional/Bidi.ff +88 -88
  43. package/experimental/random/Index.ff +53 -53
  44. package/experimental/random/Process.ff +120 -120
  45. package/experimental/random/Scrape.ff +51 -51
  46. package/experimental/random/Symbols.ff +73 -73
  47. package/experimental/random/Tensor.ff +52 -52
  48. package/experimental/random/Units.ff +36 -36
  49. package/experimental/s3/S3TestAuthorizationHeader.ff +39 -38
  50. package/experimental/s3/S3TestPut.ff +16 -15
  51. package/experimental/tests/TestJson.ff +26 -26
  52. package/firefly.sh +0 -0
  53. package/fireflysite/.firefly/package.ff +4 -0
  54. package/fireflysite/CommunityOverview.ff +20 -0
  55. package/fireflysite/CountingButtonDemo.ff +58 -0
  56. package/fireflysite/DocumentParser.ff +218 -0
  57. package/fireflysite/ExamplesOverview.ff +40 -0
  58. package/fireflysite/FrontPage.ff +360 -0
  59. package/fireflysite/Guide.ff +411 -0
  60. package/fireflysite/GuideAll.ff +21 -0
  61. package/fireflysite/GuideBaseTypes.ff +168 -0
  62. package/fireflysite/GuideControlFlow.ff +212 -0
  63. package/fireflysite/GuideIntroduction.ff +52 -0
  64. package/fireflysite/Main.ff +137 -15
  65. package/fireflysite/MatchingPasswordsDemo.ff +82 -0
  66. package/fireflysite/PackagesOverview.ff +49 -0
  67. package/fireflysite/PostgresqlDemo.ff +34 -0
  68. package/fireflysite/Styles.ff +495 -0
  69. package/fireflysite/assets/NotoSansMono-Regular.ttf +0 -0
  70. package/fireflysite/assets/NunitoSans-VariableFont_YTLC,opsz,wdth,wght.ttf +0 -0
  71. package/fireflysite/assets/autocomplete-small.png +0 -0
  72. package/fireflysite/assets/autocomplete.png +0 -0
  73. package/fireflysite/assets/edit-time-error.png +0 -0
  74. package/fireflysite/assets/firefly-logo-notext.png +0 -0
  75. package/fireflysite/assets/firefly-logo-yellow.png +0 -0
  76. package/fireflysite/assets/markdown/ControlFlow.md +136 -0
  77. package/fireflysite/assets/markdown/Example.md +78 -0
  78. package/lsp/.firefly/package.ff +1 -1
  79. package/lsp/CompletionHandler.ff +828 -828
  80. package/lsp/Handler.ff +714 -714
  81. package/lsp/HoverHandler.ff +79 -79
  82. package/lsp/LanguageServer.ff +272 -272
  83. package/lsp/SignatureHelpHandler.ff +55 -55
  84. package/lsp/SymbolHandler.ff +181 -181
  85. package/lsp/TestReferences.ff +17 -17
  86. package/lsp/TestReferencesCase.ff +7 -7
  87. package/lsp/stderr.txt +1 -1
  88. package/lsp/stdout.txt +34 -34
  89. package/lux/.firefly/package.ff +1 -1
  90. package/lux/Css.ff +648 -648
  91. package/lux/CssTest.ff +48 -48
  92. package/lux/Lux.ff +487 -487
  93. package/lux/LuxEvent.ff +116 -116
  94. package/lux/Main.ff +123 -123
  95. package/lux/Main2.ff +143 -144
  96. package/output/js/ff/compiler/Builder.mjs +43 -43
  97. package/output/js/ff/compiler/Dependencies.mjs +3 -3
  98. package/output/js/ff/core/Array.mjs +59 -59
  99. package/output/js/ff/core/Atomic.mjs +36 -36
  100. package/output/js/ff/core/BrowserSystem.mjs +11 -11
  101. package/output/js/ff/core/BuildSystem.mjs +30 -30
  102. package/output/js/ff/core/Crypto.mjs +40 -40
  103. package/output/js/ff/core/HttpClient.mjs +56 -56
  104. package/output/js/ff/core/Json.mjs +147 -147
  105. package/output/js/ff/core/List.mjs +50 -50
  106. package/output/js/ff/core/Lock.mjs +97 -97
  107. package/output/js/ff/core/NodeSystem.mjs +83 -83
  108. package/output/js/ff/core/Ordering.mjs +8 -8
  109. package/output/js/ff/core/Path.mjs +231 -231
  110. package/output/js/ff/core/Random.mjs +56 -56
  111. package/output/js/ff/core/String.mjs +20 -0
  112. package/output/js/ff/core/Task.mjs +31 -31
  113. package/package.json +1 -1
  114. package/rpc/.firefly/package.ff +1 -1
  115. package/rpc/Rpc.ff +70 -70
  116. package/s3/.firefly/package.ff +1 -1
  117. package/s3/S3.ff +94 -94
  118. package/unsafejs/UnsafeJs.ff +19 -19
  119. package/vscode/LICENSE.txt +21 -21
  120. package/vscode/Prepublish.ff +15 -15
  121. package/vscode/README.md +16 -16
  122. package/vscode/client/package.json +22 -22
  123. package/vscode/client/src/extension.ts +104 -104
  124. package/vscode/icons/firefly-icon.svg +10 -10
  125. package/vscode/language-configuration.json +61 -61
  126. package/vscode/package-lock.json +3623 -3623
  127. package/vscode/package.json +15 -1
  128. package/vscode/snippets.json +241 -241
  129. package/vscode/syntaxes/firefly-markdown-injection.json +45 -0
  130. package/webserver/.firefly/include/package-lock.json +22 -16
  131. package/webserver/.firefly/include/package.json +5 -5
  132. package/webserver/.firefly/package.ff +2 -2
  133. package/webserver/WebServer.ff +685 -685
  134. package/websocket/.firefly/package.ff +1 -1
  135. package/websocket/WebSocket.ff +131 -131
@@ -0,0 +1,212 @@
1
+ import Guide
2
+
3
+ new(): Document {
4
+ ReadyDocument([
5
+
6
+ Section("Control flow", [
7
+ Paragraph([
8
+ Text("Firefly provides several ways to implement branching. ")
9
+ Anchor("Pattern matching")
10
+ Text(" is the most powerful, built directly into the language. ")
11
+ Code("if")
12
+ Text(", ")
13
+ Code("elseIf")
14
+ Text(" and ")
15
+ Code("else")
16
+ Text(" do what you expect and are functions and methods in the standard library, implemented using the")
17
+ Anchor("Option")
18
+ Text(" type. An then finally, there are ")
19
+ Anchor("exceptions")
20
+ Text(".")
21
+ ])
22
+ ])
23
+
24
+ Section("Pattern matching", [
25
+ Paragraph([
26
+ Text("Pattern matching allows you to check a given data structure against a pattern. ")
27
+ Text("For example, if we want to parse the command line arguments provided by the user, we could do it like this:")
28
+ ])
29
+ CodeBlock("""
30
+ let pair = system.arguments().{
31
+ | [host] => Pair(host, 80)
32
+ | ["localhost", port] => Pair("localhost", port.grabInt())
33
+ | _ =>
34
+ system.writeErrorLine("Usage: 'localhost' | (host port)")
35
+ system.exit(0)
36
+ }
37
+ """, firefly = True)
38
+ Paragraph([
39
+ Text("In Firefly you construct a list of strings (")
40
+ Code("List[String]")
41
+ Text(") like this ")
42
+ Code("""["example.com", "80"]""")
43
+ Text(", and using pattern matching you can de-construct in the same way.")
44
+ ])
45
+ Paragraph([
46
+ Text("The basic syntax for pattern matching is:")
47
+ ])
48
+ CodeBlock("""
49
+ data.{
50
+ | pattern1 => // case 1
51
+ | pattern2 => // case N
52
+ ...
53
+ }
54
+ """, firefly = True)
55
+ Paragraph([
56
+ Text("The patterns must be exhaustive, that is, for any possible value of the given type, there must be a matching pattern. ")
57
+ Text("In the example above, there are no value for the empty list ")
58
+ Code("[]")
59
+ Text(", list with two values, where the first is not ")
60
+ Code(""""localhost"""")
61
+ Text(" or lists with more than 2 arguments. That's why we need the wildcard case at the end. ")
62
+ Text("Without this last case, the compiler would produce a compile-time error, stating that the patterns must be exhaustive.")
63
+ ])
64
+ Paragraph([
65
+ Text("Here are more examples — all exhaustive. Let's start with records:")
66
+ ])
67
+ CodeBlock("""
68
+ pair.{
69
+ | Pair(first, second) =>
70
+ }
71
+ """, firefly = True)
72
+
73
+ Paragraph([
74
+ Text("Numbers")
75
+ ])
76
+ CodeBlock("""
77
+ n.{
78
+ | 1 =>
79
+ | 2 =>
80
+ | n =>
81
+ }
82
+ """, firefly = True)
83
+
84
+ Paragraph([
85
+ Text("Booleans")
86
+ ])
87
+ CodeBlock("""
88
+ n.{
89
+ | True =>
90
+ | False =>
91
+ }
92
+ """, firefly = True)
93
+ Paragraph([
94
+ Text("And you can combine pattern as needed. Imagine you have a pair of type ")
95
+ Code("Pair[List[Bool], Pair(Int, String)]")
96
+ ])
97
+ CodeBlock("""
98
+ pair.{
99
+ | Pair([True, False], Pair(42, "foo")) =>
100
+ | other =>
101
+ }
102
+ """, firefly = True)
103
+ ])
104
+
105
+ Section("Option", [
106
+ Paragraph([
107
+ Text("Sometimes you don't have a value. Other languages uses ")
108
+ Code("null")
109
+ Text(" for this purpose, but Firefly does not have ")
110
+ Code("null")
111
+ Text(". Instead, we have ")
112
+ Code("Option")
113
+ Text(" from the core package.")
114
+ ])
115
+ CodeBlock("""
116
+ data Option[T] {
117
+ None
118
+ Some(value: T)
119
+ }
120
+ """, firefly = True)
121
+ Paragraph([
122
+ Text("For some type T, say String, Option[String] is either some string or no value (")
123
+ Code("None")
124
+ Text("). This way, the type system guides you to check for no-value.")
125
+ ])
126
+
127
+ Paragraph([
128
+ Text("Many functions and methods returns an ")
129
+ Code("Option")
130
+ Text(" in Firefly. For instance the ")
131
+ Code("getInt ")
132
+ Text(" method on ")
133
+ Code("String")
134
+ Text(" . This method returns ")
135
+ Code("Some[Int]")
136
+ Text(" when the string consists only of digits and ")
137
+ Code("None")
138
+ Text(" otherwise. We can perform pattern matching on ")
139
+ Code("Option")
140
+ Text("like this:")
141
+ ])
142
+ CodeBlock("""
143
+ port.getInt().{
144
+ | None => 80
145
+ | Some(p) => p
146
+ }
147
+ """, firefly = True)
148
+ Paragraph([
149
+ Text("Many methods like ")
150
+ Code("getInt")
151
+ Text(" have a non-total counterpart ")
152
+ Code("grabInt")
153
+ Text(" , which returns an ")
154
+ Code("Int")
155
+ Text(" . But it will throw an exception when the input cannot be parsed. Options let's you code in an exception-safe manner.")
156
+ ])
157
+ ])
158
+
159
+
160
+ Section("if - elseIf - else", [
161
+ Paragraph([
162
+ Text("You write if-statements in Firefly like this:")
163
+ ])
164
+ CodeBlock("""
165
+ if(path == "/") {
166
+ response.writeText("<!doctype html>")
167
+ } elseIf {path.startsWith("/js/")} {
168
+ response.writeText("<script>")
169
+ } else {
170
+ response.writeStatus("404 Not found")
171
+ }
172
+ """, firefly = True)
173
+ Paragraph([
174
+ Text("You can also use it as an expression like this")
175
+ ])
176
+ CodeBlock("""
177
+ let contentType = if(path == "/") {
178
+ "text/html; charset=UTF-8"
179
+ } elseIf(directory2.exists) {
180
+ "text/javascript; charset=UTF-8"
181
+ } else {
182
+ "text/plain; charset=UTF-8"
183
+ }
184
+ """, firefly = True)
185
+ Paragraph([
186
+ Code("if")
187
+ Text(", ")
188
+ Code("elseIf")
189
+ Text(" and ")
190
+ Code("else")
191
+ Text(" are not keywords or construct build into Firefly. ")
192
+ Text("If you are curious, you can look at how they are implemented. ")
193
+ Code("if")
194
+ Text(" is just a function defined like this: ")
195
+ ])
196
+ CodeBlock("""
197
+ if[T](condition: Bool, body: () => T): Option[T] {
198
+ condition.{
199
+ | False => None
200
+ | True => Some(body())
201
+ }
202
+ }
203
+ """, firefly = True)
204
+ // TODO: But still, why are this syntactically correct?
205
+ ])
206
+ Section("Exceptions", [
207
+ Paragraph([
208
+ Text("...")
209
+ ])
210
+ ])
211
+ ])
212
+ }
@@ -0,0 +1,52 @@
1
+ import Guide
2
+
3
+ new(): Document {
4
+ ReadyDocument([
5
+ Section("Guide", [
6
+ Paragraph([
7
+ Text("In this guide you will learn to use Firefly.")
8
+ Text("Firefly is a programming language that compiles to JavaScript.")
9
+ Text("It runs in the browser and on the server, and lets you develop webapps with a minimum of hassle.")
10
+ ])
11
+ ])
12
+ Section("Getting started", [
13
+ Paragraph([
14
+ Text("Firefly comes with a compiler, a build system and a package manager.")
15
+ ])
16
+ Paragraph([
17
+ Text("Install Firefly:")
18
+ ])
19
+ CodeBlock("npm install -g firefly-compiler")
20
+ Paragraph([
21
+ Text("Save this code as")
22
+ Code("Hello.ff")
23
+ Text(":")
24
+ ])
25
+ CodeBlock("""
26
+ nodeMain(system: NodeSystem) {
27
+ system.writeLine("Hello, World!")
28
+ }
29
+ """, firefly = True)
30
+ Paragraph([
31
+ Text("And run it:")
32
+ ])
33
+ CodeBlock("firefly Hello.ff")
34
+ Paragraph([
35
+ Text("You now know how to run Firefly code!")
36
+ ])
37
+ ])
38
+ Section("Editor support", [
39
+ Paragraph([
40
+ Text("Install the")
41
+ Link("Firefly Language VSCode extension", "https://marketplace.visualstudio.com/items?itemName=firefly-team.firefly-lang")
42
+ Text(" to get autocompletion, renaming, go to definition, highlighting, etc. You can find it under Extensions in VSCode.")
43
+ ])
44
+ Paragraph([
45
+ Text("The Firefly code highlighting on this site matches the Dark Modern theme in VSCode.")
46
+ ])
47
+ Paragraph([
48
+ Text("If you'd like to make an extension for a different editor, the language server is available, as well as the source code for the VSCode extension.")
49
+ ])
50
+ ])
51
+ ])
52
+ }
@@ -1,15 +1,137 @@
1
- dependency ff:webserver:0.0.0
2
- import WebServer from ff:webserver
3
-
4
- nodeMain(system: NodeSystem): Unit {
5
- let host = system.arguments().grab(0)
6
- let port = system.arguments().grab(1).grabInt()
7
- WebServer.new(system, host, port).listen {request =>
8
- let parameters = if(request.readRawQueryString().size() == 0) {""} else {
9
- "?" + request.readRawQueryString()
10
- }
11
- request.writeHeader("Location", "https://www.firefly-lang.org" + request.readPath() + parameters)
12
- request.writeStatus("302 Found")
13
- }
14
- }
15
-
1
+ import WebServer from ff:webserver
2
+ import Lux from ff:lux
3
+ import Guide
4
+ import GuideAll
5
+ import ExamplesOverview
6
+ import PackagesOverview
7
+ import CommunityOverview
8
+ import FrontPage
9
+ import Styles
10
+
11
+ nodeMain(system: NodeSystem): Unit {
12
+ let host = system.arguments().grab(0)
13
+ let port = system.arguments().grab(1).grabInt()
14
+ let cacheSalt = system.crypto().randomBuffer(16)
15
+ system.writeLine("Listening on " + host + ":" + port)
16
+ WebServer.new(system, host, port).listen {request =>
17
+ let path = request.readPath()
18
+ let segments = path.split('/').filter {s => s != "" && s != "." && s != ".."}
19
+ segments.{
20
+ | ["guide", ...] =>
21
+ serveGuideHtml("Firefly Guide", request)
22
+ | ["examples", ...] =>
23
+ serveGuideHtml("Firefly Examples", request)
24
+ | ["packages", ...] =>
25
+ serveGuideHtml("Firefly Examples", request)
26
+ | ["community", ...] =>
27
+ serveGuideHtml("Firefly Examples", request)
28
+ | ["front", ...] =>
29
+ serveGuideHtml("Firefly Examples", request)
30
+ | ["js", ...] =>
31
+ let asset = if(path == "/js/ff/fireflysite/Main.mjs" && system.assets().exists("/js/Main.bundle.js")) {
32
+ "/js/Main.bundle.js"
33
+ } else {
34
+ path
35
+ }
36
+ serveAsset(system, cacheSalt, request, "text/javascript; charset=UTF-8", asset)
37
+ | ["favicon.ico"] =>
38
+ serveAsset(system, cacheSalt, request, "image/png", "/assets/firefly-logo-notext.png")
39
+ | ["assets", "FireflyMono.ttf"] =>
40
+ serveAsset(system, cacheSalt, request, "image/png", "/assets/NotoSansMono-Regular.ttf")
41
+ | ["assets", "FireflySans.ttf"] =>
42
+ serveAsset(system, cacheSalt, request, "image/png", "/assets/NunitoSans-VariableFont_YTLC,opsz,wdth,wght.ttf")
43
+ | ["assets", ...rest] => serveAssets(system, cacheSalt, request, rest)
44
+ | _ =>
45
+ let parameters = if(request.readRawQueryString().size() == 0) {""} else {
46
+ "?" + request.readRawQueryString()
47
+ }
48
+ request.writeHeader("Location", "https://www.firefly-lang.org" + path + parameters)
49
+ request.writeStatus("302 Found")
50
+ }
51
+ }
52
+ }
53
+
54
+ browserMain(system: BrowserSystem): Unit {
55
+ let demos = ExamplesOverview.demos()
56
+ let guides = [
57
+ Guide("/front/", [FrontPage.new()])
58
+ Guide("/guide/", GuideAll.mock())
59
+ Guide("/examples/", ExamplesOverview.mock())
60
+ Guide("/packages/", [PackagesOverview.new()])
61
+ Guide("/community/", [CommunityOverview.new()])
62
+ ]
63
+ guides.collect {guide =>
64
+ if(system.urlPath().startsWith(guide.prefix)):
65
+ Lux.renderById(system, "main") {lux =>
66
+ let kebab = system.urlPath().dropFirst(guide.prefix.size())
67
+ Guide.render(lux, system, guide.prefix, kebab, guides, demos)
68
+ }
69
+ }
70
+ }
71
+
72
+ buildMain(system: BuildSystem) {
73
+ let browser = system.compileForBrowser("Main.ff")
74
+ let assets = AssetSystem.create()
75
+ .addAssets("/js/", browser.assets())
76
+ .addAssets("/assets/", system.packageAssets().assets("/assets/"))
77
+ system.setAssets(assets)
78
+ }
79
+
80
+ serveAssets(system: NodeSystem, salt: Buffer, request: WebRequest[WebResponse], segments: List[String]): Unit {
81
+ let asset = "/assets/" + segments.join("/")
82
+ if(!system.assets().exists(asset)) {
83
+ request.writeStatus("404 Not Found")
84
+ } else:
85
+
86
+ guessContentType(asset).or {
87
+ request.writeStatus("404 Not Found")
88
+ }: contentType =>
89
+
90
+ serveAsset(system, salt, request, contentType, asset)
91
+ }
92
+
93
+ guessContentType(path: String): Option[String] {
94
+ path.split('.').last().flatMap {
95
+ | "md" => Some("text/markdown")
96
+ | "png" => Some("image/png")
97
+ | "ttf" => Some("font/ttf")
98
+ | _ => None
99
+ }
100
+ }
101
+
102
+ serveAsset(system: NodeSystem, salt: Buffer, request: WebRequest[WebResponse], contentType: String, asset: String): Unit {
103
+ let etag = "\"" + system.crypto().hmacSha256(salt, asset.toBuffer()).toHex() + "\""
104
+ request.writeHeader("Content-Type", contentType)
105
+ if(request.readHeader("host") == Some("localhost:8080")) {
106
+ request.writeHeader("Cache-Control", "public, max-age=0, must-revalidate")
107
+ } else {
108
+ request.writeHeader("Cache-Control", "public, max-age=60, must-revalidate")
109
+ }
110
+ request.writeHeader("ETag", etag)
111
+ if(request.readHeader("if-none-match").any {_.trim() == etag}) {
112
+ request.writeStatus("304 Not Modified")
113
+ } else {
114
+ request.writeStream(system.assets().readStream(asset))
115
+ }
116
+ }
117
+
118
+ serveGuideHtml(title: String, request: WebRequest[WebResponse]): Unit {
119
+ request.writeHeader("Content-Type", "text/html; charset=UTF-8")
120
+ request.writeText("<!doctype html>")
121
+ request.writeText("<html lang='en' style='background-color: #ffffff; color: #333333; width: 100%; height: 100%; color-scheme: light;'>")
122
+ request.writeText("<head>")
123
+ request.writeText("<title>" + title + "</title>")
124
+ request.writeText("<meta name='viewport' content='width=device-width, initial-scale=1.0'>")
125
+ request.writeText("<meta name='theme-color' content='#ecc45e'>")
126
+ request.writeText("<link rel='preload' href='/assets/FireflyMono.ttf' as='font' crossorigin='anonymous'>")
127
+ request.writeText("<link rel='preload' href='/assets/FireflySans.ttf' as='font' crossorigin='anonymous'>")
128
+ request.writeText("<link rel='preload' href='/assets/firefly-logo-yellow.png' as='image'>")
129
+ request.writeText("<style>@font-face { font-family: 'Firefly Mono'; font-display: fallback; src: url('/assets/FireflyMono.ttf'); unicode-range: U+000-5FF; }</style>")
130
+ request.writeText("<style>@font-face { font-family: 'Firefly Sans'; font-display: fallback; src: url('/assets/FireflySans.ttf'); unicode-range: U+000-5FF; }</style>")
131
+ request.writeText("</head>")
132
+ request.writeText("<body style='margin: 0; padding: 0; width: 100%; height: 100%; touch-action: manipulation;'>")
133
+ request.writeText("<div id='main'></div>")
134
+ request.writeText("<script type='module' src='/js/ff/fireflysite/Main.mjs'></script>")
135
+ request.writeText("</body>")
136
+ request.writeText("</html>")
137
+ }
@@ -0,0 +1,82 @@
1
+ import Guide
2
+ import Lux from ff:lux
3
+ import LuxEvent from ff:lux
4
+
5
+ name = "Matching passwords"
6
+
7
+ new(): Demo {
8
+ Demo(
9
+ name
10
+ {render(_)}
11
+ )
12
+ }
13
+
14
+ render(lux: Lux): Unit {
15
+ function passwordInput(password: String, setPassword: String => Unit) {
16
+ lux.div {
17
+ lux.input {
18
+ lux.set("type", "password")
19
+ lux.set("autocomplete", "new-password")
20
+ lux.setValue(password)
21
+ lux.onInput {event =>
22
+ setPassword(event.text())
23
+ }
24
+ }
25
+ }
26
+ }
27
+ lux.form {
28
+ lux.useState(""): password1, setPassword1 =>
29
+ lux.useState(""): password2, setPassword2 =>
30
+ passwordInput(password1, setPassword1)
31
+ passwordInput(password2, setPassword2)
32
+ lux.div {
33
+ if(password1 != password2) {
34
+ lux.text("Passwords don't match!")
35
+ } elseIf {password2.size() != 0} {
36
+ lux.text("Passwords match!")
37
+ }
38
+ }
39
+ }
40
+ }
41
+
42
+ newDocument(): Document {
43
+ ReadyDocument([
44
+ Section(name, [
45
+ Paragraph([Text("Two passwords fields and a check that they match.")])
46
+ ])
47
+ Section("Demo", [
48
+ LuxDemo(name)
49
+ ])
50
+ Section("Code", [
51
+ CodeBlock("""
52
+ render(lux: Lux): Unit {
53
+ function passwordInput(password: String, setPassword: String => Unit) {
54
+ lux.div {
55
+ lux.input {
56
+ lux.set("type", "password")
57
+ lux.set("autocomplete", "new-password")
58
+ lux.setValue(password)
59
+ lux.onInput {event =>
60
+ setPassword(event.text())
61
+ }
62
+ }
63
+ }
64
+ }
65
+ lux.form {
66
+ lux.useState(""): password1, setPassword1 =>
67
+ lux.useState(""): password2, setPassword2 =>
68
+ passwordInput(password1, setPassword1)
69
+ passwordInput(password2, setPassword2)
70
+ lux.div {
71
+ if(password1 != password2) {
72
+ lux.text("Passwords don't match!")
73
+ } elseIf {password2.size() != 0} {
74
+ lux.text("Passwords match!")
75
+ }
76
+ }
77
+ }
78
+ }
79
+ """, firefly = True)
80
+ ])
81
+ ])
82
+ }
@@ -0,0 +1,49 @@
1
+ import Guide
2
+ import CountingButtonDemo
3
+ import MatchingPasswordsDemo
4
+
5
+ new(): Document {
6
+ ReadyDocument([
7
+ Section("Packages", [
8
+ Paragraph([
9
+ Text("Here you'll eventually find the package index.")
10
+ Text("For now, here's a short list of essential packages.")
11
+ ])
12
+ ])
13
+ Section("ff:core", [
14
+ Paragraph([
15
+ Text("The standard library of Firefly.")
16
+ ])
17
+ ])
18
+ Section("ff:webserver", [
19
+ Paragraph([
20
+ Text("A webserver package. Has HTTPS and WebSocket support.")
21
+ ])
22
+ ])
23
+ Section("ff:websocket", [
24
+ Paragraph([
25
+ Text("A package for making websocket connections.")
26
+ ])
27
+ ])
28
+ Section("ff:postgresql", [
29
+ Paragraph([
30
+ Text("A package for connecting to PostgreSQL. Has connection pool support.")
31
+ ])
32
+ ])
33
+ Section("ff:lux", [
34
+ Paragraph([
35
+ Text("A package for building interactive web interfaces.")
36
+ ])
37
+ ])
38
+ Section("ff:rpc", [
39
+ Paragraph([
40
+ Text("A package for type safe remote procedure calls.")
41
+ ])
42
+ ])
43
+ Section("ff:unsafejs", [
44
+ Paragraph([
45
+ Text("A FFI package for JavaScript.")
46
+ ])
47
+ ])
48
+ ])
49
+ }
@@ -0,0 +1,34 @@
1
+ import Guide
2
+ import Lux from ff:lux
3
+ import LuxEvent from ff:lux
4
+
5
+ name = "Connecting to PostgreSQL"
6
+
7
+ newDocument(): Document {
8
+ ReadyDocument([
9
+ Section(name, [
10
+ Paragraph([Text("Connect to a PostgreSQL database and run a query.")])
11
+ Paragraph([Text("Add a dependency on "), Code("ff:postgresql"), Text(":")])
12
+ CodeBlock("""
13
+ dependency ff:postgresql:0.0.0
14
+ """, firefly = True)
15
+ Paragraph([Text("Import the"), Code("Pg"), Text("module from it:")])
16
+ CodeBlock("""
17
+ import Pg from ff:postgresql
18
+ """, firefly = True)
19
+ Paragraph([Text("Create a connection pool with the appropriate connection parameters:")])
20
+ CodeBlock("""
21
+ let pool = Pg.newPool(...)
22
+ """, firefly = True)
23
+ Paragraph([Text("And run your first transaction, e.g.:")])
24
+ CodeBlock("""
25
+ pool.transaction {connection =>
26
+ let emails = connection.statement("select email from users")
27
+ .map {row => row.getString("email").grab()}
28
+ Log.debug(emails)
29
+ }
30
+ """, firefly = True)
31
+ Paragraph([Text("Note that"), Code(".map", firefly = True), Text("here runs for each row of the result.")])
32
+ ])
33
+ ])
34
+ }