Skip to content

Commit

Permalink
fix: properly resolve imported types
Browse files Browse the repository at this point in the history
The default resolver is not compatible with the Node.js resolution
algorithm, so we need to provide a custom resolver (which can be
extended by the user to resolve types from a dependency).
  • Loading branch information
darrachequesne committed Nov 11, 2022
1 parent a37d6ad commit 7ac8e25
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 1 deletion.
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,40 @@ console.log(nodes[0]);
}
*/
```
## Advanced
### Resolve types from a dependency
`product.ts`
```ts
import { Reference } from "my-dependency";

/**
* This is a product
*/
export interface Product {
id: string;
ref: Reference;
}
```
To resolve the types from a dependency, you need to provide a custom `resolve` method:
```js
import { doc, defaultResolver } from "tsdoc-extractor";

const url = new URL("product.ts", import.meta.url).toString();
const nodes = await doc(url, {
resolve: function (specifier, referrer) {
if (specifier === "my-dependency") {
return "file:///Projects/my-project/node_modules/my-dependency/dist/index.d.ts";
// or "file:///Projects/my-project/node_modules/my-dependency/index.ts";
// or "file:///Projects/my-project/node_modules/@types/my-dependency/index.d.ts";
} else {
return defaultResolver(specifier, referrer);
}
}
});
```
1 change: 1 addition & 0 deletions src/dummy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// this is a dummy reference
26 changes: 25 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { instantiate } from "./deno_doc/deno_doc.generated.js";
import { readFile } from "node:fs/promises";
import { parse } from "node:path";

/**
* Asynchronously generate an array of documentation nodes for the supplied
Expand All @@ -25,7 +26,7 @@ export async function doc(specifier, options = {}) {
const {
load = defaultLoader,
includeAll = false,
resolve,
resolve = defaultResolver,
importMap,
} = options;
const wasm = await instantiate();
Expand Down Expand Up @@ -71,3 +72,26 @@ async function defaultLoader(specifier) {
}
}
}

function normalize(specifier) {
const path = parse(specifier);
switch (path.ext) {
case ".js":
return specifier.slice(0, -3) + ".ts";
case ".ts":
return specifier;
default:
return specifier + ".ts";
}
}

export function defaultResolver(specifier, referrer) {
const isRelativeImport = specifier.startsWith(".");
if (isRelativeImport) {
return new URL(normalize(specifier), referrer).toString();
} else {
// note: we could also point towards the dependency in the node_modules directory (or use the definitions from the
// "@types/<module>" package), but the resolution mechanism is a bit tricky
return new URL("dummy.js", import.meta.url).toString();
}
}
12 changes: 12 additions & 0 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,16 @@ describe("tsdoc-extractor", () => {

assert.lengthOf(nodes, 48);
});

it("should resolve imported modules", async () => {
const url = new URL("resolve.ts", import.meta.url).toString();
const nodes = await doc(url);

assert.lengthOf(nodes, 5);

const node = nodes[0];
assert.equal(node.kind, "interface");
assert.oneOf(node.name, ["Product", "OtherProduct"]);
assert.equal(node.declarationKind, "export");
});
});
5 changes: 5 additions & 0 deletions test/resolve.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { type Product } from "./product";
import { type Product as OtherProduct } from "./product.js";
import { type HookFunction } from "mocha";

export { Product, OtherProduct, HookFunction };

0 comments on commit 7ac8e25

Please sign in to comment.