elm-pages 3.0.0-beta.3 → 3.0.0-beta.30
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 +10 -1
- package/codegen/{elm-pages-codegen.js → elm-pages-codegen.cjs} +2864 -2589
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmi +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmo +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateDataTest.elmo +0 -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/elm-stuff/0.19.1/i.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm.json +1 -1
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1327 -122
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +15295 -13271
- 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 +4 -4
- package/generator/dead-code-review/elm.json +8 -6
- package/generator/dead-code-review/src/Pages/Review/DeadCodeEliminateData.elm +59 -10
- package/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm +52 -36
- 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/elm-stuff/0.19.1/i.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm.json +1 -1
- package/generator/review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1327 -122
- package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +14621 -12637
- 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 +4 -4
- package/generator/review/elm.json +8 -8
- package/generator/src/RouteBuilder.elm +113 -107
- package/generator/src/SharedTemplate.elm +3 -2
- package/generator/src/SiteConfig.elm +3 -2
- package/generator/src/basepath-middleware.js +3 -3
- package/generator/src/build.js +123 -87
- package/generator/src/cli.js +256 -77
- package/generator/src/codegen.js +29 -27
- package/generator/src/compatibility-key.js +3 -0
- package/generator/src/compile-elm.js +25 -25
- package/generator/src/config.js +39 -0
- package/generator/src/copy-dir.js +2 -2
- package/generator/src/dev-server.js +150 -133
- package/generator/src/dir-helpers.js +9 -26
- package/generator/src/elm-codegen.js +5 -4
- package/generator/src/elm-file-constants.js +2 -3
- package/generator/src/error-formatter.js +12 -11
- package/generator/src/file-helpers.js +3 -4
- package/generator/src/generate-template-module-connector.js +23 -22
- package/generator/src/init.js +9 -8
- package/generator/src/pre-render-html.js +39 -28
- package/generator/src/render-test.js +109 -0
- package/generator/src/render-worker.js +25 -28
- package/generator/src/render.js +322 -142
- package/generator/src/request-cache.js +252 -163
- package/generator/src/rewrite-client-elm-json.js +5 -5
- package/generator/src/rewrite-elm-json.js +7 -7
- package/generator/src/route-codegen-helpers.js +16 -31
- package/generator/src/seo-renderer.js +12 -7
- package/generator/src/vite-utils.js +77 -0
- package/generator/static-code/hmr.js +79 -13
- package/generator/template/app/Api.elm +6 -5
- package/generator/template/app/Effect.elm +123 -0
- package/generator/template/app/ErrorPage.elm +37 -6
- package/generator/template/app/Route/Index.elm +17 -10
- package/generator/template/app/Shared.elm +24 -47
- package/generator/template/app/Site.elm +19 -6
- package/generator/template/app/View.elm +1 -8
- package/generator/template/elm-tooling.json +0 -3
- package/generator/template/elm.json +34 -25
- package/generator/template/package.json +10 -4
- package/package.json +23 -22
- package/src/ApiRoute.elm +199 -61
- package/src/BackendTask/Custom.elm +325 -0
- package/src/BackendTask/Env.elm +90 -0
- package/src/{DataSource → BackendTask}/File.elm +128 -43
- package/src/{DataSource → BackendTask}/Glob.elm +136 -125
- package/src/BackendTask/Http.elm +673 -0
- package/src/{DataSource → BackendTask}/Internal/Glob.elm +1 -1
- package/src/BackendTask/Internal/Request.elm +28 -0
- package/src/BackendTask/Random.elm +79 -0
- package/src/BackendTask/Time.elm +47 -0
- package/src/BackendTask.elm +537 -0
- package/src/FatalError.elm +89 -0
- package/src/Form/Field.elm +21 -9
- package/src/Form/FieldView.elm +94 -14
- package/src/Form.elm +275 -400
- package/src/Head.elm +237 -7
- package/src/HtmlPrinter.elm +7 -3
- package/src/Internal/ApiRoute.elm +7 -5
- package/src/PageServerResponse.elm +6 -1
- package/src/Pages/FormState.elm +6 -5
- package/src/Pages/GeneratorProgramConfig.elm +15 -0
- package/src/Pages/Internal/FatalError.elm +5 -0
- package/src/Pages/Internal/Form.elm +21 -1
- package/src/Pages/{Msg.elm → Internal/Msg.elm} +26 -16
- package/src/Pages/Internal/Platform/Cli.elm +507 -763
- package/src/Pages/Internal/Platform/CompatibilityKey.elm +6 -0
- package/src/Pages/Internal/Platform/Effect.elm +1 -2
- package/src/Pages/Internal/Platform/GeneratorApplication.elm +373 -0
- package/src/Pages/Internal/Platform/StaticResponses.elm +73 -270
- package/src/Pages/Internal/Platform/ToJsPayload.elm +4 -7
- package/src/Pages/Internal/Platform.elm +215 -102
- package/src/Pages/Internal/Script.elm +17 -0
- package/src/Pages/Internal/StaticHttpBody.elm +35 -1
- package/src/Pages/Manifest.elm +29 -4
- package/src/Pages/PageUrl.elm +23 -9
- package/src/Pages/ProgramConfig.elm +14 -10
- package/src/Pages/Script.elm +109 -0
- package/src/Pages/SiteConfig.elm +3 -2
- package/src/Pages/StaticHttp/Request.elm +2 -2
- package/src/Pages/StaticHttpRequest.elm +23 -98
- package/src/PagesMsg.elm +92 -0
- package/src/Path.elm +16 -19
- package/src/QueryParams.elm +21 -172
- package/src/RequestsAndPending.elm +8 -19
- package/src/Result/Extra.elm +26 -0
- package/src/Scaffold/Form.elm +484 -0
- package/src/Scaffold/Route.elm +1376 -0
- package/src/Server/Request.elm +43 -37
- package/src/Server/Session.elm +34 -34
- package/src/Server/SetCookie.elm +1 -1
- package/src/Test/Html/Internal/ElmHtml/ToString.elm +8 -9
- package/src/DataSource/Env.elm +0 -38
- package/src/DataSource/Http.elm +0 -446
- package/src/DataSource/Internal/Request.elm +0 -20
- package/src/DataSource/Port.elm +0 -90
- package/src/DataSource.elm +0 -538
- package/src/Pages/Generate.elm +0 -800
|
@@ -1,179 +1,245 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import * as path from "path";
|
|
2
|
+
import * as fsPromises from "fs/promises";
|
|
3
|
+
import * as kleur from "kleur/colors";
|
|
4
|
+
import { default as makeFetchHappenOriginal } from "make-fetch-happen";
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
* they're unique enough and can be expressed in a case-insensitive way so it works on Windows filesystems.
|
|
10
|
-
* And they are 40 hex characters, so the length won't be too long no matter what the request payload.
|
|
11
|
-
* @param {Object} request
|
|
12
|
-
*/
|
|
13
|
-
function requestToString(request) {
|
|
14
|
-
return objectHash(request);
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* @param {Object} request
|
|
18
|
-
*/
|
|
19
|
-
function fullPath(portsHash, request, hasFsAccess) {
|
|
20
|
-
const requestWithPortHash =
|
|
21
|
-
request.url === "elm-pages-internal://port"
|
|
22
|
-
? { portsHash, ...request }
|
|
23
|
-
: request;
|
|
24
|
-
if (hasFsAccess) {
|
|
25
|
-
return path.join(
|
|
26
|
-
process.cwd(),
|
|
27
|
-
".elm-pages",
|
|
28
|
-
"http-response-cache",
|
|
29
|
-
requestToString(requestWithPortHash)
|
|
30
|
-
);
|
|
31
|
-
} else {
|
|
32
|
-
return path.join("/", requestToString(requestWithPortHash));
|
|
33
|
-
}
|
|
34
|
-
}
|
|
6
|
+
const defaultHttpCachePath = "./.elm-pages/http-cache";
|
|
7
|
+
|
|
8
|
+
/** @typedef {{kind: 'cache-response-path', value: string} | {kind: 'response-json', value: JSON}} Response */
|
|
35
9
|
|
|
36
10
|
/**
|
|
37
11
|
* @param {string} mode
|
|
38
12
|
* @param {{url: string;headers: {[x: string]: string;};method: string;body: Body;}} rawRequest
|
|
39
|
-
* @
|
|
40
|
-
* @param {string} portsFile
|
|
13
|
+
* @param {Record<string, unknown>} portsFile
|
|
41
14
|
* @param {boolean} hasFsAccess
|
|
15
|
+
* @returns {Promise<Response>}
|
|
42
16
|
*/
|
|
43
|
-
function lookupOrPerform(
|
|
44
|
-
|
|
17
|
+
export function lookupOrPerform(
|
|
18
|
+
portsFile,
|
|
19
|
+
mode,
|
|
20
|
+
rawRequest,
|
|
21
|
+
hasFsAccess,
|
|
22
|
+
useCache
|
|
23
|
+
) {
|
|
24
|
+
const makeFetchHappen = makeFetchHappenOriginal.defaults({
|
|
25
|
+
cache: mode === "build" ? "no-cache" : "default",
|
|
26
|
+
});
|
|
45
27
|
return new Promise(async (resolve, reject) => {
|
|
46
28
|
const request = toRequest(rawRequest);
|
|
47
|
-
const portsHash = (portsFile && portsFile.match(/-([^-]+)\.js$/)[1]) || "";
|
|
48
|
-
const responsePath = fullPath(portsHash, request, hasFsAccess);
|
|
49
29
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
let portDataSource = {};
|
|
56
|
-
let portDataSourceImportError = null;
|
|
57
|
-
try {
|
|
58
|
-
if (portsFile === undefined) {
|
|
59
|
-
throw "missing";
|
|
60
|
-
}
|
|
61
|
-
const portDataSourcePath = path.resolve(portsFile);
|
|
62
|
-
// On Windows, we need cannot use paths directly and instead must use a file:// URL.
|
|
63
|
-
// portDataSource = await require(url.pathToFileURL(portDataSourcePath).href);
|
|
64
|
-
portDataSource = require(portDataSourcePath);
|
|
65
|
-
} catch (e) {
|
|
66
|
-
portDataSourceImportError = e;
|
|
30
|
+
let portBackendTask = portsFile;
|
|
31
|
+
let portBackendTaskImportError = null;
|
|
32
|
+
try {
|
|
33
|
+
if (portsFile === undefined) {
|
|
34
|
+
throw "missing";
|
|
67
35
|
}
|
|
36
|
+
} catch (e) {
|
|
37
|
+
portBackendTaskImportError = e;
|
|
38
|
+
}
|
|
68
39
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
throw `DataSource.Port.send "${portName}" was called, but I couldn't import the port definitions file, because of this exception: \`${portDataSourceImportError}\` Are there syntax errors or expections thrown during import?`;
|
|
80
|
-
}
|
|
81
|
-
} else if (typeof portDataSource[portName] !== "function") {
|
|
82
|
-
throw `DataSource.Port.send "${portName}" was called, but it is not a function. Be sure to export a function with that name from port-data-source.js`;
|
|
83
|
-
}
|
|
84
|
-
await fs.promises.writeFile(
|
|
85
|
-
responsePath,
|
|
86
|
-
JSON.stringify(jsonResponse(await portDataSource[portName](input)))
|
|
87
|
-
);
|
|
88
|
-
resolve(responsePath);
|
|
89
|
-
} catch (error) {
|
|
90
|
-
console.trace(error);
|
|
91
|
-
reject({
|
|
92
|
-
title: "DataSource.Port Error",
|
|
93
|
-
message: error.toString(),
|
|
40
|
+
if (request.url === "elm-pages-internal://port") {
|
|
41
|
+
try {
|
|
42
|
+
const { input, portName } = rawRequest.body.args[0];
|
|
43
|
+
|
|
44
|
+
if (portBackendTask === null) {
|
|
45
|
+
resolve({
|
|
46
|
+
kind: "response-json",
|
|
47
|
+
value: jsonResponse({
|
|
48
|
+
"elm-pages-internal-error": "MissingCustomBackendTaskFile",
|
|
49
|
+
}),
|
|
94
50
|
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
headers: {
|
|
103
|
-
"User-Agent": "request",
|
|
104
|
-
...request.headers,
|
|
105
|
-
},
|
|
51
|
+
} else if (portBackendTask && portBackendTask.__internalElmPagesError) {
|
|
52
|
+
resolve({
|
|
53
|
+
kind: "response-json",
|
|
54
|
+
value: jsonResponse({
|
|
55
|
+
"elm-pages-internal-error": "ErrorInCustomBackendTaskFile",
|
|
56
|
+
error: portBackendTask.__internalElmPagesError,
|
|
57
|
+
}),
|
|
106
58
|
});
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const arrayBuffer = await response.arrayBuffer();
|
|
123
|
-
body = Buffer.from(arrayBuffer).toString("base64");
|
|
124
|
-
} else if (expectString === "ExpectWhatever") {
|
|
125
|
-
bodyKind = "whatever";
|
|
126
|
-
body = null;
|
|
127
|
-
} else if (
|
|
128
|
-
expectString === "ExpectResponse" ||
|
|
129
|
-
expectString === "ExpectString"
|
|
130
|
-
) {
|
|
131
|
-
bodyKind = "string";
|
|
132
|
-
body = await response.text();
|
|
133
|
-
} else {
|
|
134
|
-
throw `Unexpected expectString ${expectString}`;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
await fs.promises.writeFile(
|
|
138
|
-
responsePath,
|
|
139
|
-
JSON.stringify({
|
|
140
|
-
headers: Object.fromEntries(response.headers.entries()),
|
|
141
|
-
statusCode: response.status,
|
|
142
|
-
body: body,
|
|
143
|
-
bodyKind,
|
|
144
|
-
url: response.url,
|
|
145
|
-
statusText: response.statusText,
|
|
146
|
-
})
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
resolve(responsePath);
|
|
59
|
+
} else if (portBackendTask && !portBackendTask[portName]) {
|
|
60
|
+
if (portBackendTaskImportError === null) {
|
|
61
|
+
resolve({
|
|
62
|
+
kind: "response-json",
|
|
63
|
+
value: jsonResponse({
|
|
64
|
+
"elm-pages-internal-error": "CustomBackendTaskNotDefined",
|
|
65
|
+
}),
|
|
66
|
+
});
|
|
67
|
+
} else if (portBackendTaskImportError === "missing") {
|
|
68
|
+
resolve({
|
|
69
|
+
kind: "response-json",
|
|
70
|
+
value: jsonResponse({
|
|
71
|
+
"elm-pages-internal-error": "MissingCustomBackendTaskFile",
|
|
72
|
+
}),
|
|
73
|
+
});
|
|
150
74
|
} else {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
75
|
+
resolve({
|
|
76
|
+
kind: "response-json",
|
|
77
|
+
value: jsonResponse({
|
|
78
|
+
"elm-pages-internal-error": "ErrorInCustomBackendTaskFile",
|
|
79
|
+
error:
|
|
80
|
+
(portBackendTaskImportError &&
|
|
81
|
+
portBackendTaskImportError.stack) ||
|
|
82
|
+
"",
|
|
83
|
+
}),
|
|
160
84
|
});
|
|
161
85
|
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
`,
|
|
86
|
+
} else if (typeof portBackendTask[portName] !== "function") {
|
|
87
|
+
resolve({
|
|
88
|
+
kind: "response-json",
|
|
89
|
+
value: jsonResponse({
|
|
90
|
+
"elm-pages-internal-error": "ExportIsNotFunction",
|
|
91
|
+
error: typeof portBackendTask[portName],
|
|
92
|
+
}),
|
|
170
93
|
});
|
|
94
|
+
} else {
|
|
95
|
+
console.time(`BackendTask.Custom.run "${portName}"`);
|
|
96
|
+
try {
|
|
97
|
+
resolve({
|
|
98
|
+
kind: "response-json",
|
|
99
|
+
value: jsonResponse(
|
|
100
|
+
toElmJson(await portBackendTask[portName](input))
|
|
101
|
+
),
|
|
102
|
+
});
|
|
103
|
+
} catch (portCallError) {
|
|
104
|
+
if (portCallError instanceof Error) {
|
|
105
|
+
resolve({
|
|
106
|
+
kind: "response-json",
|
|
107
|
+
value: jsonResponse({
|
|
108
|
+
"elm-pages-internal-error": "NonJsonException",
|
|
109
|
+
error: portCallError.message,
|
|
110
|
+
stack: portCallError.stack || null,
|
|
111
|
+
}),
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
resolve({
|
|
116
|
+
kind: "response-json",
|
|
117
|
+
value: jsonResponse({
|
|
118
|
+
"elm-pages-internal-error": "CustomBackendTaskException",
|
|
119
|
+
error: JSON.parse(JSON.stringify(portCallError, null, 0)),
|
|
120
|
+
}),
|
|
121
|
+
});
|
|
122
|
+
} catch (jsonDecodeError) {
|
|
123
|
+
resolve({
|
|
124
|
+
kind: "response-json",
|
|
125
|
+
value: jsonResponse({
|
|
126
|
+
"elm-pages-internal-error": "NonJsonException",
|
|
127
|
+
error: portCallError.toString(),
|
|
128
|
+
}),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
console.timeEnd(`BackendTask.Custom.run "${portName}"`);
|
|
171
133
|
}
|
|
134
|
+
} catch (error) {
|
|
135
|
+
console.trace(error);
|
|
136
|
+
reject({
|
|
137
|
+
title: "BackendTask.Custom Error",
|
|
138
|
+
message: error.toString(),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
try {
|
|
143
|
+
console.time(`fetch ${request.url}`);
|
|
144
|
+
const response = await safeFetch(makeFetchHappen, request.url, {
|
|
145
|
+
method: request.method,
|
|
146
|
+
body: request.body,
|
|
147
|
+
headers: {
|
|
148
|
+
"User-Agent": "request",
|
|
149
|
+
...request.headers,
|
|
150
|
+
},
|
|
151
|
+
...rawRequest.cacheOptions,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
console.timeEnd(`fetch ${request.url}`);
|
|
155
|
+
const expectString = request.headers["elm-pages-internal"];
|
|
156
|
+
|
|
157
|
+
let body;
|
|
158
|
+
let bodyKind;
|
|
159
|
+
if (expectString === "ExpectJson") {
|
|
160
|
+
try {
|
|
161
|
+
body = await response.buffer();
|
|
162
|
+
body = JSON.parse(body.toString("utf-8"));
|
|
163
|
+
bodyKind = "json";
|
|
164
|
+
} catch (error) {
|
|
165
|
+
body = body.toString("utf8");
|
|
166
|
+
bodyKind = "string";
|
|
167
|
+
}
|
|
168
|
+
} else if (
|
|
169
|
+
expectString === "ExpectBytes" ||
|
|
170
|
+
expectString === "ExpectBytesResponse"
|
|
171
|
+
) {
|
|
172
|
+
body = await response.buffer();
|
|
173
|
+
try {
|
|
174
|
+
body = body.toString("base64");
|
|
175
|
+
bodyKind = "bytes";
|
|
176
|
+
} catch (e) {
|
|
177
|
+
body = body.toString("utf8");
|
|
178
|
+
bodyKind = "string";
|
|
179
|
+
}
|
|
180
|
+
} else if (expectString === "ExpectWhatever") {
|
|
181
|
+
bodyKind = "whatever";
|
|
182
|
+
body = null;
|
|
183
|
+
} else if (
|
|
184
|
+
expectString === "ExpectResponse" ||
|
|
185
|
+
expectString === "ExpectString"
|
|
186
|
+
) {
|
|
187
|
+
bodyKind = "string";
|
|
188
|
+
body = await response.text();
|
|
189
|
+
} else {
|
|
190
|
+
throw `Unexpected expectString ${expectString}`;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
resolve({
|
|
194
|
+
kind: "response-json",
|
|
195
|
+
value: {
|
|
196
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
197
|
+
statusCode: response.status,
|
|
198
|
+
body,
|
|
199
|
+
bodyKind,
|
|
200
|
+
url: response.url,
|
|
201
|
+
statusText: response.statusText,
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
} catch (error) {
|
|
205
|
+
console.trace("@@@ request-cache2 HTTP error", error);
|
|
206
|
+
reject({
|
|
207
|
+
title: "BackendTask.Http Error",
|
|
208
|
+
message: `${kleur.yellow().underline(request.url)} ${error.toString()}
|
|
209
|
+
`,
|
|
210
|
+
});
|
|
172
211
|
}
|
|
173
212
|
}
|
|
174
213
|
});
|
|
175
214
|
}
|
|
176
215
|
|
|
216
|
+
/**
|
|
217
|
+
* @param {unknown} obj
|
|
218
|
+
* @returns {JSON}
|
|
219
|
+
*/
|
|
220
|
+
function toElmJson(obj) {
|
|
221
|
+
if (Array.isArray(obj)) {
|
|
222
|
+
return obj.map(toElmJson);
|
|
223
|
+
} else if (typeof obj === "object") {
|
|
224
|
+
for (let key in obj) {
|
|
225
|
+
const value = obj[key];
|
|
226
|
+
if (typeof value === "undefined") {
|
|
227
|
+
obj[key] = null;
|
|
228
|
+
} else if (value instanceof Date) {
|
|
229
|
+
obj[key] = {
|
|
230
|
+
"__elm-pages-normalized__": {
|
|
231
|
+
kind: "Date",
|
|
232
|
+
value: Math.floor(value.getTime()),
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
// } else if (value instanceof Object) {
|
|
236
|
+
// toElmJson(obj);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return obj;
|
|
241
|
+
}
|
|
242
|
+
|
|
177
243
|
/**
|
|
178
244
|
* @param {{url: string; headers: {[x: string]: string}; method: string; body: Body } } elmRequest
|
|
179
245
|
*/
|
|
@@ -188,15 +254,6 @@ function toRequest(elmRequest) {
|
|
|
188
254
|
body: toBody(elmRequest.body),
|
|
189
255
|
};
|
|
190
256
|
}
|
|
191
|
-
/**
|
|
192
|
-
* @param {string} file
|
|
193
|
-
*/
|
|
194
|
-
function checkFileExists(fs, file) {
|
|
195
|
-
return fs.promises
|
|
196
|
-
.access(file, fs.constants.F_OK)
|
|
197
|
-
.then(() => true)
|
|
198
|
-
.catch(() => false);
|
|
199
|
-
}
|
|
200
257
|
/**
|
|
201
258
|
* @param {Body} body
|
|
202
259
|
*/
|
|
@@ -208,6 +265,9 @@ function toBody(body) {
|
|
|
208
265
|
case "StringBody": {
|
|
209
266
|
return body.args[1];
|
|
210
267
|
}
|
|
268
|
+
case "BytesBody": {
|
|
269
|
+
return Buffer.from(body.args[1], "base64");
|
|
270
|
+
}
|
|
211
271
|
case "JsonBody": {
|
|
212
272
|
return JSON.stringify(body.args[0]);
|
|
213
273
|
}
|
|
@@ -226,13 +286,16 @@ function toContentType(body) {
|
|
|
226
286
|
case "StringBody": {
|
|
227
287
|
return { "Content-Type": body.args[0] };
|
|
228
288
|
}
|
|
289
|
+
case "BytesBody": {
|
|
290
|
+
return { "Content-Type": body.args[0] };
|
|
291
|
+
}
|
|
229
292
|
case "JsonBody": {
|
|
230
293
|
return { "Content-Type": "application/json" };
|
|
231
294
|
}
|
|
232
295
|
}
|
|
233
296
|
}
|
|
234
297
|
|
|
235
|
-
/** @typedef { { tag: 'EmptyBody'} | { tag: 'StringBody'; args: [string, string] } | {tag: 'JsonBody'; args: [ Object ] } } Body */
|
|
298
|
+
/** @typedef { { tag: 'EmptyBody'} |{ tag: 'BytesBody'; args: [string, string] } | { tag: 'StringBody'; args: [string, string] } | {tag: 'JsonBody'; args: [ Object ] } } Body */
|
|
236
299
|
function requireUncached(mode, filePath) {
|
|
237
300
|
if (mode === "dev-server") {
|
|
238
301
|
// for the build command, we can skip clearing the cache because it won't change while the build is running
|
|
@@ -249,4 +312,30 @@ function jsonResponse(json) {
|
|
|
249
312
|
return { bodyKind: "json", body: json };
|
|
250
313
|
}
|
|
251
314
|
|
|
252
|
-
|
|
315
|
+
async function safeFetch(makeFetchHappen, url, options) {
|
|
316
|
+
const { cachePath, ...optionsWithoutCachePath } = options;
|
|
317
|
+
const cachePathWithDefault = cachePath || defaultHttpCachePath;
|
|
318
|
+
if (await canAccess(cachePathWithDefault)) {
|
|
319
|
+
return await makeFetchHappen(url, {
|
|
320
|
+
cachePath: cachePathWithDefault,
|
|
321
|
+
...options,
|
|
322
|
+
});
|
|
323
|
+
} else {
|
|
324
|
+
return await makeFetchHappen(url, {
|
|
325
|
+
cache: "no-store",
|
|
326
|
+
...optionsWithoutCachePath,
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
async function canAccess(filePath) {
|
|
332
|
+
try {
|
|
333
|
+
await fsPromises.access(
|
|
334
|
+
filePath,
|
|
335
|
+
fsPromises.constants.R_OK | fsPromises.constants.W_OK
|
|
336
|
+
);
|
|
337
|
+
return true;
|
|
338
|
+
} catch {
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
export async function rewriteClientElmJson() {
|
|
4
4
|
var elmJson = JSON.parse(
|
|
5
5
|
(await fs.promises.readFile("./elm.json")).toString()
|
|
6
6
|
);
|
|
@@ -9,11 +9,11 @@ module.exports = async function () {
|
|
|
9
9
|
|
|
10
10
|
await writeFileIfChanged(
|
|
11
11
|
"./elm-stuff/elm-pages/client/elm.json",
|
|
12
|
-
JSON.stringify(
|
|
12
|
+
JSON.stringify(rewriteClientElmJsonHelp(elmJson))
|
|
13
13
|
);
|
|
14
|
-
}
|
|
14
|
+
}
|
|
15
15
|
|
|
16
|
-
function
|
|
16
|
+
function rewriteClientElmJsonHelp(elmJson) {
|
|
17
17
|
// The internal generated file will be at:
|
|
18
18
|
// ./elm-stuff/elm-pages/
|
|
19
19
|
// So, we need to take the existing elmJson and
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
export async function rewriteElmJson(sourceElmJsonPath, targetElmJsonPath) {
|
|
4
4
|
var elmJson = JSON.parse(
|
|
5
|
-
(await fs.promises.readFile(
|
|
5
|
+
(await fs.promises.readFile(sourceElmJsonPath)).toString()
|
|
6
6
|
);
|
|
7
7
|
|
|
8
8
|
// write new elm.json
|
|
9
9
|
|
|
10
10
|
await writeFileIfChanged(
|
|
11
|
-
|
|
12
|
-
JSON.stringify(
|
|
11
|
+
targetElmJsonPath,
|
|
12
|
+
JSON.stringify(rewriteElmJsonHelp(elmJson))
|
|
13
13
|
);
|
|
14
|
-
}
|
|
14
|
+
}
|
|
15
15
|
|
|
16
|
-
function
|
|
16
|
+
function rewriteElmJsonHelp(elmJson) {
|
|
17
17
|
// The internal generated file will be at:
|
|
18
18
|
// ./elm-stuff/elm-pages/
|
|
19
19
|
// So, we need to take the existing elmJson and
|
|
@@ -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
|
-
};
|