Skip to content

Commit fd9b1a6

Browse files
authored
Make API docs generator configurable (#589)
Part of running lit 1.x docs on the new site. Refactors the TypeDoc-based API docs generator to work off a config, instead of being hard-coded for Lit 2.x. Will add Lit 1.x configs in a followup.
1 parent becc773 commit fd9b1a6

File tree

3 files changed

+422
-319
lines changed

3 files changed

+422
-319
lines changed
+194
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
/**
2+
* @license
3+
* Copyright 2021 Google LLC
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*/
6+
7+
import * as pathlib from 'path';
8+
9+
import type {ApiDocsConfig} from '../types.js';
10+
11+
const root = pathlib.resolve(__dirname, '..', '..', '..', '..', '..');
12+
const workDir = pathlib.join(root, 'packages', 'lit-dev-api');
13+
const gitDir = pathlib.join(workDir, 'lit');
14+
const litDir = pathlib.join(gitDir, 'packages', 'lit');
15+
const srcDir = pathlib.join(litDir, 'src');
16+
const outDir = pathlib.join(workDir, 'api-data');
17+
18+
/**
19+
* lit.dev API docs configuration for Lit 2.x
20+
*/
21+
export const lit2Config: ApiDocsConfig = {
22+
repo: 'https://github.com/lit/lit',
23+
commit: 'f8ee010bc515e4bb319e98408d38ef3d971cc08b',
24+
gitDir,
25+
tsConfigPath: pathlib.join(litDir, 'tsconfig.json'),
26+
pagesOutPath: pathlib.resolve(outDir, 'pages.json'),
27+
symbolsOutPath: pathlib.resolve(outDir, 'symbols.json'),
28+
typedocRoot: pathlib.join(root, 'packages'),
29+
30+
entrypointModules: [
31+
pathlib.join(srcDir, 'async-directive.ts'),
32+
pathlib.join(srcDir, 'decorators.ts'),
33+
pathlib.join(srcDir, 'directives/'), // Entire directory
34+
pathlib.join(srcDir, 'directive.ts'),
35+
pathlib.join(srcDir, 'directive-helpers.ts'),
36+
// Don't include html.ts because it is already re-exported by index.ts.
37+
// pathlib.join(srcDir, 'html.ts'),
38+
// Don't include hydration because it's not ready yet.
39+
// pathlib.join(srcDir, 'hydrate.ts'),
40+
// pathlib.join(srcDir, 'hydrate-support.ts'),
41+
pathlib.join(srcDir, 'index.ts'),
42+
// Don't include polyfill-support.ts because it doesn't export anything.
43+
// pathlib.join(srcDir, 'polyfill-support.ts'),
44+
pathlib.join(srcDir, 'static-html.ts'),
45+
],
46+
47+
symbolOrder: ['LitElement', 'ReactiveElement'],
48+
49+
pages: [
50+
{
51+
slug: 'LitElement',
52+
title: 'LitElement',
53+
},
54+
{
55+
slug: 'ReactiveElement',
56+
title: 'ReactiveElement',
57+
},
58+
{
59+
slug: 'templates',
60+
title: 'Templates',
61+
},
62+
{
63+
slug: 'styles',
64+
title: 'Styles',
65+
},
66+
{
67+
slug: 'decorators',
68+
title: 'Decorators',
69+
},
70+
{
71+
slug: 'directives',
72+
title: 'Directives',
73+
anchorFilter: (node) => node.kindString === 'Function',
74+
},
75+
{
76+
slug: 'custom-directives',
77+
title: 'Custom directives',
78+
},
79+
{
80+
slug: 'static-html',
81+
title: 'Static HTML',
82+
},
83+
{
84+
slug: 'controllers',
85+
title: 'Controllers',
86+
},
87+
{
88+
slug: 'misc',
89+
title: 'Misc',
90+
},
91+
],
92+
93+
pageForSymbol(node): string {
94+
const entrypoint = node.entrypointSources?.[0]?.fileName ?? '';
95+
if (entrypoint.includes('/directives/')) {
96+
return 'directives';
97+
}
98+
99+
if (entrypoint.endsWith('/decorators.ts')) {
100+
return 'decorators';
101+
}
102+
103+
if (
104+
entrypoint.endsWith('/directive.ts') ||
105+
entrypoint.endsWith('/directive-helpers.ts') ||
106+
entrypoint.endsWith('/async-directive.ts') ||
107+
node.name === 'noChange' ||
108+
node.name === 'Part' ||
109+
node.name === 'AttributePart' ||
110+
node.name === 'BooleanAttributePart' ||
111+
node.name === 'ChildPart' ||
112+
node.name === 'ElementPart' ||
113+
node.name === 'EventPart' ||
114+
node.name === 'PropertyPart'
115+
) {
116+
return 'custom-directives';
117+
}
118+
119+
if (entrypoint.endsWith('/static-html.ts')) {
120+
return 'static-html';
121+
}
122+
123+
if (node.name === 'LitElement' || node.name === 'RenderOptions') {
124+
return 'LitElement';
125+
}
126+
127+
if (
128+
node.name === 'ReactiveElement' ||
129+
node.name === 'PropertyDeclaration' ||
130+
node.name === 'PropertyDeclarations' ||
131+
node.name === 'UpdatingElement' ||
132+
node.name === 'PropertyValues' ||
133+
node.name === 'ComplexAttributeConverter'
134+
) {
135+
return 'ReactiveElement';
136+
}
137+
138+
if (
139+
node.name === 'html' ||
140+
node.name === 'svg' ||
141+
node.name === 'render' ||
142+
node.name === 'nothing' ||
143+
node.name === 'SanitizerFactory' ||
144+
node.name === 'Template' ||
145+
node.name === 'TemplateResult' ||
146+
node.name === 'SVGTemplateResult'
147+
) {
148+
return 'templates';
149+
}
150+
151+
if (
152+
node.name === 'css' ||
153+
node.name === 'adoptStyles' ||
154+
node.name === 'getCompatibleStyle' ||
155+
node.name === 'unsafeCSS' ||
156+
node.name === 'supportsAdoptingStyleSheets' ||
157+
node.name.startsWith('CSS')
158+
) {
159+
return 'styles';
160+
}
161+
162+
if (
163+
node.name === 'ReactiveController' ||
164+
node.name === 'ReactiveControllerHost'
165+
) {
166+
return 'controllers';
167+
}
168+
169+
// TODO(aomarks) Make sure everything has a good final location, and then
170+
// throw if we get here.
171+
return 'misc';
172+
},
173+
174+
locationToUrl({page, anchor}) {
175+
return `/docs/api/${page}/#${anchor}`;
176+
},
177+
178+
fileToImportSpecifier(filename) {
179+
const match = filename.match(/^packages\/(.+?)\/src\/(.+)\.ts$/);
180+
if (!match) {
181+
return '';
182+
}
183+
// TODO(aomarks) This pkg is only our local directory name, which isn't
184+
// necessarily our NPM package name (e.g. it's @lit/reactive-element, not
185+
// reactive-element). Right now all our exports are from 'lit', so this is
186+
// fine in practice, but when we add e.g. @lit/localize we'll need to be
187+
// smarter here.
188+
let [_, pkg, pathMinusExtension] = match;
189+
// TODO(aomarks) This wrongly assumes index.ts is always the package main.
190+
return pathMinusExtension === 'index'
191+
? pkg
192+
: `${pkg}/${pathMinusExtension}.js`;
193+
},
194+
};

Diff for: packages/lit-dev-tools-cjs/src/api-docs/types.ts

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/**
2+
* @license
3+
* Copyright 2021 Google LLC
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*/
6+
7+
import type * as typedoc from 'typedoc';
8+
9+
export type DeclarationReflection = typedoc.JSONOutput.DeclarationReflection;
10+
11+
export interface ExtendedDeclarationReflection extends DeclarationReflection {
12+
location?: Location;
13+
externalLocation?: ExternalLocation;
14+
entrypointSources?: Array<ExtendedSourceReference>;
15+
heritage?: Array<{name: string; location?: Location}>;
16+
expandedCategories?: Array<{
17+
title: string;
18+
anchor: string;
19+
children: Array<DeclarationReflection>;
20+
}>;
21+
}
22+
23+
export type SourceReference = typedoc.JSONOutput.SourceReference;
24+
25+
export interface ExtendedSourceReference extends SourceReference {
26+
gitHubUrl?: string;
27+
moduleSpecifier?: string;
28+
}
29+
30+
/** Where to find a symbol in our custom API docs page structure. */
31+
export interface Location {
32+
page: string;
33+
anchor: string;
34+
}
35+
36+
/** A link to e.g. MDN. */
37+
export interface ExternalLocation {
38+
url: string;
39+
}
40+
41+
export interface ApiDocsConfig {
42+
/**
43+
* Git repo remote URL.
44+
*/
45+
repo: string;
46+
47+
/**
48+
* Git commit reference (SHA or tag).
49+
*/
50+
commit: string;
51+
52+
/**
53+
* Location where Git repo will be cloned.
54+
*/
55+
gitDir: string;
56+
57+
/**
58+
* Path to the tsconfig.json that owns the entrypoint modules.
59+
*/
60+
tsConfigPath: string;
61+
62+
/**
63+
* The directory that TypeDoc chooses as the root of this package. Unclear why
64+
* this is unpredictable.
65+
*/
66+
typedocRoot: string;
67+
68+
/**
69+
* Entrypoint TypeScript modules for TypeDoc to analyze.
70+
*
71+
* The modules listed here should be the preferred modules that users should
72+
* import from, because import statements will be generated using these
73+
* entrypoints as the module specifier (e.g. `import {LitElement} from
74+
* 'lit'`). GitHub source links will be generated pointing at the ultimate
75+
* location where the symbol is concretely defined (e.g.
76+
* `packages/lit-element/src/lit-element.ts`).
77+
*
78+
* If a directory, all .ts files within it are included.
79+
*/
80+
entrypointModules: string[];
81+
82+
/**
83+
* Where to write the API data that is consumed by our Eleventy template.
84+
*/
85+
pagesOutPath: string;
86+
87+
/**
88+
* Where to write the index from $symbol to location object.
89+
*/
90+
symbolsOutPath: string;
91+
92+
/**
93+
* Order that items in an API docs page will appear. Falls back to
94+
* lexicographic. (Note this doesn't distinguish between pages, but we don't
95+
* have any overlapping export names for now so it doesn't matter).
96+
*/
97+
symbolOrder: string[];
98+
99+
/**
100+
* Pages in the order they will appear in the navigation.
101+
*/
102+
pages: Array<{
103+
slug: string;
104+
title: string;
105+
anchorFilter?: (node: DeclarationReflection) => boolean;
106+
}>;
107+
108+
/**
109+
* Determine which generated API docs page the given TypeDoc reflection object
110+
* belongs in.
111+
*
112+
* Note that only top-level exports of each entrypoint module are passed here
113+
* (i.e. the methods of a class always go on the same page as the class).
114+
*/
115+
pageForSymbol(node: ExtendedDeclarationReflection): string;
116+
117+
/**
118+
* Generate a relative URL for the given location.
119+
*/
120+
locationToUrl({page, anchor}: Location): string;
121+
122+
/**
123+
* Maps a git-repo relative filename to an import specifier.
124+
*/
125+
fileToImportSpecifier(filename: string): string;
126+
}

0 commit comments

Comments
 (0)