typedoc 0.23.15 → 0.23.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -131,7 +131,7 @@ let SourcePlugin = class SourcePlugin extends components_1.ConverterComponent {
131
131
  }
132
132
  }
133
133
  // Try to create a new repository
134
- const repository = repository_1.Repository.tryCreateRepository(dirName, this.gitRevision, this.gitRemote);
134
+ const repository = repository_1.Repository.tryCreateRepository(dirName, this.gitRevision, this.gitRemote, this.application.logger);
135
135
  if (repository) {
136
136
  this.repositories[repository.path.toLowerCase()] = repository;
137
137
  return repository;
@@ -512,9 +512,12 @@ function convertAccessor(context, symbol, exportSymbol) {
512
512
  function isInherited(context, symbol) {
513
513
  const parentSymbol = context.project.getSymbolFromReflection(context.scope);
514
514
  assert(parentSymbol, `No parent symbol found for ${symbol.name} in ${context.scope.name}`);
515
- return (parentSymbol
516
- .getDeclarations()
517
- ?.some((d) => symbol.getDeclarations()?.some((d2) => d2.parent === d)) === false);
515
+ const parents = parentSymbol.declarations?.slice() || [];
516
+ const constructorDecls = parents.flatMap((parent) => ts.isClassDeclaration(parent)
517
+ ? parent.members.filter(ts.isConstructorDeclaration)
518
+ : []);
519
+ parents.push(...constructorDecls);
520
+ return (parents.some((d) => symbol.getDeclarations()?.some((d2) => d2.parent === d)) === false);
518
521
  }
519
522
  function setModifiers(symbol, declaration, reflection) {
520
523
  if (!declaration) {
@@ -1,56 +1,31 @@
1
- import { RepositoryType } from "../../models";
1
+ import type { Logger } from "../../utils";
2
2
  export declare const gitIsInstalled: boolean;
3
3
  /**
4
4
  * Stores data of a repository.
5
5
  */
6
6
  export declare class Repository {
7
7
  /**
8
- * The root path of this repository.
8
+ * The path of this repository on disk.
9
9
  */
10
10
  path: string;
11
11
  /**
12
- * The name of the branch this repository is on right now.
12
+ * All files tracked by the repository.
13
13
  */
14
- branch: string;
14
+ files: Set<string>;
15
15
  /**
16
- * A list of all files tracked by the repository.
16
+ * The base url for link creation.
17
17
  */
18
- files: string[];
18
+ baseUrl: string;
19
19
  /**
20
- * The user/organization name of this repository on GitHub.
20
+ * The anchor prefix used to select lines, usually `L`
21
21
  */
22
- user?: string;
23
- /**
24
- * The project name of this repository on GitHub.
25
- */
26
- project?: string;
27
- /**
28
- * The hostname for this GitHub/Bitbucket/.etc project.
29
- *
30
- * Defaults to: `github.com` (for normal, public GitHub instance projects)
31
- *
32
- * Can be the hostname for an enterprise version of GitHub, e.g. `github.acme.com`
33
- * (if found as a match in the list of git remotes).
34
- */
35
- hostname: string;
36
- /**
37
- * Whether this is a GitHub, Bitbucket, or other type of repository.
38
- */
39
- type: RepositoryType;
40
- private urlCache;
22
+ anchorPrefix: string;
41
23
  /**
42
24
  * Create a new Repository instance.
43
25
  *
44
26
  * @param path The root path of the repository.
45
27
  */
46
- constructor(path: string, gitRevision: string, repoLinks: string[]);
47
- /**
48
- * Check whether the given file is tracked by this repository.
49
- *
50
- * @param fileName The name of the file to test for.
51
- * @returns TRUE when the file is part of the repository, otherwise FALSE.
52
- */
53
- contains(fileName: string): boolean;
28
+ constructor(path: string, baseUrl: string);
54
29
  /**
55
30
  * Get the URL of the given file on GitHub or Bitbucket.
56
31
  *
@@ -68,5 +43,6 @@ export declare class Repository {
68
43
  * @param path The potential repository root.
69
44
  * @returns A new instance of {@link Repository} or undefined.
70
45
  */
71
- static tryCreateRepository(path: string, gitRevision: string, gitRemote: string): Repository | undefined;
46
+ static tryCreateRepository(path: string, gitRevision: string, gitRemote: string, logger: Logger): Repository | undefined;
72
47
  }
48
+ export declare function guessBaseUrl(gitRevision: string, remotes: string[]): string | undefined;
@@ -1,8 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Repository = exports.gitIsInstalled = void 0;
3
+ exports.guessBaseUrl = exports.Repository = exports.gitIsInstalled = void 0;
4
4
  const child_process_1 = require("child_process");
5
- const models_1 = require("../../models");
6
5
  const base_path_1 = require("../utils/base-path");
7
6
  const TEN_MEGABYTES = 1024 * 10000;
8
7
  function git(...args) {
@@ -22,89 +21,22 @@ class Repository {
22
21
  *
23
22
  * @param path The root path of the repository.
24
23
  */
25
- constructor(path, gitRevision, repoLinks) {
24
+ constructor(path, baseUrl) {
26
25
  /**
27
- * A list of all files tracked by the repository.
26
+ * All files tracked by the repository.
28
27
  */
29
- this.files = [];
30
- /**
31
- * The hostname for this GitHub/Bitbucket/.etc project.
32
- *
33
- * Defaults to: `github.com` (for normal, public GitHub instance projects)
34
- *
35
- * Can be the hostname for an enterprise version of GitHub, e.g. `github.acme.com`
36
- * (if found as a match in the list of git remotes).
37
- */
38
- this.hostname = "github.com";
39
- /**
40
- * Whether this is a GitHub, Bitbucket, or other type of repository.
41
- */
42
- this.type = models_1.RepositoryType.GitHub;
43
- this.urlCache = new Map();
28
+ this.files = new Set();
44
29
  this.path = path;
45
- this.branch = gitRevision || "master";
46
- for (let i = 0, c = repoLinks.length; i < c; i++) {
47
- let match = /(github(?!.us)(?:\.[a-z]+)*\.[a-z]{2,})[:/]([^/]+)\/(.*)/.exec(repoLinks[i]);
48
- // Github Enterprise
49
- if (!match) {
50
- match = /(\w+\.githubprivate.com)[:/]([^/]+)\/(.*)/.exec(repoLinks[i]);
51
- }
52
- // Github Enterprise
53
- if (!match) {
54
- match = /(\w+\.ghe.com)[:/]([^/]+)\/(.*)/.exec(repoLinks[i]);
55
- }
56
- // Github Enterprise
57
- if (!match) {
58
- match = /(\w+\.github.us)[:/]([^/]+)\/(.*)/.exec(repoLinks[i]);
59
- }
60
- if (!match) {
61
- match = /(bitbucket.org)[:/]([^/]+)\/(.*)/.exec(repoLinks[i]);
62
- }
63
- if (!match) {
64
- match = /(gitlab.com)[:/]([^/]+)\/(.*)/.exec(repoLinks[i]);
65
- }
66
- if (match) {
67
- this.hostname = match[1];
68
- this.user = match[2];
69
- this.project = match[3];
70
- if (this.project.endsWith(".git")) {
71
- this.project = this.project.slice(0, -4);
72
- }
73
- break;
74
- }
75
- }
76
- if (this.hostname.includes("bitbucket.org")) {
77
- this.type = models_1.RepositoryType.Bitbucket;
78
- }
79
- else if (this.hostname.includes("gitlab.com")) {
80
- this.type = models_1.RepositoryType.GitLab;
81
- }
82
- else {
83
- this.type = models_1.RepositoryType.GitHub;
84
- }
85
- let out = git("-C", path, "ls-files");
30
+ this.baseUrl = baseUrl;
31
+ this.anchorPrefix = guessAnchorPrefix(this.baseUrl);
32
+ const out = git("-C", path, "ls-files");
86
33
  if (out.status === 0) {
87
34
  out.stdout.split("\n").forEach((file) => {
88
35
  if (file !== "") {
89
- this.files.push(base_path_1.BasePath.normalize(path + "/" + file));
36
+ this.files.add(base_path_1.BasePath.normalize(path + "/" + file));
90
37
  }
91
38
  });
92
39
  }
93
- if (!gitRevision) {
94
- out = git("-C", path, "rev-parse", "--short", "HEAD");
95
- if (out.status === 0) {
96
- this.branch = out.stdout.replace("\n", "");
97
- }
98
- }
99
- }
100
- /**
101
- * Check whether the given file is tracked by this repository.
102
- *
103
- * @param fileName The name of the file to test for.
104
- * @returns TRUE when the file is part of the repository, otherwise FALSE.
105
- */
106
- contains(fileName) {
107
- return this.files.includes(fileName);
108
40
  }
109
41
  /**
110
42
  * Get the URL of the given file on GitHub or Bitbucket.
@@ -113,35 +45,13 @@ class Repository {
113
45
  * @returns A URL pointing to the web preview of the given file or undefined.
114
46
  */
115
47
  getURL(fileName) {
116
- if (this.urlCache.has(fileName)) {
117
- return this.urlCache.get(fileName);
118
- }
119
- if (!this.user || !this.project || !this.contains(fileName)) {
48
+ if (!this.files.has(fileName)) {
120
49
  return;
121
50
  }
122
- const url = [
123
- `https://${this.hostname}`,
124
- this.user,
125
- this.project,
126
- this.type === models_1.RepositoryType.GitLab ? "-" : undefined,
127
- this.type === models_1.RepositoryType.Bitbucket ? "src" : "blob",
128
- this.branch,
129
- fileName.substring(this.path.length + 1),
130
- ]
131
- .filter((s) => !!s)
132
- .join("/");
133
- this.urlCache.set(fileName, url);
134
- return url;
51
+ return `${this.baseUrl}/${fileName.substring(this.path.length + 1)}`;
135
52
  }
136
53
  getLineNumberAnchor(lineNumber) {
137
- switch (this.type) {
138
- default:
139
- case models_1.RepositoryType.GitHub:
140
- case models_1.RepositoryType.GitLab:
141
- return "L" + lineNumber;
142
- case models_1.RepositoryType.Bitbucket:
143
- return "lines-" + lineNumber;
144
- }
54
+ return `${this.anchorPrefix}${lineNumber}`;
145
55
  }
146
56
  /**
147
57
  * Try to create a new repository instance.
@@ -152,13 +62,77 @@ class Repository {
152
62
  * @param path The potential repository root.
153
63
  * @returns A new instance of {@link Repository} or undefined.
154
64
  */
155
- static tryCreateRepository(path, gitRevision, gitRemote) {
156
- const out = git("-C", path, "rev-parse", "--show-toplevel");
157
- const remotesOutput = git("-C", path, "remote", "get-url", gitRemote);
158
- if (out.status !== 0 || remotesOutput.status !== 0) {
65
+ static tryCreateRepository(path, gitRevision, gitRemote, logger) {
66
+ const topLevel = git("-C", path, "rev-parse", "--show-toplevel");
67
+ if (topLevel.status !== 0)
159
68
  return;
69
+ gitRevision || (gitRevision = git("-C", path, "rev-parse", "--short", "HEAD").stdout.trim());
70
+ if (!gitRevision)
71
+ return; // Will only happen in a repo with no commits.
72
+ let baseUrl;
73
+ if (/^https?:\/\//.test(gitRemote)) {
74
+ baseUrl = `${gitRemote}/${gitRevision}`;
160
75
  }
161
- return new Repository(base_path_1.BasePath.normalize(out.stdout.replace("\n", "")), gitRevision, remotesOutput.stdout.split("\n"));
76
+ else {
77
+ const remotesOut = git("-C", path, "remote", "get-url", gitRemote);
78
+ if (remotesOut.status === 0) {
79
+ baseUrl = guessBaseUrl(gitRevision, remotesOut.stdout.split("\n"));
80
+ }
81
+ else {
82
+ logger.warn(`The provided git remote "${gitRemote}" was not valid. Source links will be broken.`);
83
+ }
84
+ }
85
+ if (!baseUrl)
86
+ return;
87
+ return new Repository(base_path_1.BasePath.normalize(topLevel.stdout.replace("\n", "")), baseUrl);
162
88
  }
163
89
  }
164
90
  exports.Repository = Repository;
91
+ // Should have three capturing groups:
92
+ // 1. hostname
93
+ // 2. user
94
+ // 3. project
95
+ const repoExpressions = [
96
+ /(github(?!.us)(?:\.[a-z]+)*\.[a-z]{2,})[:/]([^/]+)\/(.*)/,
97
+ /(\w+\.githubprivate.com)[:/]([^/]+)\/(.*)/,
98
+ /(\w+\.ghe.com)[:/]([^/]+)\/(.*)/,
99
+ /(\w+\.github.us)[:/]([^/]+)\/(.*)/,
100
+ /(bitbucket.org)[:/]([^/]+)\/(.*)/,
101
+ /(gitlab.com)[:/]([^/]+)\/(.*)/,
102
+ ];
103
+ function guessBaseUrl(gitRevision, remotes) {
104
+ let hostname = "";
105
+ let user = "";
106
+ let project = "";
107
+ outer: for (const repoLink of remotes) {
108
+ for (const regex of repoExpressions) {
109
+ const match = regex.exec(repoLink);
110
+ if (match) {
111
+ hostname = match[1];
112
+ user = match[2];
113
+ project = match[3];
114
+ break outer;
115
+ }
116
+ }
117
+ }
118
+ if (!hostname)
119
+ return;
120
+ if (project.endsWith(".git")) {
121
+ project = project.slice(0, -4);
122
+ }
123
+ let sourcePath = "blob";
124
+ if (hostname.includes("gitlab")) {
125
+ sourcePath = "-/blob";
126
+ }
127
+ else if (hostname.includes("bitbucket")) {
128
+ sourcePath = "src";
129
+ }
130
+ return `https://${hostname}/${user}/${project}/${sourcePath}/${gitRevision}`;
131
+ }
132
+ exports.guessBaseUrl = guessBaseUrl;
133
+ function guessAnchorPrefix(url) {
134
+ if (url.includes("bitbucket")) {
135
+ return "lines-";
136
+ }
137
+ return "L";
138
+ }
@@ -1,2 +1 @@
1
1
  export { SourceReference } from "./file";
2
- export { RepositoryType } from "./repository";
@@ -1,7 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RepositoryType = exports.SourceReference = void 0;
3
+ exports.SourceReference = void 0;
4
4
  var file_1 = require("./file");
5
5
  Object.defineProperty(exports, "SourceReference", { enumerable: true, get: function () { return file_1.SourceReference; } });
6
- var repository_1 = require("./repository");
7
- Object.defineProperty(exports, "RepositoryType", { enumerable: true, get: function () { return repository_1.RepositoryType; } });
@@ -26,6 +26,7 @@ const utils_1 = require("../utils");
26
26
  const highlighter_1 = require("../utils/highlighter");
27
27
  const models_1 = require("../models");
28
28
  const icon_1 = require("./themes/default/partials/icon");
29
+ const type_1 = require("./themes/default/partials/type");
29
30
  /**
30
31
  * The renderer processes a {@link ProjectReflection} using a {@link Theme} instance and writes
31
32
  * the emitted html documents to a output directory. You can specify which theme should be used
@@ -132,6 +133,7 @@ let Renderer = class Renderer extends component_1.ChildableComponent {
132
133
  output.urls.forEach((mapping) => {
133
134
  (0, icon_1.clearSeenIconCache)();
134
135
  this.renderDocument(output.createPageEvent(mapping));
136
+ (0, type_1.validateStateIsClean)(mapping.url);
135
137
  });
136
138
  this.trigger(events_1.RendererEvent.END, output);
137
139
  }
@@ -1,4 +1,5 @@
1
1
  import type { DefaultThemeRenderContext } from "../DefaultThemeRenderContext";
2
2
  import { Type } from "../../../../models";
3
3
  import { JSX } from "../../../../utils";
4
+ export declare function validateStateIsClean(page: string): void;
4
5
  export declare function type(context: DefaultThemeRenderContext, type: Type | undefined): JSX.Element;
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.type = void 0;
3
+ exports.type = exports.validateStateIsClean = void 0;
4
4
  const models_1 = require("../../../../models");
5
5
  const utils_1 = require("../../../../utils");
6
6
  const lib_1 = require("../../lib");
7
+ const assert_1 = require("assert");
7
8
  const EXPORTABLE = models_1.ReflectionKind.Class |
8
9
  models_1.ReflectionKind.Interface |
9
10
  models_1.ReflectionKind.Enum |
@@ -51,6 +52,14 @@ function getNamespacedPath(reflection) {
51
52
  function renderUniquePath(context, reflection) {
52
53
  return (0, lib_1.join)(utils_1.JSX.createElement("span", { class: "tsd-signature-symbol" }, "."), getUniquePath(reflection), (item) => (utils_1.JSX.createElement("a", { href: context.urlTo(item), class: "tsd-signature-type", "data-tsd-kind": item.kindString }, item.name)));
53
54
  }
55
+ let indentationDepth = 0;
56
+ function includeIndentation() {
57
+ return indentationDepth > 0 ? utils_1.JSX.createElement("span", null, "\u00A0".repeat(indentationDepth * 4)) : utils_1.JSX.createElement(utils_1.JSX.Fragment, null);
58
+ }
59
+ function validateStateIsClean(page) {
60
+ (0, assert_1.ok)(indentationDepth === 0, `Rendering ${page}: Indentation depth increment/decrement not matched: ${indentationDepth}`);
61
+ }
62
+ exports.validateStateIsClean = validateStateIsClean;
54
63
  // The type helper accepts an optional needsParens parameter that is checked
55
64
  // if an inner type may result in invalid output without them. For example:
56
65
  // 1 | 2[] !== (1 | 2)[]
@@ -192,7 +201,9 @@ const typeRenderers = {
192
201
  },
193
202
  reflection(context, type) {
194
203
  const members = [];
195
- for (const item of type.declaration.children || []) {
204
+ const children = type.declaration.children || [];
205
+ indentationDepth++;
206
+ for (const item of children) {
196
207
  if (item.getSignature && item.setSignature) {
197
208
  members.push(utils_1.JSX.createElement(utils_1.JSX.Fragment, null,
198
209
  item.name,
@@ -237,6 +248,7 @@ const typeRenderers = {
237
248
  renderType(context, index.type, models_1.TypeContext.none)));
238
249
  }
239
250
  if (!members.length && type.declaration.signatures?.length === 1) {
251
+ indentationDepth--;
240
252
  return (utils_1.JSX.createElement(utils_1.JSX.Fragment, null,
241
253
  utils_1.JSX.createElement("span", { class: "tsd-signature-symbol" }, "("),
242
254
  context.memberSignatureTitle(type.declaration.signatures[0], {
@@ -249,17 +261,25 @@ const typeRenderers = {
249
261
  members.push(context.memberSignatureTitle(item, { hideName: true }));
250
262
  }
251
263
  if (members.length) {
252
- const membersWithSeparators = members.flatMap((m) => [m, utils_1.JSX.createElement("span", { class: "tsd-signature-symbol" }, "; ")]);
264
+ const membersWithSeparators = members.flatMap((m) => [
265
+ includeIndentation(),
266
+ m,
267
+ utils_1.JSX.createElement("span", { class: "tsd-signature-symbol" }, "; "),
268
+ utils_1.JSX.createElement("br", null),
269
+ ]);
253
270
  membersWithSeparators.pop();
271
+ indentationDepth--;
254
272
  return (utils_1.JSX.createElement(utils_1.JSX.Fragment, null,
255
273
  utils_1.JSX.createElement("span", { class: "tsd-signature-symbol" },
256
274
  "{",
257
275
  " "),
276
+ utils_1.JSX.createElement("br", null),
258
277
  membersWithSeparators,
259
- utils_1.JSX.createElement("span", { class: "tsd-signature-symbol" },
260
- " ",
261
- "}")));
278
+ utils_1.JSX.createElement("br", null),
279
+ includeIndentation(),
280
+ utils_1.JSX.createElement("span", { class: "tsd-signature-symbol" }, "}")));
262
281
  }
282
+ indentationDepth--;
263
283
  return utils_1.JSX.createElement("span", { class: "tsd-signature-symbol" }, "{}");
264
284
  },
265
285
  rest(context, type) {
@@ -234,7 +234,7 @@ function getEntryPointsForPackages(logger, packageGlobPaths, options) {
234
234
  if (packageEntryPoint === package_manifest_1.ignorePackage) {
235
235
  continue;
236
236
  }
237
- const tsconfigFile = ts.findConfigFile(packageEntryPoint, ts.sys.fileExists);
237
+ const tsconfigFile = ts.findConfigFile(packageEntryPoint, ts.sys.fileExists, typedocPackageConfig?.tsconfig);
238
238
  if (tsconfigFile === undefined) {
239
239
  logger.error(`Could not determine tsconfig.json for source file ${packageEntryPoint} (it must be on an ancestor path)`);
240
240
  return;
@@ -274,12 +274,24 @@ function getEntryPointsForPackages(logger, packageGlobPaths, options) {
274
274
  version: includeVersion
275
275
  ? packageJson["version"]
276
276
  : void 0,
277
- readmeFile: typedocPackageConfig?.readmeFile
278
- ? Path.resolve(Path.join(packageJsonPath, "..", typedocPackageConfig?.readmeFile))
279
- : undefined,
277
+ readmeFile: discoverReadmeFile(logger, Path.join(packageJsonPath, ".."), typedocPackageConfig?.readmeFile),
280
278
  program,
281
279
  sourceFile,
282
280
  });
283
281
  }
284
282
  return results;
285
283
  }
284
+ function discoverReadmeFile(logger, packageDir, userReadme) {
285
+ if (userReadme) {
286
+ if (!FS.existsSync(Path.join(packageDir, userReadme))) {
287
+ logger.warn(`Failed to find ${userReadme} in ${(0, paths_1.nicePath)(packageDir)}`);
288
+ return;
289
+ }
290
+ return Path.resolve(Path.join(packageDir, userReadme));
291
+ }
292
+ for (const file of FS.readdirSync(packageDir)) {
293
+ if (file.toLowerCase() === "readme.md") {
294
+ return Path.resolve(Path.join(packageDir, file));
295
+ }
296
+ }
297
+ }
@@ -9,6 +9,7 @@ declare const typedocPackageManifestConfigSchema: {
9
9
  displayName: import("./validation").Optional<StringConstructor>;
10
10
  entryPoint: import("./validation").Optional<StringConstructor>;
11
11
  readmeFile: import("./validation").Optional<StringConstructor>;
12
+ tsconfig: import("./validation").Optional<StringConstructor>;
12
13
  [additionalProperties]: boolean;
13
14
  };
14
15
  export declare type TypedocPackageManifestConfig = Infer<typeof typedocPackageManifestConfigSchema>;
@@ -32,6 +32,7 @@ const typedocPackageManifestConfigSchema = {
32
32
  displayName: (0, validation_1.optional)(String),
33
33
  entryPoint: (0, validation_1.optional)(String),
34
34
  readmeFile: (0, validation_1.optional)(String),
35
+ tsconfig: (0, validation_1.optional)(String),
35
36
  [validation_1.additionalProperties]: false,
36
37
  };
37
38
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "typedoc",
3
3
  "description": "Create api documentation for TypeScript projects.",
4
- "version": "0.23.15",
4
+ "version": "0.23.16",
5
5
  "homepage": "https://typedoc.org",
6
6
  "main": "./dist/index.js",
7
7
  "exports": {
@@ -1,5 +0,0 @@
1
- export declare enum RepositoryType {
2
- GitHub = "github",
3
- Bitbucket = "bitbucket",
4
- GitLab = "gitlab"
5
- }
@@ -1,9 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RepositoryType = void 0;
4
- var RepositoryType;
5
- (function (RepositoryType) {
6
- RepositoryType["GitHub"] = "github";
7
- RepositoryType["Bitbucket"] = "bitbucket";
8
- RepositoryType["GitLab"] = "gitlab";
9
- })(RepositoryType = exports.RepositoryType || (exports.RepositoryType = {}));