elm-pages 3.0.0-beta.10 → 3.0.0-beta.12

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 (78) hide show
  1. package/README.md +1 -1
  2. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmo +0 -0
  3. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  4. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
  5. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  6. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm.json +1 -1
  7. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1326 -121
  8. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +15156 -13244
  9. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  10. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
  11. package/generator/dead-code-review/elm.json +6 -5
  12. package/generator/dead-code-review/src/Pages/Review/DeadCodeEliminateData.elm +1 -0
  13. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  14. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
  15. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  16. package/generator/review/elm-stuff/tests-0.19.1/elm.json +1 -1
  17. package/generator/review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1326 -121
  18. package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +14574 -12631
  19. package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  20. package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
  21. package/generator/review/elm.json +6 -6
  22. package/generator/src/build.js +6 -9
  23. package/generator/src/cli.js +120 -42
  24. package/generator/src/codegen.js +11 -10
  25. package/generator/src/compatibility-key.js +1 -1
  26. package/generator/src/elm-codegen.js +3 -0
  27. package/generator/src/render-worker.js +1 -1
  28. package/generator/src/render.js +222 -37
  29. package/generator/src/request-cache.js +1 -0
  30. package/generator/src/rewrite-elm-json.js +3 -3
  31. package/package.json +12 -12
  32. package/src/ApiRoute.elm +147 -9
  33. package/src/DataSource/Env.elm +27 -3
  34. package/src/DataSource.elm +11 -22
  35. package/src/Form.elm +32 -32
  36. package/src/Head.elm +112 -8
  37. package/src/MultiDict.elm +49 -0
  38. package/src/Pages/Generate.elm +4 -1
  39. package/src/Pages/GeneratorProgramConfig.elm +15 -0
  40. package/src/Pages/Internal/Platform/CompatibilityKey.elm +1 -1
  41. package/src/Pages/Internal/Platform/GeneratorApplication.elm +455 -0
  42. package/src/Pages/Manifest.elm +24 -0
  43. package/src/Pages/Script.elm +100 -0
  44. package/src/PairingHeap.elm +137 -0
  45. package/src/Parser/Extra/String.elm +33 -0
  46. package/src/Parser/Extra.elm +69 -0
  47. package/src/ProgramTest/ComplexQuery.elm +360 -0
  48. package/src/ProgramTest/EffectSimulation.elm +122 -0
  49. package/src/ProgramTest/Failure.elm +367 -0
  50. package/src/ProgramTest/HtmlHighlighter.elm +116 -0
  51. package/src/ProgramTest/HtmlParserHacks.elm +58 -0
  52. package/src/ProgramTest/HtmlRenderer.elm +73 -0
  53. package/src/ProgramTest/Program.elm +30 -0
  54. package/src/ProgramTest/StringLines.elm +26 -0
  55. package/src/ProgramTest/TestHtmlHacks.elm +132 -0
  56. package/src/ProgramTest/TestHtmlParser.elm +201 -0
  57. package/src/ProgramTest.elm +2339 -0
  58. package/src/Query/Extra.elm +55 -0
  59. package/src/Result/Extra.elm +21 -0
  60. package/src/Server/Request.elm +2 -2
  61. package/src/SimulatedEffect/Cmd.elm +69 -0
  62. package/src/SimulatedEffect/Http.elm +330 -0
  63. package/src/SimulatedEffect/Navigation.elm +69 -0
  64. package/src/SimulatedEffect/Ports.elm +62 -0
  65. package/src/SimulatedEffect/Process.elm +24 -0
  66. package/src/SimulatedEffect/Sub.elm +48 -0
  67. package/src/SimulatedEffect/Task.elm +252 -0
  68. package/src/SimulatedEffect/Time.elm +25 -0
  69. package/src/SimulatedEffect.elm +42 -0
  70. package/src/String/Extra.elm +6 -0
  71. package/src/Test/Http.elm +145 -0
  72. package/src/TestResult.elm +35 -0
  73. package/src/TestState.elm +305 -0
  74. package/src/Url/Extra.elm +100 -0
  75. package/src/Vendored/Diff.elm +321 -0
  76. package/src/Vendored/Failure.elm +217 -0
  77. package/src/Vendored/FormatMonochrome.elm +44 -0
  78. package/src/Vendored/Highlightable.elm +53 -0
@@ -75,7 +75,7 @@ console.elmlog = (str) => logs.push(str + "\n");
75
75
  const { Elm } = require("./Runner.elm.js");
76
76
 
77
77
  // Start the Elm app
78
- const flags = { initialSeed: 2786629506, fuzzRuns: 100, filter: null };
78
+ const flags = { initialSeed: 2434458748, fuzzRuns: 100, filter: null };
79
79
  const app = Elm.Runner.init({ flags: flags });
80
80
 
81
81
  // Record the timing at which we received the last "runTest" message
@@ -82,7 +82,7 @@ const verbosity = 0;
82
82
  // Create a long lived reporter worker
83
83
  const { Elm } = require("./Reporter.elm.js");
84
84
  const flags = {
85
- initialSeed: 2786629506,
85
+ initialSeed: 2434458748,
86
86
  fuzzRuns: 100,
87
87
  mode: "consoleNoColor",
88
88
  verbosity: verbosity,
@@ -11,23 +11,23 @@
11
11
  "elm/html": "1.0.0",
12
12
  "elm/regex": "1.0.0",
13
13
  "elm-community/result-extra": "2.4.0",
14
- "jfmengels/elm-review": "2.4.2",
14
+ "jfmengels/elm-review": "2.10.0",
15
15
  "mdgriffith/elm-codegen": "2.0.0",
16
- "stil4m/elm-syntax": "7.2.5",
16
+ "stil4m/elm-syntax": "7.2.9",
17
17
  "the-sett/elm-syntax-dsl": "6.0.2"
18
18
  },
19
19
  "indirect": {
20
20
  "Chadtech/elm-bool-extra": "2.4.2",
21
+ "elm/bytes": "1.0.8",
21
22
  "elm/json": "1.1.3",
22
23
  "elm/parser": "1.1.0",
23
24
  "elm/project-metadata-utils": "1.0.2",
24
25
  "elm/random": "1.0.0",
25
26
  "elm/time": "1.0.0",
26
- "elm/virtual-dom": "1.0.2",
27
+ "elm/virtual-dom": "1.0.3",
27
28
  "elm-community/basics-extra": "4.1.0",
28
- "elm-community/list-extra": "8.3.0",
29
+ "elm-community/list-extra": "8.7.0",
29
30
  "elm-community/maybe-extra": "5.3.0",
30
- "elm-explorations/test": "1.2.2",
31
31
  "miniBill/elm-unicode": "1.0.2",
32
32
  "rtfeldman/elm-hex": "1.0.0",
33
33
  "stil4m/structured-writer": "1.0.3",
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "test-dependencies": {
38
38
  "direct": {
39
- "elm-explorations/test": "1.2.2"
39
+ "elm-explorations/test": "2.0.1"
40
40
  },
41
41
  "indirect": {}
42
42
  }
@@ -31,7 +31,6 @@ let pagesReadyCalled = false;
31
31
  let activeWorkers = 0;
32
32
  let buildError = false;
33
33
 
34
- const DIR_PATH = process.cwd();
35
34
  const OUTPUT_FILE_NAME = "elm.js";
36
35
 
37
36
  process.on("unhandledRejection", (error) => {
@@ -39,11 +38,9 @@ process.on("unhandledRejection", (error) => {
39
38
  process.exitCode = 1;
40
39
  });
41
40
 
42
- const ELM_FILE_PATH = path.join(
43
- DIR_PATH,
44
- "./elm-stuff/elm-pages",
45
- OUTPUT_FILE_NAME
46
- );
41
+ function ELM_FILE_PATH() {
42
+ return path.join(process.cwd(), "./elm-stuff/elm-pages", OUTPUT_FILE_NAME);
43
+ }
47
44
 
48
45
  async function ensureRequiredDirs() {
49
46
  ensureDirSync(`dist`);
@@ -552,7 +549,7 @@ async function compileCliApp(options) {
552
549
  path.join(process.cwd(), "elm-stuff/elm-pages")
553
550
  );
554
551
 
555
- const elmFileContent = await fsPromises.readFile(ELM_FILE_PATH, "utf-8");
552
+ const elmFileContent = await fsPromises.readFile(ELM_FILE_PATH(), "utf-8");
556
553
  // Source: https://github.com/elm-explorations/test/blob/d5eb84809de0f8bbf50303efd26889092c800609/src/Elm/Kernel/HtmlAsJson.js
557
554
  const forceThunksSource = ` _HtmlAsJson_toJson(x)
558
555
  }
@@ -598,7 +595,7 @@ function _HtmlAsJson_toJson(html) {
598
595
  `;
599
596
 
600
597
  await fsPromises.writeFile(
601
- ELM_FILE_PATH,
598
+ ELM_FILE_PATH(),
602
599
  elmFileContent
603
600
  .replace(
604
601
  /return \$elm\$json\$Json\$Encode\$string\(.REPLACE_ME_WITH_JSON_STRINGIFY.\)/g,
@@ -675,4 +672,4 @@ function defaultPreloadForFile(file) {
675
672
  * @returns {string}
676
673
  */
677
674
 
678
- module.exports = { run };
675
+ module.exports = { run, compileCliApp };
@@ -8,9 +8,13 @@ const codegen = require("./codegen.js");
8
8
  const fs = require("fs");
9
9
  const path = require("path");
10
10
  const { restoreColorSafe } = require("./error-formatter");
11
+ const renderer = require("../../generator/src/render");
12
+ const globby = require("globby");
13
+ const esbuild = require("esbuild");
14
+ const copyModifiedElmJson = require("./rewrite-elm-json.js");
15
+ const { ensureDirSync, deleteIfExists } = require("./file-helpers.js");
11
16
 
12
17
  const commander = require("commander");
13
- const { compileCliApp } = require("./compile-elm.js");
14
18
  const { runElmCodegenInstall } = require("./elm-codegen.js");
15
19
  const Argument = commander.Argument;
16
20
  const Option = commander.Option;
@@ -84,66 +88,89 @@ async function main() {
84
88
  });
85
89
 
86
90
  program
87
- .command("codegen <moduleName>")
88
- .description("run a generator")
91
+ .command("run <moduleName>")
92
+ .description("run an elm-pages script")
89
93
  .allowUnknownOption()
90
94
  .allowExcessArguments()
91
95
  .action(async (moduleName, options, options2) => {
96
+ const unprocessedCliOptions = options2.args.splice(
97
+ options2.processedArgs.length,
98
+ options2.args.length
99
+ );
92
100
  if (!/^[A-Z][a-zA-Z0-9_]*(\.[A-Z][a-zA-Z0-9_]*)*$/.test(moduleName)) {
93
101
  throw `Invalid module name "${moduleName}", must be in the format of an Elm module`;
94
102
  }
95
103
  const splitModuleName = moduleName.split(".");
96
104
  const expectedFilePath = path.join(
97
105
  process.cwd(),
98
- "codegen",
106
+ "script/src/",
99
107
  `${splitModuleName.join("/")}.elm`
100
108
  );
101
109
  if (!fs.existsSync(expectedFilePath)) {
102
110
  throw `I couldn't find a module named ${expectedFilePath}`;
103
111
  }
104
112
  try {
105
- await codegen.generate("");
106
- await runElmCodegenInstall();
107
- await compileCliApp(
108
- // { debug: true },
109
- {},
110
- `${splitModuleName.join("/")}.elm`,
111
- path.join(process.cwd(), "codegen/elm-stuff/scaffold.js"),
112
- "codegen",
113
-
114
- path.join(process.cwd(), "codegen/elm-stuff/scaffold.js")
113
+ // await codegen.generate("");
114
+ if (fs.existsSync("./codegen/")) {
115
+ await runElmCodegenInstall();
116
+ }
117
+
118
+ ensureDirSync("./script/elm-stuff");
119
+ ensureDirSync("./script/elm-stuff/elm-pages/.elm-pages");
120
+ await fs.promises.writeFile(
121
+ path.join("./script/elm-stuff/elm-pages/.elm-pages/Main.elm"),
122
+ generatorWrapperFile(moduleName)
123
+ );
124
+ await copyModifiedElmJson(
125
+ "./script/elm.json",
126
+ "./script/elm-stuff/elm-pages/elm.json"
127
+ );
128
+
129
+ const portDataSourceCompiled = esbuild
130
+ .build({
131
+ entryPoints: ["./port-data-source"],
132
+ platform: "node",
133
+ outfile: ".elm-pages/compiled-ports/port-data-source.js",
134
+ assetNames: "[name]-[hash]",
135
+ chunkNames: "chunks/[name]-[hash]",
136
+ outExtension: { ".js": ".js" },
137
+ metafile: true,
138
+ bundle: true,
139
+ watch: false,
140
+ logLevel: "silent",
141
+ })
142
+ .then((result) => {
143
+ try {
144
+ return Object.keys(result.metafile.outputs)[0];
145
+ } catch (e) {
146
+ return null;
147
+ }
148
+ })
149
+ .catch((error) => {
150
+ const portDataSourceFileFound =
151
+ globby.sync("./port-data-source.*").length > 0;
152
+ if (portDataSourceFileFound) {
153
+ // don't present error if there are no files matching port-data-source
154
+ // if there are files matching port-data-source, warn the user in case something went wrong loading it
155
+ console.error("Failed to start port-data-source watcher", error);
156
+ }
157
+ });
158
+ const portsPath = await portDataSourceCompiled;
159
+ const resolvedPortsPath = path.join(process.cwd(), portsPath);
160
+
161
+ process.chdir("./script");
162
+ // TODO have option for compiling with --debug or not (maybe allow running with elm-optimize-level-2 as well?)
163
+ await build.compileCliApp({ debug: "debug" });
164
+ process.chdir("../");
165
+ await renderer.runGenerator(
166
+ unprocessedCliOptions,
167
+ resolvedPortsPath,
168
+ requireElm("./script/elm-stuff/elm-pages/elm.js")
115
169
  );
116
170
  } catch (error) {
117
171
  console.log(restoreColorSafe(error));
118
172
  process.exit(1);
119
173
  }
120
-
121
- const elmScaffoldProgram = getAt(
122
- splitModuleName,
123
- require(path.join(process.cwd(), "./codegen/elm-stuff/scaffold.js")).Elm
124
- );
125
- const program = elmScaffoldProgram.init({
126
- flags: { argv: ["", ...options2.args], versionMessage: "1.2.3" },
127
- });
128
-
129
- safeSubscribe(program, "print", (message) => {
130
- console.log(message);
131
- });
132
- safeSubscribe(program, "printAndExitFailure", (message) => {
133
- console.log(message);
134
- process.exit(1);
135
- });
136
- safeSubscribe(program, "printAndExitSuccess", (message) => {
137
- console.log(message);
138
- process.exit(0);
139
- });
140
- safeSubscribe(program, "writeFile", async (info) => {
141
- const filePath = path.join(process.cwd(), "app", info.path);
142
- await dirHelpers.tryMkdir(path.dirname(filePath));
143
- fs.writeFileSync(filePath, info.body);
144
- console.log("Success! Created file", filePath);
145
- process.exit(0);
146
- });
147
174
  });
148
175
 
149
176
  program
@@ -180,7 +207,8 @@ function getAt(properties, object) {
180
207
  }
181
208
 
182
209
  function safeSubscribe(program, portName, subscribeFunction) {
183
- program.ports[portName] &&
210
+ program.ports &&
211
+ program.ports[portName] &&
184
212
  program.ports[portName].subscribe(subscribeFunction);
185
213
  }
186
214
 
@@ -218,5 +246,55 @@ function normalizeUrl(rawPagePath) {
218
246
  // with detecting whether the path contains the base.
219
247
  return `/${segments.join("/")}`;
220
248
  }
249
+ /**
250
+ * @param {string} compiledElmPath
251
+ */
252
+ function requireElm(compiledElmPath) {
253
+ const warnOriginal = console.warn;
254
+ console.warn = function () {};
255
+
256
+ Elm = require(path.resolve(compiledElmPath));
257
+ console.warn = warnOriginal;
258
+ return Elm;
259
+ }
260
+
261
+ /**
262
+ * @param {string} moduleName
263
+ */
264
+ function generatorWrapperFile(moduleName) {
265
+ return `port module Main exposing (main)
266
+
267
+ import Bytes
268
+ import DataSource exposing (DataSource)
269
+ import Cli.Program as Program
270
+ import Json.Decode as Decode
271
+ import Json.Encode as Encode
272
+ import Pages.Internal.Platform.GeneratorApplication
273
+ import ${moduleName}
274
+
275
+
276
+ main : Program.StatefulProgram Pages.Internal.Platform.GeneratorApplication.Model Pages.Internal.Platform.GeneratorApplication.Msg (DataSource ()) Pages.Internal.Platform.GeneratorApplication.Flags
277
+ main =
278
+ Pages.Internal.Platform.GeneratorApplication.app
279
+ { data = ${moduleName}.run
280
+ , toJsPort = toJsPort
281
+ , fromJsPort = fromJsPort identity
282
+ , gotBatchSub = gotBatchSub identity
283
+ , sendPageData = sendPageData
284
+ }
285
+
286
+
287
+ port toJsPort : Encode.Value -> Cmd msg
288
+
289
+
290
+ port fromJsPort : (Decode.Value -> msg) -> Sub msg
291
+
292
+
293
+ port gotBatchSub : (Decode.Value -> msg) -> Sub msg
294
+
295
+
296
+ port sendPageData : { oldThing : Encode.Value, binaryPageData : Bytes.Bytes } -> Cmd msg
297
+ `;
298
+ }
221
299
 
222
300
  main();
@@ -63,7 +63,7 @@ async function generate(basePath) {
63
63
  browserCode.fetcherModules
64
64
  ),
65
65
  // write modified elm.json to elm-stuff/elm-pages/
66
- copyModifiedElmJson(),
66
+ copyModifiedElmJson("./elm.json", "./elm-stuff/elm-pages/elm.json"),
67
67
  // ...(await listFiles("./Pages/Internal")).map(copyToBoth),
68
68
  ]);
69
69
  }
@@ -174,15 +174,16 @@ async function copyToBoth(moduleToCopy) {
174
174
  copyFileEnsureDir(
175
175
  path.join(__dirname, moduleToCopy),
176
176
  path.join(`./.elm-pages/`, moduleToCopy)
177
- ),
178
- copyFileEnsureDir(
177
+ ),
178
+ copyFileEnsureDir(
179
179
  path.join(__dirname, moduleToCopy),
180
180
  path.join(`./elm-stuff/elm-pages/client/.elm-pages`, moduleToCopy)
181
- ),
182
- copyFileEnsureDir(
181
+ ),
182
+ copyFileEnsureDir(
183
183
  path.join(__dirname, moduleToCopy),
184
184
  path.join(`./elm-stuff/elm-pages/.elm-pages/`, moduleToCopy)
185
- )]);
185
+ ),
186
+ ]);
186
187
  }
187
188
 
188
189
  /**
@@ -190,10 +191,10 @@ async function copyToBoth(moduleToCopy) {
190
191
  * @param {string} to
191
192
  */
192
193
  async function copyFileEnsureDir(from, to) {
193
- await fs.promises.mkdir(path.dirname(to), {
194
- recursive: true,
195
- })
196
- await fs.promises.copyFile(from, to)
194
+ await fs.promises.mkdir(path.dirname(to), {
195
+ recursive: true,
196
+ });
197
+ await fs.promises.copyFile(from, to);
197
198
  }
198
199
 
199
200
  /**
@@ -1 +1 @@
1
- module.exports = { compatibilityKey: 1 };
1
+ module.exports = { compatibilityKey: 2 };
@@ -17,6 +17,9 @@ function runElmCodegenInstall() {
17
17
  subprocess.stderr.on("data", function (data) {
18
18
  commandOutput += data;
19
19
  });
20
+ subprocess.stdout.on("data", function (data) {
21
+ commandOutput += data;
22
+ });
20
23
  subprocess.on("error", function () {
21
24
  reject(commandOutput);
22
25
  });
@@ -10,7 +10,7 @@ global.staticHttpCache = {};
10
10
  async function run({ mode, pathname, serverRequest, portsFilePath }) {
11
11
  console.time(`${threadId} ${pathname}`);
12
12
  try {
13
- const renderResult = await renderer(
13
+ const renderResult = await renderer.render(
14
14
  portsFilePath,
15
15
  workerData.basePath,
16
16
  requireElm(mode),
@@ -19,18 +19,37 @@ let foundErrors;
19
19
  let pendingDataSourceResponses;
20
20
  let pendingDataSourceCount;
21
21
 
22
- module.exports =
23
- /**
24
- *
25
- * @param {string} basePath
26
- * @param {Object} elmModule
27
- * @param {string} path
28
- * @param {{ method: string; hostname: string; query: Record<string, string | undefined>; headers: Record<string, string>; host: string; pathname: string; port: number | null; protocol: string; rawUrl: string; }} request
29
- * @param {(pattern: string) => void} addDataSourceWatcher
30
- * @param {boolean} hasFsAccess
31
- * @returns
32
- */
33
- async function run(
22
+ module.exports = { render, runGenerator };
23
+
24
+ /**
25
+ *
26
+ * @param {string} basePath
27
+ * @param {Object} elmModule
28
+ * @param {string} path
29
+ * @param {{ method: string; hostname: string; query: Record<string, string | undefined>; headers: Record<string, string>; host: string; pathname: string; port: number | null; protocol: string; rawUrl: string; }} request
30
+ * @param {(pattern: string) => void} addDataSourceWatcher
31
+ * @param {boolean} hasFsAccess
32
+ * @returns
33
+ */
34
+ async function render(
35
+ portsFile,
36
+ basePath,
37
+ elmModule,
38
+ mode,
39
+ path,
40
+ request,
41
+ addDataSourceWatcher,
42
+ hasFsAccess
43
+ ) {
44
+ const { fs, resetInMemoryFs } = require("./request-cache-fs.js")(hasFsAccess);
45
+ resetInMemoryFs();
46
+ foundErrors = false;
47
+ pendingDataSourceResponses = [];
48
+ pendingDataSourceCount = 0;
49
+ // since init/update are never called in pre-renders, and DataSource.Http is called using pure NodeJS HTTP fetching
50
+ // we can provide a fake HTTP instead of xhr2 (which is otherwise needed for Elm HTTP requests from Node)
51
+ XMLHttpRequest = {};
52
+ const result = await runElmApp(
34
53
  portsFile,
35
54
  basePath,
36
55
  elmModule,
@@ -38,31 +57,167 @@ module.exports =
38
57
  path,
39
58
  request,
40
59
  addDataSourceWatcher,
60
+ fs,
41
61
  hasFsAccess
42
- ) {
43
- const { fs, resetInMemoryFs } = require("./request-cache-fs.js")(
44
- hasFsAccess
45
- );
46
- resetInMemoryFs();
47
- foundErrors = false;
48
- pendingDataSourceResponses = [];
49
- pendingDataSourceCount = 0;
50
- // since init/update are never called in pre-renders, and DataSource.Http is called using pure NodeJS HTTP fetching
51
- // we can provide a fake HTTP instead of xhr2 (which is otherwise needed for Elm HTTP requests from Node)
52
- XMLHttpRequest = {};
53
- const result = await runElmApp(
54
- portsFile,
55
- basePath,
56
- elmModule,
57
- mode,
58
- path,
59
- request,
60
- addDataSourceWatcher,
61
- fs,
62
- hasFsAccess
63
- );
64
- return result;
65
- };
62
+ );
63
+ return result;
64
+ }
65
+
66
+ /**
67
+ * @param {Object} elmModule
68
+ * @returns
69
+ * @param {string[]} cliOptions
70
+ * @param {any} portsFile
71
+ */
72
+ async function runGenerator(cliOptions, portsFile, elmModule) {
73
+ global.isRunningGenerator = true;
74
+ const { fs, resetInMemoryFs } = require("./request-cache-fs.js")(true);
75
+ resetInMemoryFs();
76
+ foundErrors = false;
77
+ pendingDataSourceResponses = [];
78
+ pendingDataSourceCount = 0;
79
+ // since init/update are never called in pre-renders, and DataSource.Http is called using pure NodeJS HTTP fetching
80
+ // we can provide a fake HTTP instead of xhr2 (which is otherwise needed for Elm HTTP requests from Node)
81
+ XMLHttpRequest = {};
82
+ const result = await runGeneratorAppHelp(
83
+ cliOptions,
84
+ portsFile,
85
+ "",
86
+ elmModule,
87
+ "production",
88
+ "",
89
+ fs,
90
+ true
91
+ );
92
+ return result;
93
+ }
94
+ /**
95
+ * @param {string} basePath
96
+ * @param {Object} elmModule
97
+ * @param {string} pagePath
98
+ * @param {string} mode
99
+ * @returns {Promise<({is404: boolean;} & ({kind: 'json';contentJson: string;} | {kind: 'html';htmlString: string;} | {kind: 'api-response';body: string;}))>}
100
+ * @param {string[]} cliOptions
101
+ * @param {any} portsFile
102
+ * @param {typeof import("fs") | import("memfs").IFs} fs
103
+ * @param {boolean} hasFsAccess
104
+ */
105
+ function runGeneratorAppHelp(
106
+ cliOptions,
107
+ portsFile,
108
+ basePath,
109
+ elmModule,
110
+ mode,
111
+ pagePath,
112
+ fs,
113
+ hasFsAccess
114
+ ) {
115
+ const isDevServer = mode !== "build";
116
+ let patternsToWatch = new Set();
117
+ let app = null;
118
+ let killApp;
119
+ return new Promise((resolve, reject) => {
120
+ const isBytes = pagePath.match(/content\.dat\/?$/);
121
+
122
+ app = elmModule.Elm.Main.init({
123
+ flags: {
124
+ compatibilityKey,
125
+ argv: ["", "", ...cliOptions],
126
+ versionMessage: "1.2.3",
127
+ },
128
+ });
129
+
130
+ killApp = () => {
131
+ app.ports.toJsPort.unsubscribe(portHandler);
132
+ app.ports.sendPageData.unsubscribe(portHandler);
133
+ app.die();
134
+ app = null;
135
+ // delete require.cache[require.resolve(compiledElmPath)];
136
+ };
137
+
138
+ async function portHandler(/** @type { FromElm } */ newThing) {
139
+ let fromElm;
140
+ let contentDatPayload;
141
+
142
+ fromElm = newThing;
143
+ if (fromElm.command === "log") {
144
+ console.log(fromElm.value);
145
+ } else if (fromElm.tag === "ApiResponse") {
146
+ const args = fromElm.args[0];
147
+ if (mode === "build") {
148
+ global.staticHttpCache = args.staticHttpCache;
149
+ }
150
+
151
+ resolve({
152
+ kind: "api-response",
153
+ is404: args.is404,
154
+ statusCode: args.statusCode,
155
+ body: args.body,
156
+ });
157
+ } else if (fromElm.tag === "PageProgress") {
158
+ const args = fromElm.args[0];
159
+ if (mode === "build") {
160
+ global.staticHttpCache = args.staticHttpCache;
161
+ }
162
+
163
+ if (isBytes) {
164
+ resolve({
165
+ kind: "bytes",
166
+ is404: false,
167
+ contentJson: JSON.stringify({
168
+ staticData: args.contentJson,
169
+ is404: false,
170
+ }),
171
+ statusCode: args.statusCode,
172
+ headers: args.headers,
173
+ contentDatPayload,
174
+ });
175
+ } else {
176
+ resolve(
177
+ outputString(basePath, fromElm, isDevServer, contentDatPayload)
178
+ );
179
+ }
180
+ } else if (fromElm.tag === "DoHttp") {
181
+ const requestToPerform = fromElm.args[0];
182
+ if (
183
+ requestToPerform.url !== "elm-pages-internal://port" &&
184
+ requestToPerform.url.startsWith("elm-pages-internal://")
185
+ ) {
186
+ runInternalJob(
187
+ app,
188
+ mode,
189
+ requestToPerform,
190
+ fs,
191
+ hasFsAccess,
192
+ patternsToWatch
193
+ );
194
+ } else {
195
+ runHttpJob(
196
+ portsFile,
197
+ app,
198
+ mode,
199
+ requestToPerform,
200
+ fs,
201
+ hasFsAccess,
202
+ fromElm.args[1]
203
+ );
204
+ }
205
+ } else if (fromElm.tag === "Errors") {
206
+ foundErrors = true;
207
+ reject(fromElm.args[0].errorsJson);
208
+ } else {
209
+ console.log(fromElm);
210
+ }
211
+ }
212
+ app.ports.toJsPort.subscribe(portHandler);
213
+ app.ports.sendPageData.subscribe(portHandler);
214
+ }).finally(() => {
215
+ try {
216
+ killApp();
217
+ killApp = null;
218
+ } catch (error) {}
219
+ });
220
+ }
66
221
 
67
222
  /**
68
223
  * @param {string} basePath
@@ -302,7 +457,9 @@ async function runInternalJob(
302
457
  try {
303
458
  pendingDataSourceCount += 1;
304
459
 
305
- if (requestToPerform.url === "elm-pages-internal://read-file") {
460
+ if (requestToPerform.url === "elm-pages-internal://log") {
461
+ pendingDataSourceResponses.push(await runLogJob(requestToPerform));
462
+ } else if (requestToPerform.url === "elm-pages-internal://read-file") {
306
463
  pendingDataSourceResponses.push(
307
464
  await readFileJobNew(requestToPerform, patternsToWatch)
308
465
  );
@@ -322,6 +479,8 @@ async function runInternalJob(
322
479
  pendingDataSourceResponses.push(
323
480
  await runDecryptJob(requestToPerform, patternsToWatch)
324
481
  );
482
+ } else if (requestToPerform.url === "elm-pages-internal://write-file") {
483
+ pendingDataSourceResponses.push(await runWriteFileJob(requestToPerform));
325
484
  } else {
326
485
  throw `Unexpected internal DataSource request format: ${kleur.yellow(
327
486
  JSON.stringify(2, null, requestToPerform)
@@ -362,6 +521,23 @@ async function readFileJobNew(req, patternsToWatch) {
362
521
  };
363
522
  }
364
523
  }
524
+ async function runWriteFileJob(req) {
525
+ const data = req.body.args[0];
526
+ try {
527
+ const fullPathToWrite = path.join(process.cwd(), data.path);
528
+ await fsPromises.mkdir(path.dirname(fullPathToWrite), { recursive: true });
529
+ await fsPromises.writeFile(fullPathToWrite, data.body);
530
+ return jsonResponse(req, null);
531
+ } catch (error) {
532
+ console.trace(error);
533
+ throw {
534
+ title: "DataSource Error",
535
+ message: `DataSource.Generator.writeFile failed for file path: ${kleur.yellow(
536
+ data.path
537
+ )}\n${kleur.red(error.toString())}`,
538
+ };
539
+ }
540
+ }
365
541
 
366
542
  async function runGlobNew(req, patternsToWatch) {
367
543
  try {
@@ -384,6 +560,15 @@ async function runGlobNew(req, patternsToWatch) {
384
560
  }
385
561
  }
386
562
 
563
+ async function runLogJob(req) {
564
+ try {
565
+ console.log(req.body.args[0].message);
566
+ return jsonResponse(req, null);
567
+ } catch (e) {
568
+ console.log(`Error performing env '${JSON.stringify(req.body)}'`);
569
+ throw e;
570
+ }
571
+ }
387
572
  async function runEnvJob(req, patternsToWatch) {
388
573
  try {
389
574
  const expectedEnv = req.body.args[0];