@zvndev/darkmown 0.8.1 → 0.9.0

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/src/builder.js CHANGED
@@ -6,16 +6,36 @@ import { createPaths } from "./config.js";
6
6
  import { discoverRoutes, outputPathForRoute } from "./router.js";
7
7
  import { compileSkin } from "./skin.js";
8
8
 
9
+ /**
10
+ * @typedef {import("./config.js").Paths} Paths
11
+ * @typedef {import("./compiler.js").Assets} Assets
12
+ */
13
+
14
+ /**
15
+ * A built route entry written to `dist/routes.json`.
16
+ * @typedef {object} RouteManifestEntry
17
+ * @property {string} route Public route path.
18
+ * @property {string} file Source file path, relative to cwd, POSIX-separated.
19
+ * @property {{ skins: string[], scripts: string[], runtime: boolean }} assets
20
+ */
21
+
9
22
  const moduleDir = path.dirname(fileURLToPath(import.meta.url));
10
23
 
24
+ /**
25
+ * Compile the whole site under `cwd` into `dist`, returning the route manifest.
26
+ * @param {string} [cwd] Project working directory (defaults to `process.cwd()`).
27
+ * @returns {{ routes: RouteManifestEntry[], distRoot: string }}
28
+ */
11
29
  export function buildSite(cwd = process.cwd()) {
12
30
  const paths = createPaths(cwd);
13
31
  fs.rmSync(paths.distRoot, { recursive: true, force: true });
14
32
  fs.mkdirSync(paths.distRoot, { recursive: true });
15
33
  emitShelfAssets(paths);
16
34
  const routes = discoverRoutes(paths.routesRoot);
35
+ /** @type {RouteManifestEntry[]} */
17
36
  const manifest = [];
18
37
 
38
+ /** @type {Set<string>} */
19
39
  const warned = new Set();
20
40
 
21
41
  for (const route of routes) {
@@ -45,12 +65,41 @@ export function buildSite(cwd = process.cwd()) {
45
65
  return { routes: manifest, distRoot: paths.distRoot };
46
66
  }
47
67
 
68
+ /**
69
+ * Strip JSDoc `/** ... *\/` blocks from the runtime before it ships.
70
+ * The source keeps full type annotations (for `checkJs` + `.d.ts`), but the
71
+ * browser never needs to download them — this keeps the shipped runtime lean
72
+ * and the gzip budget honest (measured against what users actually receive).
73
+ * Only `/** ... *\/` blocks are removed; code and string literals are untouched.
74
+ * @param {string} source
75
+ * @returns {string}
76
+ */
77
+ export function stripRuntimeComments(source) {
78
+ return source
79
+ // Remove the JSDoc block text only — never the surrounding newlines, so an
80
+ // inline `/** @type {x} */ code` keeps its line and never glues onto a
81
+ // preceding `//` comment.
82
+ .replace(/\/\*\*[\s\S]*?\*\//g, "")
83
+ // Drop the now blank/whitespace-only lines the removed blocks leave behind.
84
+ .replace(/^[ \t]*\n/gm, "");
85
+ }
86
+
87
+ /**
88
+ * @param {Paths} paths
89
+ * @returns {void}
90
+ */
48
91
  function emitRuntime(paths) {
49
92
  const out = path.join(paths.distRoot, "__wd/runtime.js");
50
93
  fs.mkdirSync(path.dirname(out), { recursive: true });
51
- fs.copyFileSync(path.join(moduleDir, "runtime.js"), out);
94
+ const source = fs.readFileSync(path.join(moduleDir, "runtime.js"), "utf8");
95
+ fs.writeFileSync(out, stripRuntimeComments(source));
52
96
  }
53
97
 
98
+ /**
99
+ * @param {Assets} assets
100
+ * @param {Paths} paths
101
+ * @returns {void}
102
+ */
54
103
  function emitAssets(assets, paths) {
55
104
  for (const [source, href] of assets.files) {
56
105
  const out = path.join(paths.distRoot, href);
@@ -63,6 +112,11 @@ function emitAssets(assets, paths) {
63
112
  }
64
113
  }
65
114
 
115
+ /**
116
+ * Copy non-page shelf assets (JSON data, media) into `dist/__wd`.
117
+ * @param {Paths} paths
118
+ * @returns {void}
119
+ */
66
120
  function emitShelfAssets(paths) {
67
121
  if (!fs.existsSync(paths.shelfRoot)) return;
68
122
  for (const file of walk(paths.shelfRoot)) {
@@ -76,7 +130,12 @@ function emitShelfAssets(paths) {
76
130
  }
77
131
  }
78
132
 
133
+ /**
134
+ * @param {string} dir
135
+ * @returns {string[]}
136
+ */
79
137
  function walk(dir) {
138
+ /** @type {string[]} */
80
139
  const files = [];
81
140
  for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
82
141
  const abs = path.join(dir, entry.name);
package/src/cli.js CHANGED
@@ -29,7 +29,9 @@ if (command === "help" || command === "--help" || command === "-h") {
29
29
  const port = Number(process.env.PORT || 5173);
30
30
  const distRoot = path.join(process.cwd(), "dist");
31
31
  buildSite();
32
+ /** @type {Set<import("node:http").ServerResponse>} */
32
33
  const clients = new Set();
34
+ /** @type {ReturnType<typeof setTimeout> | undefined} */
33
35
  let timer;
34
36
 
35
37
  // Rebuild in a child process so changes to Darkmown's own src/ always load
@@ -94,7 +96,7 @@ if (command === "help" || command === "--help" || command === "-h") {
94
96
  serveDev(distRoot, url, res);
95
97
  } catch (error) {
96
98
  res.writeHead(500, { "content-type": "text/plain" });
97
- res.end(error.stack || String(error));
99
+ res.end((error instanceof Error && error.stack) || String(error));
98
100
  }
99
101
  });
100
102
  server.listen(port, () => {
@@ -117,6 +119,12 @@ if (command === "help" || command === "--help" || command === "-h") {
117
119
  process.exit(1);
118
120
  }
119
121
 
122
+ /**
123
+ * @param {string} distRoot
124
+ * @param {string} url
125
+ * @param {import("node:http").ServerResponse} res
126
+ * @returns {void}
127
+ */
120
128
  function serveDev(distRoot, url, res) {
121
129
  const file = resolvePublicFile(distRoot, url);
122
130
  if (!file || !fs.existsSync(file)) {
@@ -132,6 +140,11 @@ function serveDev(distRoot, url, res) {
132
140
  fs.createReadStream(file).pipe(res);
133
141
  }
134
142
 
143
+ /**
144
+ * @param {Set<import("node:http").ServerResponse>} clients
145
+ * @param {string} message
146
+ * @returns {void}
147
+ */
135
148
  function broadcast(clients, message) {
136
149
  for (const client of clients) client.write(message);
137
150
  }