UNPKG

docs-ts

Version:

Documentation tool for TypeScript packages

289 lines (288 loc) 17.6 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.main = void 0; /** * @since 0.6.0 */ var Either = require("fp-ts/Either"); var function_1 = require("fp-ts/function"); var Json = require("fp-ts/Json"); var Monoid = require("fp-ts/Monoid"); var RTE = require("fp-ts/ReaderTaskEither"); var ReadonlyArray = require("fp-ts/ReadonlyArray"); var S = require("fp-ts/string"); var TaskEither = require("fp-ts/TaskEither"); var Decoder = require("io-ts/Decoder"); var path = require("path"); var Config = require("./Config"); var FileSystem_1 = require("./FileSystem"); var Markdown_1 = require("./Markdown"); var Parser = require("./Parser"); /** * @category main * @since 0.6.0 */ exports.main = (0, function_1.pipe)(RTE.Do, RTE.bind('capabilities', function () { return RTE.ask(); }), RTE.bind('pkg', function () { return parsePackageJSON; }), RTE.bind('config', function (_a) { var pkg = _a.pkg; return getConfig(pkg.name, pkg.homepage); }), RTE.chainTaskEitherK(function (_a) { var config = _a.config, capabilities = _a.capabilities; var program = (0, function_1.pipe)(readSourceFiles, RTE.flatMap(parseFiles), RTE.tap(typeCheckExamples), RTE.flatMap(getMarkdownFiles), RTE.flatMap(writeMarkdownFiles)); return program(__assign(__assign({}, capabilities), { config: config })); })); var PackageJSONDecoder = (0, function_1.pipe)(Decoder.struct({ name: Decoder.string, homepage: Decoder.string })); var parsePackageJSON = function (_a) { var fileSystem = _a.fileSystem; var read = (0, function_1.pipe)(fileSystem.readFile(path.join(process.cwd(), 'package.json')), TaskEither.mapLeft(function () { return "Unable to read package.json in \"".concat(process.cwd(), "\""); })); var parse = function (packageJsonSource) { return (0, function_1.pipe)(Json.parse(packageJsonSource), Either.mapLeft(function (u) { return Either.toError(u).message; }), TaskEither.fromEither); }; var decode = function (json) { return (0, function_1.pipe)(PackageJSONDecoder.decode(json), Either.mapLeft(function (decodeError) { return "Unable to decode package.json:\n".concat(Decoder.draw(decodeError)); }), TaskEither.fromEither); }; return (0, function_1.pipe)(read, TaskEither.flatMap(parse), TaskEither.flatMap(decode)); }; // ------------------------------------------------------------------------------------- // config // ------------------------------------------------------------------------------------- var CONFIG_FILE_NAME = 'docs-ts.json'; var getConfig = function (projectName, projectHomepage) { return function (capabilities) { var configPath = path.join(process.cwd(), CONFIG_FILE_NAME); var defaultConfig = getDefaultConfig(projectName, projectHomepage); return (0, function_1.pipe)(capabilities.fileSystem.exists(configPath), TaskEither.flatMap(function (exists) { return exists ? (0, function_1.pipe)(capabilities.fileSystem.readFile(configPath), TaskEither.flatMap(function (content) { return TaskEither.fromEither((0, function_1.pipe)(Json.parse(content), Either.mapLeft(function (u) { return Either.toError(u).message; }))); }), TaskEither.tap(function () { return capabilities.logger.info("Configuration file found"); }), TaskEither.flatMap(function (json) { return TaskEither.fromEither(Config.decode(json)); }), TaskEither.bimap(function (decodeError) { return "Invalid configuration file detected:\n".concat(decodeError); }, function (config) { return (__assign(__assign({}, defaultConfig), config)); })) : (0, function_1.pipe)(capabilities.logger.info('No configuration file detected, using default configuration'), TaskEither.map(function () { return defaultConfig; })); })); }; }; var getDefaultConfig = function (projectName, projectHomepage) { return { projectName: projectName, projectHomepage: projectHomepage, srcDir: 'src', outDir: 'docs', theme: 'pmarsceill/just-the-docs', enableSearch: true, enforceDescriptions: false, enforceExamples: false, enforceVersion: true, exclude: [], parseCompilerOptions: {}, examplesCompilerOptions: {} }; }; // ------------------------------------------------------------------------------------- // filesystem APIs // ------------------------------------------------------------------------------------- var readFile = function (path) { return (0, function_1.pipe)(RTE.ask(), RTE.chainTaskEitherK(function (_a) { var fileSystem = _a.fileSystem; return fileSystem.readFile(path); }), RTE.map(function (content) { return (0, FileSystem_1.File)(path, content, false); })); }; var readFiles = ReadonlyArray.traverse(RTE.ApplicativePar)(readFile); var writeFile = function (file) { var overwrite = (0, function_1.pipe)(RTE.ask(), RTE.chainTaskEitherK(function (_a) { var fileSystem = _a.fileSystem, logger = _a.logger; return (0, function_1.pipe)(logger.debug("Overwriting file ".concat(file.path)), TaskEither.flatMap(function () { return fileSystem.writeFile(file.path, file.content); })); })); var skip = (0, function_1.pipe)(RTE.ask(), RTE.chainTaskEitherK(function (_a) { var logger = _a.logger; return logger.debug("File ".concat(file.path, " already exists, skipping creation")); })); var write = (0, function_1.pipe)(RTE.ask(), RTE.chainTaskEitherK(function (_a) { var fileSystem = _a.fileSystem; return fileSystem.writeFile(file.path, file.content); })); return (0, function_1.pipe)(RTE.ask(), RTE.flatMap(function (_a) { var fileSystem = _a.fileSystem; return RTE.fromTaskEither(fileSystem.exists(file.path)); }), RTE.flatMap(function (exists) { return (exists ? (file.overwrite ? overwrite : skip) : write); })); }; var writeFiles = (0, function_1.flow)(ReadonlyArray.traverse(RTE.ApplicativePar)(writeFile), RTE.map(function_1.constVoid)); var readSourcePaths = (0, function_1.pipe)(RTE.ask(), RTE.chainTaskEitherK(function (_a) { var fileSystem = _a.fileSystem, logger = _a.logger, config = _a.config; return (0, function_1.pipe)(fileSystem.search(path.join(config.srcDir, '**', '*.ts'), config.exclude), TaskEither.map(ReadonlyArray.map(path.normalize)), TaskEither.tap(function (paths) { return (0, function_1.pipe)(logger.info("".concat(paths.length, " module(s) found"))); })); })); var readSourceFiles = (0, function_1.pipe)(RTE.ask(), RTE.flatMap(function (C) { return (0, function_1.pipe)(readSourcePaths, RTE.chainTaskEitherK(function (paths) { return (0, function_1.pipe)(C, readFiles(paths)); })); })); // ------------------------------------------------------------------------------------- // parsers // ------------------------------------------------------------------------------------- var parseFiles = function (files) { return (0, function_1.pipe)(RTE.ask(), RTE.tap(function (_a) { var logger = _a.logger; return RTE.fromTaskEither(logger.debug('Parsing files...')); }), RTE.flatMap(function () { return Parser.parseFiles(files); })); }; // ------------------------------------------------------------------------------------- // examples // ------------------------------------------------------------------------------------- var foldFiles = Monoid.concatAll(ReadonlyArray.getMonoid()); var getExampleFiles = function (modules) { return (0, function_1.pipe)(RTE.ask(), RTE.map(function (env) { return (0, function_1.pipe)(modules, ReadonlyArray.flatMap(function (module) { var prefix = module.path.join('-'); var getDocumentableExamples = function (id) { return function (documentable) { return (0, function_1.pipe)(documentable.examples, ReadonlyArray.mapWithIndex(function (i, content) { return (0, FileSystem_1.File)(path.join(env.config.outDir, 'examples', "".concat(prefix, "-").concat(id, "-").concat(documentable.name, "-").concat(i, ".ts")), "".concat(content, "\n"), true); })); }; }; var moduleExamples = getDocumentableExamples('module')(module); var methods = (0, function_1.pipe)(module.classes, ReadonlyArray.flatMap(function (c) { return foldFiles([ (0, function_1.pipe)(c.methods, ReadonlyArray.flatMap(getDocumentableExamples("".concat(c.name, "-method")))), (0, function_1.pipe)(c.staticMethods, ReadonlyArray.flatMap(getDocumentableExamples("".concat(c.name, "-staticmethod")))) ]); })); var interfaces = (0, function_1.pipe)(module.interfaces, ReadonlyArray.flatMap(getDocumentableExamples('interface'))); var typeAliases = (0, function_1.pipe)(module.typeAliases, ReadonlyArray.flatMap(getDocumentableExamples('typealias'))); var constants = (0, function_1.pipe)(module.constants, ReadonlyArray.flatMap(getDocumentableExamples('constant'))); var functions = (0, function_1.pipe)(module.functions, ReadonlyArray.flatMap(getDocumentableExamples('function'))); return foldFiles([moduleExamples, methods, interfaces, typeAliases, constants, functions]); })); })); }; var addAssertImport = function (code) { return code.indexOf('assert.') !== -1 ? "import * as assert from 'assert'\n".concat(code) : code; }; var replaceProjectName = function (source) { return (0, function_1.pipe)(RTE.ask(), RTE.map(function (_a) { var config = _a.config; var importRegex = function (projectName) { return new RegExp("from (?<quote>['\"])".concat(projectName, "(?:/lib)?(?:/(?<path>.*))?\\k<quote>"), 'g'); }; return source.replace(importRegex(config.projectName), function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var groups = args[args.length - 1]; return "from '../../src".concat(groups.path ? "/".concat(groups.path) : '', "'"); }); })); }; var handleImports = ReadonlyArray.traverse(RTE.ApplicativePar)(function (file) { return (0, function_1.pipe)(replaceProjectName(file.content), RTE.map(addAssertImport), RTE.map(function (content) { return (0, FileSystem_1.File)(file.path, content, file.overwrite); })); }); var getExampleIndex = function (examples) { var content = (0, function_1.pipe)(examples, ReadonlyArray.foldMap(S.Monoid)(function (example) { return "import './".concat(path.basename(example.path, '.ts'), "'\n"); })); return (0, function_1.pipe)(RTE.ask(), RTE.map(function (env) { return (0, FileSystem_1.File)(path.join(env.config.outDir, 'examples', 'index.ts'), "".concat(content, "\n"), true); })); }; var cleanExamples = (0, function_1.pipe)(RTE.ask(), RTE.chainTaskEitherK(function (_a) { var fileSystem = _a.fileSystem, config = _a.config; return fileSystem.remove(path.join(config.outDir, 'examples')); })); var spawnTsNode = (0, function_1.pipe)(RTE.ask(), RTE.tap(function (_a) { var logger = _a.logger; return RTE.fromTaskEither(logger.debug('Type checking examples...')); }), RTE.chainTaskEitherK(function (_a) { var spawn = _a.spawn, config = _a.config; var command = process.platform === 'win32' ? 'ts-node.cmd' : 'ts-node'; var executable = path.join(process.cwd(), config.outDir, 'examples', 'index.ts'); return spawn(command, executable); })); var writeExamples = function (examples) { return (0, function_1.pipe)(RTE.ask(), RTE.tap(function (_a) { var logger = _a.logger; return RTE.fromTaskEither(logger.debug('Writing examples...')); }), RTE.flatMap(function (C) { return (0, function_1.pipe)(getExampleIndex(examples), RTE.map(function (index) { return (0, function_1.pipe)(examples, ReadonlyArray.prepend(index)); }), RTE.chainTaskEitherK(function (files) { return (0, function_1.pipe)(C, writeFiles(files)); })); })); }; var writeTsConfigJson = (0, function_1.pipe)(RTE.ask(), RTE.tap(function (_a) { var logger = _a.logger; return RTE.fromTaskEither(logger.debug('Writing examples tsconfig...')); }), RTE.flatMap(function (env) { return writeFile((0, FileSystem_1.File)(path.join(process.cwd(), env.config.outDir, 'examples', 'tsconfig.json'), JSON.stringify({ compilerOptions: env.config.examplesCompilerOptions }, null, 2), true)); })); var typeCheckExamples = function (modules) { return (0, function_1.pipe)(getExampleFiles(modules), RTE.flatMap(handleImports), RTE.flatMap(function (examples) { return examples.length === 0 ? cleanExamples : (0, function_1.pipe)(writeExamples(examples), RTE.flatMap(function () { return writeTsConfigJson; }), RTE.flatMap(function () { return spawnTsNode; }), RTE.flatMap(function () { return cleanExamples; })); })); }; // ------------------------------------------------------------------------------------- // markdown // ------------------------------------------------------------------------------------- var getHome = (0, function_1.pipe)(RTE.ask(), RTE.map(function (_a) { var config = _a.config; return (0, FileSystem_1.File)(path.join(process.cwd(), config.outDir, 'index.md'), "---\ntitle: Home\nnav_order: 1\n---\n", false); })); var getModulesIndex = (0, function_1.pipe)(RTE.ask(), RTE.map(function (_a) { var config = _a.config; return (0, FileSystem_1.File)(path.join(process.cwd(), config.outDir, 'modules', 'index.md'), "---\ntitle: Modules\nhas_children: true\npermalink: /docs/modules\nnav_order: 2\n---", false); })); var replace = function (searchValue, replaceValue) { return function (s) { return s.replace(searchValue, replaceValue); }; }; var resolveConfigYML = function (previousContent, config) { return (0, function_1.pipe)(previousContent, replace(/^remote_theme:.*$/m, "remote_theme: ".concat(config.theme)), replace(/^search_enabled:.*$/m, "search_enabled: ".concat(config.enableSearch)), replace(/^ {2}'\S* on GitHub':\n {4}- '.*'/m, " '".concat(config.projectName, " on GitHub':\n - '").concat(config.projectHomepage, "'"))); }; var getHomepageNavigationHeader = function (config) { var isGitHub = config.projectHomepage.toLowerCase().includes('github'); return isGitHub ? config.projectName + ' on GitHub' : 'Homepage'; }; var getConfigYML = (0, function_1.pipe)(RTE.ask(), RTE.chainTaskEitherK(function (_a) { var fileSystem = _a.fileSystem, config = _a.config; var filePath = path.join(process.cwd(), config.outDir, '_config.yml'); return (0, function_1.pipe)(fileSystem.exists(filePath), TaskEither.flatMap(function (exists) { return exists ? (0, function_1.pipe)(fileSystem.readFile(filePath), TaskEither.map(function (content) { return (0, FileSystem_1.File)(filePath, resolveConfigYML(content, config), true); })) : TaskEither.of((0, FileSystem_1.File)(filePath, "remote_theme: ".concat(config.theme, "\n\n# Enable or disable the site search\nsearch_enabled: ").concat(config.enableSearch, "\n\n# Aux links for the upper right navigation\naux_links:\n '").concat(getHomepageNavigationHeader(config), "':\n - '").concat(config.projectHomepage, "'"), false)); })); })); var getMarkdownOutputPath = function (module) { return (0, function_1.pipe)(RTE.ask(), RTE.map(function (_a) { var config = _a.config; return path.join(config.outDir, 'modules', "".concat(module.path.slice(1).join(path.sep), ".md")); })); }; var getModuleMarkdownFiles = function (modules) { return (0, function_1.pipe)(modules, RTE.traverseArrayWithIndex(function (order, module) { return (0, function_1.pipe)(getMarkdownOutputPath(module), RTE.bindTo('outputPath'), RTE.bind('content', function () { return RTE.right((0, Markdown_1.printModule)(module, order + 1)); }), RTE.map(function (_a) { var content = _a.content, outputPath = _a.outputPath; return (0, FileSystem_1.File)(outputPath, content, true); })); })); }; var getMarkdownFiles = function (modules) { return (0, function_1.pipe)(RTE.sequenceArray([getHome, getModulesIndex, getConfigYML]), RTE.flatMap(function (meta) { return (0, function_1.pipe)(getModuleMarkdownFiles(modules), RTE.map(function (files) { return ReadonlyArray.getMonoid().concat(meta, files); })); })); }; var writeMarkdownFiles = function (files) { return (0, function_1.pipe)(RTE.ask(), RTE.chainFirst(function (_a) { var fileSystem = _a.fileSystem, logger = _a.logger, config = _a.config; var outPattern = path.join(config.outDir, '**/*.ts.md'); return (0, function_1.pipe)(logger.debug("Cleaning up docs folder: deleting ".concat(outPattern)), TaskEither.flatMap(function () { return fileSystem.remove(outPattern); }), RTE.fromTaskEither); }), RTE.chainTaskEitherK(function (C) { return (0, function_1.pipe)(C.logger.debug('Writing markdown files...'), TaskEither.flatMap(function () { return (0, function_1.pipe)(C, writeFiles(files)); })); })); };