elm-pages 3.0.0-beta.38 → 3.0.0-beta.39
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/README.md +1 -1
- package/adapter/netlify.js +209 -0
- package/codegen/elm-pages-codegen.cjs +30 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
- package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
- package/generator/src/build.js +76 -5
- package/generator/src/compatibility-key.js +2 -2
- package/generator/src/generate-template-module-connector.js +0 -1
- package/package.json +2 -1
- package/src/BackendTask/Internal/Request.elm +4 -4
- package/src/Pages/Form.elm +2 -2
- package/src/Pages/Internal/Msg.elm +7 -12
- package/src/Pages/Internal/Platform/CompatibilityKey.elm +1 -1
- package/src/Pages/Internal/Platform/GeneratorApplication.elm +1 -1
- package/src/Pages/Internal/Platform/StaticResponses.elm +1 -9
- package/src/Pages/Internal/Platform.elm +10 -10
- package/src/Pages/Transition.elm +3 -2
- package/src/Server/Request.elm +2 -3
- package/src/Stub.elm +4 -7
- package/src/Internal/Field.elm +0 -19
- package/src/Internal/Input.elm +0 -81
package/README.md
CHANGED
|
@@ -81,7 +81,7 @@ https://github.com/dillonkearns/elm-pages/projects
|
|
|
81
81
|
You will see an error if the NPM and Elm package do not have a matching Compatibility Key. Usually it's best to upgrade to the latest version of both the Elm and NPM
|
|
82
82
|
packages when you upgrade. However, in case you want to install versions that are behind the latest, the Compatibility Key is included here for reference.
|
|
83
83
|
|
|
84
|
-
Current Compatibility Key:
|
|
84
|
+
Current Compatibility Key: 16.
|
|
85
85
|
|
|
86
86
|
## Contributors ✨
|
|
87
87
|
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
|
|
3
|
+
export default async function run({
|
|
4
|
+
renderFunctionFilePath,
|
|
5
|
+
routePatterns,
|
|
6
|
+
apiRoutePatterns,
|
|
7
|
+
}) {
|
|
8
|
+
console.log("Running Netlify adapter");
|
|
9
|
+
ensureDirSync("functions/render");
|
|
10
|
+
ensureDirSync("functions/server-render");
|
|
11
|
+
|
|
12
|
+
fs.copyFileSync(
|
|
13
|
+
renderFunctionFilePath,
|
|
14
|
+
"./functions/render/elm-pages-cli.mjs"
|
|
15
|
+
);
|
|
16
|
+
fs.copyFileSync(
|
|
17
|
+
renderFunctionFilePath,
|
|
18
|
+
"./functions/server-render/elm-pages-cli.mjs"
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
fs.writeFileSync("./functions/render/index.mjs", rendererCode(true));
|
|
22
|
+
fs.writeFileSync("./functions/server-render/index.mjs", rendererCode(false));
|
|
23
|
+
// TODO rename functions/render to functions/fallback-render
|
|
24
|
+
// TODO prepend instead of writing file
|
|
25
|
+
|
|
26
|
+
const apiServerRoutes = apiRoutePatterns.filter(isServerSide);
|
|
27
|
+
|
|
28
|
+
ensureValidRoutePatternsForNetlify(apiServerRoutes);
|
|
29
|
+
|
|
30
|
+
const apiRouteRedirects = apiServerRoutes
|
|
31
|
+
.map((apiRoute) => {
|
|
32
|
+
if (apiRoute.kind === "prerender-with-fallback") {
|
|
33
|
+
return `${apiPatternToRedirectPattern(
|
|
34
|
+
apiRoute.pathPattern
|
|
35
|
+
)} /.netlify/builders/render 200`;
|
|
36
|
+
} else if (apiRoute.kind === "serverless") {
|
|
37
|
+
return `${apiPatternToRedirectPattern(
|
|
38
|
+
apiRoute.pathPattern
|
|
39
|
+
)} /.netlify/functions/server-render 200`;
|
|
40
|
+
} else {
|
|
41
|
+
throw "Unhandled API Server Route";
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
.join("\n");
|
|
45
|
+
|
|
46
|
+
const redirectsFile =
|
|
47
|
+
routePatterns
|
|
48
|
+
.filter(isServerSide)
|
|
49
|
+
.map((route) => {
|
|
50
|
+
if (route.kind === "prerender-with-fallback") {
|
|
51
|
+
return `${route.pathPattern} /.netlify/builders/render 200
|
|
52
|
+
${route.pathPattern}/content.dat /.netlify/builders/render 200`;
|
|
53
|
+
} else {
|
|
54
|
+
return `${route.pathPattern} /.netlify/functions/server-render 200
|
|
55
|
+
${route.pathPattern}/content.dat /.netlify/functions/server-render 200`;
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
.join("\n") +
|
|
59
|
+
"\n" +
|
|
60
|
+
apiRouteRedirects +
|
|
61
|
+
"\n";
|
|
62
|
+
|
|
63
|
+
fs.writeFileSync("dist/_redirects", redirectsFile);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function ensureValidRoutePatternsForNetlify(apiRoutePatterns) {
|
|
67
|
+
const invalidNetlifyRoutes = apiRoutePatterns.filter((apiRoute) =>
|
|
68
|
+
apiRoute.pathPattern.some(({ kind }) => kind === "hybrid")
|
|
69
|
+
);
|
|
70
|
+
if (invalidNetlifyRoutes.length > 0) {
|
|
71
|
+
throw (
|
|
72
|
+
"Invalid Netlify routes!\n" +
|
|
73
|
+
invalidNetlifyRoutes
|
|
74
|
+
.map((value) => JSON.stringify(value, null, 2))
|
|
75
|
+
.join(", ")
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function isServerSide(route) {
|
|
81
|
+
return (
|
|
82
|
+
route.kind === "prerender-with-fallback" || route.kind === "serverless"
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @param {boolean} isOnDemand
|
|
88
|
+
*/
|
|
89
|
+
function rendererCode(isOnDemand) {
|
|
90
|
+
return `import * as elmPages from "./elm-pages-cli.mjs";
|
|
91
|
+
import * as busboy from "busboy";
|
|
92
|
+
|
|
93
|
+
${
|
|
94
|
+
isOnDemand
|
|
95
|
+
? `import { builder } from "@netlify/functions";
|
|
96
|
+
|
|
97
|
+
export const handler = builder(render);`
|
|
98
|
+
: `
|
|
99
|
+
|
|
100
|
+
export const handler = render;`
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @param {import('aws-lambda').APIGatewayProxyEvent} event
|
|
106
|
+
* @param {any} context
|
|
107
|
+
*/
|
|
108
|
+
async function render(event, context) {
|
|
109
|
+
try {
|
|
110
|
+
const renderResult = await elmPages.render(await reqToJson(event));
|
|
111
|
+
|
|
112
|
+
const statusCode = renderResult.statusCode;
|
|
113
|
+
const headers = renderResult.headers;
|
|
114
|
+
|
|
115
|
+
if (renderResult.kind === "bytes") {
|
|
116
|
+
return {
|
|
117
|
+
body: Buffer.from(renderResult.body).toString("base64"),
|
|
118
|
+
isBase64Encoded: true,
|
|
119
|
+
multiValueHeaders: {
|
|
120
|
+
"Content-Type": "application/octet-stream",
|
|
121
|
+
"x-powered-by": "elm-pages",
|
|
122
|
+
...headers,
|
|
123
|
+
},
|
|
124
|
+
statusCode,
|
|
125
|
+
};
|
|
126
|
+
} else if (renderResult.kind === "api-response") {
|
|
127
|
+
return {
|
|
128
|
+
body: renderResult.body,
|
|
129
|
+
multiValueHeaders: headers,
|
|
130
|
+
statusCode,
|
|
131
|
+
isBase64Encoded: renderResult.isBase64Encoded,
|
|
132
|
+
};
|
|
133
|
+
} else {
|
|
134
|
+
return {
|
|
135
|
+
body: renderResult.body,
|
|
136
|
+
multiValueHeaders: {
|
|
137
|
+
"Content-Type": "text/html",
|
|
138
|
+
"x-powered-by": "elm-pages",
|
|
139
|
+
...headers,
|
|
140
|
+
},
|
|
141
|
+
statusCode,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error(error);
|
|
146
|
+
console.error(JSON.stringify(error, null, 2));
|
|
147
|
+
return {
|
|
148
|
+
body: \`<body><h1>Error</h1><pre>\${JSON.stringify(error, null, 2)}</pre></body>\`,
|
|
149
|
+
statusCode: 500,
|
|
150
|
+
headers: {
|
|
151
|
+
"Content-Type": "text/html",
|
|
152
|
+
"x-powered-by": "elm-pages",
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* @param {import('aws-lambda').APIGatewayProxyEvent} req
|
|
160
|
+
* @returns {{method: string; rawUrl: string; body: string?; headers: Record<string, string>; multiPartFormData: unknown }}
|
|
161
|
+
*/
|
|
162
|
+
function reqToJson(req) {
|
|
163
|
+
return {
|
|
164
|
+
method: req.httpMethod,
|
|
165
|
+
headers: req.headers,
|
|
166
|
+
rawUrl: req.rawUrl,
|
|
167
|
+
body: req.body,
|
|
168
|
+
multiPartFormData: null,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
`;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* @param {fs.PathLike} dirpath
|
|
176
|
+
*/
|
|
177
|
+
function ensureDirSync(dirpath) {
|
|
178
|
+
try {
|
|
179
|
+
fs.mkdirSync(dirpath, { recursive: true });
|
|
180
|
+
} catch (err) {
|
|
181
|
+
if (err.code !== "EEXIST") throw err;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** @typedef {{kind: 'dynamic'} | {kind: 'literal', value: string}} ApiSegment */
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* @param {ApiSegment[]} pathPattern
|
|
189
|
+
*/
|
|
190
|
+
function apiPatternToRedirectPattern(pathPattern) {
|
|
191
|
+
return (
|
|
192
|
+
"/" +
|
|
193
|
+
pathPattern
|
|
194
|
+
.map((segment, index) => {
|
|
195
|
+
switch (segment.kind) {
|
|
196
|
+
case "literal": {
|
|
197
|
+
return segment.value;
|
|
198
|
+
}
|
|
199
|
+
case "dynamic": {
|
|
200
|
+
return `:dynamic${index}`;
|
|
201
|
+
}
|
|
202
|
+
default: {
|
|
203
|
+
throw "Unhandled segment: " + JSON.stringify(segment);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
})
|
|
207
|
+
.join("/")
|
|
208
|
+
);
|
|
209
|
+
}
|
|
@@ -26325,6 +26325,36 @@ var $author$project$Gen$Pages$Transition$annotation_ = {
|
|
|
26325
26325
|
_List_fromArray(
|
|
26326
26326
|
[fetcherSubmitStatusArg0]));
|
|
26327
26327
|
},
|
|
26328
|
+
formData: A4(
|
|
26329
|
+
$author$project$Elm$Annotation$alias,
|
|
26330
|
+
$author$project$Gen$Pages$Transition$moduleName_,
|
|
26331
|
+
'FormData',
|
|
26332
|
+
_List_Nil,
|
|
26333
|
+
$author$project$Elm$Annotation$record(
|
|
26334
|
+
_List_fromArray(
|
|
26335
|
+
[
|
|
26336
|
+
_Utils_Tuple2(
|
|
26337
|
+
'fields',
|
|
26338
|
+
$author$project$Elm$Annotation$list(
|
|
26339
|
+
A2($author$project$Elm$Annotation$tuple, $author$project$Elm$Annotation$string, $author$project$Elm$Annotation$string))),
|
|
26340
|
+
_Utils_Tuple2(
|
|
26341
|
+
'method',
|
|
26342
|
+
A3(
|
|
26343
|
+
$author$project$Elm$Annotation$namedWith,
|
|
26344
|
+
_List_fromArray(
|
|
26345
|
+
['Form']),
|
|
26346
|
+
'Method',
|
|
26347
|
+
_List_Nil)),
|
|
26348
|
+
_Utils_Tuple2('action', $author$project$Elm$Annotation$string),
|
|
26349
|
+
_Utils_Tuple2(
|
|
26350
|
+
'id',
|
|
26351
|
+
A3(
|
|
26352
|
+
$author$project$Elm$Annotation$namedWith,
|
|
26353
|
+
_List_Nil,
|
|
26354
|
+
'Maybe',
|
|
26355
|
+
_List_fromArray(
|
|
26356
|
+
[$author$project$Elm$Annotation$string])))
|
|
26357
|
+
]))),
|
|
26328
26358
|
loadingState: A3(
|
|
26329
26359
|
$author$project$Elm$Annotation$namedWith,
|
|
26330
26360
|
_List_fromArray(
|
|
Binary file
|
|
@@ -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:
|
|
78
|
+
const flags = { initialSeed: 2220181744, 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
|
|
Binary file
|
|
@@ -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:
|
|
78
|
+
const flags = { initialSeed: 1451258136, 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
|
package/generator/src/build.js
CHANGED
|
@@ -67,6 +67,8 @@ async function ensureRequiredExecutables() {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
export async function run(options) {
|
|
70
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
71
|
+
const __dirname = path.dirname(__filename);
|
|
70
72
|
console.warn = function (...messages) {
|
|
71
73
|
// This is a temporary hack to avoid this warning. elm-pages manages compiling the Elm code without Vite's involvement, so it is external to Vite.
|
|
72
74
|
// There is a pending issue to allow having external scripts in Vite, once this issue is fixed we can remove this hack:
|
|
@@ -182,13 +184,84 @@ export async function run(options) {
|
|
|
182
184
|
console.error("Failed to start custom-backend-task watcher", error);
|
|
183
185
|
}
|
|
184
186
|
});
|
|
185
|
-
// TODO extract common code for compiling ports file?
|
|
186
187
|
|
|
187
188
|
global.XMLHttpRequest = {};
|
|
188
189
|
const compileCli = compileCliApp(options);
|
|
189
190
|
try {
|
|
190
191
|
await compileCli;
|
|
191
192
|
await compileClientDone;
|
|
193
|
+
await portBackendTaskCompiled;
|
|
194
|
+
const inlineRenderCode = `
|
|
195
|
+
import * as renderer from "./render.js";
|
|
196
|
+
import * as elmModule from "${path.resolve("./elm-stuff/elm-pages/elm.cjs")}";
|
|
197
|
+
import * as url from 'url';
|
|
198
|
+
${
|
|
199
|
+
global.portsFilePath
|
|
200
|
+
? `import * as customBackendTask from "${path.resolve(
|
|
201
|
+
global.portsFilePath
|
|
202
|
+
)}";`
|
|
203
|
+
: `const customBackendTask = {};`
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
import * as preRenderHtml from "./pre-render-html.js";
|
|
207
|
+
const basePath = \`${options.base || "/"}\`;
|
|
208
|
+
const htmlTemplate = ${JSON.stringify(processedIndexTemplate)};
|
|
209
|
+
const mode = "build";
|
|
210
|
+
const addWatcher = () => {};
|
|
211
|
+
|
|
212
|
+
export async function render(request) {
|
|
213
|
+
const requestTime = new Date();
|
|
214
|
+
const response = await renderer.render(
|
|
215
|
+
customBackendTask,
|
|
216
|
+
basePath,
|
|
217
|
+
elmModule.default,
|
|
218
|
+
mode,
|
|
219
|
+
(new url.URL(request.rawUrl)).pathname,
|
|
220
|
+
request,
|
|
221
|
+
addWatcher,
|
|
222
|
+
false
|
|
223
|
+
);
|
|
224
|
+
console.dir(response);
|
|
225
|
+
if (response.kind === "bytes") {
|
|
226
|
+
return {
|
|
227
|
+
body: response.contentDatPayload.buffer,
|
|
228
|
+
statusCode: response.statusCode,
|
|
229
|
+
kind: response.kind,
|
|
230
|
+
headers: response.headers,
|
|
231
|
+
}
|
|
232
|
+
} else if (response.kind === "api-response") {
|
|
233
|
+
// isBase64Encoded
|
|
234
|
+
return {
|
|
235
|
+
body: response.body.body,
|
|
236
|
+
statusCode: response.statusCode,
|
|
237
|
+
kind: response.kind,
|
|
238
|
+
headers: response.headers,
|
|
239
|
+
isBase64Encoded: response.body.isBase64Encoded,
|
|
240
|
+
}
|
|
241
|
+
} else {
|
|
242
|
+
return {
|
|
243
|
+
body: preRenderHtml.replaceTemplate(htmlTemplate, response.htmlString),
|
|
244
|
+
statusCode: response.statusCode,
|
|
245
|
+
kind: response.kind,
|
|
246
|
+
headers: response.headers,
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
`;
|
|
251
|
+
await esbuild.build({
|
|
252
|
+
format: "esm",
|
|
253
|
+
platform: "node",
|
|
254
|
+
stdin: { contents: inlineRenderCode, resolveDir: __dirname },
|
|
255
|
+
bundle: true,
|
|
256
|
+
// TODO do I need to make the outfile joined with the current working directory?
|
|
257
|
+
|
|
258
|
+
outfile: ".elm-pages/compiled/render.mjs",
|
|
259
|
+
// external: ["node:*", ...options.external],
|
|
260
|
+
packages: "external",
|
|
261
|
+
minify: true,
|
|
262
|
+
// absWorkingDir: projectDirectory,
|
|
263
|
+
// banner: { js: `#!/usr/bin/env node\n\n${ESM_REQUIRE_SHIM}` },
|
|
264
|
+
});
|
|
192
265
|
} catch (cliError) {
|
|
193
266
|
// TODO make sure not to print duplicate error output if cleaner review output is printed
|
|
194
267
|
console.error(cliError);
|
|
@@ -628,19 +701,17 @@ function _HtmlAsJson_toJson(html) {
|
|
|
628
701
|
async function runAdapter(adaptFn, processedIndexTemplate) {
|
|
629
702
|
try {
|
|
630
703
|
await adaptFn({
|
|
631
|
-
renderFunctionFilePath: "
|
|
704
|
+
renderFunctionFilePath: "./.elm-pages/compiled/render.mjs",
|
|
632
705
|
routePatterns: JSON.parse(
|
|
633
706
|
await fsPromises.readFile("./dist/route-patterns.json", "utf-8")
|
|
634
707
|
),
|
|
635
708
|
apiRoutePatterns: JSON.parse(
|
|
636
709
|
await fsPromises.readFile("./dist/api-patterns.json", "utf-8")
|
|
637
710
|
),
|
|
638
|
-
portsFilePath: "./.elm-pages/compiled-ports/custom-backend-task.mjs",
|
|
639
|
-
htmlTemplate: processedIndexTemplate,
|
|
640
711
|
});
|
|
641
712
|
console.log("Success - Adapter script complete");
|
|
642
713
|
} catch (error) {
|
|
643
|
-
console.
|
|
714
|
+
console.trace("ERROR - Adapter script failed", error);
|
|
644
715
|
try {
|
|
645
716
|
console.error(JSON.stringify(error));
|
|
646
717
|
} catch (parsingError) {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export const compatibilityKey =
|
|
1
|
+
export const compatibilityKey = 16;
|
|
2
2
|
|
|
3
|
-
export const packageVersion = "3.0.0-beta.
|
|
3
|
+
export const packageVersion = "3.0.0-beta.39";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "elm-pages",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.0.0-beta.
|
|
4
|
+
"version": "3.0.0-beta.39",
|
|
5
5
|
"homepage": "https://elm-pages.com",
|
|
6
6
|
"moduleResolution": "node",
|
|
7
7
|
"description": "Type-safe static sites, written in pure elm with your own custom elm-markup syntax.",
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
"vitest": "^0.31.0"
|
|
69
69
|
},
|
|
70
70
|
"files": [
|
|
71
|
+
"adapter/",
|
|
71
72
|
"generator/src/",
|
|
72
73
|
"generator/review/",
|
|
73
74
|
"generator/dead-code-review/",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module BackendTask.Internal.Request exposing (request, request2)
|
|
2
2
|
|
|
3
3
|
import BackendTask exposing (BackendTask)
|
|
4
|
-
import BackendTask.Http exposing (Body,
|
|
4
|
+
import BackendTask.Http exposing (Body, Expect)
|
|
5
5
|
import Json.Decode exposing (Decoder)
|
|
6
6
|
import Json.Encode as Encode
|
|
7
7
|
|
|
@@ -24,7 +24,7 @@ request ({ name, body, expect } as params) =
|
|
|
24
24
|
}
|
|
25
25
|
expect
|
|
26
26
|
|> BackendTask.onError
|
|
27
|
-
(\
|
|
27
|
+
(\_ ->
|
|
28
28
|
-- TODO avoid crash here, this should be handled as an internal error
|
|
29
29
|
request params
|
|
30
30
|
)
|
|
@@ -38,7 +38,7 @@ request2 :
|
|
|
38
38
|
, onError : Json.Decode.Error -> error
|
|
39
39
|
}
|
|
40
40
|
-> BackendTask error a
|
|
41
|
-
request2
|
|
41
|
+
request2 { name, body, expect, onError, errorDecoder } =
|
|
42
42
|
-- elm-review: known-unoptimized-recursion
|
|
43
43
|
BackendTask.Http.request
|
|
44
44
|
{ url = "elm-pages-internal://" ++ name
|
|
@@ -50,7 +50,7 @@ request2 ({ name, body, expect, onError, errorDecoder } as params) =
|
|
|
50
50
|
}
|
|
51
51
|
(BackendTask.Http.expectJson Json.Decode.value)
|
|
52
52
|
|> BackendTask.onError
|
|
53
|
-
(\
|
|
53
|
+
(\_ ->
|
|
54
54
|
BackendTask.succeed Encode.null
|
|
55
55
|
)
|
|
56
56
|
|> BackendTask.andThen
|
package/src/Pages/Form.elm
CHANGED
|
@@ -16,7 +16,7 @@ import Dict exposing (Dict)
|
|
|
16
16
|
import FatalError exposing (FatalError)
|
|
17
17
|
import Form
|
|
18
18
|
import Form.Handler
|
|
19
|
-
import Form.Validation
|
|
19
|
+
import Form.Validation exposing (Validation)
|
|
20
20
|
import Html
|
|
21
21
|
import Html.Styled
|
|
22
22
|
import Pages.Internal.Msg
|
|
@@ -42,7 +42,7 @@ type alias FormWithServerValidations error combined input view =
|
|
|
42
42
|
|
|
43
43
|
{-| -}
|
|
44
44
|
type alias Handler error combined =
|
|
45
|
-
Form.Handler.Handler error (BackendTask FatalError (Validation
|
|
45
|
+
Form.Handler.Handler error (BackendTask FatalError (Validation error combined Never Never))
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
{-| -}
|
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
module Pages.Internal.Msg exposing
|
|
2
|
-
(
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
--, submitIfValid
|
|
8
|
-
|
|
2
|
+
( Msg(..)
|
|
3
|
+
--, fetcherOnSubmit
|
|
4
|
+
, map
|
|
5
|
+
--, onSubmit
|
|
6
|
+
--, submitIfValid
|
|
9
7
|
)
|
|
10
8
|
|
|
11
9
|
--import Form.FormData exposing (FormData)
|
|
12
10
|
--import FormDecoder
|
|
13
11
|
|
|
14
12
|
import Form exposing (Method)
|
|
15
|
-
import Html exposing (Attribute)
|
|
16
|
-
import Html.Attributes as Attr
|
|
17
|
-
import Json.Decode
|
|
18
13
|
|
|
19
14
|
|
|
20
15
|
{-| -}
|
|
@@ -75,6 +70,7 @@ type Msg userMsg
|
|
|
75
70
|
{-| -}
|
|
76
71
|
map : (a -> b) -> Msg a -> Msg b
|
|
77
72
|
map mapFn msg =
|
|
73
|
+
-- elm-review: known-unoptimized-recursion
|
|
78
74
|
case msg of
|
|
79
75
|
UserMsg userMsg ->
|
|
80
76
|
UserMsg (mapFn userMsg)
|
|
@@ -91,8 +87,7 @@ map mapFn msg =
|
|
|
91
87
|
}
|
|
92
88
|
|
|
93
89
|
FormMsg value ->
|
|
94
|
-
FormMsg
|
|
95
|
-
(Form.mapMsg (map mapFn) value)
|
|
90
|
+
FormMsg (Form.mapMsg (map mapFn) value)
|
|
96
91
|
|
|
97
92
|
NoOp ->
|
|
98
93
|
NoOp
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
module Pages.Internal.Platform.StaticResponses exposing (NextStep(..), empty, nextStep
|
|
1
|
+
module Pages.Internal.Platform.StaticResponses exposing (NextStep(..), empty, nextStep)
|
|
2
2
|
|
|
3
3
|
import BackendTask exposing (BackendTask)
|
|
4
4
|
import BuildError exposing (BuildError)
|
|
5
5
|
import FatalError exposing (FatalError)
|
|
6
|
-
import List.Extra
|
|
7
6
|
import Pages.Internal.FatalError
|
|
8
7
|
import Pages.StaticHttp.Request as HashRequest
|
|
9
8
|
import Pages.StaticHttpRequest as StaticHttpRequest
|
|
@@ -16,13 +15,6 @@ empty a =
|
|
|
16
15
|
BackendTask.succeed a
|
|
17
16
|
|
|
18
17
|
|
|
19
|
-
renderApiRequest :
|
|
20
|
-
BackendTask FatalError response
|
|
21
|
-
-> BackendTask FatalError response
|
|
22
|
-
renderApiRequest request =
|
|
23
|
-
request
|
|
24
|
-
|
|
25
|
-
|
|
26
18
|
type NextStep route value
|
|
27
19
|
= Continue (List HashRequest.Request) (StaticHttpRequest.RawRequest FatalError value)
|
|
28
20
|
| Finish value
|
|
@@ -505,16 +505,16 @@ update config appMsg model =
|
|
|
505
505
|
|> performUserMsg userMsg config
|
|
506
506
|
|
|
507
507
|
Pages.Internal.Msg.Submit fields ->
|
|
508
|
-
let
|
|
509
|
-
payload : { fields : List ( String, String ), method : Form.Method, action : String, id : Maybe String }
|
|
510
|
-
payload =
|
|
511
|
-
{ fields = fields.fields
|
|
512
|
-
, method = fields.method
|
|
513
|
-
, action = fields.action
|
|
514
|
-
, id = Just fields.id
|
|
515
|
-
}
|
|
516
|
-
in
|
|
517
508
|
if fields.valid then
|
|
509
|
+
let
|
|
510
|
+
payload : { fields : List ( String, String ), method : Form.Method, action : String, id : Maybe String }
|
|
511
|
+
payload =
|
|
512
|
+
{ fields = fields.fields
|
|
513
|
+
, method = fields.method
|
|
514
|
+
, action = fields.action
|
|
515
|
+
, id = Just fields.id
|
|
516
|
+
}
|
|
517
|
+
in
|
|
518
518
|
if fields.useFetcher then
|
|
519
519
|
( { model | nextTransitionKey = model.nextTransitionKey + 1 }
|
|
520
520
|
, SubmitFetcher fields.id model.nextTransitionKey payload
|
|
@@ -988,7 +988,7 @@ perform config model effect =
|
|
|
988
988
|
, fromPageMsg = Pages.Internal.Msg.UserMsg >> UserMsg
|
|
989
989
|
, key = key
|
|
990
990
|
, setField =
|
|
991
|
-
\
|
|
991
|
+
\_ ->
|
|
992
992
|
--Task.succeed (SetField info) |> Task.perform identity
|
|
993
993
|
-- TODO
|
|
994
994
|
Cmd.none
|
package/src/Pages/Transition.elm
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
module Pages.Transition exposing
|
|
2
|
-
( Transition(..), LoadingState(..), map
|
|
2
|
+
( Transition(..), LoadingState(..), map, FormData
|
|
3
3
|
, FetcherState, FetcherSubmitStatus(..)
|
|
4
4
|
)
|
|
5
5
|
|
|
6
6
|
{-|
|
|
7
7
|
|
|
8
|
-
@docs Transition, LoadingState, map
|
|
8
|
+
@docs Transition, LoadingState, map, FormData
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
## Fetchers
|
|
@@ -19,6 +19,7 @@ import Path exposing (Path)
|
|
|
19
19
|
import Time
|
|
20
20
|
|
|
21
21
|
|
|
22
|
+
{-| -}
|
|
22
23
|
type alias FormData =
|
|
23
24
|
{ fields : List ( String, String )
|
|
24
25
|
, method : Form.Method
|
package/src/Server/Request.elm
CHANGED
|
@@ -98,7 +98,6 @@ import Internal.Request
|
|
|
98
98
|
import Json.Decode
|
|
99
99
|
import Json.Encode
|
|
100
100
|
import List.NonEmpty
|
|
101
|
-
import Pages.Form
|
|
102
101
|
import QueryParams
|
|
103
102
|
import Time
|
|
104
103
|
import Url
|
|
@@ -949,7 +948,7 @@ formData formParsers =
|
|
|
949
948
|
|> andThen
|
|
950
949
|
(\rawFormData_ ->
|
|
951
950
|
case Form.Handler.run rawFormData_ formParsers of
|
|
952
|
-
(Form.Valid
|
|
951
|
+
(Form.Valid _) as validated ->
|
|
953
952
|
( { persisted =
|
|
954
953
|
{ fields = Just rawFormData_
|
|
955
954
|
, clientSideErrors = Just Dict.empty
|
|
@@ -960,7 +959,7 @@ formData formParsers =
|
|
|
960
959
|
)
|
|
961
960
|
|> succeed
|
|
962
961
|
|
|
963
|
-
(Form.Invalid
|
|
962
|
+
(Form.Invalid _ maybeErrors) as validated ->
|
|
964
963
|
( { persisted =
|
|
965
964
|
{ fields = Just rawFormData_
|
|
966
965
|
, clientSideErrors = Just maybeErrors
|
package/src/Stub.elm
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
module Stub exposing (..)
|
|
1
|
+
module Stub exposing (Id, Model, Task(..), map2, nextId)
|
|
2
2
|
|
|
3
3
|
import Json.Decode as Decode
|
|
4
4
|
import Set exposing (Set)
|
|
@@ -24,22 +24,18 @@ type alias Model =
|
|
|
24
24
|
|
|
25
25
|
type Task error value
|
|
26
26
|
= Pending (Id -> Id) (Decode.Value -> Model -> ( Model, Task error value ))
|
|
27
|
-
| Done (Result error value)
|
|
28
27
|
|
|
29
28
|
|
|
30
29
|
map2 : (value1 -> value2 -> combined) -> Task error value1 -> Task error value2 -> Task error combined
|
|
31
30
|
map2 mapFn task1 task2 =
|
|
32
31
|
case ( task1, task2 ) of
|
|
33
|
-
(
|
|
34
|
-
Debug.todo ""
|
|
35
|
-
|
|
36
|
-
( Pending toId1 resolved1, Pending toId2 resolved2 ) ->
|
|
32
|
+
( Pending toId1 _, Pending toId2 _ ) ->
|
|
37
33
|
Pending
|
|
38
34
|
(\id ->
|
|
39
35
|
max (toId1 id) (toId2 id)
|
|
40
36
|
|> nextId
|
|
41
37
|
)
|
|
42
|
-
(\
|
|
38
|
+
(\_ _ ->
|
|
43
39
|
Debug.todo ""
|
|
44
40
|
)
|
|
45
41
|
|
|
@@ -47,6 +43,7 @@ map2 mapFn task1 task2 =
|
|
|
47
43
|
Debug.todo ""
|
|
48
44
|
|
|
49
45
|
|
|
46
|
+
nextId : Int -> Int
|
|
50
47
|
nextId id =
|
|
51
48
|
id + 1
|
|
52
49
|
|
package/src/Internal/Field.elm
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
module Internal.Field exposing (Field(..), FieldInfo)
|
|
2
|
-
|
|
3
|
-
{-| -}
|
|
4
|
-
|
|
5
|
-
import Json.Encode as Encode
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
type Field error parsed input initial kind constraints
|
|
9
|
-
= Field (FieldInfo error parsed input initial) kind
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
{-| -}
|
|
13
|
-
type alias FieldInfo error parsed input initial =
|
|
14
|
-
{ initialValue : input -> Maybe String
|
|
15
|
-
, decode : Maybe String -> ( Maybe parsed, List error )
|
|
16
|
-
, properties : List ( String, Encode.Value )
|
|
17
|
-
, initialToString : initial -> String
|
|
18
|
-
, compare : String -> initial -> Order
|
|
19
|
-
}
|
package/src/Internal/Input.elm
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
module Internal.Input exposing
|
|
2
|
-
( Hidden(..)
|
|
3
|
-
, Input(..)
|
|
4
|
-
, InputType(..)
|
|
5
|
-
, Options(..)
|
|
6
|
-
, inputTypeToString
|
|
7
|
-
)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
type InputType
|
|
11
|
-
= Text
|
|
12
|
-
| Number
|
|
13
|
-
-- TODO should range have arguments for initial, min, and max?
|
|
14
|
-
| Range
|
|
15
|
-
| Radio
|
|
16
|
-
-- TODO should submit be a special type, or an Input type?
|
|
17
|
-
-- TODO have an option for a submit with a name/value?
|
|
18
|
-
| Date
|
|
19
|
-
| Time
|
|
20
|
-
| Checkbox
|
|
21
|
-
| Tel
|
|
22
|
-
| Search
|
|
23
|
-
| Password
|
|
24
|
-
| Email
|
|
25
|
-
| Url
|
|
26
|
-
| Textarea { rows : Maybe Int, cols : Maybe Int }
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
inputTypeToString : InputType -> String
|
|
30
|
-
inputTypeToString inputType =
|
|
31
|
-
case inputType of
|
|
32
|
-
Text ->
|
|
33
|
-
"text"
|
|
34
|
-
|
|
35
|
-
Textarea _ ->
|
|
36
|
-
"text"
|
|
37
|
-
|
|
38
|
-
Number ->
|
|
39
|
-
"number"
|
|
40
|
-
|
|
41
|
-
Range ->
|
|
42
|
-
"range"
|
|
43
|
-
|
|
44
|
-
Radio ->
|
|
45
|
-
"radio"
|
|
46
|
-
|
|
47
|
-
Date ->
|
|
48
|
-
"date"
|
|
49
|
-
|
|
50
|
-
Time ->
|
|
51
|
-
"time"
|
|
52
|
-
|
|
53
|
-
Checkbox ->
|
|
54
|
-
"checkbox"
|
|
55
|
-
|
|
56
|
-
Tel ->
|
|
57
|
-
"tel"
|
|
58
|
-
|
|
59
|
-
Search ->
|
|
60
|
-
"search"
|
|
61
|
-
|
|
62
|
-
Password ->
|
|
63
|
-
"password"
|
|
64
|
-
|
|
65
|
-
Email ->
|
|
66
|
-
"email"
|
|
67
|
-
|
|
68
|
-
Url ->
|
|
69
|
-
"url"
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
type Input
|
|
73
|
-
= Input InputType
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
type Hidden
|
|
77
|
-
= Hidden
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
type Options a
|
|
81
|
-
= Options (String -> Maybe a) (List String)
|