This repository has been archived by the owner on Jun 29, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 624
/
Copy pathdoc_utils.ts
122 lines (115 loc) · 3.63 KB
/
doc_utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// Copyright 2022-2023 the Deno authors. All rights reserved. MIT license.
import type { SymbolIndexItem } from "$apiland_types";
interface GlobalSymbolItem {
name: string;
library: "esnext" | "deno";
unstable?: boolean;
}
const GLOBAL_SYMBOLS_ENDPOINT = "https://apiland.deno.dev/v2/symbols/global";
const GLOBAL_SYMBOLS_INIT = { headers: { "accept": "application/json" } };
const currentSymbols = new Set<string>();
const currentImports = new Map<string, string>();
const globalSymbols = new Map<string, "esnext" | "deno" | "deno-unstable">();
/** Called to set/clear the current symbol information, so when symbol lookups
* occur, they have the correct information to resolve the link. */
export async function setSymbols(symbols?: SymbolIndexItem[]): Promise<void> {
if (!globalSymbols.size) {
try {
const res = await fetch(GLOBAL_SYMBOLS_ENDPOINT, GLOBAL_SYMBOLS_INIT);
if (res.status === 200) {
const globalSymbolItems: GlobalSymbolItem[] = await res.json();
for (const { name, library, unstable } of globalSymbolItems) {
globalSymbols.set(
name,
library === "esnext"
? "esnext"
: unstable
? "deno-unstable"
: "deno",
);
}
} else {
throw new Error(
`Unexpected fetch response: ${res.status} ${res.statusText}`,
);
}
} catch (e) {
console.error(e);
globalSymbols.set("__failed__", "deno");
}
}
currentSymbols.clear();
currentImports.clear();
if (symbols) {
for (const { name, declarationKind, kind, filename } of symbols) {
if (declarationKind === "export") {
currentSymbols.add(name);
} else if (kind === "import") {
currentImports.set(name, filename);
}
}
}
}
function globalSymbolHref(current: URL, symbol: string) {
const lib = globalSymbols.get(symbol)!;
if (lib !== "esnext") {
const target = new URL(current);
target.pathname = "/api";
target.search = "";
target.searchParams.set("s", symbol);
target.searchParams.delete("p");
if (lib === "deno-unstable") {
target.searchParams.set("unstable", "");
}
return target.href;
}
}
/** Provided the current URL, current namespace, and symbol, attempt to resolve
* a link to the symbol. */
export function lookupSymbol(
current: URL,
namespace: string | undefined,
symbol: string,
): string | undefined {
if (namespace) {
const parts = namespace.split(".");
while (parts.length) {
const name = [...parts, symbol].join(".");
if (currentSymbols.size) {
if (currentSymbols.has(name)) {
const target = new URL(current);
target.searchParams.set("s", name);
target.searchParams.delete("p");
return target.href;
}
} else {
if (globalSymbols.has(name)) {
return globalSymbolHref(current, name);
}
}
parts.pop();
}
}
if (currentSymbols.has(symbol)) {
const target = new URL(current);
target.searchParams.set("s", symbol);
target.searchParams.delete("p");
return target.href;
}
if (currentImports.has(symbol)) {
const src = currentImports.get(symbol)!;
const srcURL = new URL(src);
if (src.startsWith("https://deno.land/")) {
srcURL.searchParams.set("s", symbol);
return srcURL.href;
} else {
// other sources, we will attempt to send them to docland for
// documentation
srcURL.pathname += `/~/${symbol}`;
return `https://doc.deno.land/${srcURL.toString()}`;
}
}
if (globalSymbols.has(symbol)) {
return globalSymbolHref(current, symbol);
}
}