elm-pages 3.0.0-beta.2 → 3.0.0-beta.20
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} +2420 -1592
- 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 +1326 -121
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +15215 -13007
- 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/dead-code-review/elm.json +8 -6
- package/generator/dead-code-review/src/Pages/Review/DeadCodeEliminateData.elm +189 -17
- package/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm +255 -21
- 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 +1326 -121
- package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +14620 -12636
- 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/review/elm.json +8 -8
- package/generator/src/RouteBuilder.elm +66 -52
- 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 +122 -86
- package/generator/src/cli.js +247 -51
- package/generator/src/codegen.js +29 -27
- package/generator/src/compatibility-key.js +1 -0
- package/generator/src/compile-elm.js +20 -22
- package/generator/src/config.js +39 -0
- package/generator/src/copy-dir.js +2 -2
- package/generator/src/dev-server.js +119 -110
- 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 +14 -21
- package/generator/src/init.js +8 -7
- package/generator/src/pre-render-html.js +41 -28
- package/generator/src/render-test.js +109 -0
- package/generator/src/render-worker.js +26 -28
- package/generator/src/render.js +322 -142
- package/generator/src/request-cache.js +200 -162
- 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 +16 -2
- package/generator/template/app/Api.elm +3 -3
- package/generator/template/app/Route/Index.elm +3 -3
- package/generator/template/app/Shared.elm +3 -3
- package/generator/template/app/Site.elm +9 -4
- package/package.json +21 -21
- package/src/ApiRoute.elm +199 -61
- package/src/BackendTask/Custom.elm +214 -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 +1 -1
- package/src/Form.elm +72 -92
- 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/Generate.elm +775 -132
- 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/Internal/Platform/Cli.elm +479 -747
- package/src/Pages/Internal/Platform/Cli.elm.bak +1276 -0
- 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 +54 -53
- 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/ProgramConfig.elm +12 -8
- 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/RequestsAndPending.elm +8 -19
- package/src/Result/Extra.elm +21 -0
- package/src/Server/Request.elm +43 -34
- package/src/Server/Session.elm +166 -100
- package/src/Server/SetCookie.elm +89 -31
- 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
|
@@ -1,174 +1,189 @@
|
|
|
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
|
-
|
|
40
|
+
if (request.url === "elm-pages-internal://port") {
|
|
41
|
+
try {
|
|
42
|
+
const { input, portName } = rawRequest.body.args[0];
|
|
72
43
|
|
|
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(),
|
|
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
|
+
try {
|
|
96
|
+
resolve({
|
|
97
|
+
kind: "response-json",
|
|
98
|
+
value: jsonResponse(await portBackendTask[portName](input)),
|
|
99
|
+
});
|
|
100
|
+
} catch (portCallError) {
|
|
101
|
+
resolve({
|
|
102
|
+
kind: "response-json",
|
|
103
|
+
value: jsonResponse({
|
|
104
|
+
"elm-pages-internal-error": "CustomBackendTaskException",
|
|
105
|
+
error: portCallError,
|
|
106
|
+
}),
|
|
107
|
+
});
|
|
108
|
+
}
|
|
171
109
|
}
|
|
110
|
+
} catch (error) {
|
|
111
|
+
console.trace(error);
|
|
112
|
+
reject({
|
|
113
|
+
title: "BackendTask.Custom Error",
|
|
114
|
+
message: error.toString(),
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
try {
|
|
119
|
+
console.time(`fetch ${request.url}`);
|
|
120
|
+
const response = await safeFetch(makeFetchHappen, request.url, {
|
|
121
|
+
method: request.method,
|
|
122
|
+
body: request.body,
|
|
123
|
+
headers: {
|
|
124
|
+
"User-Agent": "request",
|
|
125
|
+
...request.headers,
|
|
126
|
+
},
|
|
127
|
+
...rawRequest.cacheOptions,
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
console.timeEnd(`fetch ${request.url}`);
|
|
131
|
+
const expectString = request.headers["elm-pages-internal"];
|
|
132
|
+
|
|
133
|
+
let body;
|
|
134
|
+
let bodyKind;
|
|
135
|
+
if (expectString === "ExpectJson") {
|
|
136
|
+
try {
|
|
137
|
+
body = await response.buffer();
|
|
138
|
+
body = JSON.parse(body.toString("utf-8"));
|
|
139
|
+
bodyKind = "json";
|
|
140
|
+
} catch (error) {
|
|
141
|
+
body = body.toString("utf8");
|
|
142
|
+
bodyKind = "string";
|
|
143
|
+
}
|
|
144
|
+
} else if (
|
|
145
|
+
expectString === "ExpectBytes" ||
|
|
146
|
+
expectString === "ExpectBytesResponse"
|
|
147
|
+
) {
|
|
148
|
+
body = await response.buffer();
|
|
149
|
+
try {
|
|
150
|
+
body = body.toString("base64");
|
|
151
|
+
bodyKind = "bytes";
|
|
152
|
+
} catch (e) {
|
|
153
|
+
body = body.toString("utf8");
|
|
154
|
+
bodyKind = "string";
|
|
155
|
+
}
|
|
156
|
+
} else if (expectString === "ExpectWhatever") {
|
|
157
|
+
bodyKind = "whatever";
|
|
158
|
+
body = null;
|
|
159
|
+
} else if (
|
|
160
|
+
expectString === "ExpectResponse" ||
|
|
161
|
+
expectString === "ExpectString"
|
|
162
|
+
) {
|
|
163
|
+
bodyKind = "string";
|
|
164
|
+
body = await response.text();
|
|
165
|
+
} else {
|
|
166
|
+
throw `Unexpected expectString ${expectString}`;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
resolve({
|
|
170
|
+
kind: "response-json",
|
|
171
|
+
value: {
|
|
172
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
173
|
+
statusCode: response.status,
|
|
174
|
+
body,
|
|
175
|
+
bodyKind,
|
|
176
|
+
url: response.url,
|
|
177
|
+
statusText: response.statusText,
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
} catch (error) {
|
|
181
|
+
console.trace("@@@ request-cache2 HTTP error", error);
|
|
182
|
+
reject({
|
|
183
|
+
title: "BackendTask.Http Error",
|
|
184
|
+
message: `${kleur.yellow().underline(request.url)} ${error.toString()}
|
|
185
|
+
`,
|
|
186
|
+
});
|
|
172
187
|
}
|
|
173
188
|
}
|
|
174
189
|
});
|
|
@@ -188,15 +203,6 @@ function toRequest(elmRequest) {
|
|
|
188
203
|
body: toBody(elmRequest.body),
|
|
189
204
|
};
|
|
190
205
|
}
|
|
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
206
|
/**
|
|
201
207
|
* @param {Body} body
|
|
202
208
|
*/
|
|
@@ -208,6 +214,9 @@ function toBody(body) {
|
|
|
208
214
|
case "StringBody": {
|
|
209
215
|
return body.args[1];
|
|
210
216
|
}
|
|
217
|
+
case "BytesBody": {
|
|
218
|
+
return Buffer.from(body.args[1], "base64");
|
|
219
|
+
}
|
|
211
220
|
case "JsonBody": {
|
|
212
221
|
return JSON.stringify(body.args[0]);
|
|
213
222
|
}
|
|
@@ -226,13 +235,16 @@ function toContentType(body) {
|
|
|
226
235
|
case "StringBody": {
|
|
227
236
|
return { "Content-Type": body.args[0] };
|
|
228
237
|
}
|
|
238
|
+
case "BytesBody": {
|
|
239
|
+
return { "Content-Type": body.args[0] };
|
|
240
|
+
}
|
|
229
241
|
case "JsonBody": {
|
|
230
242
|
return { "Content-Type": "application/json" };
|
|
231
243
|
}
|
|
232
244
|
}
|
|
233
245
|
}
|
|
234
246
|
|
|
235
|
-
/** @typedef { { tag: 'EmptyBody'} | { tag: 'StringBody'; args: [string, string] } | {tag: 'JsonBody'; args: [ Object ] } } Body */
|
|
247
|
+
/** @typedef { { tag: 'EmptyBody'} |{ tag: 'BytesBody'; args: [string, string] } | { tag: 'StringBody'; args: [string, string] } | {tag: 'JsonBody'; args: [ Object ] } } Body */
|
|
236
248
|
function requireUncached(mode, filePath) {
|
|
237
249
|
if (mode === "dev-server") {
|
|
238
250
|
// for the build command, we can skip clearing the cache because it won't change while the build is running
|
|
@@ -249,4 +261,30 @@ function jsonResponse(json) {
|
|
|
249
261
|
return { bodyKind: "json", body: json };
|
|
250
262
|
}
|
|
251
263
|
|
|
252
|
-
|
|
264
|
+
async function safeFetch(makeFetchHappen, url, options) {
|
|
265
|
+
const { cachePath, ...optionsWithoutCachePath } = options;
|
|
266
|
+
const cachePathWithDefault = cachePath || defaultHttpCachePath;
|
|
267
|
+
if (await canAccess(cachePathWithDefault)) {
|
|
268
|
+
return await makeFetchHappen(url, {
|
|
269
|
+
cachePath: cachePathWithDefault,
|
|
270
|
+
...options,
|
|
271
|
+
});
|
|
272
|
+
} else {
|
|
273
|
+
return await makeFetchHappen(url, {
|
|
274
|
+
cache: "no-store",
|
|
275
|
+
...optionsWithoutCachePath,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
async function canAccess(filePath) {
|
|
281
|
+
try {
|
|
282
|
+
await fsPromises.access(
|
|
283
|
+
filePath,
|
|
284
|
+
fsPromises.constants.R_OK | fsPromises.constants.W_OK
|
|
285
|
+
);
|
|
286
|
+
return true;
|
|
287
|
+
} catch {
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
@@ -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
|
-
};
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
module.exports = { gather };
|
|
2
|
-
|
|
3
1
|
/** @typedef { { type: 'root'; keyValuePair: [string, string] } } RootTagModifier */
|
|
4
2
|
|
|
5
3
|
/**
|
|
6
4
|
* @param {( SeoTag | RootTagModifier )[]} tags
|
|
7
5
|
*/
|
|
8
|
-
function gather(tags) {
|
|
6
|
+
export function gather(tags) {
|
|
9
7
|
const withoutRootModifiers = tags.flatMap((value) => {
|
|
10
8
|
if (value.type === "root") {
|
|
11
9
|
return [];
|
|
@@ -43,11 +41,16 @@ function headTag(rootModifiers) {
|
|
|
43
41
|
|
|
44
42
|
function toString(/** @type { SeoTag[] } */ tags) {
|
|
45
43
|
return tags
|
|
46
|
-
.
|
|
44
|
+
.flatMap((headTag) => {
|
|
47
45
|
if (headTag.type === "head") {
|
|
48
|
-
return appendTag(headTag);
|
|
46
|
+
return [appendTag(headTag)];
|
|
49
47
|
} else if (headTag.type === "json-ld") {
|
|
50
|
-
return appendJsonLdTag(headTag);
|
|
48
|
+
return [appendJsonLdTag(headTag)];
|
|
49
|
+
} else if (headTag.type === "stripped") {
|
|
50
|
+
console.warn(
|
|
51
|
+
`WARNING: Head.nonLoadingTag value ignored because it used a loading tag: ${headTag.message}`
|
|
52
|
+
);
|
|
53
|
+
return [];
|
|
51
54
|
} else {
|
|
52
55
|
throw new Error(`Unknown tag type ${JSON.stringify(headTag)}`);
|
|
53
56
|
}
|
|
@@ -55,7 +58,7 @@ function toString(/** @type { SeoTag[] } */ tags) {
|
|
|
55
58
|
.join("");
|
|
56
59
|
}
|
|
57
60
|
|
|
58
|
-
/** @typedef {HeadTag | JsonLdTag} SeoTag */
|
|
61
|
+
/** @typedef {HeadTag | JsonLdTag | StrippedTag} SeoTag */
|
|
59
62
|
|
|
60
63
|
/** @typedef {{ name: string; attributes: string[][]; type: 'head' }} HeadTag */
|
|
61
64
|
function appendTag(/** @type {HeadTag} */ tagDetails) {
|
|
@@ -66,6 +69,8 @@ function appendTag(/** @type {HeadTag} */ tagDetails) {
|
|
|
66
69
|
}
|
|
67
70
|
|
|
68
71
|
/** @typedef {{ contents: Object; type: 'json-ld' }} JsonLdTag */
|
|
72
|
+
/** @typedef {{ message: string; type: 'stripped' }} StrippedTag */
|
|
73
|
+
|
|
69
74
|
function appendJsonLdTag(/** @type {JsonLdTag} */ tagDetails) {
|
|
70
75
|
return `<script type="application/ld+json">
|
|
71
76
|
${JSON.stringify(tagDetails.contents)}
|