@@ -33,49 +33,40 @@ final class NodeJSEnv(config: NodeJSEnv.Config) extends JSEnv {
33
33
34
34
val name : String = " Node.js"
35
35
36
- def start (input : Input , runConfig : RunConfig ): JSRun = {
36
+ def start (input : Seq [ Input ] , runConfig : RunConfig ): JSRun = {
37
37
NodeJSEnv .validator.validate(runConfig)
38
38
validateInput(input)
39
- internalStart(initFiles, input, runConfig)
39
+ internalStart(initFiles ++ input, runConfig)
40
40
}
41
41
42
- def startWithCom (input : Input , runConfig : RunConfig ,
42
+ def startWithCom (input : Seq [ Input ] , runConfig : RunConfig ,
43
43
onMessage : String => Unit ): JSComRun = {
44
44
NodeJSEnv .validator.validate(runConfig)
45
45
validateInput(input)
46
46
ComRun .start(runConfig, onMessage) { comLoader =>
47
- internalStart(initFiles :+ comLoader, input, runConfig)
47
+ internalStart(initFiles ++ ( Input . Script ( comLoader) +: input) , runConfig)
48
48
}
49
49
}
50
50
51
- private def validateInput (input : Input ): Unit = {
52
- input match {
53
- case _:Input .ScriptsToLoad | _:Input .ESModulesToLoad |
54
- _:Input .CommonJSModulesToLoad =>
55
- // ok
56
- case _ =>
57
- throw new UnsupportedInputException (input)
58
- }
51
+ private def validateInput (input : Seq [Input ]): Unit = input.foreach {
52
+ case _:Input .Script | _:Input .ESModule | _:Input .CommonJSModule =>
53
+ // ok
54
+ case _ =>
55
+ throw new UnsupportedInputException (input)
59
56
}
60
57
61
- private def internalStart (initFiles : List [ Path ], input : Input , runConfig : RunConfig ): JSRun = {
58
+ private def internalStart (input : Seq [ Input ] , runConfig : RunConfig ): JSRun = {
62
59
val command = config.executable :: config.args
63
60
val externalConfig = ExternalJSRun .Config ()
64
61
.withEnv(env)
65
62
.withRunConfig(runConfig)
66
- ExternalJSRun .start(command, externalConfig)(
67
- NodeJSEnv .write(initFiles, input))
63
+ ExternalJSRun .start(command, externalConfig)(NodeJSEnv .write(input))
68
64
}
69
65
70
- private def initFiles : List [ Path ] = config.sourceMap match {
66
+ private def initFiles : Seq [ Input ] = config.sourceMap match {
71
67
case SourceMap .Disable => Nil
72
- case SourceMap .EnableIfAvailable => installSourceMapIfAvailable :: Nil
73
- case SourceMap .Enable => installSourceMap :: Nil
74
- }
75
-
76
- private def inputFiles (input : Input ) = input match {
77
- case Input .ScriptsToLoad (scripts) => scripts
78
- case _ => throw new UnsupportedInputException (input)
68
+ case SourceMap .EnableIfAvailable => Input .Script (installSourceMapIfAvailable) :: Nil
69
+ case SourceMap .Enable => Input .Script (installSourceMap) :: Nil
79
70
}
80
71
81
72
private def env : Map [String , String ] =
@@ -104,68 +95,70 @@ object NodeJSEnv {
104
95
" require('source-map-support').install();" .getBytes(StandardCharsets .UTF_8 ))
105
96
}
106
97
107
- private def write (initFiles : List [Path ], input : Input )(out : OutputStream ): Unit = {
108
- val p = new PrintStream (out, false , " UTF8" )
109
- try {
110
- def writeRunScript (path : Path ): Unit = {
111
- try {
112
- val f = path.toFile
113
- val pathJS = " \" " + escapeJS(f.getAbsolutePath) + " \" "
114
- p.println(s """
98
+ private def write (input : Seq [Input ])(out : OutputStream ): Unit = {
99
+ def runScript (path : Path ): String = {
100
+ try {
101
+ val f = path.toFile
102
+ val pathJS = " \" " + escapeJS(f.getAbsolutePath) + " \" "
103
+ s """
104
+ require('vm').runInThisContext(
105
+ require('fs').readFileSync( $pathJS, { encoding: "utf-8" }),
106
+ { filename: $pathJS, displayErrors: true }
107
+ )
108
+ """
109
+ } catch {
110
+ case _ : UnsupportedOperationException =>
111
+ val code = new String (Files .readAllBytes(path), StandardCharsets .UTF_8 )
112
+ val codeJS = " \" " + escapeJS(code) + " \" "
113
+ val pathJS = " \" " + escapeJS(path.toString) + " \" "
114
+ s """
115
115
require('vm').runInThisContext(
116
- require('fs').readFileSync( $pathJS , { encoding: "utf-8" }) ,
116
+ $codeJS ,
117
117
{ filename: $pathJS, displayErrors: true }
118
- );
119
- """ )
120
- } catch {
121
- case _ : UnsupportedOperationException =>
122
- val code = new String (Files .readAllBytes(path), StandardCharsets .UTF_8 )
123
- val codeJS = " \" " + escapeJS(code) + " \" "
124
- val pathJS = " \" " + escapeJS(path.toString) + " \" "
125
- p.println(s """
126
- require('vm').runInThisContext(
127
- $codeJS,
128
- { filename: $pathJS, displayErrors: true }
129
- );
130
- """ )
131
- }
118
+ )
119
+ """
132
120
}
121
+ }
133
122
134
- for (initFile <- initFiles)
135
- writeRunScript(initFile)
136
-
137
- input match {
138
- case Input .ScriptsToLoad (scripts) =>
139
- for (script <- scripts)
140
- writeRunScript(script)
141
-
142
- case Input .CommonJSModulesToLoad (modules) =>
143
- for (module <- modules)
144
- p.println(s """ require(" ${escapeJS(toFile(module).getAbsolutePath)}") """ )
145
-
146
- case Input .ESModulesToLoad (modules) =>
147
- if (modules.nonEmpty) {
148
- val uris = modules.map(m => toFile(m).toURI)
149
-
150
- val imports = uris.map { uri =>
151
- s """ import(" ${escapeJS(uri.toASCIIString)}") """
152
- }
153
- val importChain = imports.reduceLeft { (prev, imprt) =>
154
- s """ $prev.then(_ => $imprt) """
155
- }
156
-
157
- val importerFileContent = {
158
- s """
159
- | $importChain.catch(e => {
160
- | console.error(e);
161
- | process.exit(1);
162
- |});
163
- """ .stripMargin
164
- }
165
- val f = createTmpFile(" importer.js" )
166
- Files .write(f.toPath, importerFileContent.getBytes(StandardCharsets .UTF_8 ))
167
- p.println(s """ require(" ${escapeJS(f.getAbsolutePath)}"); """ )
168
- }
123
+ def requireCommonJSModule (module : Path ): String =
124
+ s """ require(" ${escapeJS(toFile(module).getAbsolutePath)}") """
125
+
126
+ def importESModule (module : Path ): String =
127
+ s """ import(" ${escapeJS(toFile(module).toURI.toASCIIString)}") """
128
+
129
+ def execInputExpr (input : Input ): String = input match {
130
+ case Input .Script (script) => runScript(script)
131
+ case Input .CommonJSModule (module) => requireCommonJSModule(module)
132
+ case Input .ESModule (module) => importESModule(module)
133
+ }
134
+
135
+ val p = new PrintStream (out, false , " UTF8" )
136
+ try {
137
+ if (! input.exists(_.isInstanceOf [Input .ESModule ])) {
138
+ /* If there is no ES module in the input, we can do everything
139
+ * synchronously, and directly on the standard input.
140
+ */
141
+ for (item <- input)
142
+ p.println(execInputExpr(item) + " ;" )
143
+ } else {
144
+ /* If there is at least one ES module, we must asynchronous chain things,
145
+ * and we must use an actual file to feed code to Node.js (because
146
+ * `import()` cannot be used from the standard input).
147
+ */
148
+ val importChain = input.foldLeft(" Promise.resolve()" ) { (prev, item) =>
149
+ s " $prev. \n then( ${execInputExpr(item)}) "
150
+ }
151
+ val importerFileContent = {
152
+ s """
153
+ | $importChain.catch(e => {
154
+ | console.error(e);
155
+ | process.exit(1);
156
+ |});
157
+ """ .stripMargin
158
+ }
159
+ val f = createTmpFile(" importer.js" )
160
+ Files .write(f.toPath, importerFileContent.getBytes(StandardCharsets .UTF_8 ))
161
+ p.println(s """ require(" ${escapeJS(f.getAbsolutePath)}"); """ )
169
162
}
170
163
} finally {
171
164
p.close()
0 commit comments