elm-pages 3.0.0-beta.37 → 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 +87 -10
- package/generator/src/compatibility-key.js +2 -2
- package/generator/src/dev-server.js +6 -0
- 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,16 @@ 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);
|
|
72
|
+
console.warn = function (...messages) {
|
|
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.
|
|
74
|
+
// There is a pending issue to allow having external scripts in Vite, once this issue is fixed we can remove this hack:
|
|
75
|
+
// https://github.com/vitejs/vite/issues/3533
|
|
76
|
+
if (!messages[0]?.startsWith(`<script src="/elm.js">`)) {
|
|
77
|
+
console.info(...messages);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
70
80
|
try {
|
|
71
81
|
await ensureRequiredDirs();
|
|
72
82
|
await ensureRequiredExecutables();
|
|
@@ -114,11 +124,9 @@ export async function run(options) {
|
|
|
114
124
|
withoutExtension
|
|
115
125
|
);
|
|
116
126
|
const assetManifestPath = path.join(process.cwd(), "dist/manifest.json");
|
|
117
|
-
const manifest = (
|
|
118
|
-
await
|
|
119
|
-
|
|
120
|
-
})
|
|
121
|
-
).default;
|
|
127
|
+
const manifest = JSON.parse(
|
|
128
|
+
await fsPromises.readFile(assetManifestPath, { encoding: "utf-8" })
|
|
129
|
+
);
|
|
122
130
|
const indexTemplate = await fsPromises.readFile(
|
|
123
131
|
"dist/elm-stuff/elm-pages/index.html",
|
|
124
132
|
"utf-8"
|
|
@@ -176,13 +184,84 @@ export async function run(options) {
|
|
|
176
184
|
console.error("Failed to start custom-backend-task watcher", error);
|
|
177
185
|
}
|
|
178
186
|
});
|
|
179
|
-
// TODO extract common code for compiling ports file?
|
|
180
187
|
|
|
181
188
|
global.XMLHttpRequest = {};
|
|
182
189
|
const compileCli = compileCliApp(options);
|
|
183
190
|
try {
|
|
184
191
|
await compileCli;
|
|
185
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
|
+
});
|
|
186
265
|
} catch (cliError) {
|
|
187
266
|
// TODO make sure not to print duplicate error output if cleaner review output is printed
|
|
188
267
|
console.error(cliError);
|
|
@@ -622,19 +701,17 @@ function _HtmlAsJson_toJson(html) {
|
|
|
622
701
|
async function runAdapter(adaptFn, processedIndexTemplate) {
|
|
623
702
|
try {
|
|
624
703
|
await adaptFn({
|
|
625
|
-
renderFunctionFilePath: "
|
|
704
|
+
renderFunctionFilePath: "./.elm-pages/compiled/render.mjs",
|
|
626
705
|
routePatterns: JSON.parse(
|
|
627
706
|
await fsPromises.readFile("./dist/route-patterns.json", "utf-8")
|
|
628
707
|
),
|
|
629
708
|
apiRoutePatterns: JSON.parse(
|
|
630
709
|
await fsPromises.readFile("./dist/api-patterns.json", "utf-8")
|
|
631
710
|
),
|
|
632
|
-
portsFilePath: "./.elm-pages/compiled-ports/custom-backend-task.mjs",
|
|
633
|
-
htmlTemplate: processedIndexTemplate,
|
|
634
711
|
});
|
|
635
712
|
console.log("Success - Adapter script complete");
|
|
636
713
|
} catch (error) {
|
|
637
|
-
console.
|
|
714
|
+
console.trace("ERROR - Adapter script failed", error);
|
|
638
715
|
try {
|
|
639
716
|
console.error(JSON.stringify(error));
|
|
640
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";
|
|
@@ -36,6 +36,12 @@ const __dirname = path.dirname(__filename);
|
|
|
36
36
|
* @param {{ port: string; base: string; https: boolean; debug: boolean; }} options
|
|
37
37
|
*/
|
|
38
38
|
export async function start(options) {
|
|
39
|
+
console.error = function (...messages) {
|
|
40
|
+
if (!messages[0]?.startsWith("Failed to load url")) {
|
|
41
|
+
console.info(...messages);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
39
45
|
let threadReadyQueue = [];
|
|
40
46
|
let pool = [];
|
|
41
47
|
|
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)
|