diff --git a/.config/.prettierignore b/.config/.prettierignore
index 2093e8d74..107912274 100644
--- a/.config/.prettierignore
+++ b/.config/.prettierignore
@@ -1,8 +1,10 @@
../.nyc_output
../coverage
../dist
-../package-lock.json
+**/package-lock.json
../src/test/**/specs*.json
../src/test/packages/**/*.js
../src/test/renderer/specs
+../src/test/renderer/testProject
../static/main.js
+../example/docs/
diff --git a/.eslintrc b/.eslintrc
index 457e205e0..7d654b6af 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -16,13 +16,13 @@
],
"ignorePatterns": [
"src/test/renderer/specs",
- "examples",
"dist",
"coverage",
"static/main.js",
"src/lib/output/themes/default/assets",
// Would be nice to lint these, but they shouldn't be included in the project,
// so we need a second eslint config file.
+ "example",
"src/test/converter",
"src/test/converter2",
"src/test/module",
diff --git a/.gitignore b/.gitignore
index 84ce6e1fc..368472d53 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,7 +9,7 @@ yarn-error.log
/src/test/renderer/*/doc
/src/test/renderer/testProject/json.json
-/node_modules/
+**/node_modules/
/coverage/
/dist/
@@ -21,3 +21,5 @@ src/test/renderer/specs/specs.json
# Built theme JS
static/main.js
+
+/example/docs/
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 58fbff686..1d6018acb 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -8,5 +8,6 @@
},
"prettier.enable": true,
"prettier.configPath": ".config/.prettierrc.json",
- "prettier.ignorePath": ".config/.prettierignore"
+ "prettier.ignorePath": ".config/.prettierignore",
+ "eslint.workingDirectories": [".", "./example"]
}
diff --git a/example/.eslintrc.json b/example/.eslintrc.json
new file mode 100644
index 000000000..2b2f7d166
--- /dev/null
+++ b/example/.eslintrc.json
@@ -0,0 +1,7 @@
+{
+ "extends": "../.eslintrc",
+ "parserOptions": {
+ "project": "./tsconfig.json"
+ },
+ "ignorePatterns": ["docs/"]
+}
diff --git a/example/README.md b/example/README.md
new file mode 100644
index 000000000..5e0973902
--- /dev/null
+++ b/example/README.md
@@ -0,0 +1,72 @@
+# The TypeDoc Example
+
+Welcome to the TypeDoc example! TypeDoc is a documentation generator for
+TypeScript.
+
+TypeDoc automatically documents every variable, function, and class
+that is exported by your project. You can add explanations and examples to your
+documentation site by annotating your code with doc comments, e.g.
+
+```
+/**
+ * Calculates the square root of a number.
+ *
+ * @param x the number to calculate the root of.
+ * @returns the square root if `x` is non-negative or `NaN` if `x` is negative.
+ */
+export function sqrt(x: number): number {
+ return Math.sqrt(x);
+}
+```
+
+This project shows off some of TypeDoc's features:
+
+- Built-in support for various TypeScript language constructs
+- Markdown in doc comments
+- Syntax highligting in code blocks
+
+## Index of Examples
+
+**Click the "Exports" link in the sidebar to see a complete list of everything in
+the package.**
+
+Here are some examples we wanted to highlight:
+
+### Rendering
+
+- Markdown showcase: [[`markdownShowcase`]]
+- Syntax highlighting showcase: [[`syntaxHighlightingShowcase`]]
+
+### Functions
+
+- Simple functions: [[`sqrt`]] and [[`sqrtArrowFunction`]]
+- A generic function: [[`concat`]]
+- Functions that take an options object: [[`makeHttpCallA`]] and [[`makeHttpCallB`]]
+- An overloaded function: [[`overloadedFunction`]]
+- An external function exported under a different name: [[`lodashSortBy`]]
+
+### Types
+
+- Type aliases: [[`SimpleTypeAlias`]] and [[`ComplexGenericTypeAlias`]]
+- Interfaces: [[`User`]] and [[`AdminUser`]]
+
+### Classes
+
+- A basic class: [[`Customer`]]
+- A subclass: [[`DeliveryCustomer`]]
+- A complex class: [[`CancellablePromise`]]
+- A class that extends a built-in generic type: [[`StringArray`]]
+
+### Enums
+
+- A basic enum: [[`SimpleEnum`]]
+- Using the `@enum` tag: [[`EnumLikeObject`]]
+
+### Variables
+
+- [[`PI`]], [[`STRING_CONSTANT`]], and [[`ObjectConstant`]]
+
+### React Components
+
+- Basic React components: [[`CardA`]] and [[`CardB`]]
+- A complex React component: [[`EasyFormDialog`]] and [[`EasyFormDialogProps`]]
diff --git a/example/building-the-example.md b/example/building-the-example.md
new file mode 100644
index 000000000..ae030372f
--- /dev/null
+++ b/example/building-the-example.md
@@ -0,0 +1,7 @@
+# Building the TypeDoc Example
+
+1. Build TypeDoc: `npm install` and `npm run build` in the root directory.
+2. `cd example`
+3. `npm install` (the example has its own `package.json`)
+4. Typecheck the example: `npm run tsc`
+5. Build the docs: `npm run typedoc`
diff --git a/example/media/typescript-logo.svg b/example/media/typescript-logo.svg
new file mode 100644
index 000000000..339da0b63
--- /dev/null
+++ b/example/media/typescript-logo.svg
@@ -0,0 +1,6 @@
+
+
diff --git a/example/package-lock.json b/example/package-lock.json
new file mode 100644
index 000000000..3288d3a1f
--- /dev/null
+++ b/example/package-lock.json
@@ -0,0 +1,237 @@
+{
+ "name": "typedoc-example",
+ "version": "0.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "typedoc-example",
+ "version": "0.0.0",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/react": "^17.0.26",
+ "@types/react-dom": "^17.0.9",
+ "lodash": "^4.17.21",
+ "react": "^17.0.2",
+ "react-dom": "^17.0.2"
+ },
+ "devDependencies": {
+ "@types/lodash": "^4.14.175",
+ "typescript": "^4.4.3"
+ }
+ },
+ "node_modules/@types/lodash": {
+ "version": "4.14.175",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.175.tgz",
+ "integrity": "sha512-XmdEOrKQ8a1Y/yxQFOMbC47G/V2VDO1GvMRnl4O75M4GW/abC5tnfzadQYkqEveqRM1dEJGFFegfPNA2vvx2iw==",
+ "dev": true
+ },
+ "node_modules/@types/prop-types": {
+ "version": "15.7.4",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz",
+ "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ=="
+ },
+ "node_modules/@types/react": {
+ "version": "17.0.26",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.26.tgz",
+ "integrity": "sha512-MXxuXrH2xOcv5cp/su4oz69dNQnSA90JjFw5HBd5wifw6Ihi94j7dRJm7qNsB30tnruXSCPc9qmlhGop4nh9Hw==",
+ "dependencies": {
+ "@types/prop-types": "*",
+ "@types/scheduler": "*",
+ "csstype": "^3.0.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "17.0.9",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz",
+ "integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==",
+ "dependencies": {
+ "@types/react": "*"
+ }
+ },
+ "node_modules/@types/scheduler": {
+ "version": "0.16.2",
+ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
+ "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
+ },
+ "node_modules/csstype": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.9.tgz",
+ "integrity": "sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw=="
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
+ "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
+ "dependencies": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
+ "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
+ "dependencies": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1",
+ "scheduler": "^0.20.2"
+ },
+ "peerDependencies": {
+ "react": "17.0.2"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
+ "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
+ "dependencies": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz",
+ "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ }
+ },
+ "dependencies": {
+ "@types/lodash": {
+ "version": "4.14.175",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.175.tgz",
+ "integrity": "sha512-XmdEOrKQ8a1Y/yxQFOMbC47G/V2VDO1GvMRnl4O75M4GW/abC5tnfzadQYkqEveqRM1dEJGFFegfPNA2vvx2iw==",
+ "dev": true
+ },
+ "@types/prop-types": {
+ "version": "15.7.4",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz",
+ "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ=="
+ },
+ "@types/react": {
+ "version": "17.0.26",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.26.tgz",
+ "integrity": "sha512-MXxuXrH2xOcv5cp/su4oz69dNQnSA90JjFw5HBd5wifw6Ihi94j7dRJm7qNsB30tnruXSCPc9qmlhGop4nh9Hw==",
+ "requires": {
+ "@types/prop-types": "*",
+ "@types/scheduler": "*",
+ "csstype": "^3.0.2"
+ }
+ },
+ "@types/react-dom": {
+ "version": "17.0.9",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz",
+ "integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==",
+ "requires": {
+ "@types/react": "*"
+ }
+ },
+ "@types/scheduler": {
+ "version": "0.16.2",
+ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
+ "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
+ },
+ "csstype": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.9.tgz",
+ "integrity": "sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw=="
+ },
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+ },
+ "lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
+ "loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "requires": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ }
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+ },
+ "react": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
+ "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1"
+ }
+ },
+ "react-dom": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
+ "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1",
+ "scheduler": "^0.20.2"
+ }
+ },
+ "scheduler": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
+ "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1"
+ }
+ },
+ "typescript": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz",
+ "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==",
+ "dev": true
+ }
+ }
+}
diff --git a/example/package.json b/example/package.json
new file mode 100644
index 000000000..828f56f71
--- /dev/null
+++ b/example/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "typedoc-example",
+ "version": "0.0.0",
+ "private": true,
+ "description": "An example of using the TypeDoc documentation generator.",
+ "license": "Apache-2.0",
+ "author": "TypeDoc contributors",
+ "scripts": {
+ "lint": "eslint .",
+ "tsc": "tsc",
+ "typedoc": "node ../bin/typedoc ./src"
+ },
+ "dependencies": {
+ "@types/lodash": "^4.14.175",
+ "@types/react": "^17.0.26",
+ "@types/react-dom": "^17.0.9",
+ "lodash": "^4.17.21",
+ "react": "^17.0.2",
+ "react-dom": "^17.0.2"
+ },
+ "devDependencies": {
+ "typescript": "^4.4.3"
+ }
+}
diff --git a/example/src/classes/CancellablePromise.ts b/example/src/classes/CancellablePromise.ts
new file mode 100644
index 000000000..72dcc4ebf
--- /dev/null
+++ b/example/src/classes/CancellablePromise.ts
@@ -0,0 +1,396 @@
+const noop = () => {
+ /* purposefully empty */
+};
+
+/**
+ * If canceled, a [[`CancellablePromise`]] should throw an `Cancellation` object.
+ */
+class Cancellation extends Error {
+ constructor(message = "Promise canceled.") {
+ super(message);
+ }
+}
+
+/**
+ * The most abstract thing we can cancel — a thenable with a cancel method.
+ */
+type PromiseWithCancel = PromiseLike & { cancel(): void };
+
+/**
+ * Determines if an arbitrary value is a thenable with a cancel method.
+ */
+function isPromiseWithCancel(value: unknown): value is PromiseWithCancel {
+ return (
+ typeof value === "object" &&
+ typeof (value as any).then === "function" &&
+ typeof (value as any).cancel === "function"
+ );
+}
+
+/**
+ * This example shows off how TypeDoc handles
+ *
+ * - Complex method signatures
+ * - Static methods
+ * - A method with 10 overload signatures. Wow!
+ * - Only the implementation signature has a doc comment. TypeDoc
+ * automatically copies the comment from the implementation signature to
+ * each of the visible signatures if they don't have one.
+ *
+ * A promise with a `cancel` method. If canceled, the `CancellablePromise` will
+ * reject with a `Cancellation` object. Originally from
+ * [real-cancellable-promise](https://github.com/srmagura/real-cancellable-promise).
+ *
+ * @typeParam T what the `CancellablePromise` resolves to
+ */
+export class CancellablePromise {
+ /**
+ * As a consumer of the library, you shouldn't ever need to access
+ * `CancellablePromise.promise` directly.
+ *
+ * If you are subclassing `CancellablePromise` for some reason, you
+ * can access this property.
+ */
+ protected readonly promise: Promise;
+
+ // IMPORTANT: When defining a new `cancel` function,
+ // e.g. in the implementation of `then`,
+ // always use an arrow function so that `this` is bound.
+
+ /**
+ * Cancel the `CancellablePromise`.
+ */
+ readonly cancel: (reason?: string) => void;
+
+ /**
+ * @param promise a normal promise or thenable
+ * @param cancel a function that cancels `promise`. **Calling `cancel` after
+ * `promise` has resolved must be a no-op.**
+ */
+ constructor(promise: PromiseLike, cancel: (reason?: string) => void) {
+ this.promise = Promise.resolve(promise);
+ this.cancel = cancel;
+ }
+
+ /**
+ * Analogous to `Promise.then`.
+ *
+ * `onFulfilled` on `onRejected` can return a value, a normal promise, or a
+ * `CancellablePromise`. So you can make a chain a `CancellablePromise`s
+ * like this:
+ *
+ * ```
+ * const overallPromise = cancellableAsyncFunction1()
+ * .then(cancellableAsyncFunction2)
+ * .then(cancellableAsyncFunction3)
+ * .then(cancellableAsyncFunction4)
+ * ```
+ *
+ * Then if you call `overallPromise.cancel`, `cancel` is called on all
+ * `CancellablePromise`s in the chain! In practice, this means that
+ * whichever async operation is in progress will be canceled.
+ *
+ * @returns a new CancellablePromise
+ */
+ then(
+ onFulfilled?:
+ | ((value: T) => TResult1 | PromiseLike)
+ | undefined
+ | null,
+ onRejected?:
+ | ((reason: any) => TResult2 | PromiseLike)
+ | undefined
+ | null
+ ): CancellablePromise {
+ let fulfill;
+ let reject;
+ let callbackPromiseWithCancel: PromiseWithCancel | undefined;
+
+ if (onFulfilled) {
+ fulfill = (value: T): TResult1 | PromiseLike => {
+ const nextValue: TResult1 | PromiseLike =
+ onFulfilled(value);
+
+ if (isPromiseWithCancel(nextValue))
+ callbackPromiseWithCancel = nextValue;
+
+ return nextValue;
+ };
+ }
+
+ if (onRejected) {
+ reject = (reason: any): TResult2 | PromiseLike => {
+ const nextValue: TResult2 | PromiseLike =
+ onRejected(reason);
+
+ if (isPromiseWithCancel(nextValue))
+ callbackPromiseWithCancel = nextValue;
+
+ return nextValue;
+ };
+ }
+
+ const newPromise = this.promise.then(fulfill, reject);
+
+ const newCancel = () => {
+ this.cancel();
+ callbackPromiseWithCancel?.cancel();
+ };
+
+ return new CancellablePromise(newPromise, newCancel);
+ }
+
+ /**
+ * Analogous to `Promise.catch`.
+ */
+ catch(
+ onRejected?:
+ | ((reason: any) => TResult | PromiseLike)
+ | undefined
+ | null
+ ): CancellablePromise {
+ return this.then(undefined, onRejected);
+ }
+
+ /**
+ * Attaches a callback that is invoked when the Promise is settled
+ * (fulfilled or rejected). The resolved value cannot be modified from the
+ * callback.
+ * @param onFinally The callback to execute when the Promise is settled
+ * (fulfilled or rejected).
+ * @returns A Promise for the completion of the callback.
+ */
+ finally(
+ onFinally?: (() => void) | undefined | null
+ ): CancellablePromise {
+ return new CancellablePromise(
+ this.promise.finally(onFinally),
+ this.cancel
+ );
+ }
+
+ /**
+ * Analogous to `Promise.resolve`.
+ *
+ * The returned promise should resolve even if it is canceled. The idea is
+ * that the promise is resolved instantaneously, so by the time the promise
+ * is canceled, it has already resolved.
+ */
+ static resolve(): CancellablePromise;
+
+ static resolve(value: T): CancellablePromise;
+
+ static resolve(value?: unknown): CancellablePromise {
+ return new CancellablePromise(Promise.resolve(value), noop);
+ }
+
+ /**
+ * Analogous to `Promise.reject`.
+ *
+ * Like `CancellablePromise.resolve`, canceling the returned
+ * `CancellablePromise` is a no-op.
+ *
+ * @param reason this should probably be an `Error` object
+ */
+ static reject(reason?: unknown): CancellablePromise {
+ return new CancellablePromise(Promise.reject(reason), noop);
+ }
+
+ static all(
+ values: readonly [
+ T1 | PromiseLike,
+ T2 | PromiseLike,
+ T3 | PromiseLike,
+ T4 | PromiseLike,
+ T5 | PromiseLike,
+ T6 | PromiseLike,
+ T7 | PromiseLike,
+ T8 | PromiseLike,
+ T9 | PromiseLike,
+ T10 | PromiseLike
+ ]
+ ): CancellablePromise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;
+
+ static all(
+ values: readonly [
+ T1 | PromiseLike,
+ T2 | PromiseLike,
+ T3 | PromiseLike,
+ T4 | PromiseLike,
+ T5 | PromiseLike,
+ T6 | PromiseLike,
+ T7 | PromiseLike,
+ T8 | PromiseLike,
+ T9 | PromiseLike
+ ]
+ ): CancellablePromise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>;
+
+ static all(
+ values: readonly [
+ T1 | PromiseLike,
+ T2 | PromiseLike,
+ T3 | PromiseLike,
+ T4 | PromiseLike,
+ T5 | PromiseLike,
+ T6 | PromiseLike,
+ T7 | PromiseLike,
+ T8 | PromiseLike
+ ]
+ ): CancellablePromise<[T1, T2, T3, T4, T5, T6, T7, T8]>;
+
+ static all(
+ values: readonly [
+ T1 | PromiseLike,
+ T2 | PromiseLike,
+ T3 | PromiseLike,
+ T4 | PromiseLike,
+ T5 | PromiseLike,
+ T6 | PromiseLike,
+ T7 | PromiseLike
+ ]
+ ): CancellablePromise<[T1, T2, T3, T4, T5, T6, T7]>;
+
+ static all(
+ values: readonly [
+ T1 | PromiseLike,
+ T2 | PromiseLike,
+ T3 | PromiseLike,
+ T4 | PromiseLike,
+ T5 | PromiseLike,
+ T6 | PromiseLike
+ ]
+ ): CancellablePromise<[T1, T2, T3, T4, T5, T6]>;
+
+ static all(
+ values: readonly [
+ T1 | PromiseLike,
+ T2 | PromiseLike,
+ T3 | PromiseLike,
+ T4 | PromiseLike,
+ T5 | PromiseLike
+ ]
+ ): CancellablePromise<[T1, T2, T3, T4, T5]>;
+
+ static all(
+ values: readonly [
+ T1 | PromiseLike,
+ T2 | PromiseLike,
+ T3 | PromiseLike,
+ T4 | PromiseLike
+ ]
+ ): CancellablePromise<[T1, T2, T3, T4]>;
+
+ static all(
+ values: readonly [
+ T1 | PromiseLike,
+ T2 | PromiseLike,
+ T3 | PromiseLike
+ ]
+ ): CancellablePromise<[T1, T2, T3]>;
+
+ static all(
+ values: readonly [T1 | PromiseLike, T2 | PromiseLike]
+ ): CancellablePromise<[T1, T2]>;
+
+ static all(
+ values: readonly (T | PromiseLike)[]
+ ): CancellablePromise;
+
+ /**
+ * Analogous to `Promise.all`.
+ *
+ * @param values an array that may contain `CancellablePromise`s, promises,
+ * thenables, and resolved values
+ * @returns a [[`CancellablePromise`]], which, if canceled, will cancel each
+ * of the promises passed in to `CancellablePromise.all`.
+ */
+ static all(values: readonly unknown[]): CancellablePromise {
+ return new CancellablePromise(Promise.all(values), () => {
+ for (const value of values) {
+ if (isPromiseWithCancel(value)) value.cancel();
+ }
+ });
+ }
+
+ /**
+ * Creates a `CancellablePromise` that is resolved with an array of results
+ * when all of the provided `Promises` resolve or reject.
+ * @param values An array of `Promises`.
+ * @returns A new `CancellablePromise`.
+ */
+ static allSettled(
+ values: T
+ ): CancellablePromise<{
+ -readonly [P in keyof T]: PromiseSettledResult<
+ T[P] extends PromiseLike ? U : T[P]
+ >;
+ }>;
+
+ /**
+ * Creates a `CancellablePromise` that is resolved with an array of results
+ * when all of the provided `Promise`s resolve or reject.
+ *
+ * @param values An array of `Promise`s.
+ * @returns A new `CancellablePromise`. Canceling it cancels all of the input
+ * promises.
+ */
+ static allSettled(
+ values: Iterable
+ ): CancellablePromise<
+ PromiseSettledResult ? U : T>[]
+ >;
+
+ static allSettled(values: unknown[]): CancellablePromise {
+ const cancel = (): void => {
+ for (const value of values) {
+ if (isPromiseWithCancel(value)) {
+ value.cancel();
+ }
+ }
+ };
+
+ return new CancellablePromise(Promise.allSettled(values), cancel);
+ }
+
+ /**
+ * Creates a `CancellablePromise` that is resolved or rejected when any of
+ * the provided `Promises` are resolved or rejected.
+ * @param values An array of `Promises`.
+ * @returns A new `CancellablePromise`. Canceling it cancels all of the input
+ * promises.
+ */
+ static race(
+ values: readonly T[]
+ ): CancellablePromise ? U : T> {
+ const cancel = (): void => {
+ for (const value of values) {
+ if (isPromiseWithCancel(value)) {
+ value.cancel();
+ }
+ }
+ };
+
+ return new CancellablePromise(Promise.race(values), cancel);
+ }
+
+ /**
+ * @returns a `CancellablePromise` that resolves after `ms` milliseconds.
+ */
+ static delay(ms: number): CancellablePromise {
+ let timer: NodeJS.Timer | undefined;
+ let rejectFn: (reason?: any) => void = noop;
+
+ const promise = new Promise((resolve, reject) => {
+ timer = setTimeout(() => {
+ resolve();
+ rejectFn = noop;
+ }, ms);
+ rejectFn = reject;
+ });
+
+ return new CancellablePromise(promise, () => {
+ if (timer) clearTimeout(timer);
+ rejectFn(new Cancellation());
+ });
+ }
+}
diff --git a/example/src/classes/Customer.ts b/example/src/classes/Customer.ts
new file mode 100644
index 000000000..afe1122a3
--- /dev/null
+++ b/example/src/classes/Customer.ts
@@ -0,0 +1,118 @@
+/**
+ * An abstract base class for the customer entity in our application.
+ *
+ * Notice how TypeDoc shows the inheritance hierarchy for our class.
+ */
+export abstract class Customer {
+ /** A public readonly property. */
+ readonly id: number;
+
+ /** A public property that can be reassigned. */
+ name: string;
+
+ /** An optional protected property. */
+ protected contactName?: string;
+
+ /** A private property that is accessed via a getter and setter. */
+ private _nextOrderNumber = 0;
+
+ /**
+ * A getter that prepends a number sign to the private `_nextOrderNumber`
+ * property.
+ */
+ get nextOrderNumber(): string {
+ return `#${this._nextOrderNumber}`;
+ }
+
+ /**
+ * A setter that takes in either a string or a number and sets the private
+ * `_nextOrderNumber` property.
+ */
+ set nextOrderNumber(value: string | number) {
+ if (typeof value === "number") {
+ this._nextOrderNumber = value;
+ } else {
+ this._nextOrderNumber = parseInt(value.replace(/#/g, ""));
+ }
+ }
+
+ /**
+ * The constructor of the `Customer` class.
+ *
+ * @param id the customer's database ID
+ * @param name the customer's name
+ * @param nextOrderNumber the next number to use when this customer places an order
+ */
+ constructor(id: number, name: string, nextOrderNumber: string | number) {
+ this.id = id;
+ this.name = name;
+ this.nextOrderNumber = nextOrderNumber;
+ this.doInternalStuff();
+ }
+
+ /** A public method. To be called when an order is placed for this customer. */
+ onOrderPlaced(): void {
+ this._nextOrderNumber++;
+ }
+
+ /**
+ * A public method that's defined using an arrow function.
+ *
+ * TypeDoc knows to document this as a method rather than a property.
+ */
+ onOrderPlacedArrowFunction = (): void => {
+ this._nextOrderNumber++;
+ };
+
+ /** A protected method. */
+ protected isValid(): boolean {
+ return this._nextOrderNumber >= 0;
+ }
+
+ /** A private method. */
+ private doInternalStuff(): void {
+ // does nothing
+ }
+}
+
+/**
+ * A class that extends [[`Customer`]].
+ */
+export class DeliveryCustomer extends Customer {
+ /** A property defined on the subclass. */
+ preferredCourierId?: number;
+
+ /** Another property defined on the subclass. */
+ readonly subscriptionType: "basic" | "enterprise";
+
+ /**
+ * The constructor of the `DeliveryCustomer` class.
+ *
+ * @param id the customer's database ID
+ * @param name the customer's name
+ * @param nextOrderNumber the next number to use when this customer places an order
+ * @param subscriptionType whether this customer has a basic or enterprise subscription
+ */
+ constructor(
+ id: number,
+ name: string,
+ nextOrderNumber: string | number,
+ subscriptionType: "basic" | "enterprise"
+ ) {
+ super(id, name, nextOrderNumber);
+ this.subscriptionType = subscriptionType;
+ }
+
+ /**
+ * An example of overriding a protected method.
+ *
+ * A `DeliveryCustomer` can only have a preferred courier if its
+ * subscription type is enterprise.
+ */
+ protected isValid(): boolean {
+ if (!super.isValid()) return false;
+ if (this.subscriptionType === "enterprise") return true;
+
+ return typeof this.preferredCourierId === "undefined";
+ }
+}
diff --git a/example/src/classes/StringArray.ts b/example/src/classes/StringArray.ts
new file mode 100644
index 000000000..f75dc1431
--- /dev/null
+++ b/example/src/classes/StringArray.ts
@@ -0,0 +1,19 @@
+/**
+ * An array of strings that's defined as
+ *
+ * ```
+ * export class StringArray extends Array {
+ * // ...
+ * }
+ * ```
+ *
+ * Notice how TypeDoc has substituted `string` for the generic type argument in all
+ * the methods inherited from `Array`. For example, the `values` method returns
+ * `IterableIterator`.
+ */
+export class StringArray extends Array {
+ /** A method that extends the functionality of a basic JavaScript array. */
+ customMethod(): void {
+ // do something awesome
+ }
+}
diff --git a/example/src/classes/index.ts b/example/src/classes/index.ts
new file mode 100644
index 000000000..3a46d19d0
--- /dev/null
+++ b/example/src/classes/index.ts
@@ -0,0 +1,3 @@
+export * from "./Customer";
+export * from "./StringArray";
+export * from "./CancellablePromise";
diff --git a/example/src/enums.ts b/example/src/enums.ts
new file mode 100644
index 000000000..9b24dc77c
--- /dev/null
+++ b/example/src/enums.ts
@@ -0,0 +1,53 @@
+/** Describes the status of a delivery order. */
+export enum SimpleEnum {
+ /** This order has just been placed and is yet to be processed. */
+ Pending,
+
+ /** A courier is en route delivering this order. */
+ InProgress,
+
+ /** The order has been delivered. */
+ Complete = "COMPLETE",
+}
+
+/**
+ * [A crazy enum from the TypeScript
+ * handbook](https://www.typescriptlang.org/docs/handbook/enums.html#computed-and-constant-members).
+ * This enum contains both constant and computed members.
+ *
+ * TypeDoc won't show the value of computed members since this information is
+ * only available at runtime.
+ */
+export enum CrazyEnum {
+ // constant members
+ None,
+ Read = 1 << 1,
+ Write = 1 << 2,
+ ReadWrite = Read | Write,
+ // computed member
+ ComputedMember = "123".length,
+}
+
+/**
+ * Since TypeScript's `enum` can be inconvenient to work with, some packages define their own enum-like objects:
+ *
+ * ```
+ * export const EnumLikeObject = {
+ * Pending: 'pending',
+ * InProgress: 'inProgress',
+ * Completed: 'completed'
+ * } as const
+ * ```
+ *
+ * Use the `@enum` tag to make TypeDoc document this object as an enum.
+ *
+ * @enum
+ */
+export const EnumLikeObject = {
+ Pending: "pending",
+
+ /** Indicates that a courier is en route delivering this order. */
+ InProgress: "inProgress",
+
+ Completed: "completed",
+} as const;
diff --git a/example/src/functions.ts b/example/src/functions.ts
new file mode 100644
index 000000000..27e89bbdb
--- /dev/null
+++ b/example/src/functions.ts
@@ -0,0 +1,119 @@
+/**
+ * Calculates the square root of a number.
+ *
+ * @param x the number to calculate the root of.
+ * @returns the square root if `x` is non-negative or `NaN` if `x` is negative.
+ */
+export function sqrt(x: number): number {
+ return Math.sqrt(x);
+}
+
+/**
+ * Calculates the square root of a number.
+ *
+ * `sqrtArrowFunction` is defined using a variable declaration:
+ *
+ * ```
+ * export const sqrtArrowFunction = (x: number): number => Math.sqrt(x);
+ * ```
+ *
+ * TypeDoc is smart and documents `sqrtArrowFunction` as a function rather than a variable.
+ *
+ * @param x the number do calculate the root of.
+ * @returns the square root if `x` is non-negative or `NaN` if `x` is negative.
+ */
+export const sqrtArrowFunction = (x: number): number => Math.sqrt(x);
+
+/**
+ * A simple generic function that concatenates two arrays.
+ *
+ * Use [`@typeParam `](https://typedoc.org/guides/doccomments/#%40typeparam-%3Cparam-name%3E-or-%40template-%3Cparam-name%3E)
+ * to document generic type parameters, e.g.
+ *
+ * ```text
+ * @typeParam T the element type of the arrays
+ * ```
+ *
+ * @typeParam T the element type of the arrays
+ */
+export function concat(array1: T[], array2: T[]): T[] {
+ return array1.concat(array2);
+}
+
+/**
+ * The options type for [[`makeHttpCallA`]].
+ */
+export interface MakeHttpCallAOptions {
+ url: string;
+
+ /** e.g. GET, POST, PUT, DELETE */
+ method: string;
+
+ /** e.g. `{ 'Authorization': 'Bearer ' }` */
+ headers: Record;
+ body: string | Blob | FormData;
+ mode: "cors" | "no-cors" | "same-origin";
+}
+
+/**
+ * A function that takes in an options object that is defined as a separate
+ * interface and makes an HTTP call.
+ *
+ * **Make sure to export the options type when using this pattern.** Otherwise,
+ * TypeDoc will not document the options.
+ */
+export function makeHttpCallA(
+ options: MakeHttpCallAOptions
+): Promise {
+ const { url, method, headers, body, mode } = options;
+
+ return fetch(url, { method, headers, body, mode });
+}
+
+/**
+ * A function that takes in an options object and makes an HTTP call.
+ *
+ * The options type is written directly in the function definition.
+ */
+export function makeHttpCallB(options: {
+ url: string;
+
+ /** e.g. GET, POST, PUT, DELETE */
+ method: string;
+
+ /** e.g. `{ 'Authorization': 'Bearer ' }` */
+ headers: Record;
+
+ body: string | Blob | FormData;
+ mode: "cors" | "no-cors" | "same-origin";
+}): Promise {
+ const { url, method, headers, body, mode } = options;
+
+ return fetch(url, { method, headers, body, mode });
+}
+
+/**
+ * Stringifies and concatenates two numbers into a single string.
+ *
+ * The documentation site allows you to toggle between the different overloads
+ * of a function. The implementation signature of the overloaded function is not
+ * included in the documentation.
+ */
+export function overloadedFunction(a: number, b: number): string;
+
+/**
+ * Concatenates two strings.
+ *
+ * The documentation site allows you to toggle between the different overloads
+ * of a function. The implementation signature of the overloaded function is not
+ * included in the documentation.
+ */
+export function overloadedFunction(a: string, b: string): string;
+
+export function overloadedFunction(a: unknown, b: unknown): string {
+ return (
+ (a as { toString(): string }).toString() +
+ (b as { toString(): string }).toString()
+ );
+}
diff --git a/example/src/index.ts b/example/src/index.ts
new file mode 100644
index 000000000..f1e900adb
--- /dev/null
+++ b/example/src/index.ts
@@ -0,0 +1,9 @@
+export * from "./functions";
+export * from "./variables";
+export * from "./types";
+export * from "./classes";
+export * from "./enums";
+export * from "./reexports";
+export * from "./showcase";
+export * from "./reactComponents";
+export * from "./internals";
diff --git a/example/src/internals.ts b/example/src/internals.ts
new file mode 100644
index 000000000..50a1e6422
--- /dev/null
+++ b/example/src/internals.ts
@@ -0,0 +1,19 @@
+/**
+ * @internal
+ *
+ * Use `@internal` to indicate that something is for internal use. If the
+ * `--excludeInternal` option is passed, TypeDoc will not document the given
+ * code.
+ */
+export function anInternalFunction(): void {
+ // does nothing
+}
+
+/**
+ * @ignore
+ *
+ * `@hidden` and `@ignore` keep the subsequent code from being documented.
+ */
+export function willNotBeDocumented(target: any, value: number): number {
+ return 0;
+}
diff --git a/example/src/reactComponents.tsx b/example/src/reactComponents.tsx
new file mode 100644
index 000000000..2806a0571
--- /dev/null
+++ b/example/src/reactComponents.tsx
@@ -0,0 +1,251 @@
+import { ReactElement, PropsWithChildren } from "react";
+
+/**
+ * The props type for [[`CardA`]].
+ */
+export interface CardAProps {
+ /** The theme of the card. Defaults to `primary`. */
+ variant: "primary" | "secondary" | "success" | "danger" | "light" | "dark";
+}
+
+/**
+ * Renders a card around some content.
+ *
+ * ```tsx
+ *
+ *
My Title
+ *
My content
+ *
+ * ```
+ *
+ * The props type is defined as a separate interface **which must be exported!**
+ *
+ * ```
+ * export interface CardAProps {
+ * // ...
+ * }
+ *
+ * export function CardA({
+ * children,
+ * variant = "primary",
+ * }: PropsWithChildren): ReactElement {
+ * // ...
+ * }
+ * ```
+ *
+ * This is our recommended way to define React components as it makes your code
+ * more readable. The minor drawback is you must click the `CardAProps` link to
+ * see the component's props.
+ */
+export function CardA({ children, variant = "primary" }: PropsWithChildren): ReactElement {
+ return
{children}
;
+}
+
+/**
+ * Renders a card around some content.
+ *
+ * ```tsx
+ *
+ *
My Title
+ *
My content
+ *
+ * ```
+ *
+ * The props type is written directly in the function definition:
+ *
+ * ```
+ * export function CardB({
+ * children,
+ * variant = "primary",
+ * }: PropsWithChildren<{
+ * variant: "primary" | "secondary" | "success" | "danger" | "light" | "dark";
+ * }>): ReactElement {
+ * // ...
+ * }
+ * ```
+ *
+ * This can make the TypeDoc documentation a bit cleaner for very simple components,
+ * but it makes your code less readable.
+ */
+export function CardB({
+ children,
+ variant = "primary",
+}: PropsWithChildren<{
+ /** The theme of the card. Defaults to `primary`. */
+ variant: "primary" | "secondary" | "success" | "danger" | "light" | "dark";
+}>): ReactElement {
+ return
{children}
;
+}
+
+/** The props type of [[`EasyFormDialog`]]. */
+export interface EasyFormDialogProps {
+ /** The title of the dialog. Can be a JSX element. */
+ title: React.ReactNode;
+
+ /** The text of the submit button. */
+ submitButtonText: string;
+
+ /** The CSS class of the submit button. */
+ submitButtonClass?: string;
+
+ /** The text of the cancel button. Defaults to "Cancel". */
+ cancelButtonText?: string;
+
+ /**
+ * Allows you to disable the submit button even if `getSubmitEnabled()`
+ * would return true.
+ *
+ * This can be useful if you want to disable the submit button while a query
+ * is in progress.
+ */
+ submitEnabled?: boolean;
+
+ /** A boolean indicating if the form is valid. */
+ formIsValid: boolean;
+
+ /** A boolean indicating if validation feedback is being shown. */
+ showValidation: boolean;
+
+ /** A callback that fires when the dialog is submitted. */
+ onShowValidationChange(showValidation: boolean): void;
+
+ /**
+ * A callback that fires after the `submit` function succeeds.
+ *
+ * If the `submit` function returned `responseData`, it is passed to your
+ * `onSuccess` function.
+ *
+ * Your `onSuccess` callback must return a promise. The submit button will
+ * continue showing a loading indicator until the promise resolves. This is
+ * to support refetching the data that was updated by the form submission.
+ */
+ onSuccess(payload: unknown | undefined): Promise;
+
+ /**
+ * A callback that fires when the dialog has completely closed. Your
+ * `onClose` callback should update call, for example,
+ * `setDialogVisible(false)` so that the `EasyFormDialog` is no longer
+ * rendered.
+ */
+ onClose(): void;
+
+ /**
+ * A callback that fires when the form is submitted. You will typically
+ * perform an API call in your `submit` function.
+ *
+ * Your `submit` function can optionally return an object in the shape
+ *
+ * ```
+ * {
+ * shouldClose?: boolean
+ * responseData: unknown
+ * }
+ * ```
+ *
+ * Using `formData` is deprecated. Use controlled components instead.
+ *
+ * `formData` will be `{}` if the optional peer dependency `jquery` is not
+ * installed.
+ */
+ onSubmit(formData: Record):
+ | Promise<
+ | {
+ shouldClose?: boolean;
+ responseData: unknown;
+ }
+ | undefined
+ >
+ | Promise;
+
+ /**
+ * An uncommonly-used callback that fires when the user clicks the cancel button.
+ */
+ onCancel?(): void;
+
+ /**
+ * This prop accepts a ref object that holds a function of type `() =>
+ * void`. You can execute the function to programmatically close the dialog:
+ *
+ * ```
+ * closeRef.current()
+ * ```
+ */
+ closeRef?: React.MutableRefObject<() => void>;
+
+ /** The CSS class added to the underlying Bootstrap modal. */
+ modalClass?: string;
+
+ /**
+ * Set to `false` to disable the default behavior of focusing the first
+ * input.
+ */
+ focusFirst?: boolean;
+
+ /**
+ * Set to `false` to hide the modal footer, which contains the submit and
+ * cancel buttons.
+ */
+ showFooter?: boolean;
+}
+
+/**
+ * An example of a complex React component.
+ *
+ * A wrapper around `ActionDialog` that removes a lot of the boilerplate needed
+ * for dialogs that contain a form.
+ *
+ * ```tsx
+ * interface ExampleProps {
+ * onSuccess(responseData: number): Promise
+ * onClose(): void
+ * }
+ *
+ * export function Example({
+ * onSuccess,
+ * onClose,
+ * }: ExampleProps): ReactElement {
+ * const { onChildValidChange, allFieldsValid } = useFieldValidity()
+ * const [showValidation, setShowValidation] = useState(false)
+ * const vProps = { showValidation, onValidChange: onChildValidChange }
+ *
+ * const [myNumber, setMyNumber] = useState('')
+ *
+ * async function submit() {
+ * await api.product.performOperation()
+ *
+ * return {
+ * responseData: parseInt(myNumber),
+ * }
+ * }
+ *
+ * return (
+ *
+ *
+ * {(id) => (
+ *
+ * )}
+ *
+ *
+ * )
+ * }
+ * ```
+ */
+export function EasyFormDialog(props: PropsWithChildren): ReactElement {
+ return ;
+}
diff --git a/example/src/reexports.ts b/example/src/reexports.ts
new file mode 100644
index 000000000..f7eb5a446
--- /dev/null
+++ b/example/src/reexports.ts
@@ -0,0 +1,4 @@
+/**
+ * Here is a useful function re-exported from Lodash.
+ */
+export { sortBy as lodashSortBy } from "lodash";
diff --git a/example/src/showcase.ts b/example/src/showcase.ts
new file mode 100644
index 000000000..432f8eac2
--- /dev/null
+++ b/example/src/showcase.ts
@@ -0,0 +1,119 @@
+/**
+ * # Markdown Showcase
+ *
+ * All comments are parsed as **Markdown**. TypeDoc uses the
+ * [Marked](https://github.com/markedjs/marked) markdown parser to _convert
+ * comments to HTML_.
+ *
+ * ## Symbol References
+ *
+ * You can link to other classes, members or functions using double square
+ * brackets or an inline link tag. See the [TypeDoc
+ * documentation](https://typedoc.org/guides/doccomments/#symbol-references) for
+ * details.
+ *
+ * ## Code in Doc Comments
+ *
+ * Some inline code: `npm install --save-dev typedoc`
+ *
+ * A TypeScript code block:
+ *
+ * ```
+ * // A fabulous variable
+ * const x: number | string = 12
+ * ```
+ *
+ * See [[`syntaxHighlightingShowcase`]] for more code blocks.
+ *
+ * ## A List
+ *
+ * - 🥚 ~~Eggs~~
+ * - 🍞 Bread
+ * - 🧀 Swiss cheese
+ *
+ * ## A Table
+ *
+ * | Package | Version |
+ * | ------- | ------- |
+ * | lodash | 4.17.21 |
+ * | react | 17.0.2 |
+ * | typedoc | 0.22.4 |
+ *
+ * A Random Shakespeare Quote
+ * --------------------------
+ *
+ * > Rebellious subjects, enemies to peace, Profaners of this neighbour-stained
+ * > steel,-- Will they not hear? What, ho! you men, you beasts, That quench the
+ * > fire of your pernicious rage With purple fountains issuing from your veins
+ *
+ * ## An Image
+ *
+ *
+ *
+ * This requires the [media option](https://typedoc.org/guides/options/#media)
+ * to be set.
+ */
+export function markdownShowcase(): void {
+ // does nothing
+}
+
+/**
+ * TypeDoc supports code blocks in Markdown and uses
+ * [Shiki](https://shiki.matsu.io/) to provide syntax highlighting.
+ *
+ * If no language is specified, the code block is assumed to be TypeScript:
+ *
+ * ```
+ * // A fabulous variable
+ * const x: number | string = 12
+ * ```
+ *
+ * You can specify the language at the start of your code block like this:
+ *
+ * ```text
+ * ```rust
+ * ```
+ *
+ * Use the `tsx` language to get JSX support:
+ *
+ * ```tsx
+ * function BasicComponent(): ReactElement {
+ * return
Test
+ * }
+ * ```
+ *
+ * You might want to write code in the language your backend uses. Here's some
+ * Python:
+ *
+ * ```python
+ * for i in range(30):
+ * print(i + 1)
+ * ```
+ *
+ * And some CSS:
+ *
+ * ```css
+ * .card {
+ * background-color: white;
+ * padding: 1rem;
+ * border: 1px solid lightgray;
+ * }
+ * ```
+ *
+ * If you don't want syntax highlighting, use the `text` language:
+ *
+ * ```text
+ * package.json
+ * src/
+ * index.ts
+ * __tests__/
+ * index.test.ts
+ * ```
+ *
+ * [**View the full list of supported
+ * languages.**](https://github.com/shikijs/shiki/blob/main/docs/languages.md#all-languages)
+ * You can also get this list by running `typedoc --help`.
+ */
+export function syntaxHighlightingShowcase(): void {
+ // does nothing
+}
diff --git a/example/src/types.ts b/example/src/types.ts
new file mode 100644
index 000000000..fa40a0f17
--- /dev/null
+++ b/example/src/types.ts
@@ -0,0 +1,43 @@
+/** A simple type alias defined using the `type` keyword. */
+export type SimpleTypeAlias = string | number | boolean;
+
+/** A complex generic type. */
+export type ComplexGenericTypeAlias =
+ | T
+ | T[]
+ | Promise
+ | Promise
+ | Record>;
+
+/**
+ * A simple interface. Each property has its own doc comment.
+ *
+ * TypeDoc even supports doc comments on nested type definitions, as shown by the `name` property.
+ */
+export interface User {
+ /** The user's ID. */
+ id: number;
+
+ /** The user's email address. */
+ email: string;
+
+ /** The user's name. */
+ name: {
+ /** The person's given name. */
+ first: string;
+
+ /** The person's family name. */
+ last: string;
+ };
+}
+
+/**
+ * An interface that extends [[`User`]] and adds more properties.
+ *
+ * Notice how TypeDoc automatically shows the inheritance hierarchy and where
+ * each property was originally defined.
+ */
+export interface AdminUser extends User {
+ administrativeArea: "sales" | "delivery" | "billing";
+ jobTitle: string;
+}
diff --git a/example/src/variables.ts b/example/src/variables.ts
new file mode 100644
index 000000000..3e1359418
--- /dev/null
+++ b/example/src/variables.ts
@@ -0,0 +1,22 @@
+/** A simple numeric constant. */
+export const PI = 3.14159265359;
+
+/** A simple string constant. */
+export const STRING_CONSTANT = "FOOBAR";
+
+/** An plain JavaScript object using `as const`. */
+export const ObjectConstant = {
+ library: "typedoc",
+ version: "1.2.3",
+
+ /** How many people starred us on GitHub. */
+ githubStars: 1_000_000,
+} as const;
+
+/**
+ * An exported variable defined with `let`.
+ *
+ * This pattern should generally be avoided because the variable can be reassigned.
+ */
+// eslint-disable-next-line prefer-const
+export let E = 2.718281828459045235;
diff --git a/example/tsconfig.json b/example/tsconfig.json
new file mode 100644
index 000000000..1f19e1bb9
--- /dev/null
+++ b/example/tsconfig.json
@@ -0,0 +1,26 @@
+{
+ "compilerOptions": {
+ "target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
+ "jsx": "react-jsx" /* Specify what JSX code is generated. */,
+ "experimentalDecorators": true /* Enable experimental support for TC39 stage 2 draft decorators. */,
+
+ /* Modules */
+ "module": "ESNext" /* Specify what module code is generated. */,
+ "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
+ "baseUrl": "./src" /* Specify the base directory to resolve non-relative module names. */,
+
+ /* Emit */
+ "noEmit": true /* Disable emitting files from a compilation. */,
+
+ /* Interop Constraints */
+ "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
+ "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
+
+ /* Type Checking */
+ "strict": true /* Enable all strict type-checking options. */,
+ "noFallthroughCasesInSwitch": true /* Enable error reporting for fallthrough cases in switch statements. */,
+
+ /* Completeness */
+ "skipLibCheck": true /* Skip type checking all .d.ts files. */
+ }
+}
diff --git a/example/typedoc.json b/example/typedoc.json
new file mode 100644
index 000000000..a3d70aae4
--- /dev/null
+++ b/example/typedoc.json
@@ -0,0 +1,4 @@
+{
+ "sort": "source-order",
+ "media": "media"
+}