UNPKG

@loopback/tsdocs

Version:

A package to generate api docs using Microsoft api-extractor and api-documenter

148 lines (131 loc) 4.22 kB
// Copyright IBM Corp. and LoopBack contributors 2019,2020. All Rights Reserved. // Node module: @loopback/tsdocs // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT import debugFactory from 'debug'; import fs from 'fs-extra'; import path from 'path'; import { ApiDocsOptions, DEFAULT_APIDOCS_EXTRACTION_PATH, DEFAULT_APIDOCS_GENERATION_PATH, getPackagesWithTsDocs, getUnscopedPackageName, LernaPackage, } from './helper'; const debug = debugFactory('loopback:tsdocs'); /** * Update markdown files generated by api-documenter to prepend Jekyll metadata * and generate `apidocs/index.md`. * * @param options - Options for api docs */ export async function updateApiDocs(options: ApiDocsOptions = {}) { options = Object.assign( { rootDir: process.cwd(), apiDocsGenerationPath: DEFAULT_APIDOCS_GENERATION_PATH, apiDocsExtractionPath: DEFAULT_APIDOCS_EXTRACTION_PATH, generateDefaultPackageDoc: true, }, options, ); const packages = await getPackagesWithTsDocs(options.rootDir); /* istanbul ignore if */ if (!packages.length) return; const packagesByName: Record<string, LernaPackage> = {}; for (const pkg of packages) { packagesByName[getUnscopedPackageName(pkg.name)] = pkg; } options.lernaPackages = packagesByName; const found = await addJekyllMetadata(packages[0].rootPath, options); if (found) { // await generateIndex(packages, options); } } /** * Prepend Jekyll metadata to markdown files * * @param lernaRootDir - Root directory for the monorepo * @param options - Options for api docs */ async function addJekyllMetadata( lernaRootDir: string, options: ApiDocsOptions, ) { const apiDocsRoot = path.join(lernaRootDir, options.apiDocsGenerationPath!); const exists = await fs.pathExists(apiDocsRoot); if (!exists) { console.error('No API docs found at %s.', apiDocsRoot); return false; } const apiFiles = await fs.readdir(apiDocsRoot); for (const f of apiFiles) { /* istanbul ignore if */ if (!f.endsWith('.md')) continue; const name = f.replace(/\.md$/, ''); const isPackage = f.match(/^[^\.]+.md$/) && f !== 'index.md'; /* istanbul ignore if */ if (!options.silent) { // Only print the package level name if (isPackage) { console.log('Updating *.md files for %s', name); } } const docFile = path.join(apiDocsRoot, f); let doc = await fs.readFile(docFile, 'utf-8'); doc = doc.replace(/<td>/g, '<td markdown="1">'); const pkgName = name.split('.')[0]; // Calculate the relative uri for the package let relativeUri = `packages/${pkgName}`; const pkg = options.lernaPackages?.[pkgName]; if (pkg != null) { relativeUri = path .relative(pkg.rootPath, pkg.location) .split(path.sep) // On Windows, the relative path has `\` .join('/'); } const pkgUrl = f === 'index.md' ? 'https://github.com/loopbackio/loopback-next' : `https://github.com/loopbackio/loopback-next/tree/master/${relativeUri}`; if (isPackage && options.generateDefaultPackageDoc) { const modelFile = path.join( path.join( lernaRootDir, options.apiDocsExtractionPath!, `models/${name}.api.json`, ), ); /** * "kind": "Package", * "canonicalReference": "@loopback/authentication", * "docComment": "", * "name": "@loopback/authentication", */ const model = await fs.readJson(modelFile, {encoding: 'utf-8'}); debug('Package %s', name, model); if (model.kind === 'Package' && !model.docComment) { const pkgDoc = `[${model.name}](${pkgUrl})`; doc = doc.replace( `## ${name} package`, `## ${name} package\n\n${pkgDoc}`, ); } } doc = `--- lang: en title: 'API docs: ${name}' keywords: LoopBack 4.0, LoopBack 4, Node.js, TypeScript, OpenAPI sidebar: lb4_sidebar editurl: ${pkgUrl} permalink: /doc/en/lb4/apidocs.${name}.html --- ${doc} `; if (!options.dryRun) { await fs.writeFile(docFile, doc, 'utf-8'); } } return true; }