diff --git a/packages/ts-docs-gen/src/contracts/plugin-result-registry.ts b/packages/ts-docs-gen/src/contracts/plugin-result-registry.ts new file mode 100644 index 00000000..3a956da9 --- /dev/null +++ b/packages/ts-docs-gen/src/contracts/plugin-result-registry.ts @@ -0,0 +1,11 @@ +import { PluginResult } from "./plugin"; +import { ApiItemReference } from "./api-item-reference"; + +export interface ReadonlyPluginResultRegistry { + GetItem(itemReference: ApiItemReference): PluginResult | undefined; + Exists(itemReference: ApiItemReference): boolean; +} + +export interface PluginResultRegistry extends ReadonlyPluginResultRegistry { + AddItem(itemReference: ApiItemReference, pluginResult: PluginResult): void; +} diff --git a/packages/ts-docs-gen/src/contracts/plugin.ts b/packages/ts-docs-gen/src/contracts/plugin.ts index da7f3f7e..65710657 100644 --- a/packages/ts-docs-gen/src/contracts/plugin.ts +++ b/packages/ts-docs-gen/src/contracts/plugin.ts @@ -19,12 +19,14 @@ export interface PluginMember { } export type GetItemPluginResultHandler = (reference: ApiItemReference) => PluginResult; +export type IsPluginResultExistsHandler = (reference: ApiItemReference) => boolean; export interface PluginOptions { Reference: ApiItemReference; ApiItem: TKind; ExtractedData: ExtractDto; GetItemPluginResult: GetItemPluginResultHandler; + IsPluginResultExists: IsPluginResultExistsHandler; } export interface PluginResult { diff --git a/packages/ts-docs-gen/src/debug.ts b/packages/ts-docs-gen/src/debug.ts index 0392b129..147abc82 100644 --- a/packages/ts-docs-gen/src/debug.ts +++ b/packages/ts-docs-gen/src/debug.ts @@ -7,7 +7,7 @@ import { Generator } from "./generator"; async function Main(): Promise { const projectDirectory = path.join(process.cwd(), "./examples/simple/"); // const entryFiles = ["./index.ts", "./exported-const-variables.ts", "./exported-functions.ts"]; - const entryFiles = ["./index.ts", "./exported-functions.ts"]; + const entryFiles = ["./exported-functions.ts", "./index.ts"]; const configPromise = new GeneratorConfigurationBuilder(projectDirectory).Build(entryFiles); const config = await configPromise; diff --git a/packages/ts-docs-gen/src/file-manager.ts b/packages/ts-docs-gen/src/file-manager.ts index 41436a00..d5760681 100644 --- a/packages/ts-docs-gen/src/file-manager.ts +++ b/packages/ts-docs-gen/src/file-manager.ts @@ -64,8 +64,7 @@ export class FileManager { for (const [fileLocation, items] of this.filesList) { // Link definitions to file location. const linkDefinitions: string[] = []; - for (const item of items) { - + for (const item of items.reverse()) { item.UsedReferences .forEach(referenceId => { const filePath = path.dirname(fileLocation); diff --git a/packages/ts-docs-gen/src/generator.ts b/packages/ts-docs-gen/src/generator.ts index d550516a..ae8bcfbe 100644 --- a/packages/ts-docs-gen/src/generator.ts +++ b/packages/ts-docs-gen/src/generator.ts @@ -9,10 +9,13 @@ import { ApiDefaultPlugin } from "./plugins/api-default-plugin"; import { ApiItemReference } from "./contracts/api-item-reference"; import { PluginResult, PluginOptions, GetItemPluginResultHandler } from "./contracts/plugin"; import { FileResult } from "./contracts/file-result"; +import { PluginResultRegistry } from "./contracts/plugin-result-registry"; +import { PluginResultRegistry as PluginResultRegistryClass } from "./registries/plugin-result-registry"; export class Generator { constructor(private configuration: GeneratorConfiguration) { this.fileManager = new FileManager(); + this.pluginResultRegistry = new PluginResultRegistryClass(); const { ExtractedData } = this.configuration; for (const entryFile of ExtractedData.EntryFiles) { @@ -26,10 +29,7 @@ export class Generator { this.outputData = this.fileManager.ToFilesOutput(); } - /** - * FIXME: Reference check.... how Map Works here. - */ - private renderedItems: Map = new Map(); + private pluginResultRegistry: PluginResultRegistry; private fileManager: FileManager; private outputData: FileResult[]; @@ -53,14 +53,15 @@ export class Generator { } private getItemPluginResult: GetItemPluginResultHandler = (apiItemReference: ApiItemReference): PluginResult => { - const renderedItem = this.renderedItems.get(apiItemReference); + const renderedItem = this.pluginResultRegistry.GetItem(apiItemReference); if (renderedItem == null) { const { Registry } = this.configuration.ExtractedData; - const renderedData = this.renderApiItem(apiItemReference, Registry[apiItemReference.Id]); - this.renderedItems.set(apiItemReference, renderedData); - return renderedData; + const pluginResult = this.renderApiItem(apiItemReference, Registry[apiItemReference.Id]); + this.pluginResultRegistry.AddItem(apiItemReference, pluginResult); + + return pluginResult; } return renderedItem; @@ -76,7 +77,8 @@ export class Generator { ExtractedData: this.configuration.ExtractedData, Reference: apiItemReference, ApiItem: apiItem, - GetItemPluginResult: this.getItemPluginResult + GetItemPluginResult: this.getItemPluginResult, + IsPluginResultExists: reference => this.pluginResultRegistry.Exists(reference) }; for (const plugin of plugins) { diff --git a/packages/ts-docs-gen/src/plugins/api-source-file-plugin.ts b/packages/ts-docs-gen/src/plugins/api-source-file-plugin.ts index ed1de98b..03d86f4b 100644 --- a/packages/ts-docs-gen/src/plugins/api-source-file-plugin.ts +++ b/packages/ts-docs-gen/src/plugins/api-source-file-plugin.ts @@ -7,6 +7,7 @@ import { PluginMember, Plugin, SupportedApiItemKindType, PluginOptions, PluginRe interface RenderItems { References: string[]; + Headings: PluginHeading[]; Output: string[]; Members: PluginMember[]; } @@ -23,41 +24,52 @@ export class ApiSourceFilePlugin implements Plugin { // TODO: Move this to helpers. private renderItems(data: PluginOptions): RenderItems { const references = GeneratorHelpers.GetApiItemReferences(data.ExtractedData, data.ApiItem.Members); - const referencesList: string[] = []; + let referencesList: string[] = []; + let headingsList: PluginHeading[] = []; const members: PluginMember[] = []; const builder = new MarkdownBuilder(); for (const reference of references) { const apiItem = data.ExtractedData.Registry[reference.Id]; - switch (apiItem.ApiKind) { - case Contracts.ApiItemKinds.Namespace: - case Contracts.ApiItemKinds.Class: { + if (data.IsPluginResultExists(reference)) { + builder + .Text(md => md.Header(md.Link(apiItem.Name, reference.Id, true), 2)) + .EmptyLine(); + referencesList.push(reference.Id); + } else { + switch (apiItem.ApiKind) { + case Contracts.ApiItemKinds.Namespace: + case Contracts.ApiItemKinds.Class: { - const renderedItem = data.GetItemPluginResult(reference); - members.push({ - Reference: reference, - PluginResult: renderedItem - }); + const renderedItem = data.GetItemPluginResult(reference); + members.push({ + Reference: reference, + PluginResult: renderedItem + }); - builder - .Text(md => md.Header(md.Link(renderedItem.ApiItem.Name, reference.Id, true), 2)) - .EmptyLine(); - referencesList.push(reference.Id); - break; - } - default: { - const renderedItem = data.GetItemPluginResult(reference); - // Something to do with heading. Maybe heading reference registry? - builder - .Text(renderedItem.Result) - .EmptyLine(); + builder + .Text(md => md.Header(md.Link(renderedItem.ApiItem.Name, reference.Id, true), 2)) + .EmptyLine(); + referencesList.push(reference.Id); + break; + } + default: { + const renderedItem = data.GetItemPluginResult(reference); + builder + .Text(renderedItem.Result) + .EmptyLine(); + + headingsList = headingsList.concat(renderedItem.Headings); + referencesList = referencesList.concat(renderedItem.UsedReferences); + } } } } return { References: referencesList, + Headings: headingsList, Output: builder.GetOutput(), Members: members }; @@ -65,7 +77,7 @@ export class ApiSourceFilePlugin implements Plugin { public Render(data: PluginOptions): PluginResult { const heading = path.basename(data.ApiItem.Name, path.extname(data.ApiItem.Name)); - const headings: PluginHeading[] = [ + let headings: PluginHeading[] = [ { Heading: heading, ApiItemId: data.Reference.Id @@ -74,6 +86,7 @@ export class ApiSourceFilePlugin implements Plugin { const renderedItems = this.renderItems(data); const references: string[] = renderedItems.References; + headings = headings.concat(renderedItems.Headings); // Header const builder = new MarkdownBuilder() diff --git a/packages/ts-docs-gen/src/registries/plugin-result-registry.ts b/packages/ts-docs-gen/src/registries/plugin-result-registry.ts new file mode 100644 index 00000000..d622c1db --- /dev/null +++ b/packages/ts-docs-gen/src/registries/plugin-result-registry.ts @@ -0,0 +1,36 @@ +import { ApiItemReference } from "../contracts/api-item-reference"; +import { PluginResult } from "../contracts/plugin"; +import { PluginResultRegistry as PluginResultRegistryInterface } from "../contracts/plugin-result-registry"; + +export class PluginResultRegistry implements PluginResultRegistryInterface { + private results: Map = new Map(); + + private getKey(itemReference: ApiItemReference): ApiItemReference | undefined { + for (const [reference] of this.results) { + if (itemReference.Alias === reference.Alias && + itemReference.Id === reference.Id) { + return reference; + } + } + + return undefined; + } + + public AddItem(itemReference: ApiItemReference, pluginResult: PluginResult): void { + const key = this.getKey(itemReference) || itemReference; + this.results.set(key, pluginResult); + } + + public GetItem(itemReference: ApiItemReference): PluginResult | undefined { + const realKey = this.getKey(itemReference); + if (realKey != null) { + return this.results.get(realKey); + } else { + return undefined; + } + } + + public Exists(itemReference: ApiItemReference): boolean { + return this.getKey(itemReference) != null; + } +} diff --git a/packages/ts-docs-gen/tests/cases/__tests__/__snapshots__/simple-project-1.test.ts.snap b/packages/ts-docs-gen/tests/cases/__tests__/__snapshots__/simple-project-1.test.ts.snap index a890da1a..53bab2b8 100644 --- a/packages/ts-docs-gen/tests/cases/__tests__/__snapshots__/simple-project-1.test.ts.snap +++ b/packages/ts-docs-gen/tests/cases/__tests__/__snapshots__/simple-project-1.test.ts.snap @@ -8,6 +8,8 @@ Array [ "[ClassDeclaration-0]: index/foo.md#class-foo", "[ClassDeclaration-1]: index/world.md#class-world", "[ClassDeclaration-2]: index/earth.md#class-earth", + "[ClassDeclaration-2]: index/earth.md#class-earth", + "[ClassDeclaration-1]: index/world.md#class-world", "# index", "", "## EnumList", diff --git a/packages/ts-docs-gen/tests/cases/__tests__/__snapshots__/simple-project-2.test.ts.snap b/packages/ts-docs-gen/tests/cases/__tests__/__snapshots__/simple-project-2.test.ts.snap index 97f1579d..64b34875 100644 --- a/packages/ts-docs-gen/tests/cases/__tests__/__snapshots__/simple-project-2.test.ts.snap +++ b/packages/ts-docs-gen/tests/cases/__tests__/__snapshots__/simple-project-2.test.ts.snap @@ -5,7 +5,7 @@ Array [ Object { "FileLocation": "index.md", "Result": Array [ - "[ClassDeclaration-0]: foo/foo.md#class-foo", + "[ClassDeclaration-0]: index/foo.md#class-foo", "[ClassDeclaration-1]: index/foostart.md#class-foostart", "# index", "", @@ -33,7 +33,7 @@ Array [ Object { "FileLocation": "foo.md", "Result": Array [ - "[ClassDeclaration-0]: foo/foo.md#class-foo", + "[ClassDeclaration-0]: index/foo.md#class-foo", "# foo", "", "## [Foo][ClassDeclaration-0]", @@ -41,12 +41,5 @@ Array [ "", ], }, - Object { - "FileLocation": "foo/foo.md", - "Result": Array [ - "## class: Foo", - "", - ], - }, ] `;