@quillmark/quiver 0.4.1 → 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/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  export { QuiverError } from "./errors.js";
2
2
  export type { QuiverErrorCode } from "./errors.js";
3
3
  export { Quiver } from "./quiver.js";
4
- export type { BuildOptions } from "./build.js";
5
4
  export type { QuillmarkLike, QuillLike } from "./engine-types.js";
package/dist/index.js CHANGED
@@ -1,3 +1,7 @@
1
1
  // Main browser-safe entrypoint.
2
+ //
3
+ // Exposes only browser-safe surface. Node-only factories
4
+ // (`Quiver.fromDir`, `fromPackage`, `build`) and the `BuildOptions` type
5
+ // live at `@quillmark/quiver/node`.
2
6
  export { QuiverError } from "./errors.js";
3
7
  export { Quiver } from "./quiver.js";
package/dist/node.d.ts CHANGED
@@ -1 +1,57 @@
1
- export * from "./index.js";
1
+ /**
2
+ * Node-only entrypoint.
3
+ *
4
+ * Importing this module is the consumer's explicit declaration of intent:
5
+ * "I am running in Node and want the Node-only Quiver factories." It exposes
6
+ * the same `Quiver` class as the main entry, augmented with `fromDir`,
7
+ * `fromPackage`, and `build` static methods.
8
+ *
9
+ * Side effect: at module evaluation time, the Node-only static methods are
10
+ * installed on the shared `Quiver` constructor. Any other module that already
11
+ * imports `Quiver` from the main entry will see the additional methods at
12
+ * runtime — but TypeScript will only expose them on the binding imported from
13
+ * here, so the import path remains the contract.
14
+ *
15
+ * Bundler note: importing this entry pulls in `./source-loader.js` and
16
+ * `./build.js`, both of which statically import `node:*` builtins. Browser
17
+ * bundles must never reach this module. The main entry (`./index.js`) makes
18
+ * no static or dynamic reference to it.
19
+ */
20
+ import { Quiver as Base } from "./quiver.js";
21
+ import { type BuildOptions } from "./build.js";
22
+ type NodeQuiverStatics = {
23
+ /**
24
+ * Resolves an npm specifier against `node_modules` and loads the source
25
+ * layout at the package root. The resolved package must have `Quiver.yaml`
26
+ * at its root.
27
+ *
28
+ * Throws `transport_error` on resolution/I/O failure, `quiver_invalid` on
29
+ * schema violations.
30
+ */
31
+ fromPackage(specifier: string): Promise<Base>;
32
+ /**
33
+ * Reads a Source Quiver from a local directory containing `Quiver.yaml`
34
+ * and `quills/<name>/<version>/Quill.yaml` entries.
35
+ *
36
+ * Also accepts `import.meta.url`-style `file://` URLs as a convenience for
37
+ * tests; the URL's parent directory is used as the source root.
38
+ *
39
+ * Throws `quiver_invalid` on schema violations, `transport_error` on I/O
40
+ * failure.
41
+ */
42
+ fromDir(pathOrFileUrl: string): Promise<Base>;
43
+ /**
44
+ * Reads the Source Quiver at sourceDir, validates it, and writes the
45
+ * runtime build artifact to outDir.
46
+ *
47
+ * Throws `quiver_invalid` on source validation failures, `transport_error`
48
+ * on I/O failures.
49
+ */
50
+ build(sourceDir: string, outDir: string, opts?: BuildOptions): Promise<void>;
51
+ };
52
+ export type Quiver = Base;
53
+ export declare const Quiver: typeof Base & NodeQuiverStatics;
54
+ export { QuiverError } from "./errors.js";
55
+ export type { QuiverErrorCode } from "./errors.js";
56
+ export type { BuildOptions } from "./build.js";
57
+ export type { QuillmarkLike, QuillLike } from "./engine-types.js";
package/dist/node.js CHANGED
@@ -1,5 +1,55 @@
1
- // Node-only entrypoint.
2
- // Re-export everything from the main browser-safe entrypoint.
3
- // Node-only factories (fromPackage, fromDir, build) are methods on
4
- // Quiver itself no additional exports are needed here.
5
- export * from "./index.js";
1
+ /**
2
+ * Node-only entrypoint.
3
+ *
4
+ * Importing this module is the consumer's explicit declaration of intent:
5
+ * "I am running in Node and want the Node-only Quiver factories." It exposes
6
+ * the same `Quiver` class as the main entry, augmented with `fromDir`,
7
+ * `fromPackage`, and `build` static methods.
8
+ *
9
+ * Side effect: at module evaluation time, the Node-only static methods are
10
+ * installed on the shared `Quiver` constructor. Any other module that already
11
+ * imports `Quiver` from the main entry will see the additional methods at
12
+ * runtime — but TypeScript will only expose them on the binding imported from
13
+ * here, so the import path remains the contract.
14
+ *
15
+ * Bundler note: importing this entry pulls in `./source-loader.js` and
16
+ * `./build.js`, both of which statically import `node:*` builtins. Browser
17
+ * bundles must never reach this module. The main entry (`./index.js`) makes
18
+ * no static or dynamic reference to it.
19
+ */
20
+ import { Quiver as Base } from "./quiver.js";
21
+ import { QuiverError } from "./errors.js";
22
+ import { scanSourceQuiver, SourceLoader } from "./source-loader.js";
23
+ import { buildQuiver } from "./build.js";
24
+ import { createRequire } from "node:module";
25
+ import { dirname } from "node:path";
26
+ import { fileURLToPath } from "node:url";
27
+ export const Quiver = Base;
28
+ // ---------------------------------------------------------------------------
29
+ // 2. Runtime patch — install Node-only statics on the shared class.
30
+ // ---------------------------------------------------------------------------
31
+ Quiver.fromDir = async function fromDir(pathOrFileUrl) {
32
+ const dir = pathOrFileUrl.startsWith("file://")
33
+ ? fileURLToPath(new URL(".", pathOrFileUrl))
34
+ : pathOrFileUrl;
35
+ const { meta, catalog } = await scanSourceQuiver(dir);
36
+ return Base._fromLoader(meta.name, catalog, new SourceLoader(dir));
37
+ };
38
+ Quiver.fromPackage = async function fromPackage(specifier) {
39
+ const req = createRequire(import.meta.url);
40
+ let yamlPath;
41
+ try {
42
+ yamlPath = req.resolve(`${specifier}/Quiver.yaml`);
43
+ }
44
+ catch (err) {
45
+ throw new QuiverError("transport_error", `Failed to resolve quiver package "${specifier}": ${err.message}`, { cause: err });
46
+ }
47
+ return Quiver.fromDir(dirname(yamlPath));
48
+ };
49
+ Quiver.build = async function build(sourceDir, outDir, opts) {
50
+ return buildQuiver(sourceDir, outDir, opts);
51
+ };
52
+ // ---------------------------------------------------------------------------
53
+ // 3. Re-export the rest of the public surface so consumers get one import.
54
+ // ---------------------------------------------------------------------------
55
+ export { QuiverError } from "./errors.js";
package/dist/quiver.d.ts CHANGED
@@ -3,8 +3,12 @@
3
3
  *
4
4
  * Polymorphism via composition: internally stores a pluggable loader
5
5
  * (either source-backed or build-output-backed).
6
+ *
7
+ * This module is browser-safe: only `fromBuilt` and the instance API live
8
+ * here. Node-only factories (`fromDir`, `fromPackage`, `build`) are installed
9
+ * on this class by `./node.js`, which is the consumer's explicit opt-in to
10
+ * the Node API surface.
6
11
  */
7
- import type { BuildOptions } from "./build.js";
8
12
  import type { QuillmarkLike, QuillLike } from "./engine-types.js";
9
13
  /** @internal Internal loader strategy: source or build output. */
10
14
  export interface QuiverLoader {
@@ -14,33 +18,18 @@ export declare class Quiver {
14
18
  #private;
15
19
  readonly name: string;
16
20
  /**
17
- * Private constructor — use static factory methods.
18
- * TS prevents external `new Quiver(...)` at compile time.
19
- * Static methods inside can still call it.
21
+ * Private constructor — use static factory methods (`Quiver.fromBuilt`, or
22
+ * the Node-only `Quiver.fromDir` / `Quiver.fromPackage` installed by
23
+ * `@quillmark/quiver/node`). TS prevents external `new Quiver(...)` at
24
+ * compile time.
20
25
  */
21
26
  private constructor();
22
- /** @internal Used by loadBuiltQuiver. Not part of the public API. */
23
- static _fromLoader(name: string, catalog: Map<string, string[]>, loader: QuiverLoader): Quiver;
24
27
  /**
25
- * Node-only factory. Resolves an npm specifier against `node_modules` and
26
- * loads the source layout at the package root.
27
- *
28
- * The resolved package must have `Quiver.yaml` at its root.
29
- *
30
- * Throws `transport_error` on resolution/I/O failure, `quiver_invalid`
31
- * on schema violations.
28
+ * @internal Construction escape hatch around the private constructor. Used
29
+ * by `loadBuiltQuiver` and by the Node entry (`./node.js`) when installing
30
+ * `fromDir` / `fromPackage`. Not part of the public API.
32
31
  */
33
- static fromPackage(specifier: string): Promise<Quiver>;
34
- /**
35
- * Node-only factory. Reads a Source Quiver from a local directory containing
36
- * `Quiver.yaml` and `quills/<name>/<version>/Quill.yaml` entries.
37
- *
38
- * Also accepts `import.meta.url`-style `file://` URLs as a convenience for
39
- * tests; the URL's parent directory is used as the source root.
40
- *
41
- * Throws `quiver_invalid` on schema violations, `transport_error` on I/O failure.
42
- */
43
- static fromDir(pathOrFileUrl: string): Promise<Quiver>;
32
+ static _fromLoader(name: string, catalog: Map<string, string[]>, loader: QuiverLoader): Quiver;
44
33
  /**
45
34
  * Browser-safe factory. Loads build output from an HTTP/HTTPS URL.
46
35
  *
@@ -60,17 +49,6 @@ export declare class Quiver {
60
49
  * Returns an empty array if the quill name is not in the catalog.
61
50
  */
62
51
  versionsOf(name: string): string[];
63
- /**
64
- * Node-only tooling. Reads the Source Quiver at sourceDir, validates it,
65
- * and writes the runtime build artifact to outDir.
66
- *
67
- * Uses dynamic import of `./build.js` so that this module stays
68
- * browser-safe at evaluation time.
69
- *
70
- * Throws `quiver_invalid` on source validation failures,
71
- * `transport_error` on I/O failures.
72
- */
73
- static build(sourceDir: string, outDir: string, opts?: BuildOptions): Promise<void>;
74
52
  /**
75
53
  * Lazily loads the file tree for a specific quill version.
76
54
  *
package/dist/quiver.js CHANGED
@@ -3,9 +3,13 @@
3
3
  *
4
4
  * Polymorphism via composition: internally stores a pluggable loader
5
5
  * (either source-backed or build-output-backed).
6
+ *
7
+ * This module is browser-safe: only `fromBuilt` and the instance API live
8
+ * here. Node-only factories (`fromDir`, `fromPackage`, `build`) are installed
9
+ * on this class by `./node.js`, which is the consumer's explicit opt-in to
10
+ * the Node API surface.
6
11
  */
7
12
  import { QuiverError } from "./errors.js";
8
- import { assertNode } from "./assert-node.js";
9
13
  import { parseQuillRef } from "./ref.js";
10
14
  import { matchesSemverSelector, chooseHighestVersion } from "./semver.js";
11
15
  export class Quiver {
@@ -25,62 +29,23 @@ export class Quiver {
25
29
  */
26
30
  #treeCache = new Map();
27
31
  /**
28
- * Private constructor — use static factory methods.
29
- * TS prevents external `new Quiver(...)` at compile time.
30
- * Static methods inside can still call it.
32
+ * Private constructor — use static factory methods (`Quiver.fromBuilt`, or
33
+ * the Node-only `Quiver.fromDir` / `Quiver.fromPackage` installed by
34
+ * `@quillmark/quiver/node`). TS prevents external `new Quiver(...)` at
35
+ * compile time.
31
36
  */
32
37
  constructor(name, catalog, loader) {
33
38
  this.name = name;
34
39
  this.#catalog = new Map(catalog);
35
40
  this.#loader = loader;
36
41
  }
37
- /** @internal Used by loadBuiltQuiver. Not part of the public API. */
38
- static _fromLoader(name, catalog, loader) {
39
- return new Quiver(name, catalog, loader);
40
- }
41
42
  /**
42
- * Node-only factory. Resolves an npm specifier against `node_modules` and
43
- * loads the source layout at the package root.
44
- *
45
- * The resolved package must have `Quiver.yaml` at its root.
46
- *
47
- * Throws `transport_error` on resolution/I/O failure, `quiver_invalid`
48
- * on schema violations.
43
+ * @internal Construction escape hatch around the private constructor. Used
44
+ * by `loadBuiltQuiver` and by the Node entry (`./node.js`) when installing
45
+ * `fromDir` / `fromPackage`. Not part of the public API.
49
46
  */
50
- static async fromPackage(specifier) {
51
- assertNode("Quiver.fromPackage");
52
- const { createRequire } = await import("node:module");
53
- const { dirname } = await import("node:path");
54
- const req = createRequire(import.meta.url);
55
- let yamlPath;
56
- try {
57
- yamlPath = req.resolve(`${specifier}/Quiver.yaml`);
58
- }
59
- catch (err) {
60
- throw new QuiverError("transport_error", `Failed to resolve quiver package "${specifier}": ${err.message}`, { cause: err });
61
- }
62
- return Quiver.fromDir(dirname(yamlPath));
63
- }
64
- /**
65
- * Node-only factory. Reads a Source Quiver from a local directory containing
66
- * `Quiver.yaml` and `quills/<name>/<version>/Quill.yaml` entries.
67
- *
68
- * Also accepts `import.meta.url`-style `file://` URLs as a convenience for
69
- * tests; the URL's parent directory is used as the source root.
70
- *
71
- * Throws `quiver_invalid` on schema violations, `transport_error` on I/O failure.
72
- */
73
- static async fromDir(pathOrFileUrl) {
74
- assertNode("Quiver.fromDir");
75
- let dir = pathOrFileUrl;
76
- if (pathOrFileUrl.startsWith("file://")) {
77
- const { fileURLToPath } = await import("node:url");
78
- dir = fileURLToPath(new URL(".", pathOrFileUrl));
79
- }
80
- const { scanSourceQuiver, SourceLoader } = await import("./source-loader.js");
81
- const { meta, catalog } = await scanSourceQuiver(dir);
82
- const loader = new SourceLoader(dir);
83
- return new Quiver(meta.name, catalog, loader);
47
+ static _fromLoader(name, catalog, loader) {
48
+ return new Quiver(name, catalog, loader);
84
49
  }
85
50
  /**
86
51
  * Browser-safe factory. Loads build output from an HTTP/HTTPS URL.
@@ -113,21 +78,6 @@ export class Quiver {
113
78
  versionsOf(name) {
114
79
  return [...(this.#catalog.get(name) ?? [])];
115
80
  }
116
- /**
117
- * Node-only tooling. Reads the Source Quiver at sourceDir, validates it,
118
- * and writes the runtime build artifact to outDir.
119
- *
120
- * Uses dynamic import of `./build.js` so that this module stays
121
- * browser-safe at evaluation time.
122
- *
123
- * Throws `quiver_invalid` on source validation failures,
124
- * `transport_error` on I/O failures.
125
- */
126
- static async build(sourceDir, outDir, opts) {
127
- assertNode("Quiver.build");
128
- const { buildQuiver } = await import("./build.js");
129
- return buildQuiver(sourceDir, outDir, opts);
130
- }
131
81
  /**
132
82
  * Lazily loads the file tree for a specific quill version.
133
83
  *
package/dist/testing.js CHANGED
@@ -15,7 +15,10 @@
15
15
  * Run with `node --test`.
16
16
  */
17
17
  import { describe, it, before } from "node:test";
18
- import { Quiver } from "./quiver.js";
18
+ // Import from the Node entry: this installs the runtime patch so
19
+ // `Quiver.fromDir` is callable at runtime, and gives us the augmented
20
+ // static-method type signature.
21
+ import { Quiver } from "./node.js";
19
22
  /**
20
23
  * Registers a `node:test` describe block that validates every quill
21
24
  * version in the quiver at `metaUrlOrDir` against the provided engine.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quillmark/quiver",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Quiver registry and build tooling for Quillmark",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -36,6 +36,10 @@
36
36
  "import": "./dist/testing.js"
37
37
  }
38
38
  },
39
+ "sideEffects": [
40
+ "./dist/node.js",
41
+ "./dist/testing.js"
42
+ ],
39
43
  "files": [
40
44
  "dist",
41
45
  "PROGRAM.md",
@@ -1,5 +0,0 @@
1
- /**
2
- * Throws a `transport_error` when called outside a Node.js environment.
3
- * Call at the top of each Node-only static factory to fail fast in browsers.
4
- */
5
- export declare function assertNode(method: string): void;
@@ -1,12 +0,0 @@
1
- import { QuiverError } from "./errors.js";
2
- /**
3
- * Throws a `transport_error` when called outside a Node.js environment.
4
- * Call at the top of each Node-only static factory to fail fast in browsers.
5
- */
6
- export function assertNode(method) {
7
- if (typeof globalThis.process === "undefined" ||
8
- !globalThis.process
9
- ?.versions?.node) {
10
- throw new QuiverError("transport_error", `${method} is only available in Node.js`);
11
- }
12
- }