firefly-compiler 0.5.79 → 0.5.80
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.
- package/compiler/Builder.ff +31 -39
- package/compiler/Compiler.ff +14 -4
- package/compiler/DevelopMode.ff +406 -0
- package/compiler/Main.ff +73 -53
- package/compiler/ModuleCache.ff +5 -5
- package/core/.firefly/include/package.json +1 -1
- package/core/BuildSystem.ff +82 -11
- package/core/NodeSystem.ff +47 -30
- package/core/Path.ff +7 -2
- package/experimental/proxy/Main.ff +60 -0
- package/experimental/proxy/Runner.ff +11 -0
- package/experimental/proxy/Tcp.ff +162 -0
- package/experimental/random/Superdigit.ff +18 -0
- package/experimental/terrain/Main.ff +40 -0
- package/experimental/terrain/Terrain.ff +97 -0
- package/experimental/terrain/Terrain2.ff +109 -0
- package/fireflysite/Main.ff +0 -1
- package/fireflysite/assets/markdown/reference/statements-and-expressions.md +1 -1
- package/lsp/CompletionHandler.ff +2 -2
- package/output/js/ff/compiler/Builder.mjs +24 -48
- package/output/js/ff/compiler/Builder.mjs.map +7 -11
- package/output/js/ff/compiler/Compiler.mjs +66 -12
- package/output/js/ff/compiler/Compiler.mjs.map +18 -14
- package/output/js/ff/compiler/Dependencies.mjs.map +2 -2
- package/output/js/ff/compiler/DependencyLock.mjs.map +1 -1
- package/output/js/ff/compiler/Deriver.mjs.map +1 -1
- package/output/js/ff/compiler/DevelopMode.mjs +1049 -0
- package/output/js/ff/compiler/DevelopMode.mjs.map +183 -0
- package/output/js/ff/compiler/Dictionaries.mjs.map +1 -1
- package/output/js/ff/compiler/Environment.mjs.map +1 -1
- package/output/js/ff/compiler/Inference.mjs.map +1 -1
- package/output/js/ff/compiler/JsEmitter.mjs.map +1 -1
- package/output/js/ff/compiler/JsImporter.mjs.map +1 -1
- package/output/js/ff/compiler/LspHook.mjs.map +1 -1
- package/output/js/ff/compiler/Main.mjs +256 -105
- package/output/js/ff/compiler/Main.mjs.map +43 -38
- package/output/js/ff/compiler/ModuleCache.mjs +12 -8
- package/output/js/ff/compiler/ModuleCache.mjs.map +4 -3
- package/output/js/ff/compiler/Parser.mjs.map +1 -1
- package/output/js/ff/compiler/Patterns.mjs.map +1 -1
- package/output/js/ff/compiler/Resolver.mjs.map +1 -1
- package/output/js/ff/compiler/SourceMap.mjs.map +1 -1
- package/output/js/ff/compiler/Substitution.mjs.map +1 -1
- package/output/js/ff/compiler/Syntax.mjs.map +1 -1
- package/output/js/ff/compiler/Token.mjs.map +1 -1
- package/output/js/ff/compiler/Tokenizer.mjs.map +1 -1
- package/output/js/ff/compiler/Unification.mjs.map +1 -1
- package/output/js/ff/compiler/Wildcards.mjs.map +1 -1
- package/output/js/ff/compiler/Workspace.mjs.map +1 -1
- package/output/js/ff/core/Any.mjs.map +1 -1
- package/output/js/ff/core/Array.mjs.map +1 -1
- package/output/js/ff/core/AssetSystem.mjs.map +1 -1
- package/output/js/ff/core/Atomic.mjs.map +1 -1
- package/output/js/ff/core/Bool.mjs.map +1 -1
- package/output/js/ff/core/BrowserSystem.mjs.map +1 -1
- package/output/js/ff/core/Buffer.mjs.map +1 -1
- package/output/js/ff/core/BuildSystem.mjs +116 -12
- package/output/js/ff/core/BuildSystem.mjs.map +35 -6
- package/output/js/ff/core/Channel.mjs.map +1 -1
- package/output/js/ff/core/Char.mjs.map +1 -1
- package/output/js/ff/core/Core.mjs.map +1 -1
- package/output/js/ff/core/Crypto.mjs.map +1 -1
- package/output/js/ff/core/Date.mjs.map +1 -1
- package/output/js/ff/core/Duration.mjs.map +1 -1
- package/output/js/ff/core/Equal.mjs.map +1 -1
- package/output/js/ff/core/Error.mjs.map +1 -1
- package/output/js/ff/core/FileHandle.mjs.map +1 -1
- package/output/js/ff/core/Float.mjs.map +1 -1
- package/output/js/ff/core/HttpClient.mjs.map +1 -1
- package/output/js/ff/core/Int.mjs.map +1 -1
- package/output/js/ff/core/IntMap.mjs.map +1 -1
- package/output/js/ff/core/Js.mjs.map +1 -1
- package/output/js/ff/core/JsSystem.mjs.map +1 -1
- package/output/js/ff/core/JsValue.mjs.map +1 -1
- package/output/js/ff/core/Json.mjs.map +1 -1
- package/output/js/ff/core/List.mjs.map +1 -1
- package/output/js/ff/core/Lock.mjs.map +1 -1
- package/output/js/ff/core/Log.mjs.map +1 -1
- package/output/js/ff/core/Map.mjs.map +1 -1
- package/output/js/ff/core/NodeSystem.mjs +54 -20
- package/output/js/ff/core/NodeSystem.mjs.map +14 -6
- package/output/js/ff/core/Nothing.mjs.map +1 -1
- package/output/js/ff/core/Option.mjs.map +1 -1
- package/output/js/ff/core/Ordering.mjs.map +1 -1
- package/output/js/ff/core/Pair.mjs.map +1 -1
- package/output/js/ff/core/Path.mjs +30 -4
- package/output/js/ff/core/Path.mjs.map +8 -6
- package/output/js/ff/core/Queue.mjs.map +1 -1
- package/output/js/ff/core/Random.mjs.map +1 -1
- package/output/js/ff/core/RbMap.mjs.map +1 -1
- package/output/js/ff/core/Serializable.mjs.map +1 -1
- package/output/js/ff/core/Set.mjs.map +1 -1
- package/output/js/ff/core/Show.mjs.map +1 -1
- package/output/js/ff/core/SourceLocation.mjs.map +1 -1
- package/output/js/ff/core/Stream.mjs.map +1 -1
- package/output/js/ff/core/String.mjs.map +1 -1
- package/output/js/ff/core/StringMap.mjs.map +1 -1
- package/output/js/ff/core/Task.mjs.map +1 -1
- package/output/js/ff/core/Try.mjs.map +1 -1
- package/output/js/ff/core/Unit.mjs.map +1 -1
- package/output/js/ff/core/node_modules +1 -0
- package/package.json +1 -1
- package/vscode/package.json +1 -1
- package/webserver/.firefly/include/package.json +1 -1
- package/webserver/WebServer.ff +6 -3
package/compiler/Main.ff
CHANGED
|
@@ -11,10 +11,12 @@ import Inference
|
|
|
11
11
|
import ModuleCache
|
|
12
12
|
import LspHook
|
|
13
13
|
import DependencyLock
|
|
14
|
+
import DevelopMode
|
|
14
15
|
|
|
15
16
|
data MainCommand {
|
|
16
17
|
BootstrapCommand
|
|
17
18
|
RunCommand(mainPath: String, argument: List[String])
|
|
19
|
+
DevelopCommand(mainPath: String, argument: List[String])
|
|
18
20
|
BrowserCommand(mainPath: String)
|
|
19
21
|
BuildCommand(mainPath: String)
|
|
20
22
|
CheckCommand(filePath: String)
|
|
@@ -27,43 +29,6 @@ main(system: NodeSystem): Unit {
|
|
|
27
29
|
|
|
28
30
|
let fireflyPath = detectFireflyPath(system)
|
|
29
31
|
|
|
30
|
-
function buildScript(
|
|
31
|
-
mainPath: Path
|
|
32
|
-
mainPackagePair: PackagePair
|
|
33
|
-
emitTarget: EmitTarget
|
|
34
|
-
resolvedDependencies: ResolvedDependencies
|
|
35
|
-
): ModuleKey {
|
|
36
|
-
let fixedPackagePaths = if(resolvedDependencies.packagePaths.contains(PackagePair("ff", "core"))) {
|
|
37
|
-
resolvedDependencies.packagePaths
|
|
38
|
-
} else {
|
|
39
|
-
resolvedDependencies.packagePaths.add(PackagePair("ff", "core"), fireflyPath.slash("core"))
|
|
40
|
-
}
|
|
41
|
-
let compilerModulePath = if(emitTarget != EmitBrowser && emitTarget != EmitExecutable) {
|
|
42
|
-
fireflyPath.slash("output").slash("js").slash("ff").slash("compiler/Builder.mjs")
|
|
43
|
-
}
|
|
44
|
-
let targetName = emitTarget.{
|
|
45
|
-
| EmitBuild => "build"
|
|
46
|
-
| EmitNode => "node"
|
|
47
|
-
| EmitBrowser => "browser"
|
|
48
|
-
| EmitExecutable => "executable"
|
|
49
|
-
}
|
|
50
|
-
let folders = mainPath.parent().grab().relativeListTo(fixedPackagePaths.grab(mainPackagePair))
|
|
51
|
-
let name = mainPath.base().removeLast(".ff").grab()
|
|
52
|
-
let moduleKey = ModuleKey(mainPackagePair, folders, name)
|
|
53
|
-
Builder.build(
|
|
54
|
-
system = system
|
|
55
|
-
emitTarget = emitTarget
|
|
56
|
-
mainModules = [moduleKey]
|
|
57
|
-
resolvedDependencies = resolvedDependencies.ResolvedDependencies(packagePaths = fixedPackagePaths)
|
|
58
|
-
compilerModulePath = compilerModulePath
|
|
59
|
-
tempPath = system.path(".firefly").slash("temporary")
|
|
60
|
-
jsOutputPath = system.path(".firefly").path("output").path(targetName)
|
|
61
|
-
printMeasurements = False
|
|
62
|
-
moduleCache = ModuleCache.new(0)
|
|
63
|
-
)
|
|
64
|
-
moduleKey
|
|
65
|
-
}
|
|
66
|
-
|
|
67
32
|
function runCommand(command: MainCommand) {
|
|
68
33
|
| RunCommand(mainFile, arguments) =>
|
|
69
34
|
let resolvedDependencies = Dependencies.process(
|
|
@@ -73,12 +38,15 @@ main(system: NodeSystem): Unit {
|
|
|
73
38
|
)
|
|
74
39
|
prepareFireflyDirectory(system.path("."))
|
|
75
40
|
let mainPath = system.path(mainFile)
|
|
76
|
-
let moduleKey = buildScript(mainPath, resolvedDependencies.mainPackagePair, EmitNode, resolvedDependencies)
|
|
41
|
+
let moduleKey = buildScript(system, mainPath, resolvedDependencies.mainPackagePair, EmitNode, resolvedDependencies)
|
|
77
42
|
if(!importAndRun(system, fireflyPath, "node", moduleKey, arguments)) {
|
|
78
43
|
let at = Location(system.path(mainFile).absolute(), 1, 1)
|
|
79
44
|
throw(CompileError(at, "This module does not contain a 'nodeMain' function"))
|
|
80
45
|
}
|
|
81
46
|
|
|
47
|
+
| DevelopCommand(mainFile, arguments) =>
|
|
48
|
+
DevelopMode.run(system, fireflyPath, mainFile, arguments)
|
|
49
|
+
|
|
82
50
|
| BrowserCommand(mainFile) =>
|
|
83
51
|
let resolvedDependencies = Dependencies.process(
|
|
84
52
|
system.httpClient()
|
|
@@ -88,7 +56,7 @@ main(system: NodeSystem): Unit {
|
|
|
88
56
|
prepareFireflyDirectory(system.path("."))
|
|
89
57
|
let mainPath = system.path(mainFile)
|
|
90
58
|
let moduleKey =
|
|
91
|
-
buildScript(mainPath, resolvedDependencies.mainPackagePair, EmitBrowser, resolvedDependencies)
|
|
59
|
+
buildScript(system, mainPath, resolvedDependencies.mainPackagePair, EmitBrowser, resolvedDependencies)
|
|
92
60
|
bundleForBrowser(system, resolvedDependencies.mainPackagePair, moduleKey)
|
|
93
61
|
|
|
94
62
|
| BuildCommand(mainFile) =>
|
|
@@ -99,8 +67,8 @@ main(system: NodeSystem): Unit {
|
|
|
99
67
|
)
|
|
100
68
|
prepareFireflyDirectory(system.path("."))
|
|
101
69
|
let mainPath = system.path(mainFile)
|
|
102
|
-
let moduleKey = buildScript(mainPath, resolvedDependencies.mainPackagePair, EmitBuild, resolvedDependencies)
|
|
103
|
-
buildScript(mainPath, resolvedDependencies.mainPackagePair, EmitExecutable, resolvedDependencies)
|
|
70
|
+
let moduleKey = buildScript(system, mainPath, resolvedDependencies.mainPackagePair, EmitBuild, resolvedDependencies)
|
|
71
|
+
buildScript(system, mainPath, resolvedDependencies.mainPackagePair, EmitExecutable, resolvedDependencies)
|
|
104
72
|
bundleForPkg(system, resolvedDependencies.mainPackagePair, mainPath.base())
|
|
105
73
|
importAndRun(system, fireflyPath, "build", moduleKey, [])
|
|
106
74
|
|
|
@@ -141,7 +109,6 @@ main(system: NodeSystem): Unit {
|
|
|
141
109
|
singleFilePackages = [].toSet()
|
|
142
110
|
)
|
|
143
111
|
compilerModulePath = None
|
|
144
|
-
tempPath = workingDirectory.slash("output").slash("temporary")
|
|
145
112
|
jsOutputPath = workingDirectory.slash("output").slash("js")
|
|
146
113
|
printMeasurements = True
|
|
147
114
|
moduleCache = ModuleCache.new(0)
|
|
@@ -184,14 +151,55 @@ usageString = """
|
|
|
184
151
|
usage: firefly <main-file> [<main-arguments>] | <command> [<command-arguments>]
|
|
185
152
|
|
|
186
153
|
These are the commands:
|
|
187
|
-
run <main-file> [<main-arguments>]
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
154
|
+
run <main-file> [<main-arguments>] Run the main file with the provided arguments
|
|
155
|
+
develop <main-file> [<main-arguments>] Develop the main file with the provided arguments
|
|
156
|
+
browser <main-file> Compile the main file for the browser
|
|
157
|
+
build <main-file> Build the main file
|
|
158
|
+
check <firefly-file> Check the firefly source file for errors
|
|
159
|
+
symbols <out-file> <firefly-file> Print a .tsv with the symbols of a firefly source file
|
|
160
|
+
bootstrap Bootstrap the compiler
|
|
193
161
|
"""
|
|
194
162
|
|
|
163
|
+
buildScript(
|
|
164
|
+
system: NodeSystem
|
|
165
|
+
mainPath: Path
|
|
166
|
+
mainPackagePair: PackagePair
|
|
167
|
+
emitTarget: EmitTarget
|
|
168
|
+
resolvedDependencies: ResolvedDependencies
|
|
169
|
+
moduleCache: ModuleCache = ModuleCache.new(0)
|
|
170
|
+
printMeasurements: Bool = False
|
|
171
|
+
): ModuleKey {
|
|
172
|
+
let fireflyPath = detectFireflyPath(system)
|
|
173
|
+
let fixedPackagePaths = if(resolvedDependencies.packagePaths.contains(PackagePair("ff", "core"))) {
|
|
174
|
+
resolvedDependencies.packagePaths
|
|
175
|
+
} else {
|
|
176
|
+
resolvedDependencies.packagePaths.add(PackagePair("ff", "core"), fireflyPath.slash("core"))
|
|
177
|
+
}
|
|
178
|
+
let compilerModulePath = if(emitTarget != EmitBrowser && emitTarget != EmitExecutable) {
|
|
179
|
+
fireflyPath.slash("output").slash("js").slash("ff").slash("compiler/Builder.mjs")
|
|
180
|
+
}
|
|
181
|
+
let targetName = emitTarget.{
|
|
182
|
+
| EmitBuild => "build"
|
|
183
|
+
| EmitNode => "node"
|
|
184
|
+
| EmitBrowser => "browser"
|
|
185
|
+
| EmitExecutable => "executable"
|
|
186
|
+
}
|
|
187
|
+
let folders = mainPath.parent().grab().relativeListTo(fixedPackagePaths.grab(mainPackagePair))
|
|
188
|
+
let name = mainPath.base().removeLast(".ff").grab()
|
|
189
|
+
let moduleKey = ModuleKey(mainPackagePair, folders, name)
|
|
190
|
+
Builder.build(
|
|
191
|
+
system = system
|
|
192
|
+
emitTarget = emitTarget
|
|
193
|
+
mainModules = [moduleKey]
|
|
194
|
+
resolvedDependencies = resolvedDependencies.ResolvedDependencies(packagePaths = fixedPackagePaths)
|
|
195
|
+
compilerModulePath = compilerModulePath
|
|
196
|
+
jsOutputPath = system.path(".firefly").path("output").path(targetName)
|
|
197
|
+
printMeasurements = printMeasurements
|
|
198
|
+
moduleCache = moduleCache
|
|
199
|
+
)
|
|
200
|
+
moduleKey
|
|
201
|
+
}
|
|
202
|
+
|
|
195
203
|
parseCommandLine(arguments: List[String]): MainCommand {
|
|
196
204
|
| [mainFile, ...mainArguments] {mainFile.removeLast(".ff") | Some(mainName)} =>
|
|
197
205
|
RunCommand(mainFile, mainArguments)
|
|
@@ -203,6 +211,14 @@ parseCommandLine(arguments: List[String]): MainCommand {
|
|
|
203
211
|
"You must specify a Firefly file (.ff) as first argument to run." + usageString
|
|
204
212
|
))
|
|
205
213
|
}
|
|
214
|
+
| ["develop", ...runArguments] =>
|
|
215
|
+
runArguments.{
|
|
216
|
+
| [mainFile, ...mainArguments] {mainFile.removeLast(".ff") | Some(mainName)} =>
|
|
217
|
+
DevelopCommand(mainFile, mainArguments)
|
|
218
|
+
| _ => throw(CommandLineError(
|
|
219
|
+
"You must specify a Firefly file (.ff) as first argument to develop." + usageString
|
|
220
|
+
))
|
|
221
|
+
}
|
|
206
222
|
| ["browser", ...browserArguments] =>
|
|
207
223
|
browserArguments.{
|
|
208
224
|
| [mainFile] {mainFile.removeLast(".ff") | Some(mainName)} =>
|
|
@@ -278,11 +294,7 @@ importAndRun(
|
|
|
278
294
|
moduleKey: ModuleKey
|
|
279
295
|
arguments: List[String]
|
|
280
296
|
): Bool {
|
|
281
|
-
let
|
|
282
|
-
let cwd = process->cwd()
|
|
283
|
-
let workingDirectory = if(cwd->indexOf(":") === 1) {"file:///" + cwd?} else {cwd?}
|
|
284
|
-
let packagePath = moduleKey.packagePair.groupName("/")
|
|
285
|
-
let runFile = workingDirectory + "/.firefly/output/" + target + "/" + packagePath + "/" + moduleKey.importName() + ".run.mjs"
|
|
297
|
+
let runFile = locateRunFile(system, target, moduleKey)
|
|
286
298
|
let runFilePath = if(runFile.contains("://")) {system.pathFromUrl(runFile)} else {system.path(runFile)}
|
|
287
299
|
if(runFilePath.exists()) {
|
|
288
300
|
let main = Js.await(Js.dynamicImport(runFile))
|
|
@@ -298,6 +310,14 @@ importAndRun(
|
|
|
298
310
|
}
|
|
299
311
|
}
|
|
300
312
|
|
|
313
|
+
locateRunFile(system: NodeSystem, target: String, moduleKey: ModuleKey): String {
|
|
314
|
+
let process = Js.await(Js.dynamicImport("process"))
|
|
315
|
+
let cwd = process->cwd()
|
|
316
|
+
let workingDirectory = if(cwd->indexOf(":") === 1) {"file:///" + cwd?} else {cwd?}
|
|
317
|
+
let packagePath = moduleKey.packagePair.groupName("/")
|
|
318
|
+
workingDirectory + "/.firefly/output/" + target + "/" + packagePath + "/" + moduleKey.importName() + ".run.mjs"
|
|
319
|
+
}
|
|
320
|
+
|
|
301
321
|
prepareFireflyDirectory(path: Path) {
|
|
302
322
|
if(!path.slash(".firefly").slash("output").exists()) {
|
|
303
323
|
if(!path.slash(".firefly").exists()) {
|
package/compiler/ModuleCache.ff
CHANGED
|
@@ -22,9 +22,11 @@ new(version: Int): ModuleCache {
|
|
|
22
22
|
|
|
23
23
|
extend self: ModuleCache {
|
|
24
24
|
|
|
25
|
-
remove(keys: List[String]) {
|
|
25
|
+
remove(keys: List[String], removeParsed: Bool = True) {
|
|
26
26
|
if(!keys.isEmpty()):
|
|
27
|
-
|
|
27
|
+
if(removeParsed) {
|
|
28
|
+
self.parsedModules = self.parsedModules.removeList(keys)
|
|
29
|
+
}
|
|
28
30
|
self.resolvedModules = self.resolvedModules.removeList(keys)
|
|
29
31
|
self.derivedModules = self.derivedModules.removeList(keys)
|
|
30
32
|
self.inferredModules = self.inferredModules.removeList(keys)
|
|
@@ -32,13 +34,11 @@ extend self: ModuleCache {
|
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
invalidate(key: String) {
|
|
35
|
-
//Log.trace("Invalidate: " + uri)
|
|
36
37
|
self.parsedModules.get(key).each: | Pair(module, _) =>
|
|
37
38
|
self.remove([key])
|
|
38
39
|
self.parsedModules.each {| k, Pair(m, _) =>
|
|
39
40
|
if(m.imports.any {i => i.moduleKey == module.moduleKey}) {
|
|
40
|
-
|
|
41
|
-
self.remove([k])
|
|
41
|
+
self.remove([k], removeParsed = False)
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
}
|
package/core/BuildSystem.ff
CHANGED
|
@@ -14,14 +14,48 @@ extend self: BuildSystem {
|
|
|
14
14
|
internalCompile(self, mainFiles.map {internalPath(self, _)}, "browser")
|
|
15
15
|
let browserOutputPath = internalPath(self, ".firefly/output/browser")
|
|
16
16
|
let runPaths = internalListPath(browserOutputPath).filter {_.base().endsWith(".run.mjs")}.toList()
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
if(Js.globalThis()->ffDevelopMode.typeof() == "undefined") {
|
|
18
|
+
let outputPath = runPaths.grabFirst().parent().grab()
|
|
19
|
+
let start = self.mainTask().elapsed()
|
|
20
|
+
internalBrowserCallEsBuild(self, runPaths.map {_.absolute()}, outputPath.absolute(), minify, sourceMaps)
|
|
21
|
+
let bundlePaths = runPaths.flatMap {p =>
|
|
22
|
+
let outputPath = p.parent().grab()
|
|
23
|
+
let bundlePath = outputPath.slash(p.base().removeLast(".mjs").grab() + ".bundle.js")
|
|
24
|
+
let mapPath = outputPath.slash(p.base().removeLast(".mjs").grab() + ".bundle.js.map")
|
|
25
|
+
[bundlePath, mapPath]
|
|
26
|
+
}
|
|
27
|
+
AssetSystem(bundlePaths.map {p =>
|
|
28
|
+
Pair("/" + p.relativeListTo(browserOutputPath).join("/"), {p.readStream()})
|
|
29
|
+
}.toMap())
|
|
30
|
+
} else {
|
|
31
|
+
mutable built = Set.new()
|
|
32
|
+
let lock = self.mainTask().lock()
|
|
33
|
+
AssetSystem(runPaths.flatMap {p =>
|
|
34
|
+
let outputPath = p.parent().grab()
|
|
35
|
+
let bundlePath = outputPath.slash(p.base().removeLast(".mjs").grab() + ".bundle.js")
|
|
36
|
+
let mapPath = outputPath.slash(p.base().removeLast(".mjs").grab() + ".bundle.js.map")
|
|
37
|
+
let bundleAssetPath = "/" + bundlePath.relativeListTo(browserOutputPath).join("/")
|
|
38
|
+
let mapAssetPath = "/" + mapPath.relativeListTo(browserOutputPath).join("/")
|
|
39
|
+
function bundle() {
|
|
40
|
+
lock.do {
|
|
41
|
+
if(!built.contains(p.absolute())) {
|
|
42
|
+
internalBrowserCallEsBuild(self, [p.absolute()], outputPath.absolute(), minify, sourceMaps)
|
|
43
|
+
built = built.add(p.absolute())
|
|
44
|
+
}
|
|
45
|
+
bundlePath.readStream()
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
let bundleEntry = Pair(bundleAssetPath, {
|
|
49
|
+
bundle()
|
|
50
|
+
bundlePath.readStream()
|
|
51
|
+
})
|
|
52
|
+
let mapEntry = Pair(mapAssetPath, {
|
|
53
|
+
bundle()
|
|
54
|
+
mapPath.readStream()
|
|
55
|
+
})
|
|
56
|
+
[bundleEntry, mapEntry]
|
|
57
|
+
}.toMap())
|
|
58
|
+
}
|
|
25
59
|
}
|
|
26
60
|
|
|
27
61
|
buildMode(): Bool {
|
|
@@ -82,16 +116,37 @@ internalNodeCallEsBuild(
|
|
|
82
116
|
minify: Bool
|
|
83
117
|
): Unit {
|
|
84
118
|
let esbuild = Js.import("esbuild")
|
|
85
|
-
esbuild->build(Js->(
|
|
119
|
+
Js.await(esbuild->build(Js->(
|
|
86
120
|
entryPoints = [mainJsFile]
|
|
87
121
|
bundle = True
|
|
88
122
|
minify = minify
|
|
89
123
|
sourcemap = True
|
|
90
124
|
platform = "node"
|
|
91
125
|
target = "es2017"
|
|
92
|
-
external = ["
|
|
126
|
+
external = ["esbuild", "uws.js"]
|
|
127
|
+
loader = Js.object().with(".node", "copy")
|
|
93
128
|
outfile = outputPath
|
|
94
|
-
))
|
|
129
|
+
)))
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
internalNodeCallEsBuildContext(
|
|
133
|
+
self: NodeSystem
|
|
134
|
+
mainJsFile: String
|
|
135
|
+
outputPath: String
|
|
136
|
+
minify: Bool
|
|
137
|
+
): JsValue {
|
|
138
|
+
let esbuild = Js.import("esbuild")
|
|
139
|
+
Js.await(esbuild->context(Js->(
|
|
140
|
+
entryPoints = [mainJsFile]
|
|
141
|
+
bundle = True
|
|
142
|
+
minify = minify
|
|
143
|
+
sourcemap = True
|
|
144
|
+
platform = "node"
|
|
145
|
+
target = "es2017"
|
|
146
|
+
external = ["esbuild", "uws.js"]
|
|
147
|
+
loader = Js.object().with(".node", "copy")
|
|
148
|
+
outfile = outputPath
|
|
149
|
+
)))
|
|
95
150
|
}
|
|
96
151
|
|
|
97
152
|
internalListDirectory(path: Path): List[Pair[String, () => Stream[Buffer]]] {
|
|
@@ -125,12 +180,28 @@ internalPath(buildSystem: BuildSystem, absoluteOrRelative: String): Path {
|
|
|
125
180
|
}
|
|
126
181
|
|
|
127
182
|
internalCompile(buildSystem: BuildSystem, mainFiles: List[Path], target: String): Unit {
|
|
183
|
+
if(Js.globalThis()->ffDevelopMode.typeof() != "undefined") {
|
|
184
|
+
Js->process->send(Js->(
|
|
185
|
+
ffDevelopMode = "internalCompile"
|
|
186
|
+
mainFiles = mainFiles.map {_.absolute()}
|
|
187
|
+
target = target
|
|
188
|
+
))
|
|
189
|
+
Js.awaitCancellablePromise {resolve, reject, cleanup =>
|
|
190
|
+
Js->process->on("message", Js->{message =>
|
|
191
|
+
if(message->ffDevelopMode === "internalCompile") {
|
|
192
|
+
resolve(Unit) // Handle errors?
|
|
193
|
+
}
|
|
194
|
+
})
|
|
195
|
+
}
|
|
196
|
+
} else:
|
|
128
197
|
// Ported from the old FFI. It's quite fragile w.r.t. changes in code generation.
|
|
129
198
|
Js.await(Js.rawIdentifier("$firefly_compiler")->"buildViaBuildSystem_$"(
|
|
130
199
|
buildSystem!
|
|
131
200
|
internalPath(buildSystem, buildSystem!->"fireflyPath_"?)!
|
|
132
201
|
mainFiles!
|
|
133
202
|
target
|
|
203
|
+
Js.undefined()
|
|
204
|
+
Js.undefined()
|
|
134
205
|
Js.currentTask()!
|
|
135
206
|
))
|
|
136
207
|
}
|
package/core/NodeSystem.ff
CHANGED
|
@@ -116,7 +116,9 @@ extend self: NodeSystem {
|
|
|
116
116
|
maxBuffer: Int = 16777216
|
|
117
117
|
killSignal: Int = 9
|
|
118
118
|
shell: Bool = False
|
|
119
|
+
node: Option[(JsValue, JsValue) => Unit] = None
|
|
119
120
|
): ProcessResult {
|
|
121
|
+
let inheritStdio = !node.isEmpty()
|
|
120
122
|
let childProcess = Js.import("node:child_process")
|
|
121
123
|
let env = environment.map {e =>
|
|
122
124
|
let o = Js.object()
|
|
@@ -124,43 +126,58 @@ extend self: NodeSystem {
|
|
|
124
126
|
o
|
|
125
127
|
}.else {Js->process->env}
|
|
126
128
|
Js.withSignal {signal => Js.awaitCancellablePromise {resolve, reject, onSettle =>
|
|
127
|
-
let newProcess =
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
129
|
+
let newProcess = if(!node.isEmpty()) {
|
|
130
|
+
let p = childProcess->fork(command, arguments, Js->(
|
|
131
|
+
cwd = directory.map {_.absolutePath!}.else {Js.undefined()}
|
|
132
|
+
signal = signal
|
|
133
|
+
killSignal = killSignal
|
|
134
|
+
env = env
|
|
135
|
+
silent = True
|
|
136
|
+
stdio = if(inheritStdio) {"inherit"} else {"pipe"}
|
|
137
|
+
))
|
|
138
|
+
p->on("message", Js->{message => node.grab()(message, p)})
|
|
139
|
+
p
|
|
140
|
+
} else {
|
|
141
|
+
childProcess->spawn(command, arguments, Js->(
|
|
142
|
+
cwd = directory.map {_.absolutePath!}.else {Js.undefined()}
|
|
143
|
+
windowsHide = True
|
|
144
|
+
signal = signal
|
|
145
|
+
killSignal = killSignal
|
|
146
|
+
env = env
|
|
147
|
+
shell = shell
|
|
148
|
+
))
|
|
149
|
+
}
|
|
135
150
|
mutable size = 0
|
|
136
151
|
let out = Array.new()
|
|
137
152
|
let err = Array.new()
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
size
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
153
|
+
if(!inheritStdio) {
|
|
154
|
+
newProcess->stdout->on("data", Js->{data =>
|
|
155
|
+
if(size <= maxBuffer) {
|
|
156
|
+
size += data->byteLength?
|
|
157
|
+
if(size > maxBuffer) {
|
|
158
|
+
newProcess->kill(killSignal)
|
|
159
|
+
} else {
|
|
160
|
+
out.push(data)
|
|
161
|
+
}
|
|
145
162
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
163
|
+
Unit
|
|
164
|
+
})
|
|
165
|
+
newProcess->stderr->on("data", Js->{data =>
|
|
166
|
+
if(size <= maxBuffer) {
|
|
167
|
+
size += data->byteLength?
|
|
168
|
+
if(size > maxBuffer) {
|
|
169
|
+
newProcess->kill(killSignal)
|
|
170
|
+
} else {
|
|
171
|
+
err.push(data)
|
|
172
|
+
}
|
|
156
173
|
}
|
|
174
|
+
Unit
|
|
175
|
+
})
|
|
176
|
+
if(standardIn!->byteLength !== 0) {
|
|
177
|
+
newProcess->stdin->write(standardIn!)
|
|
157
178
|
}
|
|
158
|
-
|
|
159
|
-
})
|
|
160
|
-
if(standardIn!->byteLength !== 0) {
|
|
161
|
-
newProcess->stdin->write(standardIn!)
|
|
179
|
+
newProcess->stdin->end()
|
|
162
180
|
}
|
|
163
|
-
newProcess->stdin->end()
|
|
164
181
|
newProcess->on("error", Js->{error =>
|
|
165
182
|
if(size > maxBuffer) {
|
|
166
183
|
reject(internalProcessError("maxBuffer exceeded"))
|
package/core/Path.ff
CHANGED
|
@@ -104,6 +104,11 @@ extend self: Path {
|
|
|
104
104
|
let nodePath = Js.import("path")
|
|
105
105
|
nodePath->relative(path.absolutePath, self.absolutePath)?
|
|
106
106
|
}
|
|
107
|
+
|
|
108
|
+
relativeUrlTo(path: Path): String {
|
|
109
|
+
let relative = self.relativeListTo(path)
|
|
110
|
+
if(relative.first().any {_ == ".."}) {relative.join("/")} else {"./" + relative.join("/")}
|
|
111
|
+
}
|
|
107
112
|
|
|
108
113
|
relativeListTo(path: Path): List[String] {
|
|
109
114
|
let nodePath = Js.import("path")
|
|
@@ -299,7 +304,7 @@ extend self: PathEntry {
|
|
|
299
304
|
|
|
300
305
|
}
|
|
301
306
|
|
|
302
|
-
internalReadStream(createReadStream: () => JsValue): Stream[Buffer] {
|
|
307
|
+
internalReadStream(createReadStream: () => JsValue, close: Bool = True): Stream[Buffer] {
|
|
303
308
|
mutable readable = None
|
|
304
309
|
mutable seenError = Js.null()
|
|
305
310
|
let emptyResolve = {}
|
|
@@ -357,7 +362,7 @@ internalReadStream(createReadStream: () => JsValue): Stream[Buffer] {
|
|
|
357
362
|
}
|
|
358
363
|
go()
|
|
359
364
|
} {
|
|
360
|
-
readable.each {_->destroy()}
|
|
365
|
+
if(close) {readable.each {_->destroy()}}
|
|
361
366
|
}
|
|
362
367
|
}
|
|
363
368
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
nodeMain(system: NodeSystem) {
|
|
2
|
+
let net = Js.import("node:net")
|
|
3
|
+
let targetServer = "localhost" // 127.0.0.1
|
|
4
|
+
let targetPort = 8080
|
|
5
|
+
|
|
6
|
+
function parseHeaders(headerData: JsValue): JsValue {
|
|
7
|
+
let headers = Js->()
|
|
8
|
+
let lines = headerData->split("\r\n")
|
|
9
|
+
if(lines.get(0)->endsWith(" HTTP/1.1")? || lines.get(0)->endsWith(" HTTP/1.0")?) {
|
|
10
|
+
lines->forEach(Js->{line =>
|
|
11
|
+
let index = line->indexOf(":")
|
|
12
|
+
if(index !== -1) {
|
|
13
|
+
let key = line->substring(0, index)->trim()->toLowerCase()
|
|
14
|
+
let value = line->substring(index + 1!)->trim()
|
|
15
|
+
headers.set(key, value)
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
}
|
|
19
|
+
headers
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let proxyServer = net->createServer(Js->{clientSocket =>
|
|
23
|
+
mutable buffer = Js->Buffer->alloc(0)
|
|
24
|
+
mutable isHttpNavigateRequest = False
|
|
25
|
+
clientSocket->on("data", Js->{data =>
|
|
26
|
+
buffer = Js->Buffer->concat([buffer, data])
|
|
27
|
+
let headerEnd = buffer->indexOf("\r\n\r\n")
|
|
28
|
+
if(headerEnd !== -1 || buffer->length? >= 64 * 1024) {
|
|
29
|
+
let headerData = buffer->subarray(0, headerEnd)->toString()
|
|
30
|
+
let headers = parseHeaders(headerData)
|
|
31
|
+
|
|
32
|
+
if(headers.get("sec-fetch-user") === "?1") {
|
|
33
|
+
isHttpNavigateRequest = True
|
|
34
|
+
Js->console->log("Detected HTTP request with Sec-Fetch-User")
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
mutable targetSocket = Js.undefined()
|
|
38
|
+
targetSocket = net->createConnection(targetPort, targetServer, Js->{
|
|
39
|
+
Js->console->log("Connected to target server")
|
|
40
|
+
targetSocket->write(buffer)
|
|
41
|
+
clientSocket->pipe(targetSocket)->pipe(clientSocket)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
clientSocket->on("error", Js->{err =>
|
|
45
|
+
Js->console->error("Client socket error:", err)
|
|
46
|
+
targetSocket->end()
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
targetSocket->on("error", Js->{err =>
|
|
50
|
+
Js->console->error("Target socket error:", err)
|
|
51
|
+
clientSocket->end()
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
proxyServer->listen(8081, Js->{
|
|
58
|
+
Js->console->log("Proxy server running on port 8081")
|
|
59
|
+
})
|
|
60
|
+
}
|