UNPKG

@irwinproject/storybook-addon-tsdoc

Version:
245 lines (244 loc) 8.78 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); const path_1 = __importStar(require("path")); const console_log_colors_1 = require("console-log-colors"); const ts_morph_1 = require("ts-morph"); const fs_1 = require("fs"); const minimatch_1 = require("minimatch"); const renderer_1 = require("./renderer"); require("./utils"); //adds the wrap function to strng prototype. const renderDeclarations_1 = require("./renderDeclarations"); /** * TS is a central repository for options. This will also handle code compiling based off a tsconfig */ class TS { /** * Describes the glob used to identify tsdocs documentation. */ static get docsGlob() { return `${TS.docs}/**/*.mdx`; } /** * Documents a project but catches the errors and outputs it with tsdocs prefix. */ static document({ tsconfig, entry, docs, shouldClearDocsOnStart } = {}) { //apply options if any are provided if (tsconfig) this.tsconfig = (0, path_1.isAbsolute)(tsconfig) ? tsconfig : (0, path_1.join)(process.cwd(), tsconfig); if (entry) this.entry = entry; if (docs) this.docs = (0, path_1.isAbsolute)(docs) ? docs : (0, path_1.join)(process.cwd(), docs); if (shouldClearDocsOnStart !== undefined) this.shouldClearDocsOnStart = shouldClearDocsOnStart; //update the options //clear the docs dir if (TS.shouldClearDocsOnStart) { TS.log("Clearing documents", this.docs); if ((0, fs_1.existsSync)(this.docs)) (0, fs_1.rmSync)(this.docs, { recursive: true }); (0, fs_1.mkdirSync)(this.docs); } else { if (!(0, fs_1.existsSync)(this.docs)) (0, fs_1.mkdirSync)(this.docs); } //move the styles to the docs foler (0, fs_1.cpSync)((0, path_1.join)(__dirname, "style.css"), (0, path_1.join)(this.docs, "style.css")); try { this.documentProject(TS.documentStyle === "file" ? TS.documentSourceFile : TS.documentByDeclaration); } catch (e) { TS.err(e); } TS.hasUpdates = false; } static watch() { if (TS.watcher) return; TS.watcher = (0, fs_1.watch)(process.cwd(), { recursive: true }); TS.watcher.on("change", (e, fileName) => { if (!fileName) return; fileName = typeof fileName === 'string' ? fileName : fileName.toString('utf-8'); if (!(0, minimatch_1.minimatch)(fileName, TS.entry)) return; TS.document(); }); } /** * Resolves the url to its path name that wil be used. for the path name and the path title * @param url * @returns */ static resolveUrl(url) { var _a; if (!url.startsWith(process.cwd())) return; url = url.slice(process.cwd().length + 1); //remove the root. if (!(0, minimatch_1.minimatch)(url, TS.entry)) return; const u = TS.aliases.reduce((o, v) => o.replace(...v), url); const nurl = TS.documentStyle === "declaration" ? u.replace(path_1.default.extname(u), '') : u; return (_a = TS.decs[nurl]) !== null && _a !== void 0 ? _a : nurl; } /** * Resolves the url to a doc url * * This should not be used on urls outside the entry path. * @param url * @returns */ static resolvedDocFilePath(url) { return (0, path_1.join)(this.docs, url.replace(/\//g, '-') + '.mdx'); } /** * Resolves to a storybook url path value. * @param url * @returns {string} */ static resolveDocPath(url) { var _a, _b; const u = '/docs/' + ((_a = TS.decs[url]) !== null && _a !== void 0 ? _a : url).replace(/[\/\.\(]/g, '-').replace(/[\)]/g, ''); return ((_b = TS.decs[u]) !== null && _b !== void 0 ? _b : u) + '--docs'; ; } /** * Create a project (program) and crawl the parsed data. */ static documentProject(documentor = TS.documentSourceFile) { const project = new ts_morph_1.Project({ tsConfigFilePath: this.tsconfig, }); project.addSourceFilesAtPaths((0, path_1.join)(process.cwd(), this.entry)); project.getSourceFiles().forEach(f => { const match = (0, minimatch_1.minimatch)(f.getFilePath(), (0, path_1.join)(process.cwd(), this.entry)); if (!match) project.removeSourceFile(f); }); TS.log((0, console_log_colors_1.cyan)("Documenting"), (0, path_1.join)(process.cwd(), TS.entry), (0, console_log_colors_1.red)(project.getSourceFiles().length), `file${project.getSourceFiles().length === 1 ? '' : 's'}`); project.getSourceFiles().forEach(documentor); } /** * Document the source file. * * at this time this will create an mdx file if any nodes are traversed in said directory * * * @todo wrap style in style tag since it will never be used in any other way. * @param source * @returns */ static documentSourceFile(source) { const path = TS.resolveUrl(source.getFilePath()); if (!path) return; const data = (0, renderer_1.render)(path, source); if (!data) return; return (0, fs_1.writeFileSync)(TS.resolvedDocFilePath(path), data); } static documentByDeclaration(source) { (0, renderDeclarations_1.documentDeclarations)(source); } /** * A prefixed log method to make identification easier * @param args */ static log(...args) { console.log((0, console_log_colors_1.blueBright)("TsDoc"), ...args); } /** * A red prefixed log method. * @param args */ static err(...args) { console.log((0, console_log_colors_1.red)("TsDoc"), ...args); } /** * A yellow prefixed log method. * @param args */ static warn(...args) { console.log((0, console_log_colors_1.yellow)("TsDoc"), ...args); } /** * A green prefixed log method. * @param args */ static success(...args) { console.log((0, console_log_colors_1.green)("TsDoc"), ...args); } } TS.hasUpdates = true; /** * The document folder path */ TS.docs = (0, path_1.join)(process.cwd(), ".tsdoc"); /** * The tsconfig path */ TS.tsconfig = (0, path_1.join)(process.cwd(), "tsconfig.json"); /** * @todo change to accept multiple entries. * @todo add automatic entry based on tsconfig */ TS.entry = "src/**/!(*.test|*.stories|*.d).ts"; /** * @todo add configurable option */ TS.aliases = [ [/src\//, ''] //drop the src from the docpath ]; /** * I hate this property * @todo virtualize docs in dev environment. */ TS.shouldClearDocsOnStart = true; /** * @todo support not documenting private variables. */ TS.documentPrivate = false; /** * Declaration based documentation is in development. IT DOES NOT YET WORK!!! */ TS.documentStyle = "declaration"; /** * 1 stange case I have encountered is when declarations are differenciated by case such as m and M in svg overwrite the file because file systems are not case specific. as such * a record of all links will be tracked and if an overlap is detected a different path will be provided. */ TS.decs = {}; exports.default = TS;