From 676e498c01aa42837bb9b21ff66b414bd9f38e10 Mon Sep 17 00:00:00 2001 From: griest024 Date: Fri, 10 Jan 2025 16:48:05 -0500 Subject: [PATCH] feat(dgeni,docs,daffio): implement ToC for all doc kinds (#3423) --- .../api-content/api-content.component.html | 9 ++++++- .../default-content.component.html | 2 +- .../table-of-contents.component.spec.ts | 4 +-- .../guides-content.component.ts | 6 ++--- .../docs/testing/factories/docs.factory.ts | 6 ++--- libs/docs-utils/src/doc/api.type.ts | 2 +- libs/docs-utils/src/doc/guide.type.ts | 9 ------- libs/docs-utils/src/doc/package-guide.type.ts | 17 +++++++------ libs/docs-utils/src/doc/public_api.ts | 3 --- libs/docs-utils/src/doc/type.ts | 5 ++-- libs/docs-utils/src/example/public_api.ts | 1 + .../{doc/example.type.ts => example/type.ts} | 5 ++++ libs/docs-utils/src/public_api.ts | 9 ++++--- libs/docs-utils/src/toc/public_api.ts | 1 + .../src/{doc/toc.type.ts => toc/type.ts} | 0 .../processors/add-api-symbols-to-package.ts | 11 ++++++-- .../processors/examples.ts | 25 +++++++++++++++++-- 17 files changed, 76 insertions(+), 39 deletions(-) delete mode 100644 libs/docs-utils/src/doc/guide.type.ts create mode 100644 libs/docs-utils/src/example/public_api.ts rename libs/docs-utils/src/{doc/example.type.ts => example/type.ts} (65%) create mode 100644 libs/docs-utils/src/toc/public_api.ts rename libs/docs-utils/src/{doc/toc.type.ts => toc/type.ts} (100%) diff --git a/apps/daffio/src/app/docs/api/components/api-content/api-content.component.html b/apps/daffio/src/app/docs/api/components/api-content/api-content.component.html index 5005fbba1f..45a141cc31 100644 --- a/apps/daffio/src/app/docs/api/components/api-content/api-content.component.html +++ b/apps/daffio/src/app/docs/api/components/api-content/api-content.component.html @@ -1,7 +1,14 @@ - + @if (isApiPackage()) { } @else {
+ @if (doc().examples.length > 0) { +

Examples

+ } + @for (example of doc().examples; track example.id) { +

{{example.caption}}

+
+ } }
\ No newline at end of file diff --git a/apps/daffio/src/app/docs/components/default-content/default-content.component.html b/apps/daffio/src/app/docs/components/default-content/default-content.component.html index 64a3def65f..e7a84ae3c6 100644 --- a/apps/daffio/src/app/docs/components/default-content/default-content.component.html +++ b/apps/daffio/src/app/docs/components/default-content/default-content.component.html @@ -1,3 +1,3 @@ - +
\ No newline at end of file diff --git a/apps/daffio/src/app/docs/components/table-of-contents/table-of-contents.component.spec.ts b/apps/daffio/src/app/docs/components/table-of-contents/table-of-contents.component.spec.ts index 534601d4db..dd87c4f17e 100644 --- a/apps/daffio/src/app/docs/components/table-of-contents/table-of-contents.component.spec.ts +++ b/apps/daffio/src/app/docs/components/table-of-contents/table-of-contents.component.spec.ts @@ -7,7 +7,7 @@ import { By } from '@angular/platform-browser'; import { RouterTestingModule } from '@angular/router/testing'; import { DaffLinkSetModule } from '@daffodil/design/link-set'; -import { DaffGuideDoc } from '@daffodil/docs-utils'; +import { DaffDoc } from '@daffodil/docs-utils'; import { DaffioDocsTableOfContentsComponent } from './table-of-contents.component'; import { DaffioDocsFactory } from '../../testing/factories/docs.factory'; @@ -15,7 +15,7 @@ import { DaffioDocsFactory } from '../../testing/factories/docs.factory'; describe('DaffioDocsTableOfContentsComponent', () => { let component: DaffioDocsTableOfContentsComponent; let fixture: ComponentFixture; - let stubDaffioDoc: DaffGuideDoc; + let stubDaffioDoc: DaffDoc; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ diff --git a/apps/daffio/src/app/docs/guides/components/guides-content/guides-content.component.ts b/apps/daffio/src/app/docs/guides/components/guides-content/guides-content.component.ts index f6d055c427..d9b61dc929 100644 --- a/apps/daffio/src/app/docs/guides/components/guides-content/guides-content.component.ts +++ b/apps/daffio/src/app/docs/guides/components/guides-content/guides-content.component.ts @@ -5,7 +5,7 @@ import { } from '@angular/core'; import { - DaffGuideDoc, + DaffDoc, DaffDocKind, } from '@daffodil/docs-utils'; @@ -23,8 +23,8 @@ import { DaffioDocsDynamicContent } from '../../../dynamic-content/dynamic-conte DaffioSafeHtmlPipe, ], }) -export class DaffioDocsGuidesContentComponent implements DaffioDocsDynamicContent { +export class DaffioDocsGuidesContentComponent implements DaffioDocsDynamicContent { static readonly kind = DaffDocKind.GUIDE; - doc = input(); + doc = input(); } diff --git a/apps/daffio/src/app/docs/testing/factories/docs.factory.ts b/apps/daffio/src/app/docs/testing/factories/docs.factory.ts index 09dcdd8d38..6ee555b9c8 100644 --- a/apps/daffio/src/app/docs/testing/factories/docs.factory.ts +++ b/apps/daffio/src/app/docs/testing/factories/docs.factory.ts @@ -5,10 +5,10 @@ import { sample } from '@daffodil/core'; import { DaffModelFactory } from '@daffodil/core/testing'; import { DaffDocKind, - DaffGuideDoc, + DaffDoc, } from '@daffodil/docs-utils'; -export class MockDoc implements DaffGuideDoc { +export class MockDoc implements DaffDoc { id = String(faker.datatype.number(1000)); kind = sample(Object.values(DaffDocKind)); title = faker.lorem.words(); @@ -27,7 +27,7 @@ export class MockDoc implements DaffGuideDoc { @Injectable({ providedIn: 'root', }) -export class DaffioDocsFactory extends DaffModelFactory{ +export class DaffioDocsFactory extends DaffModelFactory{ constructor() { super(MockDoc); } diff --git a/libs/docs-utils/src/doc/api.type.ts b/libs/docs-utils/src/doc/api.type.ts index bc28ee1ddf..06f1f6728e 100644 --- a/libs/docs-utils/src/doc/api.type.ts +++ b/libs/docs-utils/src/doc/api.type.ts @@ -1,5 +1,5 @@ -import { DaffDocExample } from './example.type'; import { DaffDoc } from './type'; +import { DaffDocExample } from '../example/public_api'; /** * An API doc that includes the type of the symbol. diff --git a/libs/docs-utils/src/doc/guide.type.ts b/libs/docs-utils/src/doc/guide.type.ts deleted file mode 100644 index 937965c6e8..0000000000 --- a/libs/docs-utils/src/doc/guide.type.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { DaffDocTableOfContents } from './toc.type'; -import { DaffDoc } from './type'; - -/** - * A guide doc. Includes a table of contents. - */ -export interface DaffGuideDoc extends DaffDoc { - tableOfContents: DaffDocTableOfContents; -} diff --git a/libs/docs-utils/src/doc/package-guide.type.ts b/libs/docs-utils/src/doc/package-guide.type.ts index 05d0d6b0c1..bfe40b4d7a 100644 --- a/libs/docs-utils/src/doc/package-guide.type.ts +++ b/libs/docs-utils/src/doc/package-guide.type.ts @@ -1,17 +1,20 @@ -import { DaffApiDoc } from '@daffodil/docs-utils'; - -import { DaffGuideDoc } from './guide.type'; +import { DaffDoc } from './type'; +import { DaffDocTableOfContents } from '../toc/public_api'; /** * A guide doc for a package. */ -export interface DaffPackageGuideDoc extends DaffGuideDoc { +export interface DaffPackageGuideDoc extends DaffDoc { /** * A list of symbol paths exported from the package. */ - symbols?: Array; + symbols: Array; + /** + * A list of rendered API docs. + */ + api: Array; /** - * A list of API docs for symbols exported from this package. + * A table of contents for the API section. */ - api?: Array; + apiToc: DaffDocTableOfContents; } diff --git a/libs/docs-utils/src/doc/public_api.ts b/libs/docs-utils/src/doc/public_api.ts index 529c533808..11bb58ce01 100644 --- a/libs/docs-utils/src/doc/public_api.ts +++ b/libs/docs-utils/src/doc/public_api.ts @@ -1,6 +1,3 @@ export * from './api.type'; -export * from './example.type'; -export * from './guide.type'; export * from './package-guide.type'; -export * from './toc.type'; export * from './type'; diff --git a/libs/docs-utils/src/doc/type.ts b/libs/docs-utils/src/doc/type.ts index a902230f02..184a155d47 100644 --- a/libs/docs-utils/src/doc/type.ts +++ b/libs/docs-utils/src/doc/type.ts @@ -1,6 +1,6 @@ -import { DaffBreadcrumb } from '@daffodil/docs-utils'; - +import { DaffBreadcrumb } from '../breadcrumb/public_api'; import { DaffDocKind } from '../kind/public_api'; +import { DaffDocTableOfContents } from '../toc/public_api'; /** * A basic generated document that represents some piece of documentation. @@ -11,4 +11,5 @@ export interface DaffDoc { contents: string; breadcrumbs: Array; kind: DaffDocKind; + tableOfContents: DaffDocTableOfContents; } diff --git a/libs/docs-utils/src/example/public_api.ts b/libs/docs-utils/src/example/public_api.ts new file mode 100644 index 0000000000..b38ebc9a19 --- /dev/null +++ b/libs/docs-utils/src/example/public_api.ts @@ -0,0 +1 @@ +export * from './type'; diff --git a/libs/docs-utils/src/doc/example.type.ts b/libs/docs-utils/src/example/type.ts similarity index 65% rename from libs/docs-utils/src/doc/example.type.ts rename to libs/docs-utils/src/example/type.ts index ff05705cb7..1498ded16f 100644 --- a/libs/docs-utils/src/doc/example.type.ts +++ b/libs/docs-utils/src/example/type.ts @@ -2,6 +2,11 @@ * A usage example. */ export interface DaffDocExample { + /** + * The ID of the example. + * Since not all examples will have captions, a unique is useful for fragment anchor scrolling. + */ + id: string; /** * The short caption describing the example. * This should be just plain text. diff --git a/libs/docs-utils/src/public_api.ts b/libs/docs-utils/src/public_api.ts index d3c0058b42..d87bfb5272 100644 --- a/libs/docs-utils/src/public_api.ts +++ b/libs/docs-utils/src/public_api.ts @@ -1,6 +1,9 @@ export { crossOsFilename } from './cross-os-filename'; -export * from './kind/public_api'; +export * from './path'; + export * from './breadcrumb/public_api'; -export * from './nav/public_api'; export * from './doc/public_api'; -export * from './path'; +export * from './example/public_api'; +export * from './kind/public_api'; +export * from './nav/public_api'; +export * from './toc/public_api'; diff --git a/libs/docs-utils/src/toc/public_api.ts b/libs/docs-utils/src/toc/public_api.ts new file mode 100644 index 0000000000..b38ebc9a19 --- /dev/null +++ b/libs/docs-utils/src/toc/public_api.ts @@ -0,0 +1 @@ +export * from './type'; diff --git a/libs/docs-utils/src/doc/toc.type.ts b/libs/docs-utils/src/toc/type.ts similarity index 100% rename from libs/docs-utils/src/doc/toc.type.ts rename to libs/docs-utils/src/toc/type.ts diff --git a/tools/dgeni/src/processors/add-api-symbols-to-package.ts b/tools/dgeni/src/processors/add-api-symbols-to-package.ts index 60875b69f8..09a2cbbc2c 100644 --- a/tools/dgeni/src/processors/add-api-symbols-to-package.ts +++ b/tools/dgeni/src/processors/add-api-symbols-to-package.ts @@ -1,6 +1,8 @@ import { Document } from 'dgeni'; import type { Environment } from 'nunjucks'; +import { DaffApiDoc } from '@daffodil/docs-utils'; + import { CollectLinkableSymbolsProcessor } from './collect-linkable-symbols'; import { API_TEMPLATES_PATH } from '../transforms/config'; import { FilterableProcessor } from '../utils/filterable-processor.type'; @@ -30,8 +32,13 @@ export class AddApiSymbolsToPackagesProcessor implements FilterableProcessor { const ret = docs.map(doc => { if (this.docTypes.includes(doc.docType)) { - doc.symbols = CollectLinkableSymbolsProcessor.packages.get(this.lookup(doc))?.map((d) => d.path); - doc.api = CollectLinkableSymbolsProcessor.packages.get(this.lookup(doc))?.map((symbol) => render(this.templateFinder.getFinder()(symbol), { doc: symbol, child: true })); + const exportDocs = CollectLinkableSymbolsProcessor.packages.get(this.lookup(doc)); + doc.symbols = exportDocs?.map((d) => d.path); + doc.api = exportDocs?.map((symbol) => render(this.templateFinder.getFinder()(symbol), { doc: symbol, child: true })); + doc.apiToc = exportDocs?.flatMap((symbol: DaffApiDoc) => symbol.tableOfContents.map((entry) => ({ + ...entry, + lvl: entry.lvl + 1, + }))); } return doc; }); diff --git a/tools/dgeni/src/transforms/daffodil-api-package/processors/examples.ts b/tools/dgeni/src/transforms/daffodil-api-package/processors/examples.ts index 81af889304..0262414334 100644 --- a/tools/dgeni/src/transforms/daffodil-api-package/processors/examples.ts +++ b/tools/dgeni/src/transforms/daffodil-api-package/processors/examples.ts @@ -1,12 +1,23 @@ import { Document } from 'dgeni'; +import { slugify } from 'markdown-toc'; -import { DaffDocExample } from '@daffodil/docs-utils'; +import { + DaffDocExample, + DaffDocTableOfContents, +} from '@daffodil/docs-utils'; import { MARKDOWN_CODE_PROCESSOR_NAME } from '../../../processors/markdown'; import { FilterableProcessor } from '../../../utils/filterable-processor.type'; export const EXAMPLES_PROCESSOR_NAME = 'examples'; +const genExamplesToc = (examples: Array): DaffDocTableOfContents => + examples.map((example) => ({ + content: example.caption, + lvl: 3, + slug: example.id, + })); + /** * Adds subpackage entry point docs to the containing package doc. */ @@ -20,10 +31,20 @@ export class ExamplesProcessor implements FilterableProcessor { $process(docs: Array): Array { return docs.map((doc) => { if (this.docTypes.includes(doc.docType)) { - doc.examples = doc.tags.tagsByName.get('example')?.map((example): DaffDocExample => ({ + doc.examples = doc.tags.tagsByName.get('example')?.map((example, i): DaffDocExample => ({ + id: slugify(`${doc.name}-example-${i}`), caption: example.caption, body: example.body, })) || []; + doc.tableOfContents = doc.examples.length > 0 ? [ + { + content: 'Examples', + lvl: 2, + // TODO: add doc-specific prefix + slug: 'examples', + }, + ...genExamplesToc(doc.examples), + ] : []; } return doc; });