UNPKG

@irwinproject/storybook-addon-tsdoc

Version:
204 lines (203 loc) 9.59 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.documentDeclarations = exports.documentDeclaration = void 0; const ts_morph_1 = require("ts-morph"); const decorators_1 = require("./decorators"); const TS_1 = __importDefault(require("./TS")); const node_tools_1 = require("./node-tools"); const fs_1 = require("fs"); const node_signature_1 = require("./node-signature"); const traverse_1 = require("./traverse"); const signitors_1 = require("./signitors"); const getChildrenLinks = (node) => { if (ts_morph_1.Node.isUnionTypeNode(node) || ts_morph_1.Node.isIntersectionTypeNode(node)) { return node.getTypeNodes().flatMap(getChildrenLinks); } else if (ts_morph_1.Node.isTupleTypeNode(node) || ts_morph_1.Node.isArrayLiteralExpression(node) || ts_morph_1.Node.isArrayLiteralExpression(node) || ts_morph_1.Node.isObjectBindingPattern(node)) { return node.getElements().flatMap(getChildrenLinks); } else if (ts_morph_1.Node.isObjectLiteralExpression(node) || ts_morph_1.Node.isTypeLiteral(node)) { return node.getProperties().flatMap(getChildrenLinks); } else if (ts_morph_1.Node.isPropertyDeclaration(node) || ts_morph_1.Node.isTypeReference(node) || ts_morph_1.Node.isPropertySignature(node)) { return [node]; } return []; }; /** * @param node * @returns */ const getProperties = (node) => { const properties = []; if ((0, node_tools_1.isPrivate)(node)) return []; if (ts_morph_1.Node.isInitializerExpressionGetable(node) || ts_morph_1.Node.isInitializerExpressionable(node)) { properties.push(...getProperties(node.getInitializer())); } if (ts_morph_1.Node.isTypeAliasDeclaration(node)) { properties.push(...getProperties(node.getTypeNode())); } else if (ts_morph_1.Node.isTypeElementMembered(node)) { properties.push(...node.getProperties().map(n => renderPropLink(n, 4))); } else if (ts_morph_1.Node.isUnionTypeNode(node) || ts_morph_1.Node.isIntersectionTypeNode(node)) { properties.push(...node.getTypeNodes().flatMap(getProperties)); } else if (ts_morph_1.Node.isArrayBindingPattern(node)) { properties.push(...node.getElements().flatMap(getProperties)); } return properties; }; const getMembers = (node) => { if (ts_morph_1.Node.isClassLikeDeclarationBase(node)) return node.getInstanceMembers().filter(n => !(0, node_tools_1.isPrivate)(n)).map(n => renderPropLink(n, 6)); if (ts_morph_1.Node.isVariableDeclaration(node)) { const tn = node.getInitializer(); if (ts_morph_1.Node.isClassExpression(tn)) return tn.getInstanceMembers().filter(n => !(0, node_tools_1.isPrivate)(n)).map(n => renderPropLink(n, 6)); if (ts_morph_1.Node.isObjectLiteralExpression(tn)) return tn.getProperties().filter(n => !(0, node_tools_1.isPrivate)(n)).map(n => renderPropLink(n, 6)); } if (ts_morph_1.Node.isInterfaceDeclaration(node)) return node.getMembers().filter(n => !(0, node_tools_1.isPrivate)(n)).map(n => renderPropLink(n, 6)); return []; }; const getStaticMembers = (node) => { if (ts_morph_1.Node.isClassLikeDeclarationBase(node)) return node.getStaticMembers().map(n => renderPropLink(n, 6)); return []; }; const getKind = (node) => { var _a, _b; if (ts_morph_1.Node.isTypeAliasDeclaration(node)) return 'type'; if (ts_morph_1.Node.isVariableDeclaration(node)) return (_b = (_a = node.getVariableStatement()) === null || _a === void 0 ? void 0 : _a.getDeclarationKind()) !== null && _b !== void 0 ? _b : "const"; if (ts_morph_1.Node.isClassDeclaration(node)) return 'class'; if (ts_morph_1.Node.isPropertySignature(node) || ts_morph_1.Node.isPropertyAssignment(node)) return 'property'; //todo check if its a method if (ts_morph_1.Node.isMethodSignature(node)) return 'method'; if (ts_morph_1.Node.isFunctionDeclaration(node)) return 'function'; if (ts_morph_1.Node.isParameterDeclaration(node)) return 'argument'; if (ts_morph_1.Node.isPropertyDeclaration(node)) return (node.isStatic() ? 'static ' : '') + 'property'; //todo check if its a method if (ts_morph_1.Node.isMethodDeclaration(node)) return (node.isStatic() ? 'static ' : '') + 'method'; if (ts_morph_1.Node.isGetAccessorDeclaration(node)) return (node.isStatic() ? 'static ' : '') + 'get'; if (ts_morph_1.Node.isSetAccessorDeclaration(node)) return (node.isStatic() ? 'static ' : '') + 'set'; if (ts_morph_1.Node.isConstructorDeclaration(node)) return 'constructor'; if (ts_morph_1.Node.isInterfaceDeclaration(node)) return 'interface'; TS_1.default.err("No kind support", node.getKindName()); return 'no support'; }; const getTypeParameters = (node) => { return ts_morph_1.Node.isTypeParametered(node) ? node.getTypeParameters().map(node_signature_1.getSignature).join('\n * ') : ''; }; const getArguments = (node) => { if (ts_morph_1.Node.isParametered(node)) return node.getParameters().map(n => render(n, 4)); //It makes sense that the initializer type node take precedence. Allows for later support to display default values. if (ts_morph_1.Node.isInitializerExpressionGetable(node)) { const tn = node.getInitializer(); if (ts_morph_1.Node.isParametered(tn)) { return getArguments(tn); } } if (ts_morph_1.Node.isTyped(node)) { const tn = node.getTypeNode(); if (ts_morph_1.Node.isParametered(tn)) { return getArguments(tn); } } return []; }; const getConstructor = (node) => { if (ts_morph_1.Node.isVariableDeclaration(node)) return getConstructor(node.getInitializer()); if (!(ts_morph_1.Node.isClassDeclaration(node) || ts_morph_1.Node.isClassExpression(node))) return []; return node.getConstructors().map(n => render(n, 6)); }; const getReturns = (node) => { if (ts_morph_1.Node.isReturnTyped(node)) return (0, signitors_1.fromReturn)(node); if (ts_morph_1.Node.isTyped(node)) { const tn = node.getTypeNode(); if (ts_morph_1.Node.isReturnTyped(tn)) return (0, signitors_1.fromReturn)(tn); } if (ts_morph_1.Node.isInitializerExpressionGetable(node)) { const tn = node.getInitializer(); if (ts_morph_1.Node.isReturnTyped(tn)) return (0, signitors_1.fromReturn)(tn); } return ''; }; /** * Instead of a full render method this generates a link title that can be used to go to a dedicated page. * @param node * @param h */ const renderPropLink = (node, h) => { if (!node) return ''; (0, exports.documentDeclaration)(node); const path = (0, node_tools_1.getDocPath)(node); if (!path) return ''; return (0, decorators_1.$t)(h) `[${(0, decorators_1.$kind)(getKind(node))} ${(0, node_tools_1.getName)(node)}](${path})`; }; const render = (node, h = 2) => { if (!node) return ''; return (0, decorators_1.$s)(h, getKind(node), node) + (0, decorators_1.$section)((0, node_tools_1.getComments)(node), (0, decorators_1.$section)(getConstructor(node).join('\n---\n')).wrap((0, decorators_1.$kd) `**Constructors**:` + '\n', '\n', false), getTypeParameters(node).wrap((0, decorators_1.$kd) `**Type Parameters**:` + '\n\n * ', '\n', false), (0, decorators_1.$section)(getProperties(node).join('\n---\n')).wrap((0, decorators_1.$kd) `**Type Properties**:` + '\n', '\n', false), (0, decorators_1.$section)(getArguments(node).join('\n---\n')).wrap((0, decorators_1.$kd) `**Arguments**:` + '\n', '\n', false), getReturns(node).wrap((0, decorators_1.$kd) `**Returns**: `, '\n', false), (0, node_tools_1.getExample)(node), (0, decorators_1.$section)(getMembers(node).join('\n---\n')).wrap((0, decorators_1.$kd) `**Properties**:` + '\n', '\n', false), (0, decorators_1.$section)(getStaticMembers(node).join('\n---\n')).wrap((0, decorators_1.$kd) `**Static Properties**:` + '\n', '\n', false)); }; const documentDeclaration = (node) => { let title = TS_1.default.resolveUrl(node.getSourceFile().getFilePath()) + '/' + (0, node_tools_1.getFullName)(node, '/'); const t = title.toLowerCase(); const ds = new Set(Object.keys(TS_1.default.decs).map(d => d.toLowerCase())); //Storybook titles are not case sensitive in document CSFs they appear to be in component CSF. if (ds.has(t)) { if (!TS_1.default.decs[title]) { TS_1.default.decs[title] = title + '(1)'; title = TS_1.default.decs[title]; } else { let o = 2; while (ds.has(t + o)) o++; TS_1.default.decs[title] = title + `(${o})`; title = TS_1.default.decs[title]; } } else { TS_1.default.decs[title] = title; } const docPath = TS_1.default.resolvedDocFilePath(title); const data = render(node); if (!data) { TS_1.default.err(node.getKindName()); return; } (0, fs_1.writeFileSync)(docPath, (0, decorators_1.$doc)(data, title)); }; exports.documentDeclaration = documentDeclaration; const documentDeclarations = (source) => { for (const node of (0, traverse_1.traverse)(source)) { (0, exports.documentDeclaration)(node); } }; exports.documentDeclarations = documentDeclarations;