@eighty4/dank 0.0.4-1 → 0.0.4-3
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/client/client.js +1 -0
- package/lib/bin.ts +8 -11
- package/lib/build.ts +41 -70
- package/lib/build_tag.ts +3 -3
- package/lib/config.ts +372 -11
- package/lib/dank.ts +21 -150
- package/lib/define.ts +6 -4
- package/lib/developer.ts +146 -0
- package/lib/dirs.ts +83 -0
- package/lib/errors.ts +6 -0
- package/lib/esbuild.ts +19 -29
- package/lib/flags.ts +15 -121
- package/lib/html.ts +196 -112
- package/lib/http.ts +59 -43
- package/lib/public.ts +10 -10
- package/lib/{metadata.ts → registry.ts} +216 -83
- package/lib/serve.ts +118 -270
- package/lib/services.ts +8 -8
- package/lib/watch.ts +39 -0
- package/lib_js/bin.js +79 -85
- package/lib_js/build.js +63 -86
- package/lib_js/build_tag.js +20 -21
- package/lib_js/config.js +237 -18
- package/lib_js/dank.js +5 -122
- package/lib_js/define.js +8 -5
- package/lib_js/dirs.js +61 -0
- package/lib_js/errors.js +9 -0
- package/lib_js/esbuild.js +155 -167
- package/lib_js/flags.js +30 -123
- package/lib_js/html.js +280 -231
- package/lib_js/http.js +176 -195
- package/lib_js/public.js +45 -46
- package/lib_js/registry.js +260 -0
- package/lib_js/serve.js +109 -251
- package/lib_js/services.js +152 -171
- package/lib_js/watch.js +35 -0
- package/lib_types/dank.d.ts +13 -1
- package/package.json +10 -4
- package/client/esbuild.js +0 -91
- package/lib_js/metadata.js +0 -210
package/lib_js/bin.js
CHANGED
|
@@ -1,106 +1,100 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { buildWebsite } from "./build.js";
|
|
3
|
-
import {
|
|
3
|
+
import { DankError } from "./errors.js";
|
|
4
4
|
import { serveWebsite } from "./serve.js";
|
|
5
|
-
function printHelp(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
console.log(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
5
|
+
function printHelp(task2) {
|
|
6
|
+
if (!task2 || task2 === "build") {
|
|
7
|
+
console.log("dank build [--minify] [--production]");
|
|
8
|
+
}
|
|
9
|
+
if (!task2 || task2 === "serve") {
|
|
10
|
+
console.log(
|
|
11
|
+
// 'dank serve [--minify] [--preview] [--production]',
|
|
12
|
+
"dank serve [--minify] [--production]"
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
console.log("\nOPTIONS:");
|
|
16
|
+
if (!task2 || task2 === "serve")
|
|
17
|
+
console.log(" --log-http print access logs");
|
|
18
|
+
console.log(" --minify minify sources");
|
|
19
|
+
console.log(" --production build for production release");
|
|
20
|
+
if (task2) {
|
|
21
|
+
console.log();
|
|
22
|
+
console.log("use `dank -h` for details on all commands");
|
|
23
|
+
}
|
|
24
|
+
process.exit(1);
|
|
25
25
|
}
|
|
26
26
|
const args = (function collectProgramArgs() {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
27
|
+
const programNames = ["dank", "bin.js", "bin.ts"];
|
|
28
|
+
let args2 = [...process.argv];
|
|
29
|
+
while (true) {
|
|
30
|
+
const shifted = args2.shift();
|
|
31
|
+
if (!shifted || programNames.some((name) => shifted.endsWith(name))) {
|
|
32
|
+
return args2;
|
|
34
33
|
}
|
|
34
|
+
}
|
|
35
35
|
})();
|
|
36
36
|
const task = (function resolveTask() {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
})();
|
|
65
|
-
if (showHelp) {
|
|
66
|
-
printHelp(task);
|
|
37
|
+
const showHelp = args.some((arg) => arg === "-h" || arg === "--help");
|
|
38
|
+
const task2 = (() => {
|
|
39
|
+
while (true) {
|
|
40
|
+
const shifted = args.shift();
|
|
41
|
+
switch (shifted) {
|
|
42
|
+
case "-h":
|
|
43
|
+
case "--help":
|
|
44
|
+
break;
|
|
45
|
+
case "build":
|
|
46
|
+
return "build";
|
|
47
|
+
case "dev":
|
|
48
|
+
case "serve":
|
|
49
|
+
return "serve";
|
|
50
|
+
default:
|
|
51
|
+
if (showHelp) {
|
|
52
|
+
printHelp();
|
|
53
|
+
} else if (typeof shifted === "undefined") {
|
|
54
|
+
printError("missing command");
|
|
55
|
+
printHelp();
|
|
56
|
+
} else {
|
|
57
|
+
printError(shifted + " isn't a command");
|
|
58
|
+
printHelp();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
67
61
|
}
|
|
68
|
-
|
|
62
|
+
})();
|
|
63
|
+
if (showHelp) {
|
|
64
|
+
printHelp(task2);
|
|
65
|
+
}
|
|
66
|
+
return task2;
|
|
69
67
|
})();
|
|
70
|
-
const c = await loadConfig();
|
|
71
68
|
try {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
errorExit(e);
|
|
69
|
+
switch (task) {
|
|
70
|
+
case "build":
|
|
71
|
+
await buildWebsite();
|
|
72
|
+
console.log(green("done"));
|
|
73
|
+
process.exit(0);
|
|
74
|
+
case "serve":
|
|
75
|
+
await serveWebsite();
|
|
76
|
+
}
|
|
77
|
+
} catch (e) {
|
|
78
|
+
errorExit(e);
|
|
83
79
|
}
|
|
84
80
|
function printError(e) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
console.error(e.stack);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
81
|
+
if (e !== null) {
|
|
82
|
+
if (e instanceof DankError) {
|
|
83
|
+
console.error(red("error:"), e.message);
|
|
84
|
+
} else if (e instanceof Error) {
|
|
85
|
+
console.error(red("error:"), e.stack ?? e.message);
|
|
86
|
+
} else {
|
|
87
|
+
console.error(red("error:"), e);
|
|
95
88
|
}
|
|
89
|
+
}
|
|
96
90
|
}
|
|
97
91
|
function green(s) {
|
|
98
|
-
|
|
92
|
+
return `\x1B[32m${s}\x1B[0m`;
|
|
99
93
|
}
|
|
100
94
|
function red(s) {
|
|
101
|
-
|
|
95
|
+
return `\x1B[31m${s}\x1B[0m`;
|
|
102
96
|
}
|
|
103
97
|
function errorExit(e) {
|
|
104
|
-
|
|
105
|
-
|
|
98
|
+
printError(e);
|
|
99
|
+
process.exit(1);
|
|
106
100
|
}
|
package/lib_js/build.js
CHANGED
|
@@ -1,95 +1,72 @@
|
|
|
1
|
-
import { mkdir, readFile, rm, writeFile } from
|
|
2
|
-
import { join } from
|
|
1
|
+
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
3
|
import { createBuildTag } from "./build_tag.js";
|
|
4
|
+
import { loadConfig } from "./config.js";
|
|
4
5
|
import { createGlobalDefinitions } from "./define.js";
|
|
5
6
|
import { esbuildWebpages, esbuildWorkers } from "./esbuild.js";
|
|
6
|
-
import { resolveBuildFlags } from "./flags.js";
|
|
7
|
-
import { HtmlEntrypoint } from "./html.js";
|
|
8
|
-
import { WebsiteRegistry } from "./metadata.js";
|
|
9
7
|
import { copyAssets } from "./public.js";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
registry.copiedAssets = await copyAssets(build);
|
|
26
|
-
await buildWebpages(c, registry, build, createGlobalDefinitions(build));
|
|
27
|
-
return await registry.writeManifest(buildTag);
|
|
8
|
+
import { WebsiteRegistry } from "./registry.js";
|
|
9
|
+
async function buildWebsite(c) {
|
|
10
|
+
if (!c) {
|
|
11
|
+
c = await loadConfig("build", process.cwd());
|
|
12
|
+
}
|
|
13
|
+
const buildTag = await createBuildTag(c.flags);
|
|
14
|
+
console.log(c.flags.minify ? c.flags.production ? "minified production" : "minified" : "unminified", "build", buildTag, "building in ./build/dist");
|
|
15
|
+
await rm(c.dirs.buildRoot, { recursive: true, force: true });
|
|
16
|
+
await mkdir(c.dirs.buildDist, { recursive: true });
|
|
17
|
+
for (const subdir of Object.keys(c.pages).filter((url) => url !== "/")) {
|
|
18
|
+
await mkdir(join(c.dirs.buildDist, subdir), { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
await mkdir(join(c.dirs.buildRoot, "metafiles"), { recursive: true });
|
|
21
|
+
const registry = await buildWebpages(c, createGlobalDefinitions(c));
|
|
22
|
+
return await registry.writeManifest(buildTag);
|
|
28
23
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const buildEntryPoints = [];
|
|
45
|
-
for (const pageEntryPoints of await Promise.all(loadingEntryPoints)) {
|
|
46
|
-
for (const entryPoint of pageEntryPoints) {
|
|
47
|
-
if (!uniqueEntryPoints.has(entryPoint.in)) {
|
|
48
|
-
buildEntryPoints.push(entryPoint);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
await esbuildWebpages(build, registry, define, buildEntryPoints, c.esbuild);
|
|
53
|
-
// todo recursively build workers on building workers that create workers
|
|
54
|
-
const workerEntryPoints = registry.workerEntryPoints();
|
|
55
|
-
if (workerEntryPoints?.length) {
|
|
56
|
-
await esbuildWorkers(build, registry, define, workerEntryPoints, c.esbuild);
|
|
57
|
-
}
|
|
58
|
-
await rewriteWorkerUrls(build, registry);
|
|
59
|
-
// write out html output with rewritten hrefs
|
|
60
|
-
await Promise.all(htmlEntrypoints.map(async (html) => {
|
|
61
|
-
await writeFile(join(build.dirs.buildDist, html.url, 'index.html'), html.output(registry));
|
|
62
|
-
}));
|
|
24
|
+
async function buildWebpages(c, define) {
|
|
25
|
+
const registry = new WebsiteRegistry(c);
|
|
26
|
+
registry.configSync();
|
|
27
|
+
registry.copiedAssets = await copyAssets(c.dirs);
|
|
28
|
+
await Promise.all(registry.htmlEntrypoints.map((html) => html.process()));
|
|
29
|
+
await esbuildWebpages(registry, define, registry.webpageEntryPoints);
|
|
30
|
+
const workerEntryPoints = registry.workerEntryPoints;
|
|
31
|
+
if (workerEntryPoints?.length) {
|
|
32
|
+
await esbuildWorkers(registry, define, workerEntryPoints);
|
|
33
|
+
}
|
|
34
|
+
await rewriteWorkerUrls(c.dirs, registry);
|
|
35
|
+
await Promise.all(registry.htmlEntrypoints.map(async (html) => {
|
|
36
|
+
await writeFile(join(c.dirs.buildDist, html.url, "index.html"), html.output(registry));
|
|
37
|
+
}));
|
|
38
|
+
return registry;
|
|
63
39
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
40
|
+
async function rewriteWorkerUrls(dirs, registry) {
|
|
41
|
+
const workers = registry.workers;
|
|
42
|
+
if (!workers) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const dependentBundlePaths = workers.map((w) => registry.mappedHref(w.dependentEntryPoint));
|
|
46
|
+
const bundleOutputs = {};
|
|
47
|
+
const readingFiles = Promise.all(dependentBundlePaths.map(async (p) => {
|
|
48
|
+
bundleOutputs[p] = await readFile(join(dirs.projectRootAbs, dirs.buildDist, p), "utf8");
|
|
49
|
+
}));
|
|
50
|
+
const rewriteChains = {};
|
|
51
|
+
for (const p of dependentBundlePaths)
|
|
52
|
+
rewriteChains[p] = [];
|
|
53
|
+
for (const w of workers) {
|
|
54
|
+
rewriteChains[registry.mappedHref(w.dependentEntryPoint)].push((s) => s.replace(createWorkerRegex(w.workerCtor, w.workerUrlPlaceholder), `new ${w.workerCtor}('${registry.mappedHref(w.workerEntryPoint)}')`));
|
|
55
|
+
}
|
|
56
|
+
await readingFiles;
|
|
57
|
+
await Promise.all(Object.entries(bundleOutputs).map(async ([p, content]) => {
|
|
58
|
+
let result = content;
|
|
59
|
+
for (const rewriteFn of rewriteChains[p]) {
|
|
60
|
+
result = rewriteFn(result);
|
|
81
61
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
// run rewrite regex chain and write back to dist
|
|
85
|
-
await Promise.all(Object.entries(bundleOutputs).map(async ([p, content]) => {
|
|
86
|
-
let result = content;
|
|
87
|
-
for (const rewriteFn of rewriteChains[p]) {
|
|
88
|
-
result = rewriteFn(result);
|
|
89
|
-
}
|
|
90
|
-
await writeFile(join(build.dirs.projectRootAbs, build.dirs.buildDist, p), result);
|
|
91
|
-
}));
|
|
62
|
+
await writeFile(join(dirs.projectRootAbs, dirs.buildDist, p), result);
|
|
63
|
+
}));
|
|
92
64
|
}
|
|
93
|
-
|
|
94
|
-
|
|
65
|
+
function createWorkerRegex(workerCtor, workerUrl) {
|
|
66
|
+
return new RegExp(`new(?:\\s|\\r?\\n)+${workerCtor}(?:\\s|\\r?\\n)*\\((?:\\s|\\r?\\n)*['"]${workerUrl}['"](?:\\s|\\r?\\n)*\\)`, "g");
|
|
95
67
|
}
|
|
68
|
+
export {
|
|
69
|
+
buildWebsite,
|
|
70
|
+
createWorkerRegex,
|
|
71
|
+
rewriteWorkerUrls
|
|
72
|
+
};
|
package/lib_js/build_tag.js
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
import { exec } from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
return when;
|
|
21
|
-
}
|
|
1
|
+
import { exec } from "node:child_process";
|
|
2
|
+
async function createBuildTag(flags) {
|
|
3
|
+
const now = /* @__PURE__ */ new Date();
|
|
4
|
+
const ms = now.getUTCMilliseconds() + now.getUTCSeconds() * 1e3 + now.getUTCMinutes() * 1e3 * 60 + now.getUTCHours() * 1e3 * 60 * 60;
|
|
5
|
+
const date = now.toISOString().substring(0, 10);
|
|
6
|
+
const time = String(ms).padStart(8, "0");
|
|
7
|
+
const when = `${date}-${time}`;
|
|
8
|
+
if (flags.production) {
|
|
9
|
+
const gitHash = await new Promise((res, rej) => exec("git rev-parse --short HEAD", (err, stdout) => {
|
|
10
|
+
if (err)
|
|
11
|
+
rej(err);
|
|
12
|
+
res(stdout.trim());
|
|
13
|
+
}));
|
|
14
|
+
return `${when}-${gitHash}`;
|
|
15
|
+
} else {
|
|
16
|
+
return when;
|
|
17
|
+
}
|
|
22
18
|
}
|
|
19
|
+
export {
|
|
20
|
+
createBuildTag
|
|
21
|
+
};
|
package/lib_js/config.js
CHANGED
|
@@ -1,23 +1,242 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { isAbsolute, resolve } from "node:path";
|
|
2
|
+
import { defaultProjectDirs } from "./dirs.js";
|
|
3
|
+
import { resolveFlags as lookupDankFlags } from "./flags.js";
|
|
4
|
+
var __rewriteRelativeImportExtension = function(path, preserveJsx) {
|
|
5
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
6
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
|
|
7
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js";
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
return path;
|
|
8
11
|
};
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
const DEFAULT_DEV_PORT = 3e3;
|
|
13
|
+
const DEFAULT_PREVIEW_PORT = 4e3;
|
|
14
|
+
const DEFAULT_ESBUILD_PORT = 3995;
|
|
15
|
+
const DEFAULT_CONFIG_PATH = "./dank.config.ts";
|
|
16
|
+
async function loadConfig(mode, projectRootAbs) {
|
|
17
|
+
if (!isAbsolute(projectRootAbs)) {
|
|
18
|
+
throw Error();
|
|
19
|
+
}
|
|
20
|
+
const modulePath = resolve(projectRootAbs, DEFAULT_CONFIG_PATH);
|
|
21
|
+
const dirs = await defaultProjectDirs(projectRootAbs);
|
|
22
|
+
const c = new DankConfigInternal(mode, modulePath, dirs);
|
|
23
|
+
await c.reload();
|
|
24
|
+
return c;
|
|
25
|
+
}
|
|
26
|
+
class DankConfigInternal {
|
|
27
|
+
#dirs;
|
|
28
|
+
#flags;
|
|
29
|
+
#mode;
|
|
30
|
+
#modulePath;
|
|
31
|
+
#dankPort = DEFAULT_DEV_PORT;
|
|
32
|
+
#esbuildPort = DEFAULT_ESBUILD_PORT;
|
|
33
|
+
#esbuild;
|
|
34
|
+
#pages = {};
|
|
35
|
+
#devPages;
|
|
36
|
+
#services;
|
|
37
|
+
constructor(mode, modulePath, dirs) {
|
|
38
|
+
this.#dirs = dirs;
|
|
39
|
+
this.#flags = lookupDankFlags();
|
|
40
|
+
this.#mode = mode;
|
|
41
|
+
this.#modulePath = modulePath;
|
|
42
|
+
}
|
|
43
|
+
get dankPort() {
|
|
44
|
+
return this.#dankPort;
|
|
45
|
+
}
|
|
46
|
+
get esbuildPort() {
|
|
47
|
+
return this.#esbuildPort;
|
|
48
|
+
}
|
|
49
|
+
get esbuild() {
|
|
50
|
+
return this.#esbuild;
|
|
51
|
+
}
|
|
52
|
+
get dirs() {
|
|
53
|
+
return this.#dirs;
|
|
54
|
+
}
|
|
55
|
+
get flags() {
|
|
56
|
+
return this.#flags;
|
|
57
|
+
}
|
|
58
|
+
get mode() {
|
|
59
|
+
return this.#mode;
|
|
60
|
+
}
|
|
61
|
+
get pages() {
|
|
62
|
+
return this.#pages;
|
|
63
|
+
}
|
|
64
|
+
get devPages() {
|
|
65
|
+
return this.#devPages;
|
|
66
|
+
}
|
|
67
|
+
get services() {
|
|
68
|
+
return this.#services;
|
|
69
|
+
}
|
|
70
|
+
async reload() {
|
|
71
|
+
const userConfig = await resolveConfig(this.#modulePath, resolveDankDetails(this.#mode, this.#flags));
|
|
72
|
+
this.#dankPort = resolveDankPort(this.#flags, userConfig);
|
|
73
|
+
this.#esbuildPort = resolveEsbuildPort(this.#flags, userConfig);
|
|
74
|
+
this.#esbuild = Object.freeze(userConfig.esbuild);
|
|
75
|
+
this.#pages = Object.freeze(normalizePages(userConfig.pages));
|
|
76
|
+
this.#devPages = Object.freeze(userConfig.devPages);
|
|
77
|
+
this.#services = Object.freeze(userConfig.services);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function resolveDankPort(flags, userConfig) {
|
|
81
|
+
return flags.dankPort || (flags.preview ? userConfig.previewPort || userConfig.port || DEFAULT_PREVIEW_PORT : userConfig.port || DEFAULT_DEV_PORT);
|
|
82
|
+
}
|
|
83
|
+
function resolveEsbuildPort(flags, userConfig) {
|
|
84
|
+
return flags.esbuildPort || userConfig.esbuild?.port || DEFAULT_ESBUILD_PORT;
|
|
85
|
+
}
|
|
86
|
+
async function resolveConfig(modulePath, details) {
|
|
87
|
+
const module = await import(__rewriteRelativeImportExtension(`${modulePath}?${Date.now()}`));
|
|
88
|
+
const c = typeof module.default === "function" ? await module.default(details) : module.default;
|
|
89
|
+
validateDankConfig(c);
|
|
90
|
+
return c;
|
|
91
|
+
}
|
|
92
|
+
function resolveDankDetails(mode, flags) {
|
|
93
|
+
return {
|
|
94
|
+
dev: !flags.production,
|
|
95
|
+
production: flags.production,
|
|
96
|
+
mode
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function validateDankConfig(c) {
|
|
100
|
+
try {
|
|
101
|
+
validatePorts(c);
|
|
102
|
+
validatePages(c.pages);
|
|
103
|
+
validateDevPages(c.devPages);
|
|
104
|
+
validateDevServices(c.services);
|
|
105
|
+
validateEsbuildConfig(c.esbuild);
|
|
106
|
+
} catch (e) {
|
|
107
|
+
throw e;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function validatePorts(c) {
|
|
111
|
+
if (c.port !== null && typeof c.port !== "undefined") {
|
|
112
|
+
if (typeof c.port !== "number") {
|
|
113
|
+
throw Error("DankConfig.port must be a number");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (c.previewPort !== null && typeof c.previewPort !== "undefined") {
|
|
117
|
+
if (typeof c.previewPort !== "number") {
|
|
118
|
+
throw Error("DankConfig.previewPort must be a number");
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function validateEsbuildConfig(esbuild) {
|
|
123
|
+
if (esbuild?.loaders !== null && typeof esbuild?.loaders !== "undefined") {
|
|
124
|
+
if (typeof esbuild.loaders !== "object") {
|
|
125
|
+
throw Error("DankConfig.esbuild.loaders must be a map of extensions to esbuild loaders");
|
|
126
|
+
} else {
|
|
127
|
+
for (const [ext, loader] of Object.entries(esbuild.loaders)) {
|
|
128
|
+
if (typeof loader !== "string") {
|
|
129
|
+
throw Error(`DankConfig.esbuild.loaders['${ext}'] must be a string of a loader name`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (esbuild?.plugins !== null && typeof esbuild?.plugins !== "undefined") {
|
|
135
|
+
if (!Array.isArray(esbuild.plugins)) {
|
|
136
|
+
throw Error("DankConfig.esbuild.plugins must be an array of esbuild plugins");
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (esbuild?.port !== null && typeof esbuild?.port !== "undefined") {
|
|
140
|
+
if (typeof esbuild.port !== "number") {
|
|
141
|
+
throw Error("DankConfig.esbuild.port must be a number");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function validatePages(pages) {
|
|
146
|
+
if (pages === null || typeof pages === "undefined" || Object.keys(pages).length === 0) {
|
|
147
|
+
throw Error("DankConfig.pages is required");
|
|
148
|
+
}
|
|
149
|
+
for (const [urlPath, mapping] of Object.entries(pages)) {
|
|
150
|
+
if (typeof mapping === "string" && mapping.endsWith(".html")) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (typeof mapping === "object") {
|
|
154
|
+
validatePageMapping(urlPath, mapping);
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
throw Error(`DankConfig.pages['${urlPath}'] must configure an html file`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function validateDevPages(devPages) {
|
|
161
|
+
if (devPages) {
|
|
162
|
+
for (const [urlPath, mapping] of Object.entries(devPages)) {
|
|
163
|
+
if (!urlPath.startsWith("/__")) {
|
|
164
|
+
throw Error(`DankConfig.devPages['${urlPath}'] must start \`${urlPath}\` with a \`/__\` path prefix`);
|
|
165
|
+
}
|
|
166
|
+
if (typeof mapping === "string") {
|
|
167
|
+
if (!mapping.endsWith(".html")) {
|
|
168
|
+
throw Error(`DankConfig.devPages['${urlPath}'] must configure an html file or DevPageMapping config`);
|
|
169
|
+
}
|
|
170
|
+
} else if (typeof mapping === "object") {
|
|
171
|
+
if (typeof mapping.label !== "string" || !mapping.label.length) {
|
|
172
|
+
throw Error(`DankConfig.devPages['${urlPath}'].label must declare a label`);
|
|
173
|
+
}
|
|
174
|
+
if (typeof mapping.webpage !== "string" || !mapping.webpage.endsWith(".html")) {
|
|
175
|
+
throw Error(`DankConfig.devPages['${urlPath}'].webpage must configure an html file`);
|
|
176
|
+
}
|
|
177
|
+
} else {
|
|
178
|
+
throw Error(`DankConfig.devPages['${urlPath}'] must be a DevPageMapping config with \`label\` and \`webpage\` values`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function validatePageMapping(urlPath, mapping) {
|
|
184
|
+
if (mapping.webpage === null || typeof mapping.webpage !== "string" || !mapping.webpage.endsWith(".html")) {
|
|
185
|
+
throw Error(`DankConfig.pages['${urlPath}'].webpage must configure an html file`);
|
|
186
|
+
}
|
|
187
|
+
if (mapping.pattern === null || typeof mapping.pattern === "undefined") {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (typeof mapping.pattern === "object" && mapping.pattern.constructor.name === "RegExp") {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
throw Error(`DankConfig.pages['${urlPath}'].pattern must be a RegExp`);
|
|
15
194
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
195
|
+
function validateDevServices(services) {
|
|
196
|
+
if (services === null || typeof services === "undefined") {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (!Array.isArray(services)) {
|
|
200
|
+
throw Error(`DankConfig.services must be an array`);
|
|
201
|
+
}
|
|
202
|
+
for (let i = 0; i < services.length; i++) {
|
|
203
|
+
const s = services[i];
|
|
204
|
+
if (s.command === null || typeof s.command === "undefined") {
|
|
205
|
+
throw Error(`DankConfig.services[${i}].command is required`);
|
|
206
|
+
} else if (typeof s.command !== "string" || s.command.length === 0) {
|
|
207
|
+
throw Error(`DankConfig.services[${i}].command must be a non-empty string`);
|
|
208
|
+
}
|
|
209
|
+
if (s.cwd !== null && typeof s.cwd !== "undefined") {
|
|
210
|
+
if (typeof s.cwd !== "string" || s.cwd.trim().length === 0) {
|
|
211
|
+
throw Error(`DankConfig.services[${i}].cwd must be a non-empty string`);
|
|
212
|
+
}
|
|
19
213
|
}
|
|
20
|
-
|
|
21
|
-
|
|
214
|
+
if (s.env !== null && typeof s.env !== "undefined") {
|
|
215
|
+
if (typeof s.env !== "object") {
|
|
216
|
+
throw Error(`DankConfig.services[${i}].env must be an env variable map`);
|
|
217
|
+
}
|
|
218
|
+
for (const [k, v] of Object.entries(s.env)) {
|
|
219
|
+
if (typeof v !== "string") {
|
|
220
|
+
throw Error(`DankConfig.services[${i}].env[${k}] must be a string`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
22
223
|
}
|
|
224
|
+
if (s.http !== null && typeof s.http !== "undefined") {
|
|
225
|
+
if (typeof s.http.port !== "number") {
|
|
226
|
+
throw Error(`DankConfig.services[${i}].http.port must be a number`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function normalizePages(pages) {
|
|
232
|
+
const result = {};
|
|
233
|
+
for (const [pageUrl, mapping] of Object.entries(pages)) {
|
|
234
|
+
const mappedMapping = typeof mapping === "string" ? { webpage: mapping } : mapping;
|
|
235
|
+
mappedMapping.webpage = mappedMapping.webpage.replace(/^\.\//, "");
|
|
236
|
+
result[pageUrl] = mappedMapping;
|
|
237
|
+
}
|
|
238
|
+
return result;
|
|
23
239
|
}
|
|
240
|
+
export {
|
|
241
|
+
loadConfig
|
|
242
|
+
};
|