@zvndev/darkmown 0.8.2 → 0.10.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
@@ -20,8 +20,9 @@ if (command === "help" || command === "--help" || command === "-h") {
20
20
  } else if (command === "init") {
21
21
  const target = process.argv[3] || ".";
22
22
  const result = initProject(path.resolve(process.cwd(), target));
23
- console.log(`Created Darkmown project at ${path.relative(process.cwd(), result.root) || "."}`);
24
- console.log(`Next: cd ${path.relative(process.cwd(), result.root) || "."} && npm install && npm run dev`);
23
+ const relativeRoot = path.relative(process.cwd(), result.root) || ".";
24
+ console.log(`Created Darkmown project at ${relativeRoot}`);
25
+ console.log(`Next: ${nextStep(relativeRoot)}`);
25
26
  } else if (command === "build") {
26
27
  const result = buildSite();
27
28
  console.log(`Built ${result.routes.length} routes into ${path.relative(process.cwd(), result.distRoot)}`);
@@ -29,7 +30,9 @@ if (command === "help" || command === "--help" || command === "-h") {
29
30
  const port = Number(process.env.PORT || 5173);
30
31
  const distRoot = path.join(process.cwd(), "dist");
31
32
  buildSite();
33
+ /** @type {Set<import("node:http").ServerResponse>} */
32
34
  const clients = new Set();
35
+ /** @type {ReturnType<typeof setTimeout> | undefined} */
33
36
  let timer;
34
37
 
35
38
  // Rebuild in a child process so changes to Darkmown's own src/ always load
@@ -94,7 +97,7 @@ if (command === "help" || command === "--help" || command === "-h") {
94
97
  serveDev(distRoot, url, res);
95
98
  } catch (error) {
96
99
  res.writeHead(500, { "content-type": "text/plain" });
97
- res.end(error.stack || String(error));
100
+ res.end((error instanceof Error && error.stack) || String(error));
98
101
  }
99
102
  });
100
103
  server.listen(port, () => {
@@ -117,6 +120,12 @@ if (command === "help" || command === "--help" || command === "-h") {
117
120
  process.exit(1);
118
121
  }
119
122
 
123
+ /**
124
+ * @param {string} distRoot
125
+ * @param {string} url
126
+ * @param {import("node:http").ServerResponse} res
127
+ * @returns {void}
128
+ */
120
129
  function serveDev(distRoot, url, res) {
121
130
  const file = resolvePublicFile(distRoot, url);
122
131
  if (!file || !fs.existsSync(file)) {
@@ -132,6 +141,11 @@ function serveDev(distRoot, url, res) {
132
141
  fs.createReadStream(file).pipe(res);
133
142
  }
134
143
 
144
+ /**
145
+ * @param {Set<import("node:http").ServerResponse>} clients
146
+ * @param {string} message
147
+ * @returns {void}
148
+ */
135
149
  function broadcast(clients, message) {
136
150
  for (const client of clients) client.write(message);
137
151
  }
@@ -144,6 +158,7 @@ Usage:
144
158
  darkmown dev Start the live compiler dev server
145
159
  darkmown build Compile site/pages into dist
146
160
  darkmown serve Preview the built dist locally
161
+ darkmown version Print the installed Darkmown version
147
162
  darkmown help Show this help
148
163
 
149
164
  Authoring:
@@ -154,3 +169,13 @@ Authoring:
154
169
  *.js Colocated page behavior
155
170
  `);
156
171
  }
172
+
173
+
174
+ /**
175
+ * @param {string} relativeRoot
176
+ * @returns {string}
177
+ */
178
+ function nextStep(relativeRoot) {
179
+ if (relativeRoot === ".") return "npm install && npm run dev";
180
+ return `cd ${relativeRoot} && npm install && npm run dev`;
181
+ }