Skip to content

Commit

Permalink
Improve destructured property support
Browse files Browse the repository at this point in the history
Ref: #2430 (non-fix, but makes some things nicer)
  • Loading branch information
Gerrit0 committed Oct 28, 2023
1 parent 41e6b33 commit 5305cbf
Show file tree
Hide file tree
Showing 10 changed files with 632 additions and 351 deletions.
4 changes: 4 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@
{
"selector": "ImportDeclaration[source.value=/.*perf$/]",
"message": "Benchmark calls must be removed before committing."
},
{
"selector": "MemberExpression[object.name=type][property.name=symbol]",
"message": "Use type.getSymbol() instead, Type.symbol is not properly typed."
}
]
},
Expand Down
64 changes: 64 additions & 0 deletions scripts/testcase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// @ts-check
const marked = require("marked");
const cp = require("child_process");
const { writeFile } = require("fs/promises");

const curl = `curl -s -L -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/typestrong/typedoc/issues/ISSUE`;

/**
* @param {string} cmd
* @returns {Promise<string>}
*/
function exec(cmd) {
return new Promise((resolve, reject) => {
cp.exec(cmd, { encoding: "utf-8" }, (err, stdout, stderr) => {
if (err) return reject(err);

if (stderr.trim().length) {
return reject(new Error(stderr));
}

resolve(stdout.trim());
});
});
}

/** @param {marked.marked.Tokens.Code} code */
function guessExtension(code) {
switch (code.lang) {
case "js":
case "jsx":
return ".js";
case "tsx":
return ".tsx";
}

return ".ts";
}

async function main() {
if (process.argv.length !== 3) {
console.log("Usage: node scripts/testcase.js <issue number>");
process.exit(1);
}

const issue = process.argv[2];
const data = JSON.parse(await exec(curl.replace("ISSUE", issue)));

const lexer = new marked.Lexer({ gfm: true });
const tokens = lexer.lex(data.body);

const code = /** @type {marked.marked.Tokens.Code} */ (
tokens.find((tok) => tok.type === "code")
);
if (!code) {
console.log("No codeblock found");
return;
}

const file = `src/test/converter2/issues/gh${issue}${guessExtension(code)}`;
await writeFile(file, code.text);
await exec(`code ${file} src/test/issues.c2.test.ts`);
}

void main();
7 changes: 3 additions & 4 deletions src/lib/converter/symbols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1071,10 +1071,9 @@ function convertAccessor(

function isInherited(context: Context, symbol: ts.Symbol) {
const parentSymbol = context.project.getSymbolFromReflection(context.scope);
assert(
parentSymbol,
`No parent symbol found for ${symbol.name} in ${context.scope.name}`,
);
// It'd be nice to be able to assert that this is true, but sometimes object
// types don't get symbols if they are inferred.
if (!parentSymbol) return false;

const parents = parentSymbol.declarations?.slice() || [];
const constructorDecls = parents.flatMap((parent) =>
Expand Down
29 changes: 15 additions & 14 deletions src/lib/converter/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,8 @@ const constructorConverter: TypeConverter<ts.ConstructorTypeNode, ts.Type> = {
return new ReflectionType(reflection);
},
convertType(context, type) {
if (!type.symbol) {
const symbol = type.getSymbol();
if (!symbol) {
return new IntrinsicType("Function");
}

Expand All @@ -277,14 +278,14 @@ const constructorConverter: TypeConverter<ts.ConstructorTypeNode, ts.Type> = {
ReflectionKind.Constructor,
context.scope,
);
context.registerReflection(reflection, type.symbol);
context.registerReflection(reflection, symbol);
context.trigger(ConverterEvents.CREATE_DECLARATION, reflection);

createSignature(
context.withScope(reflection),
ReflectionKind.ConstructorSignature,
type.getConstructSignatures()[0],
type.symbol,
symbol,
);

return new ReflectionType(reflection);
Expand Down Expand Up @@ -363,7 +364,8 @@ const functionTypeConverter: TypeConverter<ts.FunctionTypeNode, ts.Type> = {
return new ReflectionType(reflection);
},
convertType(context, type) {
if (!type.symbol) {
const symbol = type.getSymbol();
if (!symbol) {
return new IntrinsicType("Function");
}

Expand All @@ -372,7 +374,7 @@ const functionTypeConverter: TypeConverter<ts.FunctionTypeNode, ts.Type> = {
ReflectionKind.TypeLiteral,
context.scope,
);
context.registerReflection(reflection, type.symbol);
context.registerReflection(reflection, symbol);
context.trigger(ConverterEvents.CREATE_DECLARATION, reflection);

createSignature(
Expand Down Expand Up @@ -438,7 +440,7 @@ const inferredConverter: TypeConverter<ts.InferTypeNode> = {
},
convertType(context, type) {
return new InferredType(
type.symbol.name,
type.getSymbol()!.name,
maybeConvertType(context, type.getConstraint()),
);
},
Expand Down Expand Up @@ -601,16 +603,13 @@ const typeLiteralConverter: TypeConverter<ts.TypeLiteralNode> = {
return new ReflectionType(reflection);
},
convertType(context, type) {
if (!type.symbol) {
return new IntrinsicType("Object");
}

const symbol = type.getSymbol();
const reflection = new DeclarationReflection(
"__type",
ReflectionKind.TypeLiteral,
context.scope,
);
context.registerReflection(reflection, type.symbol);
context.registerReflection(reflection, symbol);
context.trigger(ConverterEvents.CREATE_DECLARATION, reflection);

for (const prop of context.checker.getPropertiesOfType(type)) {
Expand All @@ -621,19 +620,21 @@ const typeLiteralConverter: TypeConverter<ts.TypeLiteralNode> = {
context.withScope(reflection),
ReflectionKind.CallSignature,
signature,
type.symbol,
symbol,
);
}
for (const signature of type.getConstructSignatures()) {
createSignature(
context.withScope(reflection),
ReflectionKind.ConstructorSignature,
signature,
type.symbol,
symbol,
);
}

convertIndexSignature(context.withScope(reflection), type.symbol);
if (symbol) {
convertIndexSignature(context.withScope(reflection), symbol);
}

return new ReflectionType(reflection);
},
Expand Down
2 changes: 1 addition & 1 deletion src/lib/models/reflections/ReflectionSymbolId.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class ReflectionSymbolId {
if ("name" in symbol) {
declaration ??= symbol?.declarations?.[0];
this.fileName = normalizePath(
declaration?.getSourceFile().fileName ?? "\0",
declaration?.getSourceFile().fileName ?? "",
);
if (symbol.declarations?.some(ts.isSourceFile)) {
this.qualifiedName = "";
Expand Down
2 changes: 2 additions & 0 deletions src/lib/models/reflections/abstract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { ReflectionKind } from "./kind";
import type { Serializer, Deserializer, JSONOutput } from "../../serialization";
import type { ReflectionVariant } from "./variant";
import type { DeclarationReflection } from "./declaration";
import { NonEnumerable } from "../../utils/general";

/**
* Current reflection id.
Expand Down Expand Up @@ -274,6 +275,7 @@ export abstract class Reflection {
/**
* The reflection this reflection is a child of.
*/
@NonEnumerable // So that it doesn't show up in console.log
parent?: Reflection;

get project(): ProjectReflection {
Expand Down
13 changes: 13 additions & 0 deletions src/lib/utils/general.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,19 @@ export function assertNever(x: never): never {
);
}

export function NonEnumerable(
_cls: unknown,
context: ClassFieldDecoratorContext,
) {
context.addInitializer(function () {
Object.defineProperty(this, context.name, {
enumerable: false,
configurable: true,
writable: true,
});
});
}

/**
* This is a hack to make it possible to detect and warn about installation setups
* which result in TypeDoc being installed multiple times. If TypeDoc has been loaded
Expand Down
8 changes: 4 additions & 4 deletions src/test/converter/mixin/specs.json
Original file line number Diff line number Diff line change
Expand Up @@ -2218,7 +2218,7 @@
"qualifiedName": "Mixin1Class"
},
"24": {
"sourceFileName": "\u0000",
"sourceFileName": "",
"qualifiedName": "Mixin1Class.prototype"
},
"25": {
Expand Down Expand Up @@ -2282,7 +2282,7 @@
"qualifiedName": "Mixin2"
},
"40": {
"sourceFileName": "\u0000",
"sourceFileName": "",
"qualifiedName": "Mixin2.prototype"
},
"41": {
Expand Down Expand Up @@ -2362,7 +2362,7 @@
"qualifiedName": "Mixin3"
},
"60": {
"sourceFileName": "\u0000",
"sourceFileName": "",
"qualifiedName": "Mixin3.prototype"
},
"61": {
Expand All @@ -2386,7 +2386,7 @@
"qualifiedName": "Mixin1Class"
},
"66": {
"sourceFileName": "\u0000",
"sourceFileName": "",
"qualifiedName": "Mixin1Class.prototype"
},
"67": {
Expand Down
Loading

0 comments on commit 5305cbf

Please sign in to comment.