tsd-jsdoc
Version:
Compiles JSDoc annotated javascript into a Typescript Declaration File (.d.ts).
326 lines • 15.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const ts = require("typescript");
const logger_1 = require("./logger");
const doclet_utils_1 = require("./doclet_utils");
const PropTree_1 = require("./PropTree");
const type_resolve_helpers_1 = require("./type_resolve_helpers");
const declareModifier = ts.createModifier(ts.SyntaxKind.DeclareKeyword);
const constModifier = ts.createModifier(ts.SyntaxKind.ConstKeyword);
const readonlyModifier = ts.createModifier(ts.SyntaxKind.ReadonlyKeyword);
function validateClassLikeChildren(children, validate, msg) {
if (children) {
for (let i = children.length - 1; i >= 0; --i) {
const child = children[i];
if (!validate(child)) {
logger_1.warn(`Encountered child that is not a ${msg}, this is likely due to invalid JSDoc.`, child);
children.splice(i, 1);
}
}
}
}
function validateClassChildren(children) {
validateClassLikeChildren(children, ts.isClassElement, 'ClassElement');
}
function validateInterfaceChildren(children) {
validateClassLikeChildren(children, ts.isTypeElement, 'TypeElement');
}
function validateModuleChildren(children) {
if (children) {
for (let i = children.length - 1; i >= 0; --i) {
const child = children[i];
if (!ts.isClassDeclaration(child)
&& !ts.isInterfaceDeclaration(child)
&& !ts.isFunctionDeclaration(child)
&& !ts.isEnumDeclaration(child)
&& !ts.isModuleDeclaration(child)
&& !ts.isTypeAliasDeclaration(child)
&& !ts.isVariableStatement(child)) {
logger_1.warn('Encountered child that is not a supported declaration, this is likely due to invalid JSDoc.', child);
children.splice(i, 1);
}
}
}
}
function formatMultilineComment(comment) {
return comment.split('\n').join('\n * ');
}
function handlePropsComment(props, jsdocTagName) {
return props.map((prop) => {
if (prop.description) {
let name;
if (prop.optional) {
if (prop.defaultvalue !== undefined) {
name = `[${prop.name} = ${prop.defaultvalue}]`;
}
else {
name = `[${prop.name}]`;
}
}
else {
name = prop.name;
}
const description = ` - ${formatMultilineComment(prop.description)}`;
return `\n * @${jsdocTagName} ${name}${description}`;
}
return '';
}).filter((value) => value !== '').join('');
}
function handleReturnsComment(doclet) {
if (doclet_utils_1.isFunctionDoclet(doclet) && doclet.returns) {
return doclet.returns.map((ret) => {
if (ret.description)
return `\n * @returns ${formatMultilineComment(ret.description)}`;
return '';
})
.filter((value) => value !== '').join('');
}
return '';
}
function handleExamplesComment(doclet) {
if (doclet.examples !== undefined) {
return doclet.examples.map((example) => {
return `\n * @example
* ${formatMultilineComment(example)}`;
})
.join('');
}
return '';
}
function handleParamsComment(doclet) {
if ((doclet_utils_1.isClassDoclet(doclet)
|| doclet_utils_1.isFileDoclet(doclet)
|| doclet_utils_1.isEventDoclet(doclet)
|| doclet_utils_1.isFunctionDoclet(doclet)
|| doclet_utils_1.isTypedefDoclet(doclet))
&& doclet.params) {
return handlePropsComment(doclet.params, 'param');
}
return '';
}
function handlePropertiesComment(doclet) {
if (!doclet_utils_1.isEnumDoclet(doclet) && doclet.properties) {
return handlePropsComment(doclet.properties, 'property');
}
return '';
}
function handleComment(doclet, node) {
if (doclet.comment && doclet.comment.length > 4) {
let description = '';
if (doclet.description) {
description = `\n * ${formatMultilineComment(doclet.description)}`;
}
else if (doclet_utils_1.isClassDoclet(doclet) && doclet.classdesc) {
description = `\n * ${formatMultilineComment(doclet.classdesc)}`;
}
const examples = handleExamplesComment(doclet);
const properties = handlePropertiesComment(doclet);
const params = handleParamsComment(doclet);
const returns = handleReturnsComment(doclet);
if (doclet_utils_1.isEnumDoclet(doclet)) {
if (!ts.isEnumDeclaration(node)) {
logger_1.warn(`Node is not an enum declaration, even though the doclet is. This is likely a tsd-jsdoc bug.`);
return node;
}
if (doclet.properties) {
const enumProperties = doclet.properties;
const enumMembers = node.members;
for (let index = 0; index < enumProperties.length; index++) {
const enumProperty = enumProperties[index];
const enumMember = enumMembers[index];
handleComment(enumProperty, enumMember);
}
}
}
if (description || examples || properties || params || returns) {
let comment = `*${description}${examples}${properties}${params}${returns}
`;
const kind = ts.SyntaxKind.MultiLineCommentTrivia;
ts.addSyntheticLeadingComment(node, kind, comment, true);
}
}
return node;
}
function createClass(doclet, children) {
validateClassChildren(children);
const mods = doclet.memberof ? undefined : [declareModifier];
const members = children || [];
const typeParams = type_resolve_helpers_1.resolveTypeParameters(doclet);
const heritageClauses = type_resolve_helpers_1.resolveHeritageClauses(doclet, false);
if (doclet.name.startsWith('exports.'))
doclet.name = doclet.name.replace('exports.', '');
if (doclet.params) {
const params = type_resolve_helpers_1.createFunctionParams(doclet);
members.unshift(ts.createConstructor(undefined, undefined, params, undefined));
}
if (doclet.properties) {
const tree = new PropTree_1.PropTree(doclet.properties);
for (let i = 0; i < tree.roots.length; ++i) {
const node = tree.roots[i];
const opt = node.prop.optional ? ts.createToken(ts.SyntaxKind.QuestionToken) : undefined;
const t = node.children.length ? type_resolve_helpers_1.createTypeLiteral(node.children, node) : type_resolve_helpers_1.resolveType(node.prop.type);
const property = ts.createProperty(undefined, undefined, node.name, opt, t, undefined);
if (node.prop.description) {
let comment = `*\n * ${node.prop.description.split(/\r\s*/).join("\n * ")}\n`;
ts.addSyntheticLeadingComment(property, ts.SyntaxKind.MultiLineCommentTrivia, comment, true);
}
members.push(property);
}
}
return handleComment(doclet, ts.createClassDeclaration(undefined, mods, doclet.name, typeParams, heritageClauses, members));
}
exports.createClass = createClass;
function createInterface(doclet, children) {
validateInterfaceChildren(children);
const mods = doclet.memberof ? undefined : [declareModifier];
const members = children;
const typeParams = type_resolve_helpers_1.resolveTypeParameters(doclet);
const heritageClauses = type_resolve_helpers_1.resolveHeritageClauses(doclet, true);
if (doclet.name.startsWith('exports.'))
doclet.name = doclet.name.replace('exports.', '');
return handleComment(doclet, ts.createInterfaceDeclaration(undefined, mods, doclet.name, typeParams, heritageClauses, members));
}
exports.createInterface = createInterface;
function createFunction(doclet) {
const mods = doclet.memberof ? undefined : [declareModifier];
const params = type_resolve_helpers_1.createFunctionParams(doclet);
const type = type_resolve_helpers_1.createFunctionReturnType(doclet);
const typeParams = type_resolve_helpers_1.resolveTypeParameters(doclet);
if (doclet.name.startsWith('exports.'))
doclet.name = doclet.name.replace('exports.', '');
return handleComment(doclet, ts.createFunctionDeclaration(undefined, mods, undefined, doclet.name, typeParams, params, type, undefined));
}
exports.createFunction = createFunction;
function createClassMethod(doclet) {
const mods = [];
const params = type_resolve_helpers_1.createFunctionParams(doclet);
const type = type_resolve_helpers_1.createFunctionReturnType(doclet);
const typeParams = type_resolve_helpers_1.resolveTypeParameters(doclet);
if (!doclet.memberof)
mods.push(declareModifier);
if (doclet.access === 'private')
mods.push(ts.createModifier(ts.SyntaxKind.PrivateKeyword));
else if (doclet.access === 'protected')
mods.push(ts.createModifier(ts.SyntaxKind.ProtectedKeyword));
else if (doclet.access === 'public')
mods.push(ts.createModifier(ts.SyntaxKind.PublicKeyword));
if (doclet.scope === 'static')
mods.push(ts.createModifier(ts.SyntaxKind.StaticKeyword));
if (doclet.name.startsWith('exports.'))
doclet.name = doclet.name.replace('exports.', '');
const [name, questionToken] = type_resolve_helpers_1.resolveOptionalFromName(doclet);
return handleComment(doclet, ts.createMethod(undefined, mods, undefined, name, questionToken, typeParams, params, type, undefined));
}
exports.createClassMethod = createClassMethod;
function createInterfaceMethod(doclet) {
const mods = [];
const params = type_resolve_helpers_1.createFunctionParams(doclet);
const type = type_resolve_helpers_1.createFunctionReturnType(doclet);
const typeParams = type_resolve_helpers_1.resolveTypeParameters(doclet);
if (doclet.name.startsWith('exports.'))
doclet.name = doclet.name.replace('exports.', '');
const [name, questionToken] = type_resolve_helpers_1.resolveOptionalFromName(doclet);
return handleComment(doclet, ts.createMethodSignature(typeParams, params, type, name, questionToken));
}
exports.createInterfaceMethod = createInterfaceMethod;
function createEnum(doclet) {
const mods = [];
const props = [];
if (!doclet.memberof)
mods.push(declareModifier);
if (doclet.kind === 'constant')
mods.push(constModifier);
if (doclet.properties && doclet.properties.length) {
for (let i = 0; i < doclet.properties.length; ++i) {
const p = doclet.properties[i];
const l = p.defaultvalue !== undefined ? ts.createLiteral(p.defaultvalue) : undefined;
props.push(ts.createEnumMember(p.name, l));
}
}
return handleComment(doclet, ts.createEnumDeclaration(undefined, mods, doclet.name, props));
}
exports.createEnum = createEnum;
function createClassMember(doclet) {
const mods = [];
const type = type_resolve_helpers_1.resolveType(doclet.type, doclet);
if (doclet.access === 'private')
mods.push(ts.createModifier(ts.SyntaxKind.PrivateKeyword));
else if (doclet.access === 'protected')
mods.push(ts.createModifier(ts.SyntaxKind.ProtectedKeyword));
else if (doclet.access === 'public')
mods.push(ts.createModifier(ts.SyntaxKind.PublicKeyword));
if (doclet.scope === 'static')
mods.push(ts.createModifier(ts.SyntaxKind.StaticKeyword));
if (doclet.kind === 'constant' || doclet.readonly)
mods.push(readonlyModifier);
const [name, questionToken] = type_resolve_helpers_1.resolveOptionalFromName(doclet);
return handleComment(doclet, ts.createProperty(undefined, mods, name, questionToken, type, undefined));
}
exports.createClassMember = createClassMember;
function createInterfaceMember(doclet) {
const mods = [];
const type = type_resolve_helpers_1.resolveType(doclet.type, doclet);
if (doclet.kind === 'constant')
mods.push(readonlyModifier);
if (doclet.scope === 'static')
mods.push(ts.createModifier(ts.SyntaxKind.StaticKeyword));
const [name, questionToken] = type_resolve_helpers_1.resolveOptionalFromName(doclet);
return handleComment(doclet, ts.createPropertySignature(mods, name, questionToken, type, undefined));
}
exports.createInterfaceMember = createInterfaceMember;
function createNamespaceMember(doclet) {
const mods = doclet.memberof ? undefined : [declareModifier];
const flags = (doclet.kind === 'constant' || doclet.readonly) ? ts.NodeFlags.Const : undefined;
const literalValue = doclet.defaultvalue !== undefined ? doclet.defaultvalue
: doclet.meta && doclet.meta.code.type === 'Literal' ? doclet.meta.code.value
: undefined;
const initializer = (flags === ts.NodeFlags.Const && literalValue !== undefined) ? ts.createLiteral(literalValue) : undefined;
const type = initializer ? undefined : type_resolve_helpers_1.resolveType(doclet.type, doclet);
if (doclet.name.startsWith('exports.'))
doclet.name = doclet.name.replace('exports.', '');
return handleComment(doclet, ts.createVariableStatement(mods, ts.createVariableDeclarationList([
ts.createVariableDeclaration(doclet.name, type, initializer)
], flags)));
}
exports.createNamespaceMember = createNamespaceMember;
function createModule(doclet, nested, children) {
validateModuleChildren(children);
const mods = doclet.memberof ? undefined : [declareModifier];
let body = undefined;
let flags = ts.NodeFlags.None;
if (doclet.name.startsWith('exports.'))
doclet.name = doclet.name.replace('exports.', '');
if (nested)
flags |= ts.NodeFlags.NestedNamespace;
if (children)
body = ts.createModuleBlock(children);
const name = ts.createStringLiteral(doclet.name);
return handleComment(doclet, ts.createModuleDeclaration(undefined, mods, name, body, flags));
}
exports.createModule = createModule;
function createNamespace(doclet, nested, children) {
validateModuleChildren(children);
const mods = doclet.memberof ? undefined : [declareModifier];
let body = undefined;
let flags = ts.NodeFlags.Namespace;
if (doclet.name.startsWith('exports.'))
doclet.name = doclet.name.replace('exports.', '');
if (nested)
flags |= ts.NodeFlags.NestedNamespace;
if (children) {
body = ts.createModuleBlock(children);
}
const name = ts.createIdentifier(doclet.name);
return handleComment(doclet, ts.createModuleDeclaration(undefined, mods, name, body, flags));
}
exports.createNamespace = createNamespace;
function createTypedef(doclet, children) {
const mods = doclet.memberof ? undefined : [declareModifier];
const type = type_resolve_helpers_1.resolveType(doclet.type, doclet);
const typeParams = type_resolve_helpers_1.resolveTypeParameters(doclet);
if (doclet.name.startsWith('exports.'))
doclet.name = doclet.name.replace('exports.', '');
return handleComment(doclet, ts.createTypeAliasDeclaration(undefined, mods, doclet.name, typeParams, type));
}
exports.createTypedef = createTypedef;
//# sourceMappingURL=create_helpers.js.map