elm-pages 3.0.0-beta.1 → 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 (103) hide show
  1. package/README.md +10 -1
  2. package/codegen/elm-pages-codegen.js +803 -284
  3. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmi +0 -0
  4. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmo +0 -0
  5. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateDataTest.elmo +0 -0
  6. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  7. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
  8. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  9. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm.json +1 -1
  10. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1326 -121
  11. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +15368 -13272
  12. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  13. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
  14. package/generator/dead-code-review/elm.json +6 -5
  15. package/generator/dead-code-review/src/Pages/Review/DeadCodeEliminateData.elm +141 -17
  16. package/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm +218 -0
  17. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  18. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
  19. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  20. package/generator/review/elm-stuff/tests-0.19.1/elm.json +1 -1
  21. package/generator/review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1326 -121
  22. package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +14574 -12631
  23. package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  24. package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
  25. package/generator/review/elm.json +6 -6
  26. package/generator/src/SharedTemplate.elm +1 -1
  27. package/generator/src/build.js +81 -51
  28. package/generator/src/cli.js +120 -42
  29. package/generator/src/codegen.js +11 -10
  30. package/generator/src/compatibility-key.js +1 -0
  31. package/generator/src/config.js +41 -0
  32. package/generator/src/dev-server.js +36 -56
  33. package/generator/src/elm-codegen.js +3 -0
  34. package/generator/src/generate-template-module-connector.js +0 -28
  35. package/generator/src/pre-render-html.js +31 -17
  36. package/generator/src/render-worker.js +1 -1
  37. package/generator/src/render.js +224 -37
  38. package/generator/src/request-cache.js +1 -0
  39. package/generator/src/rewrite-elm-json.js +3 -3
  40. package/generator/src/seo-renderer.js +11 -4
  41. package/generator/src/vite-utils.js +78 -0
  42. package/generator/template/app/Api.elm +1 -1
  43. package/generator/template/app/Site.elm +6 -1
  44. package/package.json +12 -13
  45. package/src/ApiRoute.elm +146 -11
  46. package/src/DataSource/Env.elm +27 -3
  47. package/src/DataSource/File.elm +1 -1
  48. package/src/DataSource/Internal/Request.elm +0 -5
  49. package/src/DataSource.elm +50 -53
  50. package/src/Form/Field.elm +1 -1
  51. package/src/Form.elm +33 -33
  52. package/src/Head/Seo.elm +16 -27
  53. package/src/Head.elm +237 -7
  54. package/src/HtmlPrinter.elm +7 -3
  55. package/src/MultiDict.elm +49 -0
  56. package/src/Pages/Generate.elm +548 -103
  57. package/src/Pages/GeneratorProgramConfig.elm +15 -0
  58. package/src/Pages/Internal/NotFoundReason.elm +3 -2
  59. package/src/Pages/Internal/Platform/Cli.elm +91 -27
  60. package/src/Pages/Internal/Platform/Cli.elm.bak +1276 -0
  61. package/src/Pages/Internal/Platform/CompatibilityKey.elm +6 -0
  62. package/src/Pages/Internal/Platform/GeneratorApplication.elm +455 -0
  63. package/src/Pages/Internal/Platform.elm +34 -27
  64. package/src/Pages/Manifest.elm +24 -0
  65. package/src/Pages/ProgramConfig.elm +6 -3
  66. package/src/Pages/Script.elm +100 -0
  67. package/src/PairingHeap.elm +137 -0
  68. package/src/Parser/Extra/String.elm +33 -0
  69. package/src/Parser/Extra.elm +69 -0
  70. package/src/ProgramTest/ComplexQuery.elm +360 -0
  71. package/src/ProgramTest/EffectSimulation.elm +122 -0
  72. package/src/ProgramTest/Failure.elm +367 -0
  73. package/src/ProgramTest/HtmlHighlighter.elm +116 -0
  74. package/src/ProgramTest/HtmlParserHacks.elm +58 -0
  75. package/src/ProgramTest/HtmlRenderer.elm +73 -0
  76. package/src/ProgramTest/Program.elm +30 -0
  77. package/src/ProgramTest/StringLines.elm +26 -0
  78. package/src/ProgramTest/TestHtmlHacks.elm +132 -0
  79. package/src/ProgramTest/TestHtmlParser.elm +201 -0
  80. package/src/ProgramTest.elm +2339 -0
  81. package/src/Query/Extra.elm +55 -0
  82. package/src/Result/Extra.elm +21 -0
  83. package/src/Server/Request.elm +2 -2
  84. package/src/Server/Session.elm +149 -83
  85. package/src/Server/SetCookie.elm +89 -31
  86. package/src/SimulatedEffect/Cmd.elm +69 -0
  87. package/src/SimulatedEffect/Http.elm +330 -0
  88. package/src/SimulatedEffect/Navigation.elm +69 -0
  89. package/src/SimulatedEffect/Ports.elm +62 -0
  90. package/src/SimulatedEffect/Process.elm +24 -0
  91. package/src/SimulatedEffect/Sub.elm +48 -0
  92. package/src/SimulatedEffect/Task.elm +252 -0
  93. package/src/SimulatedEffect/Time.elm +25 -0
  94. package/src/SimulatedEffect.elm +42 -0
  95. package/src/String/Extra.elm +6 -0
  96. package/src/Test/Http.elm +145 -0
  97. package/src/TestResult.elm +35 -0
  98. package/src/TestState.elm +305 -0
  99. package/src/Url/Extra.elm +100 -0
  100. package/src/Vendored/Diff.elm +321 -0
  101. package/src/Vendored/Failure.elm +217 -0
  102. package/src/Vendored/FormatMonochrome.elm +44 -0
  103. package/src/Vendored/Highlightable.elm +53 -0
@@ -24,6 +24,10 @@ const busboy = require("busboy");
24
24
  const { createServer: createViteServer } = require("vite");
25
25
  const cliVersion = require("../../package.json").version;
26
26
  const esbuild = require("esbuild");
27
+ const { merge_vite_configs } = require("./vite-utils.js");
28
+ const { templateHtml } = require("./pre-render-html.js");
29
+ const { resolveConfig } = require("./config.js");
30
+ const globby = require("globby");
27
31
 
28
32
  /**
29
33
  * @param {{ port: string; base: string; https: boolean; debug: boolean; }} options
@@ -117,27 +121,23 @@ async function start(options) {
117
121
  watcher.add(sourceDirs);
118
122
  }
119
123
 
120
- const viteConfig = await import(
121
- path.join(process.cwd(), "elm-pages.config.mjs")
122
- )
123
- .then(async (elmPagesConfig) => {
124
- return elmPagesConfig.default.vite || {};
125
- })
126
- .catch((error) => {
127
- console.warn(
128
- kleur.yellow(
129
- "No `elm-pages.config.mjs` file found. Using default config."
130
- )
131
- );
132
- return {};
133
- });
134
- const vite = await createViteServer({
135
- server: { middlewareMode: "ssr", base: options.base, port: options.port },
136
- configFile: false,
137
- root: process.cwd(),
138
- base: options.base,
139
- ...viteConfig,
140
- });
124
+ const config = await resolveConfig();
125
+ const vite = await createViteServer(
126
+ merge_vite_configs(
127
+ {
128
+ server: {
129
+ middlewareMode: "ssr",
130
+ base: options.base,
131
+ port: options.port,
132
+ },
133
+ configFile: false,
134
+ root: process.cwd(),
135
+ base: options.base,
136
+ },
137
+
138
+ config.vite
139
+ )
140
+ );
141
141
  esbuild
142
142
  .build({
143
143
  entryPoints: ["./port-data-source"],
@@ -148,7 +148,7 @@ async function start(options) {
148
148
  metafile: true,
149
149
  bundle: true,
150
150
  watch: true,
151
- logLevel: "error",
151
+ logLevel: "silent",
152
152
 
153
153
  outdir: ".elm-pages/compiled-ports",
154
154
  entryNames: "[dir]/[name]-[hash]",
@@ -158,11 +158,13 @@ async function start(options) {
158
158
  name: "example",
159
159
  setup(build) {
160
160
  build.onEnd((result) => {
161
- global.portsFilePath = Object.keys(result.metafile.outputs)[0];
161
+ try {
162
+ global.portsFilePath = Object.keys(result.metafile.outputs)[0];
162
163
 
163
- clients.forEach((client) => {
164
- client.response.write(`data: content.dat\n\n`);
165
- });
164
+ clients.forEach((client) => {
165
+ client.response.write(`data: content.dat\n\n`);
166
+ });
167
+ } catch (e) {}
166
168
  });
167
169
  },
168
170
  },
@@ -172,7 +174,13 @@ async function start(options) {
172
174
  console.log("Watching port-data-source...");
173
175
  })
174
176
  .catch((error) => {
175
- console.error("Failed to start port-data-source watcher", error);
177
+ const portDataSourceFileFound =
178
+ globby.sync("./port-data-source.*").length > 0;
179
+ if (portDataSourceFileFound) {
180
+ // don't present error if there are no files matching port-data-source
181
+ // if there are files matching port-data-source, warn the user in case something went wrong loading it
182
+ console.error("Failed to start port-data-source watcher", error);
183
+ }
176
184
  });
177
185
 
178
186
  const app = connect()
@@ -459,35 +467,7 @@ async function start(options) {
459
467
  }
460
468
  case "html": {
461
469
  try {
462
- const template =
463
- /*html*/
464
- `<!DOCTYPE html>
465
- <!-- ROOT --><html lang="en">
466
- <head>
467
- <script src="/hmr.js" type="text/javascript"></script>
468
- <script src="/elm.js" type="text/javascript"></script>
469
- <link rel="stylesheet" href="/style.css">
470
- <link rel="stylesheet" href="/dev-style.css">
471
- <script src="/elm-pages.js" type="module"></script>
472
- <meta charset="UTF-8" />
473
- <meta name="viewport" content="width=device-width,initial-scale=1" />
474
- <title><!-- PLACEHOLDER_TITLE --></title>
475
- <meta name="generator" content="elm-pages v${cliVersion}" />
476
- <meta name="mobile-web-app-capable" content="yes" />
477
- <meta name="theme-color" content="#ffffff" />
478
- <meta name="apple-mobile-web-app-capable" content="yes" />
479
- <meta
480
- name="apple-mobile-web-app-status-bar-style"
481
- content="black-translucent"
482
- />
483
- <!-- PLACEHOLDER_HEAD_AND_DATA -->
484
- </head>
485
- <body>
486
- <div data-url="" display="none"></div>
487
- <!-- PLACEHOLDER_HTML -->
488
- </body>
489
- </html>
490
- `;
470
+ const template = templateHtml(true, config.headTagsTemplate);
491
471
  const processedTemplate = await vite.transformIndexHtml(
492
472
  req.originalUrl,
493
473
  template
@@ -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
  });
@@ -63,32 +63,10 @@ async function generateTemplateModuleConnector(basePath, phase) {
63
63
  }
64
64
 
65
65
  async function runElmCodegenCli(templates, basePath, phase) {
66
- // await runElmCodegenInstall();
67
- // try {
68
- // await compileCliApp(
69
- // // { debug: true },
70
- // {},
71
- // `Generate.elm`,
72
- // path.join(process.cwd(), "elm-stuff/elm-pages-codegen.js"),
73
- // path.join(__dirname, "../../codegen"),
74
-
75
- // path.join(process.cwd(), "elm-stuff/elm-pages-codegen.js")
76
- // );
77
- // } catch (error) {
78
- // console.log(restoreColorSafe(error));
79
- // process.exit(1);
80
- // // throw error;
81
- // }
82
-
83
66
  const filePath = path.join(__dirname, `../../codegen/elm-pages-codegen.js`);
84
67
 
85
- // TODO use uncached require here to prevent stale code from running
86
-
87
68
  const promise = new Promise((resolve, reject) => {
88
69
  const elmPagesCodegen = require(filePath).Elm.Generate;
89
- // path.join(
90
- // process.cwd(),
91
- // "./elm-stuff/elm-pages-codegen.js")
92
70
 
93
71
  const app = elmPagesCodegen.init({
94
72
  flags: { templates: templates, basePath, phase },
@@ -104,12 +82,10 @@ async function runElmCodegenCli(templates, basePath, phase) {
104
82
  }
105
83
  });
106
84
  const filesToGenerate = await promise;
107
- console.dir(filesToGenerate.map((file) => file.path));
108
85
 
109
86
  return filesToGenerate;
110
87
  }
111
88
 
112
-
113
89
  /**
114
90
  *
115
91
  * @param {string[][]} templates
@@ -175,8 +151,6 @@ function sortScore(name) {
175
151
  );
176
152
  }
177
153
 
178
-
179
-
180
154
  function fetcherModule(name) {
181
155
  let moduleName = name.join(".");
182
156
  // TODO need to account for splat routes/etc.
@@ -248,7 +222,6 @@ submit toMsg options =
248
222
  `;
249
223
  }
250
224
 
251
-
252
225
  /**
253
226
  * Convert Strings from camelCase to kebab-case
254
227
  * @param {string} input
@@ -258,5 +231,4 @@ function camelToKebab(input) {
258
231
  return input.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
259
232
  }
260
233
 
261
-
262
234
  module.exports = { generateTemplateModuleConnector, sortTemplates };
@@ -17,28 +17,32 @@ function wrapHtml(basePath, fromElm, contentDatPayload) {
17
17
  };
18
18
  }
19
19
 
20
- function templateHtml() {
20
+ /**
21
+ * @param {boolean} devMode
22
+ * @param {(context: {cliVersion: string;}) => string} userHeadTagsTemplate
23
+ */
24
+ function templateHtml(devMode, userHeadTagsTemplate) {
21
25
  return /* html */ `<!DOCTYPE html>
22
26
  <!-- ROOT --><html lang="en">
23
27
  <head>
24
- <!-- PLACEHOLDER_PRELOADS -->
25
- <script defer src="/elm.js" type="text/javascript"></script>
26
- <script defer src="${path.join(
27
- __dirname,
28
- "../static-code/elm-pages.js"
29
- )}" type="module"></script>
30
- <link rel="stylesheet" href="/style.css" />
31
28
  <meta charset="UTF-8" />
32
- <meta name="viewport" content="width=device-width,initial-scale=1" />
33
29
  <title><!-- PLACEHOLDER_TITLE --></title>
34
- <meta name="generator" content="elm-pages v${cliVersion}" />
35
- <meta name="mobile-web-app-capable" content="yes" />
36
- <meta name="theme-color" content="#ffffff" />
37
- <meta name="apple-mobile-web-app-capable" content="yes" />
38
- <meta
39
- name="apple-mobile-web-app-status-bar-style"
40
- content="black-translucent"
41
- />
30
+ ${
31
+ devMode
32
+ ? `<script src="/hmr.js" type="text/javascript"></script>
33
+ <link rel="stylesheet" href="/dev-style.css">`
34
+ : `<!-- PLACEHOLDER_PRELOADS -->`
35
+ }
36
+ <script defer src="/elm.js" type="text/javascript"></script>
37
+ ${
38
+ devMode
39
+ ? `<script src="/elm-pages.js" type="module"></script>`
40
+ : `<script defer src="${path.join(
41
+ __dirname,
42
+ "../static-code/elm-pages.js"
43
+ )}" type="module"></script>`
44
+ }
45
+ ${indent(userHeadTagsTemplate({ cliVersion }))}
42
46
  <!-- PLACEHOLDER_HEAD_AND_DATA -->
43
47
  </head>
44
48
  <body>
@@ -48,6 +52,16 @@ function templateHtml() {
48
52
  </html>`;
49
53
  }
50
54
 
55
+ /**
56
+ * @param {string} snippet
57
+ */
58
+ function indent(snippet) {
59
+ return snippet
60
+ .split("\n")
61
+ .map((line) => ` ${line}`)
62
+ .join("\n");
63
+ }
64
+
51
65
  /**
52
66
  * @param {string} processedTemplate
53
67
  */
@@ -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),
@@ -9,6 +9,7 @@ const preRenderHtml = require("./pre-render-html.js");
9
9
  const { lookupOrPerform } = require("./request-cache.js");
10
10
  const kleur = require("kleur");
11
11
  const cookie = require("cookie-signature");
12
+ const { compatibilityKey } = require("./compatibility-key.js");
12
13
  kleur.enabled = true;
13
14
 
14
15
  process.on("unhandledRejection", (error) => {
@@ -18,18 +19,37 @@ let foundErrors;
18
19
  let pendingDataSourceResponses;
19
20
  let pendingDataSourceCount;
20
21
 
21
- module.exports =
22
- /**
23
- *
24
- * @param {string} basePath
25
- * @param {Object} elmModule
26
- * @param {string} path
27
- * @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
28
- * @param {(pattern: string) => void} addDataSourceWatcher
29
- * @param {boolean} hasFsAccess
30
- * @returns
31
- */
32
- 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(
33
53
  portsFile,
34
54
  basePath,
35
55
  elmModule,
@@ -37,31 +57,167 @@ module.exports =
37
57
  path,
38
58
  request,
39
59
  addDataSourceWatcher,
60
+ fs,
40
61
  hasFsAccess
41
- ) {
42
- const { fs, resetInMemoryFs } = require("./request-cache-fs.js")(
43
- hasFsAccess
44
- );
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(
53
- portsFile,
54
- basePath,
55
- elmModule,
56
- mode,
57
- path,
58
- request,
59
- addDataSourceWatcher,
60
- fs,
61
- hasFsAccess
62
- );
63
- return result;
64
- };
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
+ }
65
221
 
66
222
  /**
67
223
  * @param {string} basePath
@@ -98,6 +254,7 @@ function runElmApp(
98
254
  app = elmModule.Elm.Main.init({
99
255
  flags: {
100
256
  mode,
257
+ compatibilityKey,
101
258
  request: {
102
259
  payload: modifiedRequest,
103
260
  kind: "single-page",
@@ -300,7 +457,9 @@ async function runInternalJob(
300
457
  try {
301
458
  pendingDataSourceCount += 1;
302
459
 
303
- 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") {
304
463
  pendingDataSourceResponses.push(
305
464
  await readFileJobNew(requestToPerform, patternsToWatch)
306
465
  );
@@ -320,6 +479,8 @@ async function runInternalJob(
320
479
  pendingDataSourceResponses.push(
321
480
  await runDecryptJob(requestToPerform, patternsToWatch)
322
481
  );
482
+ } else if (requestToPerform.url === "elm-pages-internal://write-file") {
483
+ pendingDataSourceResponses.push(await runWriteFileJob(requestToPerform));
323
484
  } else {
324
485
  throw `Unexpected internal DataSource request format: ${kleur.yellow(
325
486
  JSON.stringify(2, null, requestToPerform)
@@ -360,6 +521,23 @@ async function readFileJobNew(req, patternsToWatch) {
360
521
  };
361
522
  }
362
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
+ }
363
541
 
364
542
  async function runGlobNew(req, patternsToWatch) {
365
543
  try {
@@ -382,6 +560,15 @@ async function runGlobNew(req, patternsToWatch) {
382
560
  }
383
561
  }
384
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
+ }
385
572
  async function runEnvJob(req, patternsToWatch) {
386
573
  try {
387
574
  const expectedEnv = req.body.args[0];
@@ -24,6 +24,7 @@ function fullPath(portsHash, request, hasFsAccess) {
24
24
  if (hasFsAccess) {
25
25
  return path.join(
26
26
  process.cwd(),
27
+ // TODO use parameter or something other than global for this `global.isRunningGenerator` condition
27
28
  ".elm-pages",
28
29
  "http-response-cache",
29
30
  requestToString(requestWithPortHash)
@@ -1,14 +1,14 @@
1
1
  const fs = require("fs");
2
2
 
3
- module.exports = async function () {
3
+ module.exports = async function (sourceElmJsonPath, targetElmJsonPath) {
4
4
  var elmJson = JSON.parse(
5
- (await fs.promises.readFile("./elm.json")).toString()
5
+ (await fs.promises.readFile(sourceElmJsonPath)).toString()
6
6
  );
7
7
 
8
8
  // write new elm.json
9
9
 
10
10
  await writeFileIfChanged(
11
- "./elm-stuff/elm-pages/elm.json",
11
+ targetElmJsonPath,
12
12
  JSON.stringify(rewriteElmJson(elmJson))
13
13
  );
14
14
  };
@@ -43,11 +43,16 @@ function headTag(rootModifiers) {
43
43
 
44
44
  function toString(/** @type { SeoTag[] } */ tags) {
45
45
  return tags
46
- .map((headTag) => {
46
+ .flatMap((headTag) => {
47
47
  if (headTag.type === "head") {
48
- return appendTag(headTag);
48
+ return [appendTag(headTag)];
49
49
  } else if (headTag.type === "json-ld") {
50
- return appendJsonLdTag(headTag);
50
+ return [appendJsonLdTag(headTag)];
51
+ } else if (headTag.type === "stripped") {
52
+ console.warn(
53
+ `WARNING: Head.nonLoadingTag value ignored because it used a loading tag: ${headTag.message}`
54
+ );
55
+ return [];
51
56
  } else {
52
57
  throw new Error(`Unknown tag type ${JSON.stringify(headTag)}`);
53
58
  }
@@ -55,7 +60,7 @@ function toString(/** @type { SeoTag[] } */ tags) {
55
60
  .join("");
56
61
  }
57
62
 
58
- /** @typedef {HeadTag | JsonLdTag} SeoTag */
63
+ /** @typedef {HeadTag | JsonLdTag | StrippedTag} SeoTag */
59
64
 
60
65
  /** @typedef {{ name: string; attributes: string[][]; type: 'head' }} HeadTag */
61
66
  function appendTag(/** @type {HeadTag} */ tagDetails) {
@@ -66,6 +71,8 @@ function appendTag(/** @type {HeadTag} */ tagDetails) {
66
71
  }
67
72
 
68
73
  /** @typedef {{ contents: Object; type: 'json-ld' }} JsonLdTag */
74
+ /** @typedef {{ message: string; type: 'stripped' }} StrippedTag */
75
+
69
76
  function appendJsonLdTag(/** @type {JsonLdTag} */ tagDetails) {
70
77
  return `<script type="application/ld+json">
71
78
  ${JSON.stringify(tagDetails.contents)}