@tsdoctor/model 0.1.0 → 0.2.1
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/ApiItems.js +111 -0
- package/CrossLinker.js +81 -0
- package/EntryPoints.js +76 -0
- package/Model.js +90 -0
- package/README.md +55 -52
- package/Render.js +182 -0
- package/Routes.js +110 -0
- package/Signature.js +100 -0
- package/StructuredData.js +18 -0
- package/SyntheticBases.js +83 -0
- package/Tsdoc.js +250 -0
- package/_virtual/_rolldown/runtime.js +18 -0
- package/index.d.ts +477 -66
- package/index.js +11 -6
- package/internal/prose.js +18 -0
- package/internal/text.js +11 -0
- package/package.json +11 -1
- package/cross-linker.js +0 -37
- package/formatter.js +0 -70
- package/model-loader.js +0 -24
- package/render.js +0 -118
- package/tsdoc.js +0 -158
package/internal/text.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/internal/text.ts
|
|
2
|
+
/**
|
|
3
|
+
* Shared private text helpers.
|
|
4
|
+
*
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
/** Escape a literal string for embedding in a RegExp pattern. */
|
|
8
|
+
const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
export { escapeRegExp };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tsdoctor/model",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Render Microsoft API Extractor models into LLM-lean markdown. Pure model loading, TSDoc extraction, type-signature formatting, and per-item markdown rendering.",
|
|
6
6
|
"keywords": [
|
|
@@ -41,6 +41,16 @@
|
|
|
41
41
|
"@microsoft/api-extractor-model": "^7.33.10",
|
|
42
42
|
"@microsoft/tsdoc": "^0.16.0"
|
|
43
43
|
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"@effected/markdown": "^0.7.0",
|
|
46
|
+
"@effected/package-json": "^0.12.0",
|
|
47
|
+
"effect": "4.0.0-rc.109"
|
|
48
|
+
},
|
|
49
|
+
"peerDependenciesMeta": {
|
|
50
|
+
"@effected/package-json": {
|
|
51
|
+
"optional": true
|
|
52
|
+
}
|
|
53
|
+
},
|
|
44
54
|
"engines": {
|
|
45
55
|
"node": ">=24.11.0"
|
|
46
56
|
}
|
package/cross-linker.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
//#region src/cross-linker.ts
|
|
2
|
-
const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3
|
-
/**
|
|
4
|
-
* Links known API item names in prose to their docs, using an injected
|
|
5
|
-
* {@link RouteFormatter} so each consumer supplies its own URL scheme.
|
|
6
|
-
*
|
|
7
|
-
* @public
|
|
8
|
-
*/
|
|
9
|
-
var CrossLinker = class {
|
|
10
|
-
byName;
|
|
11
|
-
routeFor;
|
|
12
|
-
constructor(refs, routeFor) {
|
|
13
|
-
this.byName = new Map(refs.map((r) => [r.name, r]));
|
|
14
|
-
this.routeFor = routeFor;
|
|
15
|
-
}
|
|
16
|
-
/** Wrap known item names in markdown links, skipping code spans + existing links. */
|
|
17
|
-
addLinks(text) {
|
|
18
|
-
let result = text;
|
|
19
|
-
const names = [...this.byName.keys()].sort((a, b) => b.length - a.length);
|
|
20
|
-
for (const name of names) {
|
|
21
|
-
const ref = this.byName.get(name);
|
|
22
|
-
if (!ref) continue;
|
|
23
|
-
const route = this.routeFor(ref);
|
|
24
|
-
const regex = new RegExp(`\\b${escapeRegExp(name)}\\b`, "g");
|
|
25
|
-
result = result.replace(regex, (match, offset) => {
|
|
26
|
-
const before = result.slice(0, offset);
|
|
27
|
-
if (before.endsWith("](") || before.endsWith("[")) return match;
|
|
28
|
-
if ((before.match(/`/g) || []).length % 2 === 1) return match;
|
|
29
|
-
return `[${match}](${route})`;
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
return result;
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
//#endregion
|
|
37
|
-
export { CrossLinker };
|
package/formatter.js
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
//#region src/formatter.ts
|
|
2
|
-
/**
|
|
3
|
-
* Formats an API Extractor `Excerpt` into a clean, line-wrapped type signature string.
|
|
4
|
-
*
|
|
5
|
-
* @public
|
|
6
|
-
*/
|
|
7
|
-
var TypeSignatureFormatter = class {
|
|
8
|
-
maxLineLength;
|
|
9
|
-
indent;
|
|
10
|
-
constructor(opts = {}) {
|
|
11
|
-
this.maxLineLength = opts.maxLineLength ?? 80;
|
|
12
|
-
this.indent = opts.indent ?? " ";
|
|
13
|
-
}
|
|
14
|
-
format(excerpt) {
|
|
15
|
-
if (!excerpt.spannedTokens || excerpt.spannedTokens.length === 0) return this.stripExportDeclare(excerpt.text);
|
|
16
|
-
const tokens = excerpt.spannedTokens;
|
|
17
|
-
let currentLine = "";
|
|
18
|
-
const lines = [];
|
|
19
|
-
let bracketDepth = 0;
|
|
20
|
-
let lastTokenText = "";
|
|
21
|
-
for (let i = 0; i < tokens.length; i++) {
|
|
22
|
-
let tokenText = tokens[i].text;
|
|
23
|
-
if (i === 0) tokenText = this.stripExportDeclare(tokenText);
|
|
24
|
-
if (tokenText.trim() === "") continue;
|
|
25
|
-
if (tokenText === "{" || tokenText === "[" || tokenText === "(") bracketDepth++;
|
|
26
|
-
else if (tokenText === "}" || tokenText === "]" || tokenText === ")") bracketDepth--;
|
|
27
|
-
const isOperator = tokenText.trim() === "|" || tokenText.trim() === "&";
|
|
28
|
-
if (lastTokenText && this.needsSpaceBefore(lastTokenText, tokenText)) currentLine += " ";
|
|
29
|
-
currentLine += tokenText;
|
|
30
|
-
lastTokenText = tokenText;
|
|
31
|
-
if (isOperator && bracketDepth === 0 && currentLine.length > this.maxLineLength && i < tokens.length - 1) {
|
|
32
|
-
lines.push(currentLine.trimEnd());
|
|
33
|
-
currentLine = this.indent;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
if (currentLine.trim()) lines.push(currentLine.trimEnd());
|
|
37
|
-
if (lines.length <= 1) return lines.length === 1 ? lines[0].trimStart() : "";
|
|
38
|
-
return this.stripExportDeclare(lines.join("\n"));
|
|
39
|
-
}
|
|
40
|
-
stripExportDeclare(text) {
|
|
41
|
-
let result = text.trim().replace(/^export\s+declare\s+/i, "").replace(/^export\s+/i, "").replace(/^declare\s+/i, "");
|
|
42
|
-
result = result.replace(/\bexport\s+declare\s+/gi, "").replace(/\bexport\s+/gi, "").replace(/\bdeclare\s+/gi, "");
|
|
43
|
-
return result;
|
|
44
|
-
}
|
|
45
|
-
needsSpaceBefore(prevText, currentText) {
|
|
46
|
-
if (/\s$/.test(prevText)) return false;
|
|
47
|
-
if (/^\s/.test(currentText)) return false;
|
|
48
|
-
if (currentText.trim().startsWith("<")) return false;
|
|
49
|
-
if (currentText.trim().match(/^[,;]/)) return false;
|
|
50
|
-
if (prevText.trim().endsWith(",")) return true;
|
|
51
|
-
if (currentText.trim() === "=" || currentText.trim().startsWith("=")) return true;
|
|
52
|
-
if (prevText.trim().endsWith("=")) return true;
|
|
53
|
-
if (currentText.trim() === "|" || currentText.trim() === "&") return true;
|
|
54
|
-
if (prevText.trim() === "|" || prevText.trim() === "&") return true;
|
|
55
|
-
if (prevText.trim() === "{" && currentText.trim() !== "}") return true;
|
|
56
|
-
if (currentText.trim() === "}" && prevText.trim() !== "{") return true;
|
|
57
|
-
if (prevText.trim().match(/^[[(]$/)) return false;
|
|
58
|
-
if (currentText.trim().match(/^[\])]$/)) return false;
|
|
59
|
-
if (prevText.trim().endsWith(":")) return true;
|
|
60
|
-
if (prevText.trim().endsWith("?:")) return true;
|
|
61
|
-
if (currentText.trim().startsWith(":") && !prevText.trim().match(/[,;:?]$/)) return false;
|
|
62
|
-
if (currentText.trim().startsWith("{") && /[a-zA-Z0-9_>]$/.test(prevText.trim())) return true;
|
|
63
|
-
const prevEndsAlnum = /[a-zA-Z0-9_>]$/.test(prevText.trim());
|
|
64
|
-
const currStartsAlnum = /^[a-zA-Z0-9_<]/.test(currentText.trim());
|
|
65
|
-
return prevEndsAlnum && currStartsAlnum;
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
//#endregion
|
|
70
|
-
export { TypeSignatureFormatter };
|
package/model-loader.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import { resolve } from "node:path";
|
|
3
|
-
import { ApiModel } from "@microsoft/api-extractor-model";
|
|
4
|
-
|
|
5
|
-
//#region src/model-loader.ts
|
|
6
|
-
/**
|
|
7
|
-
* Load a Microsoft API Extractor `.api.json` model from disk and return its
|
|
8
|
-
* single `ApiPackage`. Ported from rspress-plugin-api-extractor's ApiModelLoader.
|
|
9
|
-
*
|
|
10
|
-
* @packageDocumentation
|
|
11
|
-
*/
|
|
12
|
-
/**
|
|
13
|
-
* Load a `.api.json` model file and return its first (only) package.
|
|
14
|
-
*
|
|
15
|
-
* @public
|
|
16
|
-
*/
|
|
17
|
-
async function loadApiModel(modelPath) {
|
|
18
|
-
const resolved = resolve(modelPath);
|
|
19
|
-
if (!existsSync(resolved)) throw new Error(`API model file not found: ${resolved}`);
|
|
20
|
-
return new ApiModel().loadPackage(resolved);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
//#endregion
|
|
24
|
-
export { loadApiModel };
|
package/render.js
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { CrossLinker } from "./cross-linker.js";
|
|
2
|
-
import { TypeSignatureFormatter } from "./formatter.js";
|
|
3
|
-
import { getDeprecation, getExamples, getParams, getReturns, getSummary } from "./tsdoc.js";
|
|
4
|
-
import { ApiItemContainerMixin } from "@microsoft/api-extractor-model";
|
|
5
|
-
|
|
6
|
-
//#region src/render.ts
|
|
7
|
-
const KIND_SLUG = {
|
|
8
|
-
Class: "class",
|
|
9
|
-
Interface: "interface",
|
|
10
|
-
Function: "function",
|
|
11
|
-
TypeAlias: "type",
|
|
12
|
-
Variable: "variable",
|
|
13
|
-
Enum: "enum",
|
|
14
|
-
Namespace: "namespace"
|
|
15
|
-
};
|
|
16
|
-
/**
|
|
17
|
-
* The default emit rule for {@link renderPackage}: drop compiler-synthetic
|
|
18
|
-
* forgotten exports — items the model retains only because API Extractor ran with
|
|
19
|
-
* `includeForgottenExports: true` (e.g. the `*_base` classes TypeScript hoists for
|
|
20
|
-
* Effect class mixins). Those carry `isExported === false` on `ApiExportedMixin`.
|
|
21
|
-
* Every other item, including any lacking the flag, is kept.
|
|
22
|
-
*
|
|
23
|
-
* @public
|
|
24
|
-
*/
|
|
25
|
-
const isEmittable = (item) => item.isExported !== false;
|
|
26
|
-
const formatter = new TypeSignatureFormatter();
|
|
27
|
-
const signatureOf = (item) => {
|
|
28
|
-
const declared = item;
|
|
29
|
-
return declared.excerpt?.text ? formatter.format(declared.excerpt).trim() : "";
|
|
30
|
-
};
|
|
31
|
-
/**
|
|
32
|
-
* Render one API item to a markdown body (no frontmatter).
|
|
33
|
-
*
|
|
34
|
-
* @public
|
|
35
|
-
*/
|
|
36
|
-
function renderItem(item, opts) {
|
|
37
|
-
const link = (text) => opts.crossLinker ? opts.crossLinker.addLinks(text) : text;
|
|
38
|
-
const lines = [`# ${item.displayName}`, ""];
|
|
39
|
-
const deprecation = getDeprecation(item);
|
|
40
|
-
if (deprecation) lines.push(`> **Deprecated:** ${link(deprecation.message)}`, "");
|
|
41
|
-
const summary = getSummary(item);
|
|
42
|
-
if (summary) lines.push(link(summary), "");
|
|
43
|
-
const signature = signatureOf(item);
|
|
44
|
-
if (signature) lines.push("```ts", signature, "```", "");
|
|
45
|
-
const params = getParams(item);
|
|
46
|
-
if (params.length > 0) {
|
|
47
|
-
lines.push("## Parameters", "");
|
|
48
|
-
for (const p of params) {
|
|
49
|
-
const type = p.type ? ` \`${p.type}\`` : "";
|
|
50
|
-
const desc = p.description ? ` — ${link(p.description)}` : "";
|
|
51
|
-
lines.push(`- \`${p.name}\`${type}${desc}`);
|
|
52
|
-
}
|
|
53
|
-
lines.push("");
|
|
54
|
-
}
|
|
55
|
-
const returns = getReturns(item);
|
|
56
|
-
if (returns) lines.push("## Returns", "", link(returns.description), "");
|
|
57
|
-
const members = item.members;
|
|
58
|
-
if (Array.isArray(members) && members.length > 0 && ApiItemContainerMixin.isBaseClassOf(item)) {
|
|
59
|
-
lines.push("## Members", "");
|
|
60
|
-
for (const m of members) {
|
|
61
|
-
const sig = signatureOf(m);
|
|
62
|
-
const mSummary = getSummary(m);
|
|
63
|
-
lines.push(`### ${m.displayName}`, "");
|
|
64
|
-
if (sig) lines.push("```ts", sig, "```", "");
|
|
65
|
-
if (mSummary) lines.push(link(mSummary), "");
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
const examples = getExamples(item);
|
|
69
|
-
if (examples.length > 0) {
|
|
70
|
-
lines.push("## Examples", "");
|
|
71
|
-
for (const ex of examples) lines.push(`\`\`\`${ex.language}`, ex.code, "```", "");
|
|
72
|
-
}
|
|
73
|
-
return `${lines.join("\n").trim()}\n`;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Walk a package's first entry point and assemble one RenderedDoc per top-level member.
|
|
77
|
-
*
|
|
78
|
-
* @public
|
|
79
|
-
*/
|
|
80
|
-
function renderPackage(apiPackage, opts) {
|
|
81
|
-
const entryPoint = apiPackage.entryPoints[0];
|
|
82
|
-
if (!entryPoint) return [];
|
|
83
|
-
const keep = opts.filter ?? isEmittable;
|
|
84
|
-
const pairs = [];
|
|
85
|
-
for (const member of entryPoint.members) {
|
|
86
|
-
const kind = KIND_SLUG[member.kind];
|
|
87
|
-
if (kind === void 0) continue;
|
|
88
|
-
if (!keep(member)) continue;
|
|
89
|
-
pairs.push({
|
|
90
|
-
item: member,
|
|
91
|
-
ref: {
|
|
92
|
-
name: member.displayName,
|
|
93
|
-
kind,
|
|
94
|
-
slug: member.displayName.toLowerCase()
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
const crossLinker = opts.routeFor ? new CrossLinker(pairs.map((p) => p.ref), opts.routeFor) : void 0;
|
|
99
|
-
return pairs.map(({ item, ref }) => {
|
|
100
|
-
const body = renderItem(item, {
|
|
101
|
-
packageName: opts.packageName,
|
|
102
|
-
...crossLinker ? { crossLinker } : {}
|
|
103
|
-
});
|
|
104
|
-
const meta = {
|
|
105
|
-
...ref,
|
|
106
|
-
summary: getSummary(item),
|
|
107
|
-
packageName: opts.packageName
|
|
108
|
-
};
|
|
109
|
-
const frontmatter = opts.frontmatter ? opts.frontmatter(meta) : "";
|
|
110
|
-
return {
|
|
111
|
-
...meta,
|
|
112
|
-
markdown: frontmatter + body
|
|
113
|
-
};
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
//#endregion
|
|
118
|
-
export { isEmittable, renderItem, renderPackage };
|
package/tsdoc.js
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import { ApiDocumentedItem, ApiReleaseTagMixin, ReleaseTag } from "@microsoft/api-extractor-model";
|
|
2
|
-
|
|
3
|
-
//#region src/tsdoc.ts
|
|
4
|
-
/**
|
|
5
|
-
* Recursively flatten a TSDoc DocNode tree to plain text (code spans → backticks).
|
|
6
|
-
*
|
|
7
|
-
* @public
|
|
8
|
-
*/
|
|
9
|
-
function extractPlainText(node) {
|
|
10
|
-
const nodeAny = node;
|
|
11
|
-
if (node.kind === "PlainText") return nodeAny.text || "";
|
|
12
|
-
if (node.kind === "SoftBreak") return " ";
|
|
13
|
-
if (node.kind === "CodeSpan") return `\`${nodeAny.code || ""}\``;
|
|
14
|
-
if (node.kind === "LinkTag") {
|
|
15
|
-
if (nodeAny.linkText) return extractPlainText(nodeAny.linkText);
|
|
16
|
-
return (nodeAny.codeDestination?.memberReferences?.[0]?.memberIdentifier)?.identifier || "";
|
|
17
|
-
}
|
|
18
|
-
const parts = [];
|
|
19
|
-
if (typeof nodeAny.getChildNodes === "function") for (const child of nodeAny.getChildNodes()) {
|
|
20
|
-
const childText = extractPlainText(child);
|
|
21
|
-
if (childText) parts.push(childText);
|
|
22
|
-
}
|
|
23
|
-
return parts.join("");
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* The TSDoc `@summary` section as a single cleaned line.
|
|
27
|
-
*
|
|
28
|
-
* @public
|
|
29
|
-
*/
|
|
30
|
-
function getSummary(item) {
|
|
31
|
-
if (item instanceof ApiDocumentedItem) {
|
|
32
|
-
const tsdoc = item.tsdocComment;
|
|
33
|
-
if (tsdoc?.summarySection) return extractPlainText(tsdoc.summarySection).replace(/\s+/g, " ").trim();
|
|
34
|
-
}
|
|
35
|
-
return "";
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* `@param` blocks merged with parameter types from the declaration excerpt.
|
|
39
|
-
*
|
|
40
|
-
* @public
|
|
41
|
-
*/
|
|
42
|
-
function getParams(item) {
|
|
43
|
-
const out = [];
|
|
44
|
-
const paramTypes = /* @__PURE__ */ new Map();
|
|
45
|
-
const parameters = item.parameters;
|
|
46
|
-
if (Array.isArray(parameters)) for (const param of parameters) {
|
|
47
|
-
const excerpt = param.parameterTypeExcerpt;
|
|
48
|
-
const name = param.name || "";
|
|
49
|
-
if (excerpt?.text) paramTypes.set(name, String(excerpt.text).trim());
|
|
50
|
-
}
|
|
51
|
-
if (item instanceof ApiDocumentedItem) {
|
|
52
|
-
const tsdoc = item.tsdocComment;
|
|
53
|
-
if (tsdoc?.params) {
|
|
54
|
-
for (const block of tsdoc.params.blocks) {
|
|
55
|
-
const blockAny = block;
|
|
56
|
-
const name = blockAny.parameterName || "";
|
|
57
|
-
const description = extractPlainText(blockAny.content).replace(/\s+/g, " ").trim();
|
|
58
|
-
const type = paramTypes.get(name);
|
|
59
|
-
out.push({
|
|
60
|
-
name,
|
|
61
|
-
...type != null ? { type } : {},
|
|
62
|
-
description
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
return out;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
for (const [name, type] of paramTypes.entries()) out.push({
|
|
69
|
-
name,
|
|
70
|
-
type,
|
|
71
|
-
description: ""
|
|
72
|
-
});
|
|
73
|
-
return out;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* The `@returns` block description, if present.
|
|
77
|
-
*
|
|
78
|
-
* @public
|
|
79
|
-
*/
|
|
80
|
-
function getReturns(item) {
|
|
81
|
-
if (item instanceof ApiDocumentedItem) {
|
|
82
|
-
const tsdoc = item.tsdocComment;
|
|
83
|
-
if (tsdoc?.returnsBlock) {
|
|
84
|
-
const description = extractPlainText(tsdoc.returnsBlock.content).replace(/\s+/g, " ").trim();
|
|
85
|
-
return description.length > 0 ? { description } : null;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* All `@example` fenced-code blocks (falls back to plain text).
|
|
92
|
-
*
|
|
93
|
-
* @public
|
|
94
|
-
*/
|
|
95
|
-
function getExamples(item) {
|
|
96
|
-
const examples = [];
|
|
97
|
-
if (!(item instanceof ApiDocumentedItem)) return examples;
|
|
98
|
-
const tsdoc = item.tsdocComment;
|
|
99
|
-
for (const block of tsdoc?.customBlocks || []) {
|
|
100
|
-
if (block.blockTag?.tagNameWithUpperCase !== "@EXAMPLE") continue;
|
|
101
|
-
const content = block.content;
|
|
102
|
-
let found = false;
|
|
103
|
-
for (const node of content?.nodes || []) if (node.kind === "FencedCode") {
|
|
104
|
-
examples.push({
|
|
105
|
-
language: node.language || "typescript",
|
|
106
|
-
code: node.code || ""
|
|
107
|
-
});
|
|
108
|
-
found = true;
|
|
109
|
-
}
|
|
110
|
-
if (!found) {
|
|
111
|
-
const text = extractPlainText(content).trim();
|
|
112
|
-
if (text) examples.push({
|
|
113
|
-
language: "typescript",
|
|
114
|
-
code: text
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
return examples;
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Reads the deprecation-block message from an ApiItem, if one is present.
|
|
122
|
-
*
|
|
123
|
-
* @public
|
|
124
|
-
*/
|
|
125
|
-
function getDeprecation(item) {
|
|
126
|
-
if (item instanceof ApiDocumentedItem) {
|
|
127
|
-
const tsdoc = item.tsdocComment;
|
|
128
|
-
if (tsdoc?.deprecatedBlock) return { message: extractPlainText(tsdoc.deprecatedBlock.content).replace(/\s+/g, " ").trim() };
|
|
129
|
-
}
|
|
130
|
-
return null;
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* The release tag (Public/Beta/Alpha/Internal) or "Public" when absent.
|
|
134
|
-
*
|
|
135
|
-
* @public
|
|
136
|
-
*/
|
|
137
|
-
function getReleaseTag(item) {
|
|
138
|
-
if (ApiReleaseTagMixin.isBaseClassOf(item)) switch (item.releaseTag) {
|
|
139
|
-
case ReleaseTag.Public: return "Public";
|
|
140
|
-
case ReleaseTag.Beta: return "Beta";
|
|
141
|
-
case ReleaseTag.Alpha: return "Alpha";
|
|
142
|
-
case ReleaseTag.Internal: return "Internal";
|
|
143
|
-
default: return "Public";
|
|
144
|
-
}
|
|
145
|
-
return "Public";
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* True when the item carries the given TSDoc modifier tag (without the `@`).
|
|
149
|
-
*
|
|
150
|
-
* @public
|
|
151
|
-
*/
|
|
152
|
-
function hasModifierTag(item, tagName) {
|
|
153
|
-
if (item instanceof ApiDocumentedItem) return ((item.tsdocComment?.modifierTagSet)?.nodes || []).some((t) => t.tagName === `@${tagName}`);
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
//#endregion
|
|
158
|
-
export { extractPlainText, getDeprecation, getExamples, getParams, getReleaseTag, getReturns, getSummary, hasModifierTag };
|