Skip to content

Commit

Permalink
feat: Support for TypeScript 4.3
Browse files Browse the repository at this point in the history
  • Loading branch information
Gerrit0 committed Jun 5, 2021
1 parent ec17e83 commit 432008c
Show file tree
Hide file tree
Showing 28 changed files with 326 additions and 471 deletions.
4 changes: 0 additions & 4 deletions .prettierignore
Expand Up @@ -5,7 +5,3 @@ dist
package-lock.json
src/test/**/specs*.json
src/test/renderer/specs

# Temporarily ignored until Prettier 2.3
examples/basic/src/classes.ts
src/test/converter/class/class.ts
6 changes: 3 additions & 3 deletions examples/basic/src/classes.ts
Expand Up @@ -208,7 +208,7 @@ class InternalClass<TTT extends keyof BaseClass> {
* from BaseClass.
*/
export class SubClassA extends BaseClass implements PrintNameInterface {
public name: string;
public declare name: string;

/**
* This is a simple interface function.
Expand Down Expand Up @@ -269,7 +269,7 @@ export class SubClassA extends BaseClass implements PrintNameInterface {
* The constructor of the original class should be overwritten.
*/
export class SubClassB extends BaseClass {
public name: string;
public declare name: string;

constructor(name: string) {
super(name);
Expand Down Expand Up @@ -323,4 +323,4 @@ export class GenericClass<T extends BaseClass> {
export class NonGenericClass extends GenericClass<SubClassB> {}

// TS 4.2
export type AbstractMe = abstract new () => NonGenericClass
export type AbstractMe = abstract new () => NonGenericClass;
6 changes: 3 additions & 3 deletions examples/basic/src/mixin.ts
Expand Up @@ -56,15 +56,15 @@ export const Mixin2 = <T extends AnyConstructor<Mixin1Type & Base>>(base: T) =>
class Mixin2 extends base {
property2 = "init";

method2(arg: Mixin2): Mixin2[] {
return [arg, this];
method2(arg: Mixin2Type): Mixin2Type {
return arg;
}
};

/**
* The "instance type" of the Mixin2 using the interface notation (supports recursive type definition)
*/
export interface Mixin2 extends Mixin<typeof Mixin2> {}
export interface Mixin2Type extends Mixin<typeof Mixin2> {}

/**
* The "mixin function" of the Mixin3
Expand Down
272 changes: 147 additions & 125 deletions package-lock.json

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions package.json
Expand Up @@ -23,29 +23,29 @@
"handlebars": "^4.7.7",
"lodash": "^4.17.21",
"lunr": "^2.3.9",
"marked": "^2.0.3",
"marked": "^2.0.7",
"minimatch": "^3.0.0",
"progress": "^2.0.3",
"shiki": "^0.9.3",
"typedoc-default-themes": "^0.12.10"
},
"peerDependencies": {
"typescript": "4.0.x || 4.1.x || 4.2.x"
"typescript": "4.0.x || 4.1.x || 4.2.x || 4.3.x"
},
"devDependencies": {
"@types/lodash": "^4.14.168",
"@types/lodash": "^4.14.170",
"@types/lunr": "^2.3.3",
"@types/marked": "^2.0.2",
"@types/marked": "^2.0.3",
"@types/minimatch": "3.0.4",
"@types/mocha": "^8.2.2",
"@types/node": "^15.0.1",
"@typescript-eslint/eslint-plugin": "^4.22.0",
"@typescript-eslint/parser": "^4.22.0",
"eslint": "^7.25.0",
"mocha": "^8.3.2",
"@types/node": "^15.12.1",
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0",
"eslint": "^7.28.0",
"mocha": "^8.4.0",
"nyc": "^15.1.0",
"prettier": "^2.2.1",
"typescript": "^4.2.4"
"prettier": "2.2.1",
"typescript": "^4.3.2"
},
"files": [
"bin",
Expand Down
3 changes: 2 additions & 1 deletion src/lib/converter/context.ts
Expand Up @@ -78,7 +78,7 @@ export class Context {
* /** We should use this comment *&#47;
* export * as Mod from "./mod"
* ```
* Will be removed in 0.21.
* Will be removed in 0.22.
* @internal
*/
exportSymbol?: ts.Symbol;
Expand Down Expand Up @@ -288,6 +288,7 @@ const builtInSymbolRegExp = /^__@(\w+)$/;
const uniqueSymbolRegExp = /^__@(.*)@\d+$/;

function getHumanName(name: string) {
// TS 4.0, 4.1, 4.2 - well known symbols are treated specially.
let match = builtInSymbolRegExp.exec(name);
if (match) {
return `[Symbol.${match[1]}]`;
Expand Down
79 changes: 35 additions & 44 deletions src/lib/converter/factories/comment.ts
Expand Up @@ -2,21 +2,7 @@ import * as ts from "typescript";
import { toArray } from "lodash";

import { Comment, CommentTag } from "../../models/comments/index";

/**
* Return the parsed comment of the given TypeScript node.
*
* @param node The node whose comment should be returned.
* @return The parsed comment as a [[Comment]] instance or undefined if no comment is present.
*/
export function createComment(node: ts.Node): Comment | undefined {
const comment = getRawComment(node);
if (!comment) {
return;
}

return parseComment(comment);
}
import { Logger } from "../../utils";

/**
* Check whether the given module declaration is the topmost.
Expand Down Expand Up @@ -88,13 +74,24 @@ function getJSDocCommentRanges(node: ts.Node, text: string): ts.CommentRange[] {
);
}

export function getJsDocCommentText(comment: ts.JSDocTag["comment"]) {
if (typeof comment === "string") {
return comment;
}

return comment?.map((val) => val.text).join("");
}

/**
* Return the raw comment string for the given node.
*
* @param node The node whose comment should be resolved.
* @returns The raw comment string or undefined if no comment could be found.
*/
export function getRawComment(node: ts.Node): string | undefined {
export function getRawComment(
node: ts.Node,
logger: Logger
): string | undefined {
// This happens if we are converting a JS project that has @typedef "interfaces"
// with an @property tag, a @typedef type alias, a callback with parameters, etc.
if (
Expand All @@ -105,7 +102,7 @@ export function getRawComment(node: ts.Node): string | undefined {
) {
// Also strip off leading dashes:
// @property {string} name - docs
return node.comment?.replace(/^\s*-\s*/, "");
return getJsDocCommentText(node.comment)?.replace(/^\s*-\s*/, "");
}

if (
Expand All @@ -129,52 +126,46 @@ export function getRawComment(node: ts.Node): string | undefined {
const comments = getJSDocCommentRanges(node, sourceFile.text);
if (comments.length) {
let comment: ts.CommentRange;
let explicitPackageComment = comments.find((comment) =>
sourceFile.text
.substring(comment.pos, comment.end)
.includes("@module")
);

// TODO: Deprecate and remove. This is an abuse of the @packageDocumentation tag. See:
// https://github.com/TypeStrong/typedoc/issues/1504#issuecomment-775842609
// Deprecate in 0.21, remove in 0.22
explicitPackageComment ??= comments.find((comment) =>
sourceFile.text
.substring(comment.pos, comment.end)
.includes("@packageDocumentation")
);
if (node.kind === ts.SyntaxKind.SourceFile) {
const explicitPackageComment =
comments.find((comment) =>
sourceFile.text
.substring(comment.pos, comment.end)
.includes("@module")
) ??
comments.find((comment) =>
sourceFile.text
.substring(comment.pos, comment.end)
.includes("@packageDocumentation")
);

if (explicitPackageComment) {
comment = explicitPackageComment;
} else if (comments.length > 1) {
// Legacy behavior, require more than one comment and use the first comment.
// FUTURE: GH#1083, follow deprecation process to phase this out.
comment = comments[0];

logger.deprecated(
`Specifying multiple comments at the start of a file to use the first comment as the comment for the module has been deprecated. Use @module or @packageDocumentation instead.`,
false
);
} else {
// Single comment that may be a license comment, or no comments, bail.
return;
}
} else {
comment = comments[comments.length - 1];
// If a non-SourceFile node comment has this tag, it should not be attached to the node
// as it documents the whole file by convention.
// TODO: Deprecate and remove. This is an abuse of the @packageDocumentation tag. See:
// https://github.com/TypeStrong/typedoc/issues/1504#issuecomment-775842609
// Deprecate in 0.21, remove in 0.22
if (
sourceFile.text
.substring(comment.pos, comment.end)
.includes("@packageDocumentation")
) {
return;
}

// If a non-SourceFile node comment has this tag, it should not be attached to the node
// as it documents the module.
if (
sourceFile.text
.substring(comment.pos, comment.end)
.includes("@module")
.includes("@module") ||
sourceFile.text
.substring(comment.pos, comment.end)
.includes("@packageDocumentation")
) {
return;
}
Expand Down
18 changes: 12 additions & 6 deletions src/lib/converter/plugins/CommentPlugin.ts
Expand Up @@ -9,7 +9,11 @@ import {
DeclarationReflection,
} from "../../models/reflections/index";
import { Component, ConverterComponent } from "../components";
import { parseComment, getRawComment } from "../factories/comment";
import {
parseComment,
getRawComment,
getJsDocCommentText,
} from "../factories/comment";
import { Converter } from "../converter";
import { Context } from "../context";
import { partition, uniq } from "lodash";
Expand Down Expand Up @@ -124,8 +128,9 @@ export class CommentPlugin extends ConverterComponent {
node?: ts.Node
) {
if (node && ts.isJSDocTemplateTag(node.parent)) {
if (node.parent.comment) {
reflection.comment = new Comment(node.parent.comment);
const comment = getJsDocCommentText(node.parent.comment);
if (comment) {
reflection.comment = new Comment(comment);
}
}

Expand Down Expand Up @@ -167,10 +172,11 @@ export class CommentPlugin extends ConverterComponent {
return;
}

// Clean this up in 0.21. We should really accept a ts.Symbol so we don't need exportSymbol on Context
// Clean this up in 0.22. We should really accept a ts.Symbol so we don't need exportSymbol on Context
const exportNode = context.exportSymbol?.getDeclarations()?.[0];
let rawComment = exportNode && getRawComment(exportNode);
rawComment ??= node && getRawComment(node);
let rawComment =
exportNode && getRawComment(exportNode, this.application.logger);
rawComment ??= node && getRawComment(node, this.application.logger);
if (!rawComment) {
return;
}
Expand Down
23 changes: 15 additions & 8 deletions src/lib/converter/symbols.ts
Expand Up @@ -491,7 +491,7 @@ function convertClassOrInterface(
if (instanceType.typeParameters) {
reflection.typeParameters = instanceType.typeParameters.map((param) => {
const declaration = param.symbol?.declarations?.[0];
assert(ts.isTypeParameterDeclaration(declaration));
assert(declaration && ts.isTypeParameterDeclaration(declaration));
return createTypeParamReflection(declaration, reflectionContext);
});
}
Expand Down Expand Up @@ -596,7 +596,9 @@ function convertProperty(
reflection.type = context.converter.convertType(
context,
(context.isConvertingTypeNode() ? parameterType : void 0) ??
context.checker.getTypeOfSymbolAtLocation(symbol, {} as any)
context.checker.getTypeOfSymbolAtLocation(symbol, {
kind: ts.SyntaxKind.SourceFile,
} as any)
);

if (reflection.flags.isOptional) {
Expand Down Expand Up @@ -801,17 +803,18 @@ function convertVariableAsFunction(
.getDeclarations()
?.find(ts.isVariableDeclaration);

const type = context.checker.getTypeOfSymbolAtLocation(
symbol,
declaration ?? symbol.valueDeclaration
);
const accessDeclaration = declaration ?? symbol.valueDeclaration;

const type = accessDeclaration
? context.checker.getTypeOfSymbolAtLocation(symbol, accessDeclaration)
: context.checker.getDeclaredTypeOfSymbol(symbol);

const reflection = context.createDeclarationReflection(
ReflectionKind.Function,
symbol,
exportSymbol
);
setModifiers(symbol, declaration ?? symbol.valueDeclaration, reflection);
setModifiers(symbol, accessDeclaration, reflection);
// Does anyone care about this? I doubt it...
if (
declaration &&
Expand Down Expand Up @@ -906,9 +909,13 @@ function isInherited(context: Context, symbol: ts.Symbol) {

function setModifiers(
symbol: ts.Symbol,
declaration: ts.Declaration,
declaration: ts.Declaration | undefined,
reflection: Reflection
) {
if (!declaration) {
return;
}

const modifiers = ts.getCombinedModifierFlags(declaration);

if (
Expand Down
10 changes: 6 additions & 4 deletions src/lib/utils/loggers.ts
Expand Up @@ -167,10 +167,12 @@ export class Logger {
}

/** @internal */
deprecated(text: string) {
const stack = new Error().stack?.split("\n");
if (stack && stack.length >= 4) {
text = text + "\n" + stack[3];
deprecated(text: string, addStack = true) {
if (addStack) {
const stack = new Error().stack?.split("\n");
if (stack && stack.length >= 4) {
text = text + "\n" + stack[3];
}
}
if (!this.deprecationWarnings.has(text)) {
this.deprecationWarnings.add(text);
Expand Down

0 comments on commit 432008c

Please sign in to comment.