@eighty4/dank 0.0.4-0 → 0.0.4-2

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.
@@ -1,198 +1,190 @@
1
- import EventEmitter from 'node:events';
2
- import { writeFile } from 'node:fs/promises';
3
- import { dirname, join, resolve, sep } from 'node:path';
4
- // manages website resources during `dank build` and `dank serve`
5
- export class WebsiteRegistry extends EventEmitter {
6
- #build;
7
- // paths of bundled esbuild outputs
8
- #bundles = new Set();
9
- // public dir assets
10
- #copiedAssets = null;
11
- // map of entrypoints to their output path
12
- #entrypointHrefs = {};
13
- #pageUrls = [];
14
- #workers = null;
15
- constructor(build) {
16
- super();
17
- this.#build = build;
18
- }
19
- // bundleOutputs(type?: 'css' | 'js'): Array<string> {
20
- // if (!type) {
21
- // return Array.from(this.#bundles)
22
- // } else {
23
- // return Array.from(this.#bundles).filter(p => p.endsWith(type))
24
- // }
25
- // }
26
- buildRegistry() {
27
- return new BuildRegistry(this.#build, this.#onBuildManifest);
28
- }
29
- files() {
30
- const files = new Set();
31
- for (const pageUrl of this.#pageUrls)
32
- files.add(pageUrl === '/' ? '/index.html' : `${pageUrl}/index.html`);
33
- for (const f of this.#bundles)
34
- files.add(f);
35
- if (this.#copiedAssets)
36
- for (const f of this.#copiedAssets)
37
- files.add(f);
38
- return files;
39
- }
40
- mappedHref(lookup) {
41
- const found = this.#entrypointHrefs[lookup];
42
- if (found) {
43
- return found;
44
- }
45
- else {
46
- throw Error(`mapped href for ${lookup} not found`);
47
- }
48
- }
49
- resolve(from, href) {
50
- return resolveImpl(this.#build, from, href);
51
- }
52
- workerEntryPoints() {
53
- return (this.#workers?.map(({ workerEntryPoint }) => ({
54
- in: workerEntryPoint,
55
- out: workerEntryPoint
56
- .replace(/^pages[\//]/, '')
57
- .replace(/\.(mj|t)s$/, '.js'),
58
- })) || null);
59
- }
60
- workers() {
61
- return this.#workers;
62
- }
63
- async writeManifest(buildTag) {
64
- const manifest = this.#manifest(buildTag);
65
- await writeFile(join(this.#build.dirs.projectRootAbs, this.#build.dirs.buildRoot, 'website.json'), JSON.stringify({
66
- buildTag,
67
- files: Array.from(manifest.files),
68
- pageUrls: Array.from(manifest.pageUrls),
69
- }, null, 4));
70
- return manifest;
71
- }
72
- set copiedAssets(copiedAssets) {
73
- this.#copiedAssets =
74
- copiedAssets === null ? null : new Set(copiedAssets);
75
- }
76
- set pageUrls(pageUrls) {
77
- this.#pageUrls = pageUrls;
78
- }
79
- #manifest(buildTag) {
80
- return {
81
- buildTag,
82
- files: this.files(),
83
- pageUrls: new Set(this.#pageUrls),
84
- };
85
- }
86
- #onBuildManifest = (build) => {
87
- // collect built bundle entrypoint hrefs
88
- for (const [outPath, entrypoint] of Object.entries(build.bundles)) {
89
- this.#bundles.add(outPath);
90
- if (entrypoint) {
91
- this.#entrypointHrefs[entrypoint] = outPath;
92
- }
93
- }
94
- // determine if worker entrypoints have changed
95
- let updatedWorkerEntrypoints = false;
96
- const previousWorkers = this.#workers === null
97
- ? null
98
- : new Set(this.#workers.map(w => w.workerEntryPoint));
99
- if (build.workers) {
100
- if (!previousWorkers ||
101
- previousWorkers.size !==
102
- new Set(build.workers.map(w => w.workerEntryPoint)).size) {
103
- updatedWorkerEntrypoints = true;
104
- }
105
- else {
106
- updatedWorkerEntrypoints = !build.workers.every(w => previousWorkers.has(w.workerEntryPoint));
107
- }
108
- }
109
- else if (previousWorkers) {
110
- updatedWorkerEntrypoints = true;
111
- }
112
- // merge unique entrypoints from built workers with registry state
113
- // todo filtering out unique occurrences of clientScript and workerUrl
114
- // drops reporting/summary/debugging capabilities, but currently
115
- // this.#workers is used for unique worker/client entrypoints
116
- if (build.workers) {
117
- if (!this.#workers) {
118
- this.#workers = build.workers;
119
- }
120
- else {
121
- for (const w of build.workers) {
122
- const found = this.#workers.find(w2 => {
123
- return (w.dependentEntryPoint === w2.dependentEntryPoint &&
124
- w.workerEntryPoint === w2.workerEntryPoint);
125
- });
126
- if (!found) {
127
- this.#workers.push(w);
128
- }
129
- }
130
- }
131
- }
132
- if (updatedWorkerEntrypoints) {
133
- this.emit('workers');
134
- }
135
- };
1
+ import EventEmitter from "node:events";
2
+ import { writeFile } from "node:fs/promises";
3
+ import { dirname, join, resolve } from "node:path";
4
+ class ResolverImpl {
5
+ #dirs;
6
+ constructor(dirs) {
7
+ this.#dirs = dirs;
8
+ }
9
+ isProjectSubpathInPagesDir(p) {
10
+ return resolve(join(this.#dirs.projectResolved, p)).startsWith(this.#dirs.pagesResolved);
11
+ }
12
+ isPagesSubpathInPagesDir(p) {
13
+ return this.isProjectSubpathInPagesDir(join(this.#dirs.pages, p));
14
+ }
15
+ resolveHrefInPagesDir(from, href) {
16
+ const p = join(dirname(from), href);
17
+ if (this.isProjectSubpathInPagesDir(p)) {
18
+ return p;
19
+ } else {
20
+ return "outofbounds";
21
+ }
22
+ }
136
23
  }
137
- // result accumulator of an esbuild `build` or `Context.rebuild`
138
- export class BuildRegistry {
139
- #build;
140
- #onComplete;
141
- #workers = null;
142
- constructor(build, onComplete) {
143
- this.#build = build;
144
- this.#onComplete = onComplete;
145
- }
146
- // resolve web worker imported by a webpage module
147
- addWorker(worker) {
148
- // todo normalize path
149
- if (!this.#workers) {
150
- this.#workers = [worker];
151
- }
152
- else {
153
- this.#workers.push(worker);
154
- }
155
- }
156
- completeBuild(result) {
157
- const bundles = {};
158
- for (const [outPath, output] of Object.entries(result.metafile.outputs)) {
159
- bundles[outPath.replace(/^build[/\\]dist/, '')] =
160
- output.entryPoint || null;
161
- }
162
- let workers = null;
163
- if (this.#workers) {
164
- workers = [];
165
- for (const output of Object.values(result.metafile.outputs)) {
166
- if (!output.entryPoint)
167
- continue;
168
- const inputs = Object.keys(output.inputs);
169
- for (const worker of this.#workers) {
170
- if (inputs.includes(worker.clientScript)) {
171
- workers.push({
172
- ...worker,
173
- dependentEntryPoint: output.entryPoint,
174
- });
175
- }
176
- }
177
- }
24
+ class WebsiteRegistry extends EventEmitter {
25
+ #build;
26
+ // paths of bundled esbuild outputs
27
+ #bundles = /* @__PURE__ */ new Set();
28
+ // public dir assets
29
+ #copiedAssets = null;
30
+ // map of entrypoints to their output path
31
+ #entrypointHrefs = {};
32
+ #pageUrls = [];
33
+ #resolver;
34
+ #workers = null;
35
+ constructor(build) {
36
+ super();
37
+ this.#build = build;
38
+ this.#resolver = new ResolverImpl(build.dirs);
39
+ }
40
+ set copiedAssets(copiedAssets) {
41
+ this.#copiedAssets = copiedAssets === null ? null : new Set(copiedAssets);
42
+ }
43
+ set pageUrls(pageUrls) {
44
+ this.#pageUrls = pageUrls;
45
+ }
46
+ get resolver() {
47
+ return this.#resolver;
48
+ }
49
+ // bundleOutputs(type?: 'css' | 'js'): Array<string> {
50
+ // if (!type) {
51
+ // return Array.from(this.#bundles)
52
+ // } else {
53
+ // return Array.from(this.#bundles).filter(p => p.endsWith(type))
54
+ // }
55
+ // }
56
+ buildRegistry() {
57
+ return new BuildRegistry(this.#build, this.#onBuildManifest);
58
+ }
59
+ files() {
60
+ const files = /* @__PURE__ */ new Set();
61
+ for (const pageUrl of this.#pageUrls)
62
+ files.add(pageUrl === "/" ? "/index.html" : `${pageUrl}/index.html`);
63
+ for (const f of this.#bundles)
64
+ files.add(f);
65
+ if (this.#copiedAssets)
66
+ for (const f of this.#copiedAssets)
67
+ files.add(f);
68
+ return files;
69
+ }
70
+ mappedHref(lookup) {
71
+ const found = this.#entrypointHrefs[lookup];
72
+ if (found) {
73
+ return found;
74
+ } else {
75
+ throw Error(`mapped href for ${lookup} not found`);
76
+ }
77
+ }
78
+ workerEntryPoints() {
79
+ return this.#workers?.map(({ workerEntryPoint }) => ({
80
+ in: workerEntryPoint,
81
+ out: workerEntryPoint.replace(/^pages[\//]/, "").replace(/\.(mj|t)s$/, ".js")
82
+ })) || null;
83
+ }
84
+ workers() {
85
+ return this.#workers;
86
+ }
87
+ async writeManifest(buildTag) {
88
+ const manifest = this.#manifest(buildTag);
89
+ await writeFile(join(this.#build.dirs.projectRootAbs, this.#build.dirs.buildRoot, "website.json"), JSON.stringify({
90
+ buildTag,
91
+ files: Array.from(manifest.files),
92
+ pageUrls: Array.from(manifest.pageUrls)
93
+ }, null, 4));
94
+ return manifest;
95
+ }
96
+ #manifest(buildTag) {
97
+ return {
98
+ buildTag,
99
+ files: this.files(),
100
+ pageUrls: new Set(this.#pageUrls)
101
+ };
102
+ }
103
+ #onBuildManifest = (build) => {
104
+ for (const [outPath, entrypoint] of Object.entries(build.bundles)) {
105
+ this.#bundles.add(outPath);
106
+ if (entrypoint) {
107
+ this.#entrypointHrefs[entrypoint] = outPath;
108
+ }
109
+ }
110
+ let updatedWorkerEntrypoints = false;
111
+ const previousWorkers = this.#workers === null ? null : new Set(this.#workers.map((w) => w.workerEntryPoint));
112
+ if (build.workers) {
113
+ if (!previousWorkers || previousWorkers.size !== new Set(build.workers.map((w) => w.workerEntryPoint)).size) {
114
+ updatedWorkerEntrypoints = true;
115
+ } else {
116
+ updatedWorkerEntrypoints = !build.workers.every((w) => previousWorkers.has(w.workerEntryPoint));
117
+ }
118
+ } else if (previousWorkers) {
119
+ updatedWorkerEntrypoints = true;
120
+ }
121
+ if (build.workers) {
122
+ if (!this.#workers) {
123
+ this.#workers = build.workers;
124
+ } else {
125
+ for (const w of build.workers) {
126
+ const found = this.#workers.find((w2) => {
127
+ return w.dependentEntryPoint === w2.dependentEntryPoint && w.workerEntryPoint === w2.workerEntryPoint;
128
+ });
129
+ if (!found) {
130
+ this.#workers.push(w);
131
+ }
178
132
  }
179
- this.#onComplete({
180
- bundles,
181
- workers,
182
- });
133
+ }
183
134
  }
184
- resolve(from, href) {
185
- return resolveImpl(this.#build, from, href);
135
+ if (updatedWorkerEntrypoints) {
136
+ this.emit("workers");
186
137
  }
138
+ };
187
139
  }
188
- function resolveImpl(build, from, href) {
189
- const { pagesResolved, projectRootAbs } = build.dirs;
190
- const fromDir = dirname(from);
191
- const resolvedFromProjectRoot = join(projectRootAbs, fromDir, href);
192
- if (!resolve(resolvedFromProjectRoot).startsWith(pagesResolved)) {
193
- throw Error(`href ${href} cannot be resolved from pages${sep}${from} to a path outside of the pages directory`);
194
- }
195
- else {
196
- return join(fromDir, href);
140
+ class BuildRegistry {
141
+ #onComplete;
142
+ #resolver;
143
+ #workers = null;
144
+ constructor(build, onComplete) {
145
+ this.#onComplete = onComplete;
146
+ this.#resolver = new ResolverImpl(build.dirs);
147
+ }
148
+ get resolver() {
149
+ return this.#resolver;
150
+ }
151
+ // resolve web worker imported by a webpage module
152
+ addWorker(worker) {
153
+ if (!this.#workers) {
154
+ this.#workers = [worker];
155
+ } else {
156
+ this.#workers.push(worker);
157
+ }
158
+ }
159
+ completeBuild(result) {
160
+ const bundles = {};
161
+ for (const [outPath, output] of Object.entries(result.metafile.outputs)) {
162
+ bundles[outPath.replace(/^build[/\\]dist/, "")] = output.entryPoint || null;
163
+ }
164
+ let workers = null;
165
+ if (this.#workers) {
166
+ workers = [];
167
+ for (const output of Object.values(result.metafile.outputs)) {
168
+ if (!output.entryPoint)
169
+ continue;
170
+ const inputs = Object.keys(output.inputs);
171
+ for (const worker of this.#workers) {
172
+ if (inputs.includes(worker.clientScript)) {
173
+ workers.push({
174
+ ...worker,
175
+ dependentEntryPoint: output.entryPoint
176
+ });
177
+ }
178
+ }
179
+ }
197
180
  }
181
+ this.#onComplete({
182
+ bundles,
183
+ workers
184
+ });
185
+ }
198
186
  }
187
+ export {
188
+ BuildRegistry,
189
+ WebsiteRegistry
190
+ };
package/lib_js/public.js CHANGED
@@ -1,51 +1,50 @@
1
- import { copyFile, mkdir, readdir, stat } from 'node:fs/promises';
2
- import { platform } from 'node:os';
3
- import { join } from 'node:path';
4
- export async function copyAssets(build) {
5
- try {
6
- const stats = await stat(build.dirs.public);
7
- if (stats.isDirectory()) {
8
- await mkdir(build.dirs.buildDist, { recursive: true });
9
- return await recursiveCopyAssets(build);
10
- }
11
- else {
12
- throw Error('./public cannot be a file');
13
- }
14
- }
15
- catch (e) {
16
- return null;
1
+ import { copyFile, mkdir, readdir, stat } from "node:fs/promises";
2
+ import { platform } from "node:os";
3
+ import { join } from "node:path";
4
+ async function copyAssets(build) {
5
+ try {
6
+ const stats = await stat(build.dirs.public);
7
+ if (stats.isDirectory()) {
8
+ await mkdir(build.dirs.buildDist, { recursive: true });
9
+ return await recursiveCopyAssets(build);
10
+ } else {
11
+ throw Error("./public cannot be a file");
17
12
  }
13
+ } catch (e) {
14
+ return null;
15
+ }
18
16
  }
19
- const IGNORE = platform() === 'darwin' ? ['.DS_Store'] : [];
20
- async function recursiveCopyAssets(build, dir = '') {
21
- const copied = [];
22
- const to = join(build.dirs.buildDist, dir);
23
- let madeDir = dir === '';
24
- const listingDir = join(build.dirs.public, dir);
25
- for (const p of await readdir(listingDir)) {
26
- if (IGNORE.includes(p)) {
27
- continue;
28
- }
29
- try {
30
- const stats = await stat(join(listingDir, p));
31
- if (stats.isDirectory()) {
32
- copied.push(...(await recursiveCopyAssets(build, join(dir, p))));
33
- }
34
- else {
35
- if (!madeDir) {
36
- await mkdir(join(build.dirs.buildDist, dir), {
37
- recursive: true,
38
- });
39
- madeDir = true;
40
- }
41
- await copyFile(join(listingDir, p), join(to, p));
42
- copied.push('/' + join(dir, p).replaceAll('\\', '/'));
43
- }
44
- }
45
- catch (e) {
46
- console.error('stat error', e);
47
- process.exit(1);
17
+ const IGNORE = platform() === "darwin" ? [".DS_Store"] : [];
18
+ async function recursiveCopyAssets(build, dir = "") {
19
+ const copied = [];
20
+ const to = join(build.dirs.buildDist, dir);
21
+ let madeDir = dir === "";
22
+ const listingDir = join(build.dirs.public, dir);
23
+ for (const p of await readdir(listingDir)) {
24
+ if (IGNORE.includes(p)) {
25
+ continue;
26
+ }
27
+ try {
28
+ const stats = await stat(join(listingDir, p));
29
+ if (stats.isDirectory()) {
30
+ copied.push(...await recursiveCopyAssets(build, join(dir, p)));
31
+ } else {
32
+ if (!madeDir) {
33
+ await mkdir(join(build.dirs.buildDist, dir), {
34
+ recursive: true
35
+ });
36
+ madeDir = true;
48
37
  }
38
+ await copyFile(join(listingDir, p), join(to, p));
39
+ copied.push("/" + join(dir, p).replaceAll("\\", "/"));
40
+ }
41
+ } catch (e) {
42
+ console.error("stat error", e);
43
+ process.exit(1);
49
44
  }
50
- return copied;
45
+ }
46
+ return copied;
51
47
  }
48
+ export {
49
+ copyAssets
50
+ };