Skip to content

Commit e758771

Browse files
committed
Finish moving Node references out of models
Ref: #2528
1 parent c868545 commit e758771

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+2936
-1643
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ title: Changelog
1616
control over export conversion order, #2856
1717
- API: `Deserializer.reviveProject(s)` no longer accepts an option to add project documents.
1818
- API: `Deserializer.reviveProjects` now requires an `alwaysCreateEntryPointModule` option.
19+
- API: `Comment.serializeDisplayParts` no longer requires a serializer argument.
20+
- API: `ReflectionSymbolId.fileName` has been removed, TypeDoc now stores a combination of a package name and package relative path instead.
21+
- API: Removed `DeclarationReflection.relevanceBoost` attribute which was added for plugins, but never used.
22+
- The `source-order` sort ordering now considers package names / package relative paths instead of using the absolute paths to a file.
23+
- File name references in `intentionallyNotExported` now use a package name/package relative path instead of an absolute path for matching.
24+
- Introduced `packagesRequiringDocumentation` option for `validation.notDocumented`, TypeDoc will expect comments to be present for symbols in the specified packages.
25+
- TypeDoc's `--entryPointStrategy merge` mode now requires JSON from at least version 0.28.0.
1926

2027
TODO:
2128

eslint.config.mjs

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ const config = {
3434
],
3535

3636
// This can probably be turned back on in 0.27, when the component hierarchy goes away
37-
"@typescript-eslint/no-unsafe-function-type": "off",
37+
// "@typescript-eslint/no-unsafe-function-type": "off", GERRIT
3838

3939
// This one is just annoying since it complains at incomplete code
4040
"no-empty": "off",
@@ -196,29 +196,21 @@ export default tslint.config(
196196
],
197197
},
198198
},
199-
// Down to 14 issues!
200-
// {
201-
// files: ["src/lib/models/**/*.ts"],
202-
// rules: {
203-
// "no-restricted-imports": [
204-
// "error",
205-
// {
206-
// paths: nodeModules,
207-
// patterns: [
208-
// "node:*",
209-
// "\\#*",
210-
// "!\\#utils",
211-
// "!\\#serialization",
212-
// "../*",
213-
// "!../FileRegistry.js",
214-
// "!../types.js",
215-
// "!../comments/index.js",
216-
// "!../sources/file.js",
217-
// ],
218-
// },
219-
// ],
220-
// },
221-
// },
199+
{
200+
files: ["src/lib/models/**/*.ts"],
201+
rules: {
202+
"no-restricted-imports": [
203+
"error",
204+
{
205+
paths: nodeModules,
206+
patterns: [{
207+
regex: "^(?!\./|#utils|#serialization).*",
208+
message: "models may only import within this directory or #utils/#serialization",
209+
}],
210+
},
211+
],
212+
},
213+
},
222214
{
223215
files: ["src/lib/serialization/**/*.ts"],
224216
rules: {

scripts/generate_options_schema.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,13 @@ const schema = {
1717
allowTrailingCommas: true,
1818
};
1919

20-
const i18n = new Internationalization.Internationalization(null).proxy;
21-
2220
addTypeDocOptions({
2321
/** @param {import("../dist/index.js").DeclarationOption} option */
2422
addDeclaration(option) {
2523
if (IGNORED_OPTIONS.has(option.name)) return;
2624

2725
const data = {
28-
description: option.help(i18n),
26+
description: option.help(),
2927
};
3028

3129
const type = option.type ?? ParameterType.String;
@@ -42,6 +40,7 @@ addTypeDocOptions({
4240
break;
4341
case ParameterType.String:
4442
case ParameterType.Path:
43+
case ParameterType.UrlOrPath:
4544
data.type = "string";
4645
if (!IGNORED_DEFAULT_OPTIONS.has(option.name)) {
4746
data.default = /** @type {import("../dist/index.js").StringDeclarationOption} */ (

scripts/rebuild_specs.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import * as td from "../dist/index.js";
99
import { getExpandedEntryPointsForPaths } from "../dist/lib/utils/index.js";
1010
import { ok } from "assert";
1111
import { fileURLToPath } from "url";
12+
import { diagnostics } from "../dist/lib/utils/loggers.js";
1213

1314
const base = path.join(
1415
fileURLToPath(import.meta.url),
@@ -101,7 +102,7 @@ function rebuildConverterTests(app, dirs) {
101102

102103
const errors = ts.getPreEmitDiagnostics(program);
103104
if (errors.length) {
104-
app.logger.diagnostics(errors);
105+
diagnostics(app.logger, errors);
105106
return;
106107
}
107108

@@ -124,7 +125,7 @@ function rebuildConverterTests(app, dirs) {
124125
result.name = basename(fullPath);
125126
const serialized = app.serializer.projectToObject(
126127
result,
127-
process.cwd(),
128+
td.normalizePath(process.cwd()),
128129
);
129130

130131
const data = JSON.stringify(serialized, null, 4) + "\n";

site/options/package-options.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ at the root level. The following tables indicate where an option should be set.
8383
| [`favicon`](output.md#favicon) | Root | |
8484
| [`sourceLinkExternal`](output.md#sourcelinkexternal) | Root | |
8585
| [`markdownLinkExternal`](output.md#markdownlinkexternal) | Root | |
86-
| [`lang`](output.md#lang) | Both | Will move to Root in TypeDoc 0.28 |
87-
| [`locales`](output.md#locales) | Both | Will move to Root in TypeDoc 0.28 |
86+
| [`lang`](output.md#lang) | Root | |
87+
| [`locales`](output.md#locales) | Root | |
8888
| [`githubPages`](output.md#githubpages) | Root | |
8989
| [`cacheBust`](output.md#cachebust) | Root | |
9090
| [`hideGenerator`](output.md#hidegenerator) | Root | |
@@ -144,6 +144,7 @@ at the root level. The following tables indicate where an option should be set.
144144
| [`treatValidationWarningsAsErrors`](validation.md#treatvalidationwarningsaserrors) | Root | |
145145
| [`intentionallyNotExported`](validation.md#intentionallynotexported) | Both | |
146146
| [`requiredToBeDocumented`](validation.md#requiredtobedocumented) | Both | |
147+
| [`packagesRequiringDocumentation`](validation.md#packagesrequiringdocumentation) | Both | |
147148
| [`intentionallyNotDocumented`](validation.md#intentionallynotdocumented) | Both | |
148149

149150
## Other Options

site/options/validation.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,16 @@ This option cannot be used to turn `treatWarningsAsErrors` off for validation wa
6767
## intentionallyNotExported
6868

6969
Lists symbols which are intentionally excluded from the documentation output and should not produce warnings.
70-
Entries may optionally specify a file name before a colon to only suppress warnings for symbols declared in a specific file.
70+
Entries may optionally specify a package name / package relative file name before a colon to only suppress warnings for symbols declared in a specific file.
7171

7272
typedoc.json:
7373

7474
```json
7575
{
76-
"intentionallyNotExported": ["InternalClass", "src/other.ts:OtherInternal"]
76+
"intentionallyNotExported": [
77+
"InternalClass",
78+
"typedoc/src/other.ts:OtherInternal"
79+
]
7780
}
7881
```
7982

@@ -124,6 +127,17 @@ typedoc.json:
124127
}
125128
```
126129

130+
## packagesRequiringDocumentation
131+
132+
Specifies which packages TypeDoc should expect to have documentation.
133+
Defaults to the name of your package from `package.json`.
134+
135+
```json
136+
{
137+
"packagesRequiringDocumentation": ["typedoc", "typedoc-plugin-mdn-links"]
138+
}
139+
```
140+
127141
## intentionallyNotDocumented
128142

129143
Used to selectively ignore undocumented fields, used by `validation.notDocumented`.

site/overview.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ the supported version range will generally not include versions not supported by
1919

2020
| TypeDoc Version | TypeScript Version | Status |
2121
| --------------- | ------------------ | ------------------ |
22-
| 0.27 | 5.0 through 5.7 | ✅ Maintained |
23-
| 0.26 | 4.6 through 5.6 | ⚠️ Security Updates |
22+
| 0.28 | 5.1 through 5.8 | ✅ Maintained |
23+
| 0.27 | 5.0 through 5.7 | ⚠️ Security Updates |
24+
| 0.26 | 4.6 through 5.6 | ❌ Unmaintained |
2425
| 0.25 | 4.6 through 5.4 | ❌ Unmaintained |
2526
| 0.24 | 4.6 through 5.1 | ❌ Unmaintained |
2627
| 0.23 | 4.6 through 5.0 | ❌ Unmaintained |

src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*/
99
export { Application, type ApplicationEvents } from "./lib/application.js";
1010

11-
export { resetReflectionID } from "./lib/models/reflections/abstract.js";
11+
export { resetReflectionID } from "./lib/models/Reflection.js";
1212
/**
1313
* All symbols documented under the Models namespace are also available in the root import.
1414
* @primaryExport
@@ -87,6 +87,7 @@ export {
8787
ParameterType,
8888
TSConfigReader,
8989
TypeDocReader,
90+
ValidatingFileRegistry,
9091
} from "./lib/utils/index.js";
9192

9293
export type {

src/lib/application.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import ts from "typescript";
44
import { Deserializer, type JSONOutput, Serializer } from "./serialization/index.js";
55
import { Converter } from "./converter/index.js";
66
import { Renderer } from "./output/renderer.js";
7-
import type { ProjectReflection } from "./models/index.js";
7+
import { type ProjectReflection, ReflectionSymbolId } from "./models/index.js";
88
import {
99
AbstractComponent,
1010
FancyConsoleLogger,
@@ -35,7 +35,6 @@ import { validateDocumentation } from "./validation/documentation.js";
3535
import { validateLinks } from "./validation/links.js";
3636
import { ApplicationEvents } from "./application-events.js";
3737
import { deriveRootDir, findTsConfigFile, glob, readFile } from "#node-utils";
38-
import { addInferredDeclarationMapPaths } from "./models/ReflectionSymbolId.js";
3938
import { Internationalization } from "./internationalization/internationalization.js";
4039
import { FileRegistry } from "./models/FileRegistry.js";
4140
import { readFileSync } from "fs";
@@ -45,6 +44,7 @@ import { Outputs } from "./output/output.js";
4544
import { validateMergeModuleWith } from "./validation/unusedMergeModuleWith.js";
4645
import { diagnostic, diagnostics } from "./utils/loggers.js";
4746
import { ValidatingFileRegistry } from "./utils/ValidatingFileRegistry.js";
47+
import { addInferredDeclarationMapPaths } from "./converter/factories/symbol-id.js";
4848

4949
const packageInfo = JSON.parse(
5050
readFileSync(
@@ -670,11 +670,16 @@ export class Application extends AbstractComponent<
670670
}
671671

672672
if (checks.notDocumented) {
673+
const packagesRequiringDocumentation = this.options.isSet("packagesRequiringDocumentation")
674+
? this.options.getValue("packagesRequiringDocumentation")
675+
: [project.packageName ?? ReflectionSymbolId.UNKNOWN_PACKAGE];
676+
673677
validateDocumentation(
674678
project,
675679
this.logger,
676680
this.options.getValue("requiredToBeDocumented"),
677681
this.options.getValue("intentionallyNotDocumented"),
682+
packagesRequiringDocumentation,
678683
);
679684
}
680685

src/lib/converter/comments/blockLexer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import ts from "typescript";
22
import { type Token, TokenSyntaxKind } from "./lexer.js";
3-
import { ReflectionSymbolId } from "../../models/ReflectionSymbolId.js";
43
import { resolveAliasedSymbol } from "../utils/symbols.js";
4+
import { createSymbolId } from "../factories/symbol-id.js";
55

66
export function* lexBlockComment(
77
file: string,
@@ -356,7 +356,7 @@ function* lexBlockComment2(
356356
getRightmostName(link.name),
357357
);
358358
if (tsTarget) {
359-
token.tsLinkTarget = new ReflectionSymbolId(
359+
token.tsLinkTarget = createSymbolId(
360360
resolveAliasedSymbol(tsTarget, checker!),
361361
);
362362
token.tsLinkText = link.text.replace(/^\s*\|\s*/, "");

src/lib/converter/context.ts

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import { resolveAliasedSymbol } from "./utils/symbols.js";
1818
import { getComment, getFileComment, getJsDocComment, getNodeComment, getSignatureComment } from "./comments/index.js";
1919
import { getHumanName } from "../utils/tsutils.js";
2020
import { normalizePath } from "#node-utils";
21+
import { createSymbolId } from "./factories/symbol-id.js";
22+
import { type NormalizedPath, removeIf } from "#utils";
2123

2224
/**
2325
* The context describes the current state the converter is in.
@@ -67,6 +69,8 @@ export class Context {
6769
convertingClassOrInterface = false; // Not inherited
6870
shouldBeStatic = false; // Not inherited
6971

72+
private reflectionIdToSymbolMap = new Map<number, ts.Symbol>();
73+
7074
/**
7175
* Create a new Context instance.
7276
*
@@ -77,7 +81,7 @@ export class Context {
7781
converter: Converter,
7882
programs: readonly ts.Program[],
7983
project: ProjectReflection,
80-
scope: Context["scope"] = project,
84+
scope: Reflection = project,
8185
) {
8286
this.converter = converter;
8387
this.programs = programs;
@@ -197,15 +201,15 @@ export class Context {
197201
}
198202

199203
if (reflection instanceof DeclarationReflection) {
200-
reflection.escapedName = symbol?.escapedName;
204+
reflection.escapedName = symbol?.escapedName ? String(symbol.escapedName) : undefined;
201205
this.addChild(reflection);
202206
}
203207

204208
if (symbol && this.converter.isExternal(symbol)) {
205209
reflection.setFlag(ReflectionFlag.External);
206210
}
207211
if (exportSymbol) {
208-
this.registerReflection(reflection, exportSymbol);
212+
this.registerReflection(reflection, exportSymbol, void 0);
209213
}
210214

211215
const path = reflection.kindOf(
@@ -215,9 +219,9 @@ export class Context {
215219
: undefined;
216220

217221
if (path) {
218-
this.project.registerReflection(reflection, symbol, normalizePath(path));
222+
this.registerReflection(reflection, symbol, normalizePath(path));
219223
} else {
220-
this.project.registerReflection(reflection, symbol, undefined);
224+
this.registerReflection(reflection, symbol, undefined);
221225
}
222226
}
223227

@@ -250,8 +254,51 @@ export class Context {
250254
* @param reflection The reflection that should be registered.
251255
* @param symbol The symbol the given reflection was resolved from.
252256
*/
253-
registerReflection(reflection: Reflection, symbol: ts.Symbol | undefined) {
254-
this.project.registerReflection(reflection, symbol, void 0);
257+
registerReflection(reflection: Reflection, symbol: ts.Symbol | undefined, filePath?: NormalizedPath) {
258+
if (symbol) {
259+
this.reflectionIdToSymbolMap.set(reflection.id, symbol);
260+
const id = createSymbolId(symbol);
261+
262+
// #2466
263+
// If we just registered a member of a class or interface, then we need to check if
264+
// we've registered this symbol before under the wrong parent reflection.
265+
// This can happen because the compiler API will use non-dependently-typed symbols
266+
// for properties of classes/interfaces which inherit them, so we can't rely on the
267+
// property being unique for each class.
268+
if (
269+
reflection.parent?.kindOf(ReflectionKind.ClassOrInterface) &&
270+
reflection.kindOf(ReflectionKind.SomeMember)
271+
) {
272+
const saved = this.project["symbolToReflectionIdMap"].get(id);
273+
const parentSymbolReflection = symbol.parent &&
274+
this.getReflectionFromSymbol(symbol.parent);
275+
276+
if (
277+
typeof saved === "object" &&
278+
saved.length > 1 &&
279+
parentSymbolReflection
280+
) {
281+
removeIf(
282+
saved,
283+
(item) =>
284+
this.project.getReflectionById(item)?.parent !==
285+
parentSymbolReflection,
286+
);
287+
}
288+
}
289+
290+
this.project.registerReflection(reflection, id, filePath);
291+
} else {
292+
this.project.registerReflection(reflection, void 0, filePath);
293+
}
294+
}
295+
296+
getReflectionFromSymbol(symbol: ts.Symbol) {
297+
return this.project.getReflectionFromSymbolId(createSymbolId(symbol));
298+
}
299+
300+
getSymbolFromReflection(reflection: Reflection) {
301+
return this.reflectionIdToSymbolMap.get(reflection.id);
255302
}
256303

257304
/** @internal */
@@ -321,6 +368,9 @@ export class Context {
321368
}
322369

323370
public withScope(scope: Reflection): Context {
371+
// TODO: This will be important for #2862
372+
// assert(scope.parent === this.scope, "Incorrect context used for withScope");
373+
324374
const context = new Context(
325375
this.converter,
326376
this.programs,
@@ -329,6 +379,7 @@ export class Context {
329379
);
330380
context.convertingTypeNode = this.convertingTypeNode;
331381
context.setActiveProgram(this._program);
382+
context.reflectionIdToSymbolMap = this.reflectionIdToSymbolMap;
332383
return context;
333384
}
334385
}

0 commit comments

Comments
 (0)