elm-pages 3.0.0-beta.4 → 3.0.0-beta.41
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/adapter/netlify.js +207 -0
- package/codegen/{elm-pages-codegen.js → elm-pages-codegen.cjs} +2828 -2933
- 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 +1447 -342
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +17004 -13817
- 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 +9 -7
- 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/Pages-Internal-RoutePattern.elmi +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Internal-RoutePattern.elmo +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmi +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmo +0 -0
- 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 +1447 -342
- package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +25025 -21739
- 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 +10 -10
- package/generator/src/RouteBuilder.elm +121 -114
- package/generator/src/SharedTemplate.elm +8 -7
- package/generator/src/SiteConfig.elm +3 -2
- package/generator/src/basepath-middleware.js +3 -3
- package/generator/src/build.js +209 -92
- package/generator/src/cli.js +292 -88
- package/generator/src/codegen.js +29 -27
- package/generator/src/compatibility-key.js +3 -0
- package/generator/src/compile-elm.js +43 -26
- package/generator/src/config.js +39 -0
- package/generator/src/copy-dir.js +2 -2
- package/generator/src/dev-server.js +176 -138
- 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 -23
- 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 +321 -142
- package/generator/src/request-cache.js +265 -162
- package/generator/src/resolve-elm-module.js +64 -0
- package/generator/src/rewrite-client-elm-json.js +6 -5
- package/generator/src/rewrite-elm-json-help.js +56 -0
- package/generator/src/rewrite-elm-json.js +17 -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/elm-pages.js +10 -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 +32 -24
- package/generator/template/package.json +10 -4
- package/package.json +30 -27
- 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 +171 -56
- package/src/{DataSource → BackendTask}/Glob.elm +136 -125
- package/src/BackendTask/Http.elm +679 -0
- package/src/{DataSource → BackendTask}/Internal/Glob.elm +1 -1
- package/src/BackendTask/Internal/Request.elm +69 -0
- package/src/BackendTask/Random.elm +79 -0
- package/src/BackendTask/Time.elm +47 -0
- package/src/BackendTask.elm +531 -0
- package/src/FatalError.elm +90 -0
- package/src/Head/Seo.elm +4 -4
- 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/ConcurrentSubmission.elm +127 -0
- package/src/Pages/Form.elm +340 -0
- package/src/Pages/FormData.elm +18 -0
- package/src/Pages/GeneratorProgramConfig.elm +15 -0
- package/src/Pages/Internal/FatalError.elm +5 -0
- package/src/Pages/Internal/Msg.elm +93 -0
- package/src/Pages/Internal/NotFoundReason.elm +4 -4
- package/src/Pages/Internal/Platform/Cli.elm +617 -768
- 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 +379 -0
- package/src/Pages/Internal/Platform/StaticResponses.elm +65 -276
- package/src/Pages/Internal/Platform/ToJsPayload.elm +6 -9
- package/src/Pages/Internal/Platform.elm +359 -225
- package/src/Pages/Internal/ResponseSketch.elm +2 -2
- package/src/Pages/Internal/Script.elm +17 -0
- package/src/Pages/Internal/StaticHttpBody.elm +35 -1
- package/src/Pages/Manifest.elm +52 -11
- package/src/Pages/Navigation.elm +87 -0
- package/src/Pages/PageUrl.elm +26 -12
- package/src/Pages/ProgramConfig.elm +35 -23
- package/src/Pages/Script.elm +166 -0
- package/src/Pages/SiteConfig.elm +3 -2
- package/src/Pages/StaticHttp/Request.elm +2 -2
- package/src/Pages/StaticHttpRequest.elm +23 -99
- package/src/Pages/Url.elm +3 -3
- package/src/PagesMsg.elm +88 -0
- package/src/QueryParams.elm +21 -172
- package/src/RenderRequest.elm +7 -7
- package/src/RequestsAndPending.elm +37 -20
- package/src/Result/Extra.elm +26 -0
- package/src/Scaffold/Form.elm +569 -0
- package/src/Scaffold/Route.elm +1411 -0
- package/src/Server/Request.elm +74 -72
- package/src/Server/Session.elm +62 -42
- package/src/Server/SetCookie.elm +80 -32
- package/src/Stub.elm +53 -0
- package/src/Test/Html/Internal/ElmHtml/ToString.elm +8 -9
- package/src/{Path.elm → UrlPath.elm} +33 -36
- 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/Form/Field.elm +0 -717
- package/src/Form/FieldStatus.elm +0 -36
- package/src/Form/FieldView.elm +0 -417
- package/src/Form/FormData.elm +0 -22
- package/src/Form/Validation.elm +0 -391
- package/src/Form/Value.elm +0 -118
- package/src/Form.elm +0 -1683
- package/src/FormDecoder.elm +0 -102
- package/src/Pages/FormState.elm +0 -256
- package/src/Pages/Generate.elm +0 -800
- package/src/Pages/Internal/Form.elm +0 -17
- package/src/Pages/Msg.elm +0 -79
- package/src/Pages/Transition.elm +0 -70
|
@@ -1,172 +1,225 @@
|
|
|
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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
+
}),
|
|
50
|
+
});
|
|
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
|
+
}),
|
|
58
|
+
});
|
|
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
|
+
});
|
|
74
|
+
} else {
|
|
75
|
+
resolve({
|
|
76
|
+
kind: "response-json",
|
|
77
|
+
value: jsonResponse({
|
|
78
|
+
"elm-pages-internal-error": "ErrorInCustomBackendTaskFile",
|
|
79
|
+
error:
|
|
80
|
+
(portBackendTaskImportError &&
|
|
81
|
+
portBackendTaskImportError.stack) ||
|
|
82
|
+
"",
|
|
83
|
+
}),
|
|
84
|
+
});
|
|
83
85
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
reject({
|
|
92
|
-
title: "DataSource.Port Error",
|
|
93
|
-
message: error.toString(),
|
|
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
|
+
}),
|
|
94
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}"`);
|
|
95
133
|
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
+
});
|
|
107
153
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if (response.ok || expectString === "ExpectResponse") {
|
|
112
|
-
let body;
|
|
113
|
-
let bodyKind;
|
|
114
|
-
if (expectString === "ExpectJson") {
|
|
115
|
-
body = await response.json();
|
|
116
|
-
bodyKind = "json";
|
|
117
|
-
} else if (
|
|
118
|
-
expectString === "ExpectBytes" ||
|
|
119
|
-
expectString === "ExpectBytesResponse"
|
|
120
|
-
) {
|
|
121
|
-
bodyKind = "bytes";
|
|
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
|
-
}
|
|
154
|
+
console.timeEnd(`fetch ${request.url}`);
|
|
155
|
+
const expectString = request.headers["elm-pages-internal"];
|
|
136
156
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
`,
|
|
160
|
-
});
|
|
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";
|
|
161
179
|
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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
|
+
if (error.code === "ECONNREFUSED") {
|
|
206
|
+
resolve({
|
|
207
|
+
kind: "response-json",
|
|
208
|
+
value: { "elm-pages-internal-error": "NetworkError" },
|
|
209
|
+
});
|
|
210
|
+
} else if (
|
|
211
|
+
error.code === "ETIMEDOUT" ||
|
|
212
|
+
error.code === "ERR_SOCKET_TIMEOUT"
|
|
213
|
+
) {
|
|
214
|
+
resolve({
|
|
215
|
+
kind: "response-json",
|
|
216
|
+
value: { "elm-pages-internal-error": "Timeout" },
|
|
217
|
+
});
|
|
218
|
+
} else {
|
|
219
|
+
console.trace("elm-pages unhandled HTTP error", error);
|
|
220
|
+
resolve({
|
|
221
|
+
kind: "response-json",
|
|
222
|
+
value: { "elm-pages-internal-error": "NetworkError" },
|
|
170
223
|
});
|
|
171
224
|
}
|
|
172
225
|
}
|
|
@@ -174,6 +227,33 @@ function lookupOrPerform(portsFile, mode, rawRequest, hasFsAccess, useCache) {
|
|
|
174
227
|
});
|
|
175
228
|
}
|
|
176
229
|
|
|
230
|
+
/**
|
|
231
|
+
* @param {unknown} obj
|
|
232
|
+
* @returns {JSON}
|
|
233
|
+
*/
|
|
234
|
+
function toElmJson(obj) {
|
|
235
|
+
if (Array.isArray(obj)) {
|
|
236
|
+
return obj.map(toElmJson);
|
|
237
|
+
} else if (typeof obj === "object") {
|
|
238
|
+
for (let key in obj) {
|
|
239
|
+
const value = obj[key];
|
|
240
|
+
if (typeof value === "undefined") {
|
|
241
|
+
obj[key] = null;
|
|
242
|
+
} else if (value instanceof Date) {
|
|
243
|
+
obj[key] = {
|
|
244
|
+
"__elm-pages-normalized__": {
|
|
245
|
+
kind: "Date",
|
|
246
|
+
value: Math.floor(value.getTime()),
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
// } else if (value instanceof Object) {
|
|
250
|
+
// toElmJson(obj);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return obj;
|
|
255
|
+
}
|
|
256
|
+
|
|
177
257
|
/**
|
|
178
258
|
* @param {{url: string; headers: {[x: string]: string}; method: string; body: Body } } elmRequest
|
|
179
259
|
*/
|
|
@@ -188,15 +268,6 @@ function toRequest(elmRequest) {
|
|
|
188
268
|
body: toBody(elmRequest.body),
|
|
189
269
|
};
|
|
190
270
|
}
|
|
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
271
|
/**
|
|
201
272
|
* @param {Body} body
|
|
202
273
|
*/
|
|
@@ -208,6 +279,9 @@ function toBody(body) {
|
|
|
208
279
|
case "StringBody": {
|
|
209
280
|
return body.args[1];
|
|
210
281
|
}
|
|
282
|
+
case "BytesBody": {
|
|
283
|
+
return Buffer.from(body.args[1], "base64");
|
|
284
|
+
}
|
|
211
285
|
case "JsonBody": {
|
|
212
286
|
return JSON.stringify(body.args[0]);
|
|
213
287
|
}
|
|
@@ -226,13 +300,16 @@ function toContentType(body) {
|
|
|
226
300
|
case "StringBody": {
|
|
227
301
|
return { "Content-Type": body.args[0] };
|
|
228
302
|
}
|
|
303
|
+
case "BytesBody": {
|
|
304
|
+
return { "Content-Type": body.args[0] };
|
|
305
|
+
}
|
|
229
306
|
case "JsonBody": {
|
|
230
307
|
return { "Content-Type": "application/json" };
|
|
231
308
|
}
|
|
232
309
|
}
|
|
233
310
|
}
|
|
234
311
|
|
|
235
|
-
/** @typedef { { tag: 'EmptyBody'} | { tag: 'StringBody'; args: [string, string] } | {tag: 'JsonBody'; args: [ Object ] } } Body */
|
|
312
|
+
/** @typedef { { tag: 'EmptyBody'} |{ tag: 'BytesBody'; args: [string, string] } | { tag: 'StringBody'; args: [string, string] } | {tag: 'JsonBody'; args: [ Object ] } } Body */
|
|
236
313
|
function requireUncached(mode, filePath) {
|
|
237
314
|
if (mode === "dev-server") {
|
|
238
315
|
// for the build command, we can skip clearing the cache because it won't change while the build is running
|
|
@@ -249,4 +326,30 @@ function jsonResponse(json) {
|
|
|
249
326
|
return { bodyKind: "json", body: json };
|
|
250
327
|
}
|
|
251
328
|
|
|
252
|
-
|
|
329
|
+
async function safeFetch(makeFetchHappen, url, options) {
|
|
330
|
+
const { cachePath, ...optionsWithoutCachePath } = options;
|
|
331
|
+
const cachePathWithDefault = cachePath || defaultHttpCachePath;
|
|
332
|
+
if (await canAccess(cachePathWithDefault)) {
|
|
333
|
+
return await makeFetchHappen(url, {
|
|
334
|
+
cachePath: cachePathWithDefault,
|
|
335
|
+
...options,
|
|
336
|
+
});
|
|
337
|
+
} else {
|
|
338
|
+
return await makeFetchHappen(url, {
|
|
339
|
+
cache: "no-store",
|
|
340
|
+
...optionsWithoutCachePath,
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
async function canAccess(filePath) {
|
|
346
|
+
try {
|
|
347
|
+
await fsPromises.access(
|
|
348
|
+
filePath,
|
|
349
|
+
fsPromises.constants.R_OK | fsPromises.constants.W_OK
|
|
350
|
+
);
|
|
351
|
+
return true;
|
|
352
|
+
} catch {
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
|
|
4
|
+
function findNearestElmJson(filePath) {
|
|
5
|
+
function searchForElmJson(directory) {
|
|
6
|
+
if (directory === "/") {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const elmJsonPath = path.join(directory, "elm.json");
|
|
11
|
+
return fs.existsSync(elmJsonPath)
|
|
12
|
+
? elmJsonPath
|
|
13
|
+
: searchForElmJson(path.dirname(directory));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return searchForElmJson(path.dirname(filePath));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function getElmModuleName(inputPath) {
|
|
20
|
+
const filePath = path.normalize(
|
|
21
|
+
path.isAbsolute(inputPath) ? inputPath : path.resolve(inputPath)
|
|
22
|
+
);
|
|
23
|
+
const elmJsonPath = findNearestElmJson(filePath);
|
|
24
|
+
|
|
25
|
+
if (!elmJsonPath) {
|
|
26
|
+
throw new Error("No elm.json found");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const elmJson = JSON.parse(fs.readFileSync(elmJsonPath, "utf8"));
|
|
30
|
+
const sourceDirectories = elmJson["source-directories"];
|
|
31
|
+
const projectDirectory = path.dirname(elmJsonPath);
|
|
32
|
+
|
|
33
|
+
const matchingSourceDir = sourceDirectories
|
|
34
|
+
.map((sourceDir) => path.join(projectDirectory, sourceDir))
|
|
35
|
+
.find((absoluteSourceDir) => filePath.startsWith(absoluteSourceDir));
|
|
36
|
+
|
|
37
|
+
if (!matchingSourceDir) {
|
|
38
|
+
throw new Error(
|
|
39
|
+
"File is not in any source-directories specified in elm.json"
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const relativePath = path.relative(matchingSourceDir, filePath);
|
|
44
|
+
const moduleName = relativePath
|
|
45
|
+
.replace(path.extname(relativePath), "")
|
|
46
|
+
.replace("/", ".");
|
|
47
|
+
|
|
48
|
+
return { projectDirectory, moduleName, sourceDirectory: matchingSourceDir };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function resolveInputPathOrModuleName(inputPathOrModuleName) {
|
|
52
|
+
if (
|
|
53
|
+
/^[A-Z][a-zA-Z0-9_]*(\.[A-Z][a-zA-Z0-9_]*)*$/.test(inputPathOrModuleName)
|
|
54
|
+
) {
|
|
55
|
+
const absolutePathForScript = path.resolve("./script/src");
|
|
56
|
+
return {
|
|
57
|
+
moduleName: inputPathOrModuleName,
|
|
58
|
+
projectDirectory: path.resolve("./script"),
|
|
59
|
+
sourceDirectory: path.resolve("./script/src"),
|
|
60
|
+
};
|
|
61
|
+
} else {
|
|
62
|
+
return getElmModuleName(inputPathOrModuleName);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -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
|
|
@@ -27,6 +27,7 @@ function rewriteElmJson(elmJson) {
|
|
|
27
27
|
elmJson["source-directories"] = elmJson["source-directories"].map((item) => {
|
|
28
28
|
return "../../../" + item;
|
|
29
29
|
});
|
|
30
|
+
elmJson["dependencies"]["direct"]["lamdera/codecs"] = "1.0.0";
|
|
30
31
|
// 3. add our own secret My.elm module 😈
|
|
31
32
|
elmJson["source-directories"].push(".elm-pages");
|
|
32
33
|
elmJson["source-directories"].push("app");
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {string} sourceElmJsonPath
|
|
6
|
+
* @param {string} targetElmJsonPath
|
|
7
|
+
* @param {( (arg0: JSON) => JSON )?} modifyElmJson
|
|
8
|
+
*/
|
|
9
|
+
export async function rewriteElmJson(
|
|
10
|
+
sourceElmJsonPath,
|
|
11
|
+
targetElmJsonPath,
|
|
12
|
+
modifyElmJson
|
|
13
|
+
) {
|
|
14
|
+
if (!modifyElmJson) {
|
|
15
|
+
modifyElmJson = function (json) {
|
|
16
|
+
return json;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
var elmJson = JSON.parse(
|
|
20
|
+
(
|
|
21
|
+
await fs.promises.readFile(path.join(sourceElmJsonPath, "elm.json"))
|
|
22
|
+
).toString()
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
let modifiedElmJson = modifyElmJson(elmJson);
|
|
26
|
+
// always add `lamdera/codecs` dependency
|
|
27
|
+
modifiedElmJson["dependencies"]["direct"]["lamdera/codecs"] = "1.0.0";
|
|
28
|
+
|
|
29
|
+
// write new elm.json
|
|
30
|
+
await writeFileIfChanged(
|
|
31
|
+
path.join(targetElmJsonPath, "elm.json"),
|
|
32
|
+
JSON.stringify(modifiedElmJson)
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @param {fs.PathLike | fs.promises.FileHandle} filePath
|
|
38
|
+
* @param {string | NodeJS.ArrayBufferView | Iterable<string | NodeJS.ArrayBufferView> | AsyncIterable<string | NodeJS.ArrayBufferView> | import("stream").Stream} content
|
|
39
|
+
*/
|
|
40
|
+
async function writeFileIfChanged(filePath, content) {
|
|
41
|
+
if (
|
|
42
|
+
!(await fileExists(filePath)) ||
|
|
43
|
+
(await fs.promises.readFile(filePath, "utf8")) !== content
|
|
44
|
+
) {
|
|
45
|
+
await fs.promises.writeFile(filePath, content);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* @param {fs.PathLike} file
|
|
50
|
+
*/
|
|
51
|
+
function fileExists(file) {
|
|
52
|
+
return fs.promises
|
|
53
|
+
.access(file, fs.constants.F_OK)
|
|
54
|
+
.then(() => true)
|
|
55
|
+
.catch(() => false);
|
|
56
|
+
}
|
|
@@ -1,19 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
export async function rewriteElmJson(
|
|
4
|
+
sourceElmJsonPath,
|
|
5
|
+
targetElmJsonPath,
|
|
6
|
+
options
|
|
7
|
+
) {
|
|
4
8
|
var elmJson = JSON.parse(
|
|
5
|
-
(await fs.promises.readFile(
|
|
9
|
+
(await fs.promises.readFile(sourceElmJsonPath)).toString()
|
|
6
10
|
);
|
|
7
11
|
|
|
8
12
|
// write new elm.json
|
|
9
13
|
|
|
10
14
|
await writeFileIfChanged(
|
|
11
|
-
|
|
12
|
-
JSON.stringify(
|
|
15
|
+
targetElmJsonPath,
|
|
16
|
+
JSON.stringify(rewriteElmJsonHelp(elmJson, options))
|
|
13
17
|
);
|
|
14
|
-
}
|
|
18
|
+
}
|
|
15
19
|
|
|
16
|
-
function
|
|
20
|
+
function rewriteElmJsonHelp(elmJson, options) {
|
|
17
21
|
// The internal generated file will be at:
|
|
18
22
|
// ./elm-stuff/elm-pages/
|
|
19
23
|
// So, we need to take the existing elmJson and
|
|
@@ -27,6 +31,12 @@ function rewriteElmJson(elmJson) {
|
|
|
27
31
|
elmJson["source-directories"] = elmJson["source-directories"].map((item) => {
|
|
28
32
|
return "../../" + item;
|
|
29
33
|
});
|
|
34
|
+
if (options && options.executableName === "elm") {
|
|
35
|
+
// elm, don't add lamdera/codecs
|
|
36
|
+
} else {
|
|
37
|
+
// lamdera, add codecs dependency
|
|
38
|
+
elmJson["dependencies"]["direct"]["lamdera/codecs"] = "1.0.0";
|
|
39
|
+
}
|
|
30
40
|
// 3. add our own secret My.elm module 😈
|
|
31
41
|
elmJson["source-directories"].push(".elm-pages");
|
|
32
42
|
return elmJson;
|