@eighty4/dank 0.0.4-3 → 0.0.5-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/lib/config.ts CHANGED
@@ -45,14 +45,15 @@ export async function loadConfig(
45
45
  throw Error()
46
46
  }
47
47
  const modulePath = resolve(projectRootAbs, DEFAULT_CONFIG_PATH)
48
+ const dirs = await defaultProjectDirs(projectRootAbs)
48
49
  LOG({
49
50
  realm: 'config',
50
51
  message: 'loading config module',
51
52
  data: {
53
+ dirs,
52
54
  modulePath,
53
55
  },
54
56
  })
55
- const dirs = await defaultProjectDirs(projectRootAbs)
56
57
  const c = new DankConfigInternal(mode, modulePath, dirs)
57
58
  await c.reload()
58
59
  return c
@@ -149,7 +150,7 @@ async function resolveConfig(
149
150
  modulePath: string,
150
151
  details: DankDetails,
151
152
  ): Promise<DankConfig> {
152
- const module = await import(`${modulePath}?${Date.now()}`)
153
+ const module = await import(`file:${modulePath}?${Date.now()}`)
153
154
  const c: Partial<DankConfig> =
154
155
  typeof module.default === 'function'
155
156
  ? await module.default(details)
package/lib/dirs.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { realpath } from 'node:fs/promises'
2
2
  import { dirname, isAbsolute, join, resolve } from 'node:path'
3
- import { cwd } from 'node:process'
4
3
 
5
4
  export type DankDirectories = {
6
5
  buildRoot: string
@@ -17,9 +16,7 @@ export type DankDirectories = {
17
16
  export async function defaultProjectDirs(
18
17
  projectRootAbs: string,
19
18
  ): Promise<Readonly<DankDirectories>> {
20
- if (!projectRootAbs) {
21
- projectRootAbs = cwd()
22
- } else if (!isAbsolute(projectRootAbs)) {
19
+ if (!isAbsolute(projectRootAbs)) {
23
20
  throw Error()
24
21
  }
25
22
  const projectResolved = await realpath(projectRootAbs)
@@ -40,9 +37,17 @@ export async function defaultProjectDirs(
40
37
  export type ResolveError = 'outofbounds'
41
38
 
42
39
  export class Resolver {
40
+ static create(dirs: DankDirectories): Resolver {
41
+ if (process.platform === 'win32') {
42
+ return new WindowsResolver(dirs)
43
+ } else {
44
+ return new Resolver(dirs)
45
+ }
46
+ }
47
+
43
48
  #dirs: DankDirectories
44
49
 
45
- constructor(dirs: DankDirectories) {
50
+ protected constructor(dirs: DankDirectories) {
46
51
  this.#dirs = dirs
47
52
  }
48
53
 
@@ -68,6 +73,10 @@ export class Resolver {
68
73
  return this.isProjectSubpathInPagesDir(join(this.#dirs.pages, p))
69
74
  }
70
75
 
76
+ projectPathFromAbsolute(p: string) {
77
+ return p.replace(this.#dirs.projectRootAbs, '').substring(1)
78
+ }
79
+
71
80
  // resolve a pages subpath from a resource within the pages directory by a relative href
72
81
  // `from` is expected to be a pages resource fs path starting with `pages/` and ending with filename
73
82
  // the result will be a pages subpath and will not have the pages dir prefix
@@ -81,3 +90,17 @@ export class Resolver {
81
90
  }
82
91
  }
83
92
  }
93
+
94
+ class WindowsResolver extends Resolver {
95
+ constructor(dirs: DankDirectories) {
96
+ super(dirs)
97
+ }
98
+
99
+ projectPathFromAbsolute(p: string): string {
100
+ return super.projectPathFromAbsolute(p).replaceAll('\\', '/')
101
+ }
102
+
103
+ resolveHrefInPagesDir(from: string, href: string): string | ResolveError {
104
+ return super.resolveHrefInPagesDir(from, href).replaceAll('\\', '/')
105
+ }
106
+ }
package/lib/esbuild.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { readFile } from 'node:fs/promises'
2
+ // import { sep as windowsSep } from 'node:path/win32'
3
+ // import { sep as posixSep } from 'node:path/posix'
2
4
  import esbuild, {
3
5
  type BuildContext,
4
6
  type BuildOptions,
@@ -123,6 +125,7 @@ export function workersPlugin(r: BuildRegistry): Plugin {
123
125
  let contents = await readFile(args.path, 'utf8')
124
126
  let offset = 0
125
127
  let errors: Array<PartialMessage> | undefined = undefined
128
+ let clientScript: string | undefined = undefined
126
129
  for (const workerCtorMatch of contents.matchAll(
127
130
  WORKER_CTOR_REGEX,
128
131
  )) {
@@ -143,9 +146,11 @@ export function workersPlugin(r: BuildRegistry): Plugin {
143
146
  if (isIndexCommented(contents, workerCtorMatch.index)) {
144
147
  continue
145
148
  }
146
- const clientScript = args.path
147
- .replace(r.dirs.projectResolved, '')
148
- .substring(1)
149
+ if (!clientScript) {
150
+ clientScript = r.resolver.projectPathFromAbsolute(
151
+ args.path,
152
+ )
153
+ }
149
154
  const workerUrl = workerCtorMatch.groups!.url.substring(
150
155
  1,
151
156
  workerCtorMatch.groups!.url.length - 1,
@@ -174,6 +179,7 @@ export function workersPlugin(r: BuildRegistry): Plugin {
174
179
  const workerUrlPlaceholder = workerEntryPoint
175
180
  .replace(/^pages/, '')
176
181
  .replace(/\.(t|m?j)s$/, '.js')
182
+ .replaceAll('\\', '/')
177
183
  const workerCtorReplacement = `new ${workerCtor}('${workerUrlPlaceholder}'${workerCtorMatch.groups!.end}`
178
184
  contents =
179
185
  contents.substring(0, workerCtorMatch.index + offset) +
package/lib/html.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import EventEmitter from 'node:events'
2
2
  import { readFile } from 'node:fs/promises'
3
- import { dirname, isAbsolute, join, relative, resolve } from 'node:path'
3
+ import { dirname, isAbsolute, relative, resolve } from 'node:path'
4
+ import { join } from 'node:path/posix'
4
5
  import { extname } from 'node:path/posix'
5
6
  import {
6
7
  defaultTreeAdapter,
package/lib/registry.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  import EventEmitter from 'node:events'
2
2
  import { writeFile } from 'node:fs/promises'
3
- import { join } from 'node:path'
3
+ import { join } from 'node:path/posix'
4
4
  import type { BuildResult } from 'esbuild'
5
5
  import type { ResolvedDankConfig } from './config.ts'
6
+ import type { PageMapping } from './dank.ts'
6
7
  import { LOG } from './developer.ts'
7
8
  import { Resolver, type DankDirectories } from './dirs.ts'
8
9
  import type { EntryPoint } from './esbuild.ts'
9
10
  import { HtmlEntrypoint } from './html.ts'
10
- import type { PageMapping } from './dank.ts'
11
11
 
12
12
  // summary of a website build
13
13
  export type WebsiteManifest = {
@@ -80,7 +80,7 @@ export class WebsiteRegistry extends EventEmitter<WebsiteRegistryEvents> {
80
80
  constructor(config: ResolvedDankConfig) {
81
81
  super()
82
82
  this.#c = config
83
- this.#resolver = new Resolver(config.dirs)
83
+ this.#resolver = Resolver.create(config.dirs)
84
84
  }
85
85
 
86
86
  get config(): ResolvedDankConfig {
@@ -257,6 +257,7 @@ export class WebsiteRegistry extends EventEmitter<WebsiteRegistryEvents> {
257
257
  this.#setWebpageBundles(html.url, entrypoints),
258
258
  )
259
259
  this.emit('webpage', html)
260
+ html.emit('change')
260
261
  }
261
262
 
262
263
  #configPageUpdate(urlPath: `/${string}`, mapping: PageMapping) {
@@ -399,9 +400,7 @@ export class BuildRegistry {
399
400
  return this.#resolver
400
401
  }
401
402
 
402
- // resolve web worker imported by a webpage module
403
403
  addWorker(worker: Omit<WorkerManifest, 'dependentEntryPoint'>) {
404
- // todo normalize path
405
404
  if (!this.#workers) {
406
405
  this.#workers = [worker]
407
406
  } else {
@@ -433,7 +432,6 @@ export class BuildRegistry {
433
432
  }
434
433
  }
435
434
  }
436
-
437
435
  this.#onComplete({
438
436
  bundles,
439
437
  workers,
package/lib/serve.ts CHANGED
@@ -66,7 +66,14 @@ async function startDevMode(signal: AbortSignal) {
66
66
  await mkdir(c.dirs.buildWatch, { recursive: true })
67
67
  let buildContext: BuildContextState = null
68
68
 
69
- watch('dank.config.ts', signal, async () => {
69
+ watch('dank.config.ts', signal, async filename => {
70
+ LOG({
71
+ realm: 'serve',
72
+ message: 'config watch event',
73
+ data: {
74
+ file: filename,
75
+ },
76
+ })
70
77
  try {
71
78
  await c.reload()
72
79
  } catch (ignore) {
package/lib_js/config.js CHANGED
@@ -84,7 +84,7 @@ function resolveEsbuildPort(flags, userConfig) {
84
84
  return flags.esbuildPort || userConfig.esbuild?.port || DEFAULT_ESBUILD_PORT;
85
85
  }
86
86
  async function resolveConfig(modulePath, details) {
87
- const module = await import(__rewriteRelativeImportExtension(`${modulePath}?${Date.now()}`));
87
+ const module = await import(__rewriteRelativeImportExtension(`file:${modulePath}?${Date.now()}`));
88
88
  const c = typeof module.default === "function" ? await module.default(details) : module.default;
89
89
  validateDankConfig(c);
90
90
  return c;
package/lib_js/dirs.js CHANGED
@@ -1,10 +1,7 @@
1
1
  import { realpath } from "node:fs/promises";
2
2
  import { dirname, isAbsolute, join, resolve } from "node:path";
3
- import { cwd } from "node:process";
4
3
  async function defaultProjectDirs(projectRootAbs) {
5
- if (!projectRootAbs) {
6
- projectRootAbs = cwd();
7
- } else if (!isAbsolute(projectRootAbs)) {
4
+ if (!isAbsolute(projectRootAbs)) {
8
5
  throw Error();
9
6
  }
10
7
  const projectResolved = await realpath(projectRootAbs);
@@ -22,6 +19,13 @@ async function defaultProjectDirs(projectRootAbs) {
22
19
  });
23
20
  }
24
21
  class Resolver {
22
+ static create(dirs) {
23
+ if (process.platform === "win32") {
24
+ return new WindowsResolver(dirs);
25
+ } else {
26
+ return new Resolver(dirs);
27
+ }
28
+ }
25
29
  #dirs;
26
30
  constructor(dirs) {
27
31
  this.#dirs = dirs;
@@ -42,6 +46,9 @@ class Resolver {
42
46
  isPagesSubpathInPagesDir(p) {
43
47
  return this.isProjectSubpathInPagesDir(join(this.#dirs.pages, p));
44
48
  }
49
+ projectPathFromAbsolute(p) {
50
+ return p.replace(this.#dirs.projectRootAbs, "").substring(1);
51
+ }
45
52
  // resolve a pages subpath from a resource within the pages directory by a relative href
46
53
  // `from` is expected to be a pages resource fs path starting with `pages/` and ending with filename
47
54
  // the result will be a pages subpath and will not have the pages dir prefix
@@ -55,6 +62,17 @@ class Resolver {
55
62
  }
56
63
  }
57
64
  }
65
+ class WindowsResolver extends Resolver {
66
+ constructor(dirs) {
67
+ super(dirs);
68
+ }
69
+ projectPathFromAbsolute(p) {
70
+ return super.projectPathFromAbsolute(p).replaceAll("\\", "/");
71
+ }
72
+ resolveHrefInPagesDir(from, href) {
73
+ return super.resolveHrefInPagesDir(from, href).replaceAll("\\", "/");
74
+ }
75
+ }
58
76
  export {
59
77
  Resolver,
60
78
  defaultProjectDirs
package/lib_js/esbuild.js CHANGED
@@ -83,6 +83,7 @@ function workersPlugin(r) {
83
83
  let contents = await readFile(args.path, "utf8");
84
84
  let offset = 0;
85
85
  let errors = void 0;
86
+ let clientScript = void 0;
86
87
  for (const workerCtorMatch of contents.matchAll(WORKER_CTOR_REGEX)) {
87
88
  if (!WORKER_URL_REGEX.test(workerCtorMatch.groups.url)) {
88
89
  if (!errors)
@@ -93,7 +94,9 @@ function workersPlugin(r) {
93
94
  if (isIndexCommented(contents, workerCtorMatch.index)) {
94
95
  continue;
95
96
  }
96
- const clientScript = args.path.replace(r.dirs.projectResolved, "").substring(1);
97
+ if (!clientScript) {
98
+ clientScript = r.resolver.projectPathFromAbsolute(args.path);
99
+ }
97
100
  const workerUrl = workerCtorMatch.groups.url.substring(1, workerCtorMatch.groups.url.length - 1);
98
101
  const workerEntryPoint = r.resolver.resolveHrefInPagesDir(clientScript, workerUrl);
99
102
  if (workerEntryPoint === "outofbounds") {
@@ -103,7 +106,7 @@ function workersPlugin(r) {
103
106
  continue;
104
107
  }
105
108
  const workerCtor = workerCtorMatch.groups.ctor;
106
- const workerUrlPlaceholder = workerEntryPoint.replace(/^pages/, "").replace(/\.(t|m?j)s$/, ".js");
109
+ const workerUrlPlaceholder = workerEntryPoint.replace(/^pages/, "").replace(/\.(t|m?j)s$/, ".js").replaceAll("\\", "/");
107
110
  const workerCtorReplacement = `new ${workerCtor}('${workerUrlPlaceholder}'${workerCtorMatch.groups.end}`;
108
111
  contents = contents.substring(0, workerCtorMatch.index + offset) + workerCtorReplacement + contents.substring(workerCtorMatch.index + workerCtorMatch[0].length + offset);
109
112
  offset += workerCtorReplacement.length - workerCtorMatch[0].length;
package/lib_js/html.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import EventEmitter from "node:events";
2
2
  import { readFile } from "node:fs/promises";
3
- import { dirname, isAbsolute, join, relative, resolve } from "node:path";
3
+ import { dirname, isAbsolute, relative, resolve } from "node:path";
4
+ import { join } from "node:path/posix";
4
5
  import { extname } from "node:path/posix";
5
6
  import { defaultTreeAdapter, parse, parseFragment, serialize } from "parse5";
6
7
  import { DankError } from "./errors.js";
@@ -1,6 +1,6 @@
1
1
  import EventEmitter from "node:events";
2
2
  import { writeFile } from "node:fs/promises";
3
- import { join } from "node:path";
3
+ import { join } from "node:path/posix";
4
4
  import { Resolver } from "./dirs.js";
5
5
  import { HtmlEntrypoint } from "./html.js";
6
6
  class WebsiteRegistry extends EventEmitter {
@@ -17,7 +17,7 @@ class WebsiteRegistry extends EventEmitter {
17
17
  constructor(config) {
18
18
  super();
19
19
  this.#c = config;
20
- this.#resolver = new Resolver(config.dirs);
20
+ this.#resolver = Resolver.create(config.dirs);
21
21
  }
22
22
  get config() {
23
23
  return this.#c;
@@ -132,6 +132,7 @@ class WebsiteRegistry extends EventEmitter {
132
132
  };
133
133
  html.on("entrypoints", (entrypoints) => this.#setWebpageBundles(html.url, entrypoints));
134
134
  this.emit("webpage", html);
135
+ html.emit("change");
135
136
  }
136
137
  #configPageUpdate(urlPath, mapping) {
137
138
  const existingRegistration = this.#pages[urlPath];
@@ -218,7 +219,6 @@ class BuildRegistry {
218
219
  get resolver() {
219
220
  return this.#resolver;
220
221
  }
221
- // resolve web worker imported by a webpage module
222
222
  addWorker(worker) {
223
223
  if (!this.#workers) {
224
224
  this.#workers = [worker];
package/lib_js/serve.js CHANGED
@@ -36,7 +36,7 @@ async function startDevMode(signal) {
36
36
  const registry = new WebsiteRegistry(c);
37
37
  await mkdir(c.dirs.buildWatch, { recursive: true });
38
38
  let buildContext = null;
39
- watch("dank.config.ts", signal, async () => {
39
+ watch("dank.config.ts", signal, async (filename) => {
40
40
  try {
41
41
  await c.reload();
42
42
  } catch (ignore) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eighty4/dank",
3
- "version": "0.0.4-3",
3
+ "version": "0.0.5-0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "author": "Adam McKee Bennett <adam.be.g84d@gmail.com>",
@@ -46,7 +46,7 @@
46
46
  "build": "pnpm build:client && pnpm build:lib",
47
47
  "build:client": "node scripts/build_client.ts",
48
48
  "build:lib": "tsc && tsc -p tsconfig.exports.json",
49
- "build:release": "pnpm build && ./scripts/prepare_release.ts",
49
+ "build:release": "pnpm build && node scripts/prepare_release.ts",
50
50
  "fmt": "prettier --write .",
51
51
  "fmtcheck": "prettier --check .",
52
52
  "test": "node --test \"test/**/*.test.ts\"",