elm-pages 3.0.0-beta.4 → 3.0.0-beta.40

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 (140) hide show
  1. package/README.md +10 -1
  2. package/adapter/netlify.js +207 -0
  3. package/codegen/{elm-pages-codegen.js → elm-pages-codegen.cjs} +2678 -2725
  4. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmi +0 -0
  5. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmo +0 -0
  6. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateDataTest.elmo +0 -0
  7. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  8. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
  9. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  10. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm.json +1 -1
  11. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1447 -342
  12. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +17004 -13817
  13. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  14. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +4 -4
  15. package/generator/dead-code-review/elm.json +9 -7
  16. package/generator/dead-code-review/src/Pages/Review/DeadCodeEliminateData.elm +59 -10
  17. package/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm +52 -36
  18. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Internal-RoutePattern.elmi +0 -0
  19. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Internal-RoutePattern.elmo +0 -0
  20. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmi +0 -0
  21. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmo +0 -0
  22. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  23. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
  24. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  25. package/generator/review/elm-stuff/tests-0.19.1/elm.json +1 -1
  26. package/generator/review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1447 -342
  27. package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +25025 -21739
  28. package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  29. package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +4 -4
  30. package/generator/review/elm.json +10 -10
  31. package/generator/src/RouteBuilder.elm +115 -109
  32. package/generator/src/SharedTemplate.elm +3 -2
  33. package/generator/src/SiteConfig.elm +3 -2
  34. package/generator/src/basepath-middleware.js +3 -3
  35. package/generator/src/build.js +209 -92
  36. package/generator/src/cli.js +292 -88
  37. package/generator/src/codegen.js +29 -27
  38. package/generator/src/compatibility-key.js +3 -0
  39. package/generator/src/compile-elm.js +43 -26
  40. package/generator/src/config.js +39 -0
  41. package/generator/src/copy-dir.js +2 -2
  42. package/generator/src/dev-server.js +176 -138
  43. package/generator/src/dir-helpers.js +9 -26
  44. package/generator/src/elm-codegen.js +5 -4
  45. package/generator/src/elm-file-constants.js +2 -3
  46. package/generator/src/error-formatter.js +12 -11
  47. package/generator/src/file-helpers.js +3 -4
  48. package/generator/src/generate-template-module-connector.js +23 -23
  49. package/generator/src/init.js +9 -8
  50. package/generator/src/pre-render-html.js +39 -28
  51. package/generator/src/render-test.js +109 -0
  52. package/generator/src/render-worker.js +25 -28
  53. package/generator/src/render.js +321 -142
  54. package/generator/src/request-cache.js +265 -162
  55. package/generator/src/resolve-elm-module.js +64 -0
  56. package/generator/src/rewrite-client-elm-json.js +6 -5
  57. package/generator/src/rewrite-elm-json-help.js +56 -0
  58. package/generator/src/rewrite-elm-json.js +17 -7
  59. package/generator/src/route-codegen-helpers.js +16 -31
  60. package/generator/src/seo-renderer.js +12 -7
  61. package/generator/src/vite-utils.js +77 -0
  62. package/generator/static-code/elm-pages.js +10 -0
  63. package/generator/static-code/hmr.js +79 -13
  64. package/generator/template/app/Api.elm +6 -5
  65. package/generator/template/app/Effect.elm +123 -0
  66. package/generator/template/app/ErrorPage.elm +37 -6
  67. package/generator/template/app/Route/Index.elm +17 -10
  68. package/generator/template/app/Shared.elm +24 -47
  69. package/generator/template/app/Site.elm +19 -6
  70. package/generator/template/app/View.elm +1 -8
  71. package/generator/template/elm-tooling.json +0 -3
  72. package/generator/template/elm.json +32 -24
  73. package/generator/template/package.json +10 -4
  74. package/package.json +30 -27
  75. package/src/ApiRoute.elm +199 -61
  76. package/src/BackendTask/Custom.elm +325 -0
  77. package/src/BackendTask/Env.elm +90 -0
  78. package/src/{DataSource → BackendTask}/File.elm +171 -56
  79. package/src/{DataSource → BackendTask}/Glob.elm +136 -125
  80. package/src/BackendTask/Http.elm +679 -0
  81. package/src/{DataSource → BackendTask}/Internal/Glob.elm +1 -1
  82. package/src/BackendTask/Internal/Request.elm +69 -0
  83. package/src/BackendTask/Random.elm +79 -0
  84. package/src/BackendTask/Time.elm +47 -0
  85. package/src/BackendTask.elm +537 -0
  86. package/src/FatalError.elm +90 -0
  87. package/src/Head.elm +237 -7
  88. package/src/HtmlPrinter.elm +7 -3
  89. package/src/Internal/ApiRoute.elm +7 -5
  90. package/src/PageServerResponse.elm +6 -1
  91. package/src/Pages/Form.elm +229 -0
  92. package/src/Pages/GeneratorProgramConfig.elm +15 -0
  93. package/src/Pages/Internal/FatalError.elm +5 -0
  94. package/src/Pages/Internal/Msg.elm +93 -0
  95. package/src/Pages/Internal/Platform/Cli.elm +612 -763
  96. package/src/Pages/Internal/Platform/CompatibilityKey.elm +6 -0
  97. package/src/Pages/Internal/Platform/Effect.elm +1 -2
  98. package/src/Pages/Internal/Platform/GeneratorApplication.elm +379 -0
  99. package/src/Pages/Internal/Platform/StaticResponses.elm +65 -276
  100. package/src/Pages/Internal/Platform/ToJsPayload.elm +6 -9
  101. package/src/Pages/Internal/Platform.elm +327 -194
  102. package/src/Pages/Internal/Script.elm +17 -0
  103. package/src/Pages/Internal/StaticHttpBody.elm +35 -1
  104. package/src/Pages/Manifest.elm +29 -4
  105. package/src/Pages/PageUrl.elm +23 -9
  106. package/src/Pages/ProgramConfig.elm +26 -15
  107. package/src/Pages/Script.elm +109 -0
  108. package/src/Pages/SiteConfig.elm +3 -2
  109. package/src/Pages/StaticHttp/Request.elm +2 -2
  110. package/src/Pages/StaticHttpRequest.elm +23 -99
  111. package/src/Pages/Transition.elm +12 -3
  112. package/src/PagesMsg.elm +82 -0
  113. package/src/Path.elm +16 -19
  114. package/src/QueryParams.elm +21 -172
  115. package/src/RequestsAndPending.elm +37 -20
  116. package/src/Result/Extra.elm +26 -0
  117. package/src/Scaffold/Form.elm +546 -0
  118. package/src/Scaffold/Route.elm +1402 -0
  119. package/src/Server/Request.elm +73 -72
  120. package/src/Server/Session.elm +62 -42
  121. package/src/Server/SetCookie.elm +12 -4
  122. package/src/Stub.elm +53 -0
  123. package/src/Test/Html/Internal/ElmHtml/ToString.elm +8 -9
  124. package/src/DataSource/Env.elm +0 -38
  125. package/src/DataSource/Http.elm +0 -446
  126. package/src/DataSource/Internal/Request.elm +0 -20
  127. package/src/DataSource/Port.elm +0 -90
  128. package/src/DataSource.elm +0 -538
  129. package/src/Form/Field.elm +0 -717
  130. package/src/Form/FieldStatus.elm +0 -36
  131. package/src/Form/FieldView.elm +0 -417
  132. package/src/Form/FormData.elm +0 -22
  133. package/src/Form/Validation.elm +0 -391
  134. package/src/Form/Value.elm +0 -118
  135. package/src/Form.elm +0 -1683
  136. package/src/FormDecoder.elm +0 -102
  137. package/src/Pages/FormState.elm +0 -256
  138. package/src/Pages/Generate.elm +0 -800
  139. package/src/Pages/Internal/Form.elm +0 -17
  140. package/src/Pages/Msg.elm +0 -79
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @param {string[]} name
3
3
  */
4
- function routeParams(name) {
4
+ export function routeParams(name) {
5
5
  return name
6
6
  .map((section) => {
7
7
  const routeParamMatch = section.match(/([A-Z][A-Za-z0-9]*)__?$/);
@@ -17,7 +17,7 @@ function routeParams(name) {
17
17
  * @param {string[]} name
18
18
  * @returns {Segment[]}
19
19
  */
20
- function parseRouteParams(name) {
20
+ export function parseRouteParams(name) {
21
21
  return name.flatMap((section) => {
22
22
  const routeParamMatch = section.match(/([A-Z][A-Za-z0-9]*)(_?_?)$/);
23
23
  const maybeParam = (routeParamMatch && routeParamMatch[1]) || "TODO";
@@ -68,7 +68,7 @@ function parseRouteParams(name) {
68
68
  * @param {string[]} name
69
69
  * @returns {( Segment | {kind: 'static'; name: string})[]}
70
70
  */
71
- function parseRouteParamsWithStatic(name) {
71
+ export function parseRouteParamsWithStatic(name) {
72
72
  return name.flatMap((section) => {
73
73
  const routeParamMatch = section.match(/([A-Z][A-Za-z0-9]*)(_?_?)$/);
74
74
  const maybeParam = (routeParamMatch && routeParamMatch[1]) || "TODO";
@@ -123,7 +123,7 @@ function parseRouteParamsWithStatic(name) {
123
123
  * @param {string[]} name
124
124
  * @returns {string}
125
125
  */
126
- function routeVariantDefinition(name) {
126
+ export function routeVariantDefinition(name) {
127
127
  const newLocal = parseRouteParams(name);
128
128
  if (newLocal.length == 0) {
129
129
  return routeVariant(name);
@@ -151,7 +151,7 @@ function routeVariantDefinition(name) {
151
151
  * @param {string[]} name
152
152
  * @returns {string}
153
153
  */
154
- function toPathPattern(name) {
154
+ export function toPathPattern(name) {
155
155
  return (
156
156
  "/" +
157
157
  parseRouteParamsWithStatic(name)
@@ -181,7 +181,7 @@ function toPathPattern(name) {
181
181
  * @param {string[]} name
182
182
  * @returns {string[]}
183
183
  */
184
- function toPathPatterns(name) {
184
+ export function toPathPatterns(name) {
185
185
  const segments = parseRouteParamsWithStatic(name);
186
186
 
187
187
  const lastSegment = segments[segments.length - 1];
@@ -199,7 +199,7 @@ function toPathPatterns(name) {
199
199
  /**
200
200
  * @param {string[]} segments
201
201
  */
202
- function joinPath(segments) {
202
+ export function joinPath(segments) {
203
203
  const joined = segments.join("/");
204
204
  if (joined.startsWith("/")) {
205
205
  return joined;
@@ -211,7 +211,7 @@ function joinPath(segments) {
211
211
  /**
212
212
  * @return {string[]}
213
213
  */
214
- function newHelper(segments) {
214
+ export function newHelper(segments) {
215
215
  return segments.map((param) => {
216
216
  switch (param.kind) {
217
217
  case "static": {
@@ -238,7 +238,7 @@ function newHelper(segments) {
238
238
  * @param {string[]} name
239
239
  * @returns {string}
240
240
  */
241
- function toElmPathPattern(name) {
241
+ export function toElmPathPattern(name) {
242
242
  const parsedSegments = parseRouteParamsWithStatic(name);
243
243
 
244
244
  const foundEndings = parsedSegments.flatMap((segment) => {
@@ -297,14 +297,14 @@ function toElmPathPattern(name) {
297
297
  * @param {string} input
298
298
  * @returns {string}
299
299
  */
300
- function camelToKebab(input) {
300
+ export function camelToKebab(input) {
301
301
  return input.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
302
302
  }
303
303
 
304
304
  /**
305
305
  * @param {string[]} name
306
306
  */
307
- function paramsRecord(name) {
307
+ export function paramsRecord(name) {
308
308
  return `{ ${parseRouteParams(name).map((param) => {
309
309
  switch (param.kind) {
310
310
  case "dynamic": {
@@ -326,7 +326,7 @@ function paramsRecord(name) {
326
326
  /**
327
327
  * @param {string[]} name
328
328
  */
329
- function routeVariant(name) {
329
+ export function routeVariant(name) {
330
330
  return `${name.join("__")}`;
331
331
  }
332
332
 
@@ -334,44 +334,29 @@ function routeVariant(name) {
334
334
  * @param {string[]} name
335
335
  * @param {string} paramsName
336
336
  */
337
- function destructureRoute(name, paramsName) {
337
+ export function destructureRoute(name, paramsName) {
338
338
  return emptyRouteParams(name)
339
339
  ? `Route.${routeVariant(name)}`
340
340
  : `(Route.${routeVariant(name)} ${paramsName})`;
341
341
  }
342
342
 
343
- function referenceRouteParams(name, paramsName) {
343
+ export function referenceRouteParams(name, paramsName) {
344
344
  return emptyRouteParams(name) ? `{}` : paramsName;
345
345
  }
346
346
  /**
347
347
  * @param {string[]} name
348
348
  */
349
- function emptyRouteParams(name) {
349
+ export function emptyRouteParams(name) {
350
350
  return parseRouteParams(name).length === 0;
351
351
  }
352
352
 
353
353
  /**
354
354
  * @param {string} name
355
355
  */
356
- function toFieldName(name) {
356
+ export function toFieldName(name) {
357
357
  if (name === "SPLAT") {
358
358
  return "splat";
359
359
  } else {
360
360
  return name.charAt(0).toLowerCase() + name.slice(1);
361
361
  }
362
362
  }
363
-
364
- module.exports = {
365
- routeParams,
366
- routeVariantDefinition,
367
- routeVariant,
368
- toFieldName,
369
- paramsRecord,
370
- toPathPattern,
371
- toPathPatterns,
372
- parseRouteParams,
373
- parseRouteParamsWithStatic,
374
- toElmPathPattern,
375
- destructureRoute,
376
- referenceRouteParams,
377
- };
@@ -1,11 +1,9 @@
1
- module.exports = { gather };
2
-
3
1
  /** @typedef { { type: 'root'; keyValuePair: [string, string] } } RootTagModifier */
4
2
 
5
3
  /**
6
4
  * @param {( SeoTag | RootTagModifier )[]} tags
7
5
  */
8
- function gather(tags) {
6
+ export function gather(tags) {
9
7
  const withoutRootModifiers = tags.flatMap((value) => {
10
8
  if (value.type === "root") {
11
9
  return [];
@@ -43,11 +41,16 @@ function headTag(rootModifiers) {
43
41
 
44
42
  function toString(/** @type { SeoTag[] } */ tags) {
45
43
  return tags
46
- .map((headTag) => {
44
+ .flatMap((headTag) => {
47
45
  if (headTag.type === "head") {
48
- return appendTag(headTag);
46
+ return [appendTag(headTag)];
49
47
  } else if (headTag.type === "json-ld") {
50
- return appendJsonLdTag(headTag);
48
+ return [appendJsonLdTag(headTag)];
49
+ } else if (headTag.type === "stripped") {
50
+ console.warn(
51
+ `WARNING: Head.nonLoadingTag value ignored because it used a loading tag: ${headTag.message}`
52
+ );
53
+ return [];
51
54
  } else {
52
55
  throw new Error(`Unknown tag type ${JSON.stringify(headTag)}`);
53
56
  }
@@ -55,7 +58,7 @@ function toString(/** @type { SeoTag[] } */ tags) {
55
58
  .join("");
56
59
  }
57
60
 
58
- /** @typedef {HeadTag | JsonLdTag} SeoTag */
61
+ /** @typedef {HeadTag | JsonLdTag | StrippedTag} SeoTag */
59
62
 
60
63
  /** @typedef {{ name: string; attributes: string[][]; type: 'head' }} HeadTag */
61
64
  function appendTag(/** @type {HeadTag} */ tagDetails) {
@@ -66,6 +69,8 @@ function appendTag(/** @type {HeadTag} */ tagDetails) {
66
69
  }
67
70
 
68
71
  /** @typedef {{ contents: Object; type: 'json-ld' }} JsonLdTag */
72
+ /** @typedef {{ message: string; type: 'stripped' }} StrippedTag */
73
+
69
74
  function appendJsonLdTag(/** @type {JsonLdTag} */ tagDetails) {
70
75
  return `<script type="application/ld+json">
71
76
  ${JSON.stringify(tagDetails.contents)}
@@ -0,0 +1,77 @@
1
+ /** This code is from https://github.com/sveltejs/kit/blob/3b457f67d4d7c59fc63bb3f600a490e4dacc2e62/packages/kit/src/exports/vite/utils.js */
2
+
3
+ /**
4
+ * @param {...import('vite').UserConfig} configs
5
+ * @returns {import('vite').UserConfig}
6
+ */
7
+ export function merge_vite_configs(...configs) {
8
+ return deep_merge(
9
+ ...configs.map((config) => ({
10
+ ...config,
11
+ resolve: {
12
+ ...config.resolve,
13
+ alias: normalize_alias(config.resolve?.alias || {}),
14
+ },
15
+ }))
16
+ );
17
+ }
18
+
19
+ /**
20
+ * Takes zero or more objects and returns a new object that has all the values
21
+ * deeply merged together. None of the original objects will be mutated at any
22
+ * level, and the returned object will have no references to the original
23
+ * objects at any depth. If there's a conflict the last one wins, except for
24
+ * arrays which will be combined.
25
+ * @param {...Object} objects
26
+ * @returns {Record<string, any>} the merged object
27
+ */
28
+ function deep_merge(...objects) {
29
+ const result = {};
30
+ /** @type {string[]} */
31
+ objects.forEach((o) => merge_into(result, o));
32
+ return result;
33
+ }
34
+
35
+ /**
36
+ * normalize kit.vite.resolve.alias as an array
37
+ * @param {import('vite').AliasOptions} o
38
+ * @returns {import('vite').Alias[]}
39
+ */
40
+ function normalize_alias(o) {
41
+ if (Array.isArray(o)) return o;
42
+ return Object.entries(o).map(([find, replacement]) => ({
43
+ find,
44
+ replacement,
45
+ }));
46
+ }
47
+
48
+ /**
49
+ * Merges b into a, recursively, mutating a.
50
+ * @param {Record<string, any>} a
51
+ * @param {Record<string, any>} b
52
+ */
53
+ function merge_into(a, b) {
54
+ /**
55
+ * Checks for "plain old Javascript object", typically made as an object
56
+ * literal. Excludes Arrays and built-in types like Buffer.
57
+ * @param {any} x
58
+ */
59
+ const is_plain_object = (x) =>
60
+ typeof x === "object" && x.constructor === Object;
61
+
62
+ for (const prop in b) {
63
+ if (is_plain_object(b[prop])) {
64
+ if (!is_plain_object(a[prop])) {
65
+ a[prop] = {};
66
+ }
67
+ merge_into(a[prop], b[prop]);
68
+ } else if (Array.isArray(b[prop])) {
69
+ if (!Array.isArray(a[prop])) {
70
+ a[prop] = [];
71
+ }
72
+ a[prop].push(...b[prop]);
73
+ } else {
74
+ a[prop] = b[prop];
75
+ }
76
+ }
77
+ }
@@ -103,4 +103,14 @@ function find_anchor(node) {
103
103
  return /** @type {HTMLAnchorElement} */ (node);
104
104
  }
105
105
 
106
+ Object.defineProperty(SubmitEvent.prototype, "fields", {
107
+ get: function fields() {
108
+ let formData = new FormData(this.currentTarget);
109
+ if (this.submitter?.name) {
110
+ formData.append(this.submitter.name, this.submitter.value);
111
+ }
112
+ return [...formData.entries()];
113
+ },
114
+ });
115
+
106
116
  setup();
@@ -5,15 +5,69 @@ var eventSource = null;
5
5
  let updateAppContentJson = new Promise((resolve, reject) => resolve(() => {}));
6
6
 
7
7
  function connect(sendContentJsonPort, initialErrorPage) {
8
+ let reconnectFrequencySeconds = 1;
9
+ // reconnect logic based on: https://stackoverflow.com/a/61148682/383983
8
10
  // Listen for the server to tell us that an HMR update is available
9
- eventSource = new EventSource("/stream");
10
- window.reloadOnOk = initialErrorPage;
11
- if (initialErrorPage) {
12
- handleEvent(sendContentJsonPort, { data: "content.dat" });
11
+ function waitFunc() {
12
+ return reconnectFrequencySeconds * 1000;
13
13
  }
14
- eventSource.onmessage = async function (evt) {
15
- handleEvent(sendContentJsonPort, evt);
16
- };
14
+ function tryToSetupFunc() {
15
+ setupEventSource();
16
+ reconnectFrequencySeconds *= 2;
17
+ if (reconnectFrequencySeconds >= 8) {
18
+ reconnectFrequencySeconds = 8;
19
+ }
20
+ }
21
+ function reconnectFunc() {
22
+ console.log(
23
+ `Attempting dev server reconnect in ${reconnectFrequencySeconds}...`
24
+ );
25
+ setTimeout(tryToSetupFunc, waitFunc());
26
+ }
27
+ function setupEventSource() {
28
+ eventSource = new EventSource("/stream");
29
+ window.reloadOnOk = initialErrorPage;
30
+
31
+ try {
32
+ if (initialErrorPage) {
33
+ handleEvent(sendContentJsonPort, { data: "content.dat" });
34
+ }
35
+ } catch (e) {}
36
+ eventSource.onopen = async function () {
37
+ hideError();
38
+ reconnectFrequencySeconds = 1;
39
+ };
40
+ eventSource.onerror = async function (evt) {
41
+ eventSource && eventSource.close();
42
+ reconnectFunc();
43
+
44
+ showReconnectBanner();
45
+ };
46
+ eventSource.onmessage = async function (evt) {
47
+ handleEvent(sendContentJsonPort, evt);
48
+ };
49
+ }
50
+
51
+ setupEventSource();
52
+ }
53
+
54
+ function showReconnectBanner() {
55
+ showError({
56
+ type: "compile-errors",
57
+ errors: [
58
+ {
59
+ path: "",
60
+ name: "",
61
+ problems: [
62
+ {
63
+ title: "",
64
+ // region: "",
65
+ message: ["Dev server is disconnected..."],
66
+ },
67
+ ],
68
+ },
69
+ ],
70
+ });
17
71
  }
18
72
 
19
73
  async function handleEvent(sendContentJsonPort, evt) {
@@ -28,8 +82,7 @@ async function handleEvent(sendContentJsonPort, evt) {
28
82
 
29
83
  try {
30
84
  await fetchContentJson;
31
- const elmJsResponse = await elmJsRequest;
32
- thenApplyHmr(elmJsResponse);
85
+ thenApplyHmr(await elmJsRequest);
33
86
  } catch (errorJson) {
34
87
  if (typeof errorJson === "string") {
35
88
  errorJson = JSON.parse(errorJson);
@@ -116,8 +169,7 @@ var myDisposeCallback = function () {
116
169
  var module = {
117
170
  hot: {
118
171
  accept: async function () {
119
- const sendInUpdatedContentJson = await updateAppContentJson;
120
- sendInUpdatedContentJson();
172
+ (await updateAppContentJson)();
121
173
  },
122
174
 
123
175
  dispose: function (callback) {
@@ -224,8 +276,11 @@ function htmlSanitize(str, type) {
224
276
  );
225
277
  }
226
278
 
227
- const parseHeader = (title, path) =>
228
- `-- ${title.replace("-", " ")} --------------- ${path}`;
279
+ function parseHeader(title, path) {
280
+ return `-- ${(title || "ERROR").replace("-", " ")} --------------- ${
281
+ path || ""
282
+ }`;
283
+ }
229
284
 
230
285
  /*
231
286
  |-------------------------------------------------------------------------------
@@ -253,6 +308,14 @@ const parseConsoleErrors =
253
308
  * */
254
309
  (info) => {
255
310
  if (info.rule) {
311
+ if (info.details) {
312
+ return joinMessage(
313
+ info.details.reduce(consoleMsg, {
314
+ error: [consoleHeader(info.rule, path)],
315
+ style: [styleColor("blue")],
316
+ })
317
+ );
318
+ }
256
319
  return joinMessage(
257
320
  info.formatted.reduce(consoleMsg, {
258
321
  error: [consoleHeader(info.rule, path)],
@@ -313,6 +376,9 @@ const parseHtmlErrors = (path) => (info) => {
313
376
  if (info.rule) {
314
377
  return info.formatted.reduce(htmlMsg, htmlHeader(info.rule, path));
315
378
  } else {
379
+ if (info.details) {
380
+ return info.details.reduce(htmlMsg, htmlHeader(info.title, path));
381
+ }
316
382
  return info.message.reduce(htmlMsg, htmlHeader(info.title, path));
317
383
  }
318
384
  };
@@ -1,16 +1,17 @@
1
1
  module Api exposing (routes)
2
2
 
3
- import ApiRoute exposing (ApiRoute)
4
- import DataSource exposing (DataSource)
3
+ import ApiRoute
4
+ import BackendTask exposing (BackendTask)
5
+ import FatalError exposing (FatalError)
5
6
  import Html exposing (Html)
6
7
  import Pages.Manifest as Manifest
7
8
  import Route exposing (Route)
8
9
 
9
10
 
10
11
  routes :
11
- DataSource (List Route)
12
- -> (Html Never -> String)
13
- -> List (ApiRoute ApiRoute.Response)
12
+ BackendTask FatalError (List Route)
13
+ -> (Maybe { indent : Int, newLines : Bool } -> Html Never -> String)
14
+ -> List (ApiRoute.ApiRoute ApiRoute.Response)
14
15
  routes getStaticRoutes htmlToString =
15
16
  []
16
17
 
@@ -0,0 +1,123 @@
1
+ module Effect exposing (Effect(..), batch, fromCmd, map, none, perform)
2
+
3
+ import Browser.Navigation
4
+ import Form.FormData exposing (FormData)
5
+ import Http
6
+ import Json.Decode as Decode
7
+ import Pages.Fetcher
8
+ import Url exposing (Url)
9
+
10
+
11
+ type Effect msg
12
+ = None
13
+ | Cmd (Cmd msg)
14
+ | Batch (List (Effect msg))
15
+ | SetField { formId : String, name : String, value : String }
16
+ | FetchRouteData
17
+ { data : Maybe FormData
18
+ , toMsg : Result Http.Error Url -> msg
19
+ }
20
+ | Submit
21
+ { values : FormData
22
+ , toMsg : Result Http.Error Url -> msg
23
+ }
24
+ | SubmitFetcher (Pages.Fetcher.Fetcher msg)
25
+
26
+
27
+ type alias RequestInfo =
28
+ { contentType : String
29
+ , body : String
30
+ }
31
+
32
+
33
+ none : Effect msg
34
+ none =
35
+ None
36
+
37
+
38
+ batch : List (Effect msg) -> Effect msg
39
+ batch =
40
+ Batch
41
+
42
+
43
+ fromCmd : Cmd msg -> Effect msg
44
+ fromCmd =
45
+ Cmd
46
+
47
+
48
+ map : (a -> b) -> Effect a -> Effect b
49
+ map fn effect =
50
+ case effect of
51
+ None ->
52
+ None
53
+
54
+ Cmd cmd ->
55
+ Cmd (Cmd.map fn cmd)
56
+
57
+ Batch list ->
58
+ Batch (List.map (map fn) list)
59
+
60
+ FetchRouteData fetchInfo ->
61
+ FetchRouteData
62
+ { data = fetchInfo.data
63
+ , toMsg = fetchInfo.toMsg >> fn
64
+ }
65
+
66
+ Submit fetchInfo ->
67
+ Submit
68
+ { values = fetchInfo.values
69
+ , toMsg = fetchInfo.toMsg >> fn
70
+ }
71
+
72
+ SetField info ->
73
+ SetField info
74
+
75
+ SubmitFetcher fetcher ->
76
+ fetcher
77
+ |> Pages.Fetcher.map fn
78
+ |> SubmitFetcher
79
+
80
+
81
+ perform :
82
+ { fetchRouteData :
83
+ { data : Maybe FormData
84
+ , toMsg : Result Http.Error Url -> pageMsg
85
+ }
86
+ -> Cmd msg
87
+ , submit :
88
+ { values : FormData
89
+ , toMsg : Result Http.Error Url -> pageMsg
90
+ }
91
+ -> Cmd msg
92
+ , runFetcher :
93
+ Pages.Fetcher.Fetcher pageMsg
94
+ -> Cmd msg
95
+ , fromPageMsg : pageMsg -> msg
96
+ , key : Browser.Navigation.Key
97
+ , setField : { formId : String, name : String, value : String } -> Cmd msg
98
+ }
99
+ -> Effect pageMsg
100
+ -> Cmd msg
101
+ perform ({ fromPageMsg, key } as helpers) effect =
102
+ case effect of
103
+ None ->
104
+ Cmd.none
105
+
106
+ Cmd cmd ->
107
+ Cmd.map fromPageMsg cmd
108
+
109
+ SetField info ->
110
+ helpers.setField info
111
+
112
+ Batch list ->
113
+ Cmd.batch (List.map (perform helpers) list)
114
+
115
+ FetchRouteData fetchInfo ->
116
+ helpers.fetchRouteData
117
+ fetchInfo
118
+
119
+ Submit record ->
120
+ helpers.submit record
121
+
122
+ SubmitFetcher record ->
123
+ helpers.runFetcher record
@@ -1,6 +1,36 @@
1
- module ErrorPage exposing (ErrorPage(..), internalError, notFound, statusCode, view)
1
+ module ErrorPage exposing (ErrorPage(..), Model, Msg, head, init, internalError, notFound, statusCode, update, view)
2
2
 
3
+ import Effect exposing (Effect)
4
+ import Head
3
5
  import Html exposing (Html)
6
+ import View exposing (View)
7
+
8
+
9
+ type Msg
10
+ = NoOp
11
+
12
+
13
+ type alias Model =
14
+ {}
15
+
16
+
17
+ init : ErrorPage -> ( Model, Effect Msg )
18
+ init errorPage =
19
+ ( {}
20
+ , Effect.none
21
+ )
22
+
23
+
24
+ update : ErrorPage -> Msg -> Model -> ( Model, Effect Msg )
25
+ update errorPage msg model =
26
+ case msg of
27
+ NoOp ->
28
+ ( {}, Effect.none )
29
+
30
+
31
+ head : ErrorPage -> List Head.Tag
32
+ head errorPage =
33
+ []
4
34
 
5
35
 
6
36
  type ErrorPage
@@ -18,13 +48,14 @@ internalError =
18
48
  InternalError
19
49
 
20
50
 
21
- view : ErrorPage -> { body : Html msg, title : String }
22
- view error =
51
+ view : ErrorPage -> Model -> View Msg
52
+ view error model =
23
53
  { body =
24
- Html.div []
25
- [ Html.text "Hi! This is a NotFound error"
54
+ [ Html.div []
55
+ [ Html.p [] [ Html.text "Page not found. Maybe try another URL?" ]
26
56
  ]
27
- , title = "Error"
57
+ ]
58
+ , title = "Page Not Found"
28
59
  }
29
60
 
30
61
 
@@ -1,14 +1,17 @@
1
- module Route.Index exposing (Data, Model, Msg, route)
1
+ module Route.Index exposing (ActionData, Data, Model, Msg, route)
2
2
 
3
- import DataSource exposing (DataSource)
3
+ import BackendTask exposing (BackendTask)
4
+ import FatalError exposing (FatalError)
4
5
  import Head
5
6
  import Head.Seo as Seo
6
7
  import Html
7
- import Html.Attributes as Attr
8
+ import Html.Styled.Attributes as Attr
9
+ import PagesMsg exposing (PagesMsg)
8
10
  import Pages.PageUrl exposing (PageUrl)
9
11
  import Pages.Url
10
12
  import Path
11
- import RouteBuilder exposing (StatelessRoute, StaticPayload)
13
+ import Route
14
+ import RouteBuilder exposing (StatefulRoute, StatelessRoute, App)
12
15
  import Shared
13
16
  import View exposing (View)
14
17
 
@@ -25,7 +28,7 @@ type alias RouteParams =
25
28
  {}
26
29
 
27
30
 
28
- type alias Data =
31
+ type alias ActionData =
29
32
  {}
30
33
 
31
34
 
@@ -38,13 +41,17 @@ route =
38
41
  |> RouteBuilder.buildNoState { view = view }
39
42
 
40
43
 
41
- data : DataSource Data
44
+ type alias Data =
45
+ ()
46
+
47
+
48
+ data : BackendTask FatalError Data
42
49
  data =
43
- DataSource.succeed Data
50
+ BackendTask.succeed ()
44
51
 
45
52
 
46
53
  head :
47
- StaticPayload Data ActionData RouteParams
54
+ App Data ActionData RouteParams
48
55
  -> List Head.Tag
49
56
  head static =
50
57
  Seo.summary
@@ -66,8 +73,8 @@ head static =
66
73
  view :
67
74
  Maybe PageUrl
68
75
  -> Shared.Model
69
- -> StaticPayload Data ActionData RouteParams
70
- -> View Msg
76
+ -> App Data ActionData RouteParams
77
+ -> View (PagesMsg Msg)
71
78
  view maybeUrl sharedModel static =
72
79
  { title = "elm-pages is running"
73
80
  , body =