Skip to content

Commit

Permalink
Add more sphinxJsConfig hooks
Browse files Browse the repository at this point in the history
I added hooks preConvert and postConvert. preCommit receives just the typedoc
app and runs right after application bootstrap. (To run earlier I think you'd
need to make an actual typedoc plugin). `postConvert` runs right at the end. I
also added a map from typedoc reflections to the corresponding ir item that
postConvert can look at. I also added an extra_data dictionary which we pass to
Python so that implementations of these hooks can pass extra information to be
handled on the Pythons side. (None of the Python-side hooks can use this info
yet, it can only be used via a monkeypatch.)

No test coverage for any of this...
  • Loading branch information
hoodmane committed May 3, 2024
1 parent f48890d commit 112ec5d
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 18 deletions.
10 changes: 8 additions & 2 deletions sphinx_js/js/call_typedoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,13 @@ async function main() {
console.log(app.toString());
return ExitCodes.Ok;
}
app.extraData = {};
app.options.getValue("modifierTags").push("@hidetype");
const config = await loadConfig(app.options.getValue("sphinxJsConfig"));
const userConfigPath = app.options.getValue("sphinxJsConfig");
const config = await loadConfig(userConfigPath);
app.logger.info(`Loaded user config from ${userConfigPath}`);
const symbolToType = redirectPrivateTypes(app);
await config.preConvert?.(app);

const project = await app.convert();
if (!project) {
Expand All @@ -82,7 +86,9 @@ async function main() {
const converter = new Converter(project, basePath, config, symbolToType);
converter.computePaths();
const space = app.options.getValue("pretty") ? "\t" : "";
const res = JSON.stringify(converter.convertAll(), null, space);
const result = converter.convertAll();
await config.postConvert?.(app, project, converter.typedocToIRMap);
const res = JSON.stringify([result, app.extraData], null, space);
const json = app.options.getValue("json");
await writeFile(json, res);
app.logger.info(`JSON written to ${json}`);
Expand Down
6 changes: 4 additions & 2 deletions sphinx_js/js/convertTopLevel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ import {
TopLevel,
Type,
TypeParam,
TypeXRefInternal,
TypeXRefExternal,
} from "./ir.ts";
import { sep, relative } from "path";
import { SphinxJsConfig } from "./sphinxJsConfig.ts";
Expand Down Expand Up @@ -341,6 +339,7 @@ export class Converter {
Pathname
>;
readonly documentationRoots: Set<DeclarationReflection | SignatureReflection>;
readonly typedocToIRMap: Map<DeclarationReflection, TopLevel>;

constructor(
project: ProjectReflection,
Expand All @@ -352,9 +351,11 @@ export class Converter {
this.basePath = basePath;
this.config = config;
this.symbolToType = symbolToType;

this.pathMap = new Map();
this.filePathMap = new Map();
this.documentationRoots = new Set();
this.typedocToIRMap = new Map();
}

renderType(type: SomeType, context: TypeContext = TypeContext.none): Type {
Expand Down Expand Up @@ -397,6 +398,7 @@ export class Converter {
const node = todo.pop()!;
const [converted, rest] = this.toIr(node);
if (converted) {
this.typedocToIRMap.set(node, converted);
result.push(converted);
}
todo.push(...(rest || []));
Expand Down
8 changes: 6 additions & 2 deletions sphinx_js/js/redirectPrivateAliases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,17 @@ export function redirectPrivateTypes(app: Application): ReadonlySymbolToType {
}

const origCreateSymbolReference = ReferenceType.createSymbolReference;
ReferenceType.createSymbolReference = function (symbol, context, name) {
ReferenceType.createSymbolReference = function (
symbol: ts.Symbol,
context: Context,
name: string,
) {
const owningModule = getOwningModule(context);
getReferencedSymbols(owningModule).add(symbol);
return origCreateSymbolReference.call(this, symbol, context, name);
};

function onResolveBegin(context: Context) {
function onResolveBegin(context: Context): void {
const modules: (DeclarationReflection | ProjectReflection)[] =
context.project.getChildrenByKind(ReflectionKind.Module);
if (modules.length === 0) {
Expand Down
16 changes: 14 additions & 2 deletions sphinx_js/js/sphinxJsConfig.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import { ParameterReflection } from "typedoc";
import {
Application,
DeclarationReflection,
ParameterReflection,
ProjectReflection,
} from "typedoc";
import { TopLevel } from "./ir.ts";

export type SphinxJsConfig = {
shouldDestructureArg?: (p: ParameterReflection) => boolean;
shouldDestructureArg?: (param: ParameterReflection) => boolean;
preConvert?: (app: Application) => Promise<void>;
postConvert?: (
app: Application,
project: ProjectReflection,
typedocToIRMap: ReadonlyMap<DeclarationReflection, TopLevel>,
) => Promise<void>;
};
6 changes: 5 additions & 1 deletion sphinx_js/js/typedocPatches.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
/** Declare some extra stuff we monkeypatch on to typedoc */

declare module "typedoc" {
export interface TypeDocOptionMap {
sphinxJsConfig: string;
}
export interface Application {
extraData: {
[key: string]: any;
};
}
}
2 changes: 1 addition & 1 deletion sphinx_js/js/typedocPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// TODO: we don't seem to resolve imports correctly in this file, but it works
// to do a dynamic import. Figure out why.

export async function load(app: any) {
export async function load(app: any): Promise<void> {
// @ts-ignore
const typedoc = await import("typedoc");
app.options.addDeclaration({
Expand Down
17 changes: 11 additions & 6 deletions sphinx_js/typedoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from operator import attrgetter
from pathlib import Path
from tempfile import NamedTemporaryFile
from typing import Literal
from typing import Any, Literal

from sphinx.application import Sphinx
from sphinx.errors import SphinxError
Expand Down Expand Up @@ -54,7 +54,7 @@ def typedoc_output(
typedoc_config_path: str | None,
tsconfig_path: str | None,
ts_sphinx_js_config: str | None,
) -> list[ir.TopLevelUnion]:
) -> tuple[list[ir.TopLevelUnion], dict[str, Any]]:
"""Return the loaded JSON output of the TypeDoc command run over the given
paths."""
typedoc = search_node_modules("typedoc", "typedoc/bin/typedoc", sphinx_conf_dir)
Expand Down Expand Up @@ -100,14 +100,19 @@ def typedoc_output(
else:
raise
# typedoc emits a valid JSON file even if it finds no TS files in the dir:
return ir.json_to_ir(load(temp))
json_ir, extra_data = load(temp)
return ir.json_to_ir(json_ir), extra_data


class Analyzer:
_objects_by_path: SuffixTree[ir.TopLevel]
_modules_by_path: SuffixTree[ir.Module]
_extra_data: dict[str, Any]

def __init__(self, objects: Sequence[ir.TopLevel], base_dir: str) -> None:
def __init__(
self, objects: Sequence[ir.TopLevel], extra_data: dict[str, Any], base_dir: str
) -> None:
self._extra_data = extra_data
self._base_dir = base_dir
self._objects_by_path = SuffixTree()
self._objects_by_path.add_many((obj.path.segments, obj) for obj in objects)
Expand All @@ -130,15 +135,15 @@ def get_object(
def from_disk(
cls, abs_source_paths: Sequence[str], app: Sphinx, base_dir: str
) -> "Analyzer":
json = typedoc_output(
json, extra_data = typedoc_output(
abs_source_paths,
base_dir=base_dir,
sphinx_conf_dir=app.confdir,
typedoc_config_path=app.config.jsdoc_config_path,
tsconfig_path=app.config.jsdoc_tsconfig_path,
ts_sphinx_js_config=app.config.ts_sphinx_js_config,
)
return cls(json, base_dir)
return cls(json, extra_data, base_dir)

def _get_toplevel_objects(
self, ir_objects: Sequence[ir.TopLevel]
Expand Down
4 changes: 2 additions & 2 deletions tests/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def setup_class(cls):

config_file = Path(__file__).parent / "sphinxJsConfig.ts"

cls.json = typedoc_output(
[cls.json, cls.extra_data] = typedoc_output(
abs_source_paths=[join(cls._source_dir, file) for file in cls.files],
base_dir=cls._source_dir,
ts_sphinx_js_config=str(config_file),
Expand All @@ -103,7 +103,7 @@ def setup_class(cls):
def should_destructure(sig, p):
return p.name == "destructureThisPlease"

cls.analyzer = TsAnalyzer(cls.json, cls._source_dir)
cls.analyzer = TsAnalyzer(cls.json, cls.extra_data, cls._source_dir)


NO_MATCH = object()
Expand Down

0 comments on commit 112ec5d

Please sign in to comment.