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 @@ + + +TypeScript logo + + + 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" +}