@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/AGENTS.md +1 -1
- package/CHANGELOG.md +21 -0
- package/README.md +16 -10
- package/docs/cli.md +24 -2
- package/docs/spec-alignment.md +4 -4
- package/package.json +21 -4
- package/site/_/roadmap.json +2 -2
- package/site/pages/docs/index.wd +2 -2
- package/site/pages/index.skin +158 -0
- package/site/pages/index.wd +94 -6
- package/src/builder.js +60 -1
- package/src/cli.js +28 -3
- package/src/compiler.js +503 -14
- package/src/config.js +19 -0
- package/src/dev.js +9 -0
- package/src/router.js +26 -0
- package/src/runtime.js +102 -26
- package/src/scaffold.js +32 -1
- package/src/skin.js +31 -3
- package/src/statics.js +20 -0
- package/types/builder.d.ts +39 -0
- package/types/compiler.d.ts +184 -0
- package/types/config.d.ts +45 -0
- package/types/dev.d.ts +13 -0
- package/types/index.d.ts +33 -0
- package/types/router.d.ts +39 -0
- package/types/scaffold.d.ts +8 -0
- package/types/skin.d.ts +21 -0
- package/types/statics.d.ts +23 -0
- package/docs/okf-integration.md +0 -120
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.
|
|
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
|
-
|
|
24
|
-
console.log(`
|
|
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
|
+
}
|