diff --git a/.github/workflows/covector-status.yml b/.github/workflows/covector-status.yml new file mode 100644 index 0000000..72f9bee --- /dev/null +++ b/.github/workflows/covector-status.yml @@ -0,0 +1,16 @@ +name: covector status +on: [pull_request] + +jobs: + covector: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: covector status + uses: jbolda/covector/packages/action@covector-v0 + id: covector + with: + command: 'status' diff --git a/.github/workflows/covector-version-or-publish.yml b/.github/workflows/covector-version-or-publish.yml new file mode 100644 index 0000000..5ca500a --- /dev/null +++ b/.github/workflows/covector-version-or-publish.yml @@ -0,0 +1,40 @@ +name: covector version or publish +on: + push: + branches: + - main + - master + +jobs: + covector: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - uses: actions/setup-node@v1 + with: + node-version: 12 + registry-url: 'https://registry.npmjs.org' + - name: git config + run: | + git config --global user.name "${{ github.event.pusher.name }}" + git config --global user.email "${{ github.event.pusher.email }}" + - name: covector version-or-publish + uses: jbolda/covector/packages/action@covector-v0 + id: covector + with: + token: ${{ secrets.GITHUB_TOKEN }} + command: 'version-or-publish' + createRelease: true + - name: create pull request + id: cpr + uses: tauri-apps/create-pull-request@v2.8.0 + if: steps.covector.outputs.commandRan == 'version' + with: + title: "Publish New Versions" + commit-message: "publish new versions" + labels: "version updates" + branch: "release" + body: ${{ steps.covector.outputs.change }} diff --git a/.github/workflows/test-action.yml b/.github/workflows/test-action.yml new file mode 100644 index 0000000..226491f --- /dev/null +++ b/.github/workflows/test-action.yml @@ -0,0 +1,27 @@ +name: test action + +on: + pull_request: + +jobs: + update-docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: checkout tauri-docs + uses: actions/checkout@v2 + with: + repository: tauri-apps/tauri-docs + path: tauri-docs + - name: checkout tauri + uses: actions/checkout@v2 + with: + repository: tauri-apps/tauri + path: tauri + - name: run typedocusaurus + uses: ./ + with: + originPath: ./tauri/tooling/api/ + sidebarFile: ./tauri-docs/sidebars/typedoc.json + targetPath: ./tauri-docs/docs/en/api/js/ + docusaurusPath: ./tauri-docs/ diff --git a/.gitignore b/.gitignore index 4ebdbee..520b9e0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ node_modules -docs -api \ No newline at end of file +/index.js \ No newline at end of file diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..c20a007 --- /dev/null +++ b/action.yml @@ -0,0 +1,14 @@ +name: 'typedocusaurus' +description: 'Generate Typedoc to Docusaurus.' +inputs: + originPath: + required: true + sidebarFile: + required: true + targetPath: + required: true + docusaurusPath: + required: true +runs: + using: 'node12' + main: 'dist/index.js' \ No newline at end of file diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..f72cf99 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,1047 @@ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ 351: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +const os = __importStar(__nccwpck_require__(87)); +const utils_1 = __nccwpck_require__(278); +/** + * Commands + * + * Command Format: + * ::name key=value,key=value::message + * + * Examples: + * ::warning::This is the message + * ::set-env name=MY_VAR::some value + */ +function issueCommand(command, properties, message) { + const cmd = new Command(command, properties, message); + process.stdout.write(cmd.toString() + os.EOL); +} +exports.issueCommand = issueCommand; +function issue(name, message = '') { + issueCommand(name, {}, message); +} +exports.issue = issue; +const CMD_STRING = '::'; +class Command { + constructor(command, properties, message) { + if (!command) { + command = 'missing.command'; + } + this.command = command; + this.properties = properties; + this.message = message; + } + toString() { + let cmdStr = CMD_STRING + this.command; + if (this.properties && Object.keys(this.properties).length > 0) { + cmdStr += ' '; + let first = true; + for (const key in this.properties) { + if (this.properties.hasOwnProperty(key)) { + const val = this.properties[key]; + if (val) { + if (first) { + first = false; + } + else { + cmdStr += ','; + } + cmdStr += `${key}=${escapeProperty(val)}`; + } + } + } + } + cmdStr += `${CMD_STRING}${escapeData(this.message)}`; + return cmdStr; + } +} +function escapeData(s) { + return utils_1.toCommandValue(s) + .replace(/%/g, '%25') + .replace(/\r/g, '%0D') + .replace(/\n/g, '%0A'); +} +function escapeProperty(s) { + return utils_1.toCommandValue(s) + .replace(/%/g, '%25') + .replace(/\r/g, '%0D') + .replace(/\n/g, '%0A') + .replace(/:/g, '%3A') + .replace(/,/g, '%2C'); +} +//# sourceMappingURL=command.js.map + +/***/ }), + +/***/ 186: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +const command_1 = __nccwpck_require__(351); +const file_command_1 = __nccwpck_require__(717); +const utils_1 = __nccwpck_require__(278); +const os = __importStar(__nccwpck_require__(87)); +const path = __importStar(__nccwpck_require__(622)); +/** + * The code to exit an action + */ +var ExitCode; +(function (ExitCode) { + /** + * A code indicating that the action was successful + */ + ExitCode[ExitCode["Success"] = 0] = "Success"; + /** + * A code indicating that the action was a failure + */ + ExitCode[ExitCode["Failure"] = 1] = "Failure"; +})(ExitCode = exports.ExitCode || (exports.ExitCode = {})); +//----------------------------------------------------------------------- +// Variables +//----------------------------------------------------------------------- +/** + * Sets env variable for this action and future actions in the job + * @param name the name of the variable to set + * @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function exportVariable(name, val) { + const convertedVal = utils_1.toCommandValue(val); + process.env[name] = convertedVal; + const filePath = process.env['GITHUB_ENV'] || ''; + if (filePath) { + const delimiter = '_GitHubActionsFileCommandDelimeter_'; + const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}`; + file_command_1.issueCommand('ENV', commandValue); + } + else { + command_1.issueCommand('set-env', { name }, convertedVal); + } +} +exports.exportVariable = exportVariable; +/** + * Registers a secret which will get masked from logs + * @param secret value of the secret + */ +function setSecret(secret) { + command_1.issueCommand('add-mask', {}, secret); +} +exports.setSecret = setSecret; +/** + * Prepends inputPath to the PATH (for this action and future actions) + * @param inputPath + */ +function addPath(inputPath) { + const filePath = process.env['GITHUB_PATH'] || ''; + if (filePath) { + file_command_1.issueCommand('PATH', inputPath); + } + else { + command_1.issueCommand('add-path', {}, inputPath); + } + process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`; +} +exports.addPath = addPath; +/** + * Gets the value of an input. The value is also trimmed. + * + * @param name name of the input to get + * @param options optional. See InputOptions. + * @returns string + */ +function getInput(name, options) { + const val = process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || ''; + if (options && options.required && !val) { + throw new Error(`Input required and not supplied: ${name}`); + } + return val.trim(); +} +exports.getInput = getInput; +/** + * Sets the value of an output. + * + * @param name name of the output to set + * @param value value to store. Non-string values will be converted to a string via JSON.stringify + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function setOutput(name, value) { + command_1.issueCommand('set-output', { name }, value); +} +exports.setOutput = setOutput; +/** + * Enables or disables the echoing of commands into stdout for the rest of the step. + * Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set. + * + */ +function setCommandEcho(enabled) { + command_1.issue('echo', enabled ? 'on' : 'off'); +} +exports.setCommandEcho = setCommandEcho; +//----------------------------------------------------------------------- +// Results +//----------------------------------------------------------------------- +/** + * Sets the action status to failed. + * When the action exits it will be with an exit code of 1 + * @param message add error issue message + */ +function setFailed(message) { + process.exitCode = ExitCode.Failure; + error(message); +} +exports.setFailed = setFailed; +//----------------------------------------------------------------------- +// Logging Commands +//----------------------------------------------------------------------- +/** + * Gets whether Actions Step Debug is on or not + */ +function isDebug() { + return process.env['RUNNER_DEBUG'] === '1'; +} +exports.isDebug = isDebug; +/** + * Writes debug message to user log + * @param message debug message + */ +function debug(message) { + command_1.issueCommand('debug', {}, message); +} +exports.debug = debug; +/** + * Adds an error issue + * @param message error issue message. Errors will be converted to string via toString() + */ +function error(message) { + command_1.issue('error', message instanceof Error ? message.toString() : message); +} +exports.error = error; +/** + * Adds an warning issue + * @param message warning issue message. Errors will be converted to string via toString() + */ +function warning(message) { + command_1.issue('warning', message instanceof Error ? message.toString() : message); +} +exports.warning = warning; +/** + * Writes info to log with console.log. + * @param message info message + */ +function info(message) { + process.stdout.write(message + os.EOL); +} +exports.info = info; +/** + * Begin an output group. + * + * Output until the next `groupEnd` will be foldable in this group + * + * @param name The name of the output group + */ +function startGroup(name) { + command_1.issue('group', name); +} +exports.startGroup = startGroup; +/** + * End an output group. + */ +function endGroup() { + command_1.issue('endgroup'); +} +exports.endGroup = endGroup; +/** + * Wrap an asynchronous function call in a group. + * + * Returns the same type as the function itself. + * + * @param name The name of the group + * @param fn The function to wrap in the group + */ +function group(name, fn) { + return __awaiter(this, void 0, void 0, function* () { + startGroup(name); + let result; + try { + result = yield fn(); + } + finally { + endGroup(); + } + return result; + }); +} +exports.group = group; +//----------------------------------------------------------------------- +// Wrapper action state +//----------------------------------------------------------------------- +/** + * Saves state for current action, the state can only be retrieved by this action's post job execution. + * + * @param name name of the state to store + * @param value value to store. Non-string values will be converted to a string via JSON.stringify + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function saveState(name, value) { + command_1.issueCommand('save-state', { name }, value); +} +exports.saveState = saveState; +/** + * Gets the value of an state set by this action's main execution. + * + * @param name name of the state to get + * @returns string + */ +function getState(name) { + return process.env[`STATE_${name}`] || ''; +} +exports.getState = getState; +//# sourceMappingURL=core.js.map + +/***/ }), + +/***/ 717: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +// For internal use, subject to change. +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +// We use any as a valid input type +/* eslint-disable @typescript-eslint/no-explicit-any */ +const fs = __importStar(__nccwpck_require__(747)); +const os = __importStar(__nccwpck_require__(87)); +const utils_1 = __nccwpck_require__(278); +function issueCommand(command, message) { + const filePath = process.env[`GITHUB_${command}`]; + if (!filePath) { + throw new Error(`Unable to find environment variable for file command ${command}`); + } + if (!fs.existsSync(filePath)) { + throw new Error(`Missing file at path: ${filePath}`); + } + fs.appendFileSync(filePath, `${utils_1.toCommandValue(message)}${os.EOL}`, { + encoding: 'utf8' + }); +} +exports.issueCommand = issueCommand; +//# sourceMappingURL=file-command.js.map + +/***/ }), + +/***/ 278: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +// We use any as a valid input type +/* eslint-disable @typescript-eslint/no-explicit-any */ +Object.defineProperty(exports, "__esModule", ({ value: true })); +/** + * Sanitizes an input into a string so it can be passed into issueCommand safely + * @param input input to sanitize into a string + */ +function toCommandValue(input) { + if (input === null || input === undefined) { + return ''; + } + else if (typeof input === 'string' || input instanceof String) { + return input; + } + return JSON.stringify(input); +} +exports.toCommandValue = toCommandValue; +//# sourceMappingURL=utils.js.map + +/***/ }), + +/***/ 975: +/***/ ((module, exports, __nccwpck_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); + +var _module = __nccwpck_require__(282); + +var _module2 = _interopRequireDefault(_module); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/*:: type ParentType = { + children: Array, + exports: any, + filename: string, + id: string, + loaded: boolean, + parent: any, + paths: Array +};*/ // @flow + +/*:: type IsOverrideType = (request: string, parent: ParentType) => boolean;*/ +/*:: type ResolverOverrideType = (request: string, parent: ParentType) => any;*/ + + +/** + * @param isOverride A condition used to check whether to override Module._load. + * @param resolveOverride A function used to override Module._load result. + */ +/*:: type OverrideRequireType = (...rest: Array) => void;*/ + +exports.default = (isOverride /*: IsOverrideType*/, resolveOverride /*: ResolverOverrideType*/) /*: OverrideRequireType*/ => { + const originalLoad = _module2.default._load; + + // eslint-disable-next-line id-match + _module2.default._load = function (request /*: string*/, parent /*: ParentType*/) { + if (isOverride(request, parent)) { + return resolveOverride(request, parent); + } + + // eslint-disable-next-line prefer-rest-params + return originalLoad.apply(this, arguments); + }; + + return () => { + // eslint-disable-next-line id-match + _module2.default._load = originalLoad; + }; +}; + +module.exports = exports['default']; + +/***/ }), + +/***/ 879: +/***/ ((__unused_webpack_module, __webpack_exports__, __nccwpck_require__) => { + +"use strict"; +// ESM COMPAT FLAG +__nccwpck_require__.r(__webpack_exports__); + +// EXPORTS +__nccwpck_require__.d(__webpack_exports__, { + "default": () => (/* binding */ generate) +}); + +;// CONCATENATED MODULE: external "typedoc" +const external_typedoc_namespaceObject = require("typedoc");; +;// CONCATENATED MODULE: external "typedoc-plugin-markdown" +const external_typedoc_plugin_markdown_namespaceObject = require("typedoc-plugin-markdown");; +// EXTERNAL MODULE: external "path" +var external_path_ = __nccwpck_require__(622); +// EXTERNAL MODULE: ./node_modules/@vercel/ncc/dist/ncc/@@notfound.js?typedoc/dist/lib/converter/components +var components = __nccwpck_require__(137); +// EXTERNAL MODULE: ./node_modules/@vercel/ncc/dist/ncc/@@notfound.js?typedoc/dist/lib/output/components +var output_components = __nccwpck_require__(813); +// EXTERNAL MODULE: ./node_modules/@vercel/ncc/dist/ncc/@@notfound.js?typedoc/dist/lib/output/events +var events = __nccwpck_require__(906); +// EXTERNAL MODULE: ./node_modules/@vercel/ncc/dist/ncc/@@notfound.js?typedoc-plugin-markdown/dist/resources/helpers/reflection-title +var reflection_title = __nccwpck_require__(794); +;// CONCATENATED MODULE: ./src/front-matter.ts +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; + +// @ts-ignore + +// @ts-ignore + +// @ts-ignore + +// @ts-ignore + +// @ts-ignore + +/** + * Prepends YAML block to a string + * @param contents - the string to prepend + * @param vars - object of required front matter variables + */ +const prependYAML = (contents, vars) => { + return contents + .replace(/^/, toYAML(vars) + '\n\n') + .replace(/[\r\n]{3,}/g, '\n\n'); +}; +/** + * Returns the page title as rendered in the document h1(# title) + * @param page + */ +const getPageTitle = (page) => { + return reflection_title.reflectionTitle.call(page, false); +}; +/** + * Converts YAML object to a YAML string + * @param vars + */ +const toYAML = (vars) => { + const yaml = `--- +${Object.entries(vars) + .map(([key, value]) => `${key}: ${typeof value === 'string' ? `"${escapeString(value)}"` : value}`) + .join('\n')} +---`; + return yaml; +}; +// prettier-ignore +const escapeString = (str) => str.replace(/([^\\])'/g, '$1\\\''); +let FrontMatterComponent = class FrontMatterComponent extends output_components.RendererComponent { + constructor() { + super(...arguments); + this.globalsFile = 'modules.md'; + } + initialize() { + super.initialize(); + // @ts-ignore + this.listenTo(this.application.renderer, { + [events.PageEvent.END]: this.onPageEnd, + }); + } + onPageEnd(page) { + if (page.contents) { + page.contents = prependYAML(page.contents, this.getYamlItems(page)); + } + } + getYamlItems(page) { + const pageTitle = this.getTitle(page); + const sidebarLabel = this.getSidebarLabel(page); + let items = { + title: pageTitle, + }; + if (sidebarLabel && sidebarLabel !== pageTitle) { + items = { ...items, sidebar_label: sidebarLabel }; + } + return { + ...items, + custom_edit_url: null, + hide_title: true, + }; + } + getSidebarLabel(page) { + if (!this.sidebar) { + return null; + } + if (page.url === this.entryDocument) { + return page.url === page.project.url + ? this.sidebar.indexLabel + : this.sidebar.readmeLabel; + } + if (page.url === this.globalsFile) { + return this.sidebar.indexLabel; + } + return this.sidebar.fullNames ? page.model.getFullName() : page.model.name; + } + getId(page) { + return external_path_.basename(page.url, external_path_.extname(page.url)); + } + getTitle(page) { + const readmeTitle = this.readmeTitle || page.project.name; + if (page.url === this.entryDocument && page.url !== page.project.url) { + return readmeTitle; + } + return getPageTitle(page); + } +}; +__decorate([ + (0,external_typedoc_namespaceObject.BindOption)('out') +], FrontMatterComponent.prototype, "out", void 0); +__decorate([ + (0,external_typedoc_namespaceObject.BindOption)('sidebar') +], FrontMatterComponent.prototype, "sidebar", void 0); +__decorate([ + (0,external_typedoc_namespaceObject.BindOption)('globalsTitle') +], FrontMatterComponent.prototype, "globalsTitle", void 0); +__decorate([ + (0,external_typedoc_namespaceObject.BindOption)('readmeTitle') +], FrontMatterComponent.prototype, "readmeTitle", void 0); +__decorate([ + (0,external_typedoc_namespaceObject.BindOption)('entryDocument') +], FrontMatterComponent.prototype, "entryDocument", void 0); +FrontMatterComponent = __decorate([ + (0,components.Component)({ name: 'front-matter' }) +], FrontMatterComponent); + + +;// CONCATENATED MODULE: ./src/options.ts + + +/** + * Default plugin options + */ +const DEFAULT_PLUGIN_OPTIONS = { + id: 'default', + docsRoot: 'docs', + out: 'api', + entryDocument: 'index.md', + hideInPageTOC: true, + hideBreadcrumbs: true, + sidebar: { + fullNames: false, + sidebarFile: 'typedoc-sidebar.js', + indexLabel: 'Table of contents', + readmeLabel: 'Readme', + sidebarPath: '', + }, + plugin: ['none'], + outputDirectory: '', + siteDir: '', + watch: false, +}; +/** + * Merge default with user options + * @param opts + */ +const getOptions = (siteDir, opts) => { + // base options + let options = { + ...DEFAULT_PLUGIN_OPTIONS, + ...opts, + }; + // sidebar + if (opts.sidebar === null) { + options = { ...options, sidebar: null }; + } + else { + const sidebar = { + ...DEFAULT_PLUGIN_OPTIONS.sidebar, + ...opts.sidebar, + }; + options = { + ...options, + sidebar: { + ...sidebar, + sidebarPath: external_path_.resolve(siteDir, sidebar.sidebarFile), + }, + }; + } + // additional + options = { + ...options, + siteDir, + outputDirectory: external_path_.resolve(siteDir, options.docsRoot, options.out), + }; + return options; +}; +/** + * Add docusaurus options to converter + * @param app + */ +const addOptions = (app) => { + // configure deault typedoc options + app.options.addReader(new external_typedoc_namespaceObject.TypeDocReader()); + app.options.addReader(new external_typedoc_namespaceObject.TSConfigReader()); + // expose plugin options to typedoc so we can access if required + app.options.addDeclaration({ + name: 'id', + }); + app.options.addDeclaration({ + name: 'docsRoot', + }); + app.options.addDeclaration({ + name: 'siteDir', + }); + app.options.addDeclaration({ + name: 'outputDirectory', + }); + app.options.addDeclaration({ + name: 'globalsTitle', + }); + app.options.addDeclaration({ + name: 'readmeTitle', + }); + app.options.addDeclaration({ + name: 'sidebar', + type: external_typedoc_namespaceObject.ParameterType.Mixed, + }); +}; + +;// CONCATENATED MODULE: ./src/render.ts +// @ts-ignore + +async function render(project, outputDirectory) { + var _a; + if (!this.prepareTheme() || !this.prepareOutputDirectory(outputDirectory)) { + return; + } + const output = new events.RendererEvent(events.RendererEvent.BEGIN, outputDirectory, project); + output.settings = this.application.options.getRawValues(); + output.urls = this.theme.getUrls(project); + this.trigger(output); + if (!output.isDefaultPrevented) { + (_a = output.urls) === null || _a === void 0 ? void 0 : _a.forEach((mapping, i) => { + var _a; + this.renderDocument(output.createPageEvent(mapping)); + console.log(`\rGenerated ${i + 1} of ${(_a = output.urls) === null || _a === void 0 ? void 0 : _a.length} TypeDoc docs`); + }); + console.log(`\n`); + this.trigger(events.RendererEvent.END, output); + } +} + +// EXTERNAL MODULE: external "fs" +var external_fs_ = __nccwpck_require__(747); +;// CONCATENATED MODULE: ./src/sidebar.ts +var sidebar_decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; + + +// @ts-ignore + +// @ts-ignore + +// @ts-ignore + +// @ts-ignore + +let SidebarComponent = class SidebarComponent extends output_components.RendererComponent { + initialize() { + // @ts-ignore + this.listenTo(this.application.renderer, { + [events.RendererEvent.BEGIN]: this.onRendererBegin, + }); + } + async onRendererBegin(renderer) { + var _a; + // @ts-ignore + const navigation = (_a = this.application.renderer.theme) === null || _a === void 0 ? void 0 : _a.getNavigation(renderer.project); + const out = this.out.match(/(?:.*)en\/(.*)/)[1]; + // map the navigation object to a Docuaurus sidebar format + const sidebarItems = (navigation === null || navigation === void 0 ? void 0 : navigation.children) + ? navigation.children.map((navigationItem) => { + if (navigationItem.isLabel) { + const sidebarCategoryItems = navigationItem.children + ? navigationItem.children.map((navItem) => { + const url = this.getUrlKey(out, navItem.url); + if (navItem.children && navItem.children.length > 0) { + const sidebarCategoryChildren = navItem.children.map((childGroup) => this.getSidebarCategory(childGroup.title, childGroup.children + ? childGroup.children.map((childItem) => this.getUrlKey(out, childItem.url)) + : [])); + return this.getSidebarCategory(navItem.title, [ + url, + ...sidebarCategoryChildren, + ]); + } + return url; + }) + : []; + return this.getSidebarCategory(navigationItem.title, sidebarCategoryItems); + } + return this.getUrlKey(out, navigationItem.url); + }) + : []; + const sidebarPath = this.sidebar.sidebarPath; + external_fs_.writeFileSync(sidebarPath, JSON.stringify(sidebarItems, null, 2)); + // @ts-ignore + this.application.logger.success(`TypeDoc sidebar written to ${sidebarPath}`); + } + /** + * returns a sidebar category node + */ + getSidebarCategory(title, items) { + return { + items, + type: 'category', + label: title, + }; + } + /** + * returns the url key for relevant doc + */ + getUrlKey(out, url) { + const urlKey = url.replace('.md', ''); + return out ? out + '/' + urlKey : urlKey; + } +}; +sidebar_decorate([ + (0,external_typedoc_namespaceObject.BindOption)('sidebar') +], SidebarComponent.prototype, "sidebar", void 0); +sidebar_decorate([ + (0,external_typedoc_namespaceObject.BindOption)('siteDir') +], SidebarComponent.prototype, "siteDir", void 0); +sidebar_decorate([ + (0,external_typedoc_namespaceObject.BindOption)('out') +], SidebarComponent.prototype, "out", void 0); +SidebarComponent = sidebar_decorate([ + (0,components.Component)({ name: 'sidebar' }) +], SidebarComponent); + +/** + * Write content to sidebar file + */ +const writeSidebar = (sidebar, content) => { + if (!fs.existsSync(path.dirname(sidebar.sidebarPath))) { + fs.mkdirSync(path.dirname(sidebar.sidebarPath)); + } + fs.writeFileSync(sidebar.sidebarPath, content); +}; + +;// CONCATENATED MODULE: ./src/plugin.ts +// @ts-ignore + +// @ts-ignore + + + + + +async function generate(siteDir, opts) { + // we need to generate an empty sidebar up-front so it can be resolved from sidebars.js + const options = getOptions(siteDir, opts); + // if (options.sidebar) { + // writeSidebar(options.sidebar, 'module.exports=[];'); + // } + // initialize and build app + const app = new external_typedoc_namespaceObject.Application(); + // load the markdown plugin + (0,external_typedoc_plugin_markdown_namespaceObject.load)(app); + // customise render + app.renderer.render = render; + // add plugin options + addOptions(app); + // bootstrap typedoc app + app.bootstrap(options); + // add frontmatter component to typedoc renderer + // @ts-ignore + app.renderer.addComponent('fm', new FrontMatterComponent(app.renderer)); + // add sidebar component to typedoc renderer + // @ts-ignore + app.renderer.addComponent('sidebar', new SidebarComponent(app.renderer)); + // return the generated reflections + const project = app.convert(); + // if project is undefined typedoc has a problem - error logging will be supplied by typedoc. + if (!project) { + return; + } + // generate or watch app + return app.generateDocs(project, options.outputDirectory); +} + + +/***/ }), + +/***/ 794: +/***/ ((module) => { + +module.exports = eval("require")("typedoc-plugin-markdown/dist/resources/helpers/reflection-title"); + + +/***/ }), + +/***/ 137: +/***/ ((module) => { + +module.exports = eval("require")("typedoc/dist/lib/converter/components"); + + +/***/ }), + +/***/ 813: +/***/ ((module) => { + +module.exports = eval("require")("typedoc/dist/lib/output/components"); + + +/***/ }), + +/***/ 906: +/***/ ((module) => { + +module.exports = eval("require")("typedoc/dist/lib/output/events"); + + +/***/ }), + +/***/ 747: +/***/ ((module) => { + +"use strict"; +module.exports = require("fs");; + +/***/ }), + +/***/ 282: +/***/ ((module) => { + +"use strict"; +module.exports = require("module");; + +/***/ }), + +/***/ 87: +/***/ ((module) => { + +"use strict"; +module.exports = require("os");; + +/***/ }), + +/***/ 622: +/***/ ((module) => { + +"use strict"; +module.exports = require("path");; + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __nccwpck_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ var threw = true; +/******/ try { +/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __nccwpck_require__); +/******/ threw = false; +/******/ } finally { +/******/ if(threw) delete __webpack_module_cache__[moduleId]; +/******/ } +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __nccwpck_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__nccwpck_require__.o(definition, key) && !__nccwpck_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __nccwpck_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __nccwpck_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/compat */ +/******/ +/******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/";/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. +(() => { +let core = __nccwpck_require__(186); +const { rmdir } = __nccwpck_require__(747).promises; +const path = __nccwpck_require__(622); +const overrideRequire = __nccwpck_require__(975); +if (process.env.DEV) { + core = { + getInput: (variable) => process.env[variable], + setFailed: (message) => console.log(message) + }; +} +(async () => { + try { + // Where your docs live, should be the folder containing the crates docs + const originPath = core.getInput("originPath"); // e.g. "/path/to/project/src/"; + const sidebarFile = core.getInput("sidebarFile"); + // Where you'll save your MD files + const targetPath = core.getInput("targetPath"); // e.g. "/path/to/docusaurus/website/docs/api/js/"; + const docusaurusPath = core.getInput("docusaurusPath"); + const overrideCondition = (request) => request.startsWith("typedoc"); + const resolveRequest = (request) => require(path.normalize(process.cwd().replace("/dist/typedocusaurus", "") + `/${originPath}node_modules/${request}`)); + overrideRequire(overrideCondition, resolveRequest); + const { default: generate } = __nccwpck_require__(879); + await rmdir(targetPath, { recursive: true }); + await generate(docusaurusPath, { + entryPoints: originPath + "src", + out: targetPath, + entryDocument: "index.md", + hideInPageTOC: true, + hideBreadcrumbs: true, + watch: false, + tsconfig: originPath + "tsconfig.json", + sidebar: { + sidebarFile, + }, + readme: "none", + }); + console.log("Tasks completed!"); + } + catch (error) { + core.setFailed(error.message); + } +})(); + +})(); + +module.exports = __webpack_exports__; +/******/ })() +; \ No newline at end of file diff --git a/package.json b/package.json index d5e600c..e858116 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,17 @@ "main": "index.js", "license": "MIT", "scripts": { - "build": "typedoc --plugin typedoc-plugin-markdown --out docs api/src --tsconfig api/tsconfig.json --hideInPageTOC true --hideBreadcrumbs true" + "run-source": "node index.js", + "pkg": "ncc build src/index.ts -o dist -e typedoc -e typedoc-plugin-markdown" }, "devDependencies": { - "docusaurus-plugin-typedoc": "^0.16.7", - "typedoc": "^0.22.10", - "typedoc-plugin-markdown": "^3.11.11", - "typescript": "^4.5.4" + "@types/node": "^14.14.35", + "@vercel/ncc": "^0.28.5", + "override-require": "^1.1.1", + "tslib": "^2.1.0", + "typescript": "^4.2.3" + }, + "dependencies": { + "@actions/core": "^1.2.6" } } diff --git a/src/front-matter.ts b/src/front-matter.ts new file mode 100644 index 0000000..47e88d4 --- /dev/null +++ b/src/front-matter.ts @@ -0,0 +1,132 @@ +import * as path from 'path'; + +// @ts-ignore +import { BindOption } from 'typedoc'; +// @ts-ignore +import { Component } from 'typedoc/dist/lib/converter/components'; +// @ts-ignore +import { RendererComponent } from 'typedoc/dist/lib/output/components'; +// @ts-ignore +import { PageEvent } from 'typedoc/dist/lib/output/events'; + +import { FrontMatter, Sidebar } from './types'; + +// @ts-ignore +import { reflectionTitle } from 'typedoc-plugin-markdown/dist/resources/helpers/reflection-title'; + +export interface FrontMatterVars { + [key: string]: string | number | boolean; +} + +/** + * Prepends YAML block to a string + * @param contents - the string to prepend + * @param vars - object of required front matter variables + */ +export const prependYAML = (contents: string, vars: FrontMatterVars) => { + return contents + .replace(/^/, toYAML(vars) + '\n\n') + .replace(/[\r\n]{3,}/g, '\n\n'); +}; + +/** + * Returns the page title as rendered in the document h1(# title) + * @param page + */ +export const getPageTitle = (page: PageEvent) => { + return reflectionTitle.call(page, false); +}; + +/** + * Converts YAML object to a YAML string + * @param vars + */ +const toYAML = (vars: FrontMatterVars) => { + const yaml = `--- +${Object.entries(vars) + .map( + ([key, value]) => + `${key}: ${ + typeof value === 'string' ? `"${escapeString(value)}"` : value + }`, + ) + .join('\n')} +---`; + return yaml; +}; + +// prettier-ignore +const escapeString=(str: string) => str.replace(/([^\\])'/g, '$1\\\''); + +@Component({ name: 'front-matter' }) +export class FrontMatterComponent extends RendererComponent { + @BindOption('out') + out!: string; + @BindOption('sidebar') + sidebar!: Sidebar; + @BindOption('globalsTitle') + globalsTitle!: string; + @BindOption('readmeTitle') + readmeTitle!: string; + @BindOption('entryDocument') + entryDocument!: string; + + globalsFile = 'modules.md'; + + initialize() { + super.initialize(); + // @ts-ignore + this.listenTo(this.application.renderer, { + [PageEvent.END]: this.onPageEnd, + }); + } + onPageEnd(page: PageEvent) { + if (page.contents) { + page.contents = prependYAML(page.contents, this.getYamlItems(page)); + } + } + + getYamlItems(page: PageEvent): any { + const pageTitle = this.getTitle(page); + const sidebarLabel = this.getSidebarLabel(page); + let items: FrontMatter = { + title: pageTitle, + }; + if (sidebarLabel && sidebarLabel !== pageTitle) { + items = { ...items, sidebar_label: sidebarLabel }; + } + return { + ...items, + custom_edit_url: null, + hide_title: true, + }; + } + + getSidebarLabel(page: PageEvent) { + if (!this.sidebar) { + return null; + } + if (page.url === this.entryDocument) { + return page.url === page.project.url + ? this.sidebar.indexLabel + : this.sidebar.readmeLabel; + } + + if (page.url === this.globalsFile) { + return this.sidebar.indexLabel; + } + return this.sidebar.fullNames ? page.model.getFullName() : page.model.name; + } + + getId(page: PageEvent) { + return path.basename(page.url, path.extname(page.url)); + } + + getTitle(page: PageEvent) { + const readmeTitle = this.readmeTitle || page.project.name; + if (page.url === this.entryDocument && page.url !== page.project.url) { + return readmeTitle; + } + return getPageTitle(page); + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..680a2dd --- /dev/null +++ b/src/index.ts @@ -0,0 +1,54 @@ +let core = require("@actions/core"); +const { rmdir } = require("fs").promises; + +const path = require("path"); + +const overrideRequire = require("override-require"); +if (process.env.DEV) { + core = { + getInput: (variable) => process.env[variable], + setFailed: (message) => console.log(message) + }; +} +(async () => { + try { + // Where your docs live, should be the folder containing the crates docs + const originPath = core.getInput("originPath"); // e.g. "/path/to/project/src/"; + + const sidebarFile = core.getInput("sidebarFile"); + // Where you'll save your MD files + const targetPath = core.getInput("targetPath"); // e.g. "/path/to/docusaurus/website/docs/api/js/"; + const docusaurusPath = core.getInput("docusaurusPath"); + + const overrideCondition = (request) => request.startsWith("typedoc"); + + const resolveRequest = (request) => + require(path.normalize( + process.cwd().replace("/dist/typedocusaurus", "") + `/${originPath}node_modules/${request}` + )); + + overrideRequire(overrideCondition, resolveRequest); + + const { default: generate } = require("./plugin"); + + await rmdir(targetPath, { recursive: true }); + + await generate(docusaurusPath, { + entryPoints: originPath + "src", + out: targetPath, + entryDocument: "index.md", + hideInPageTOC: true, + hideBreadcrumbs: true, + watch: false, + tsconfig: originPath + "tsconfig.json", + sidebar: { + sidebarFile, + }, + readme: "none", + }); + + console.log("Tasks completed!"); + } catch (error) { + core.setFailed(error.message); + } +})(); diff --git a/src/options.ts b/src/options.ts new file mode 100644 index 0000000..0626b5b --- /dev/null +++ b/src/options.ts @@ -0,0 +1,120 @@ +import * as path from 'path'; + +import { + // @ts-ignore + Application, + // @ts-ignore + MixedDeclarationOption, + // @ts-ignore + ParameterType, + // @ts-ignore + StringDeclarationOption, + // @ts-ignore + TSConfigReader, + // @ts-ignore + TypeDocReader, + // @ts-ignore +} from 'typedoc'; + +import { PluginOptions, SidebarOptions } from './types'; + +/** + * Default plugin options + */ +const DEFAULT_PLUGIN_OPTIONS: PluginOptions = { + id: 'default', + docsRoot: 'docs', + out: 'api', + entryDocument: 'index.md', + hideInPageTOC: true, + hideBreadcrumbs: true, + sidebar: { + fullNames: false, + sidebarFile: 'typedoc-sidebar.js', + indexLabel: 'Table of contents', + readmeLabel: 'Readme', + sidebarPath: '', + }, + plugin: ['none'], + outputDirectory: '', + siteDir: '', + watch: false, +}; + +/** + * Merge default with user options + * @param opts + */ +export const getOptions = ( + siteDir: string, + opts: Partial, +): PluginOptions => { + // base options + let options = { + ...DEFAULT_PLUGIN_OPTIONS, + ...opts, + }; + // sidebar + if (opts.sidebar === null) { + options = { ...options, sidebar: null }; + } else { + const sidebar = { + ...DEFAULT_PLUGIN_OPTIONS.sidebar, + ...opts.sidebar, + } as SidebarOptions; + options = { + ...options, + sidebar: { + ...sidebar, + sidebarPath: path.resolve(siteDir, sidebar.sidebarFile), + }, + }; + } + // additional + options = { + ...options, + siteDir, + outputDirectory: path.resolve(siteDir, options.docsRoot, options.out), + }; + return options; +}; + +/** + * Add docusaurus options to converter + * @param app + */ +export const addOptions = (app: Application) => { + // configure deault typedoc options + app.options.addReader(new TypeDocReader()); + app.options.addReader(new TSConfigReader()); + + // expose plugin options to typedoc so we can access if required + app.options.addDeclaration({ + name: 'id', + } as StringDeclarationOption); + + app.options.addDeclaration({ + name: 'docsRoot', + } as StringDeclarationOption); + + app.options.addDeclaration({ + name: 'siteDir', + } as MixedDeclarationOption); + + app.options.addDeclaration({ + name: 'outputDirectory', + } as StringDeclarationOption); + + app.options.addDeclaration({ + name: 'globalsTitle', + } as StringDeclarationOption); + + app.options.addDeclaration({ + name: 'readmeTitle', + } as StringDeclarationOption); + + app.options.addDeclaration({ + name: 'sidebar', + type: ParameterType.Mixed, + } as MixedDeclarationOption); +}; diff --git a/src/plugin.ts b/src/plugin.ts new file mode 100644 index 0000000..310aa95 --- /dev/null +++ b/src/plugin.ts @@ -0,0 +1,56 @@ +// @ts-ignore +import { Application } from 'typedoc'; +// @ts-ignore +import { load } from 'typedoc-plugin-markdown'; + +import { FrontMatterComponent } from './front-matter'; +import { addOptions, getOptions } from './options'; +import { render } from './render'; +import { SidebarComponent } from './sidebar'; +import { PluginOptions } from './types'; + + +export default async function generate( + siteDir: string, + opts: Partial, +) { + // we need to generate an empty sidebar up-front so it can be resolved from sidebars.js + const options = getOptions(siteDir, opts); + // if (options.sidebar) { + // writeSidebar(options.sidebar, 'module.exports=[];'); + // } + + // initialize and build app + const app = new Application(); + + // load the markdown plugin + load(app); + + // customise render + app.renderer.render = render; + + // add plugin options + addOptions(app); + + // bootstrap typedoc app + app.bootstrap(options); + + // add frontmatter component to typedoc renderer + // @ts-ignore + app.renderer.addComponent('fm', new FrontMatterComponent(app.renderer)); + + // add sidebar component to typedoc renderer + // @ts-ignore + app.renderer.addComponent('sidebar', new SidebarComponent(app.renderer)); + + // return the generated reflections + const project = app.convert(); + + // if project is undefined typedoc has a problem - error logging will be supplied by typedoc. + if (!project) { + return; + } + + // generate or watch app + return app.generateDocs(project, options.outputDirectory); +} diff --git a/src/render.ts b/src/render.ts new file mode 100644 index 0000000..5598a5e --- /dev/null +++ b/src/render.ts @@ -0,0 +1,35 @@ +// @ts-ignore +import { ProjectReflection, UrlMapping } from 'typedoc'; +// @ts-ignore +import { RendererEvent } from 'typedoc/dist/lib/output/events'; + +export async function render( + project: ProjectReflection, + outputDirectory: string, +) { + if (!this.prepareTheme() || !this.prepareOutputDirectory(outputDirectory)) { + return; + } + + const output = new RendererEvent( + RendererEvent.BEGIN, + outputDirectory, + project, + ); + + output.settings = this.application.options.getRawValues(); + output.urls = this.theme!.getUrls(project); + + this.trigger(output); + + if (!output.isDefaultPrevented) { + output.urls?.forEach((mapping: UrlMapping, i) => { + this.renderDocument(output.createPageEvent(mapping)); + console.log( + `\rGenerated ${i + 1} of ${output.urls?.length} TypeDoc docs`, + ); + }); + console.log(`\n`); + this.trigger(RendererEvent.END, output); + } +} diff --git a/src/sidebar.ts b/src/sidebar.ts new file mode 100644 index 0000000..9f2ec49 --- /dev/null +++ b/src/sidebar.ts @@ -0,0 +1,111 @@ +import * as fs from 'fs'; +import * as path from 'path'; +// @ts-ignore +import { BindOption } from 'typedoc'; +// @ts-ignore +import { Component } from 'typedoc/dist/lib/converter/components'; +// @ts-ignore +import { RendererComponent } from 'typedoc/dist/lib/output/components'; +// @ts-ignore +import { RendererEvent } from 'typedoc/dist/lib/output/events'; + +import { SidebarItem, SidebarOptions } from './types'; + +@Component({ name: 'sidebar' }) +export class SidebarComponent extends RendererComponent { + @BindOption('sidebar') + sidebar!: SidebarOptions; + @BindOption('siteDir') + siteDir!: string; + @BindOption('out') + out!: string; + + initialize() { + // @ts-ignore + this.listenTo(this.application.renderer, { + [RendererEvent.BEGIN]: this.onRendererBegin, + }); + } + + async onRendererBegin(renderer: RendererEvent) { + // @ts-ignore + const navigation = this.application.renderer.theme?.getNavigation( + renderer.project, + ); + + const out = this.out.match(/(?:.*)en\/(.*)/)![1]; + + // map the navigation object to a Docuaurus sidebar format + const sidebarItems = navigation?.children + ? navigation.children.map((navigationItem) => { + if (navigationItem.isLabel) { + const sidebarCategoryItems = navigationItem.children + ? navigationItem.children.map((navItem) => { + const url = this.getUrlKey(out, navItem.url); + if (navItem.children && navItem.children.length > 0) { + const sidebarCategoryChildren = navItem.children.map( + (childGroup) => + this.getSidebarCategory( + childGroup.title, + childGroup.children + ? childGroup.children.map((childItem) => + this.getUrlKey(out, childItem.url), + ) + : [], + ), + ); + return this.getSidebarCategory(navItem.title, [ + url, + ...sidebarCategoryChildren, + ]); + } + return url; + }) + : []; + return this.getSidebarCategory( + navigationItem.title, + sidebarCategoryItems, + ); + } + return this.getUrlKey(out, navigationItem.url); + }) + : []; + + const sidebarPath = this.sidebar.sidebarPath; + + fs.writeFileSync(sidebarPath, JSON.stringify(sidebarItems, null, 2)); + // @ts-ignore + this.application.logger.success( + `TypeDoc sidebar written to ${sidebarPath}`, + ); + } + + /** + * returns a sidebar category node + */ + getSidebarCategory(title: string, items: SidebarItem[]) { + return { + items, + type: 'category', + label: title, + }; + } + + /** + * returns the url key for relevant doc + */ + getUrlKey(out: string, url: string) { + const urlKey = url.replace('.md', ''); + return out ? out + '/' + urlKey : urlKey; + } +} + +/** + * Write content to sidebar file + */ +export const writeSidebar = (sidebar: SidebarOptions, content: string) => { + if (!fs.existsSync(path.dirname(sidebar.sidebarPath))) { + fs.mkdirSync(path.dirname(sidebar.sidebarPath)); + } + fs.writeFileSync(sidebar.sidebarPath, content); +}; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..ba24417 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,46 @@ +export interface PluginOptions { + id: string; + docsRoot: string; + out: string; + sidebar: SidebarOptions | null; + readmeTitle?: string; + globalsTitle?: string; + plugin: string[]; + readme?: string; + disableOutputCheck?: boolean; + entryPoints?: string[]; + entryDocument: string; + hideInPageTOC: boolean; + hideBreadcrumbs: boolean; + siteDir: string; + outputDirectory: string; + watch: boolean; +} + +export interface FrontMatter { + id?: string; + title: string; + slug?: string; + sidebar_label?: string; + hide_title?: boolean; +} + +export interface SidebarOptions { + fullNames?: boolean; + sidebarFile: string; + sidebarPath: string; + indexLabel?: string; + readmeLabel?: string; +} + +export interface Sidebar { + [sidebarId: string]: SidebarItem[]; +} + +export interface SidebarCategory { + type: string; + label: string; + items: SidebarItem[]; +} + +export type SidebarItem = SidebarCategory | string; diff --git a/src/watch.ts b/src/watch.ts new file mode 100644 index 0000000..94b07c5 --- /dev/null +++ b/src/watch.ts @@ -0,0 +1,23 @@ +import * as fs from 'fs'; +import * as path from 'path'; +// @ts-ignore +import { Application } from 'typedoc'; + +import { PluginOptions } from './types'; + +/** + * Calls TypeDoc's `convertAndWatch` and force trigger sidebars refresh. + */ +export const convertAndWatch = (app: Application, options: PluginOptions) => { + const sidebarsJsPath = path.resolve(options.siteDir, 'sidebars.js'); + app.convertAndWatch(async (project) => { + if (options.sidebar) { + // remove typedoc sidebar from require cache + delete require.cache[options.sidebar.sidebarPath]; + // force trigger a sidebars.js refresh + const sidebarJsContent = fs.readFileSync(sidebarsJsPath); + fs.writeFileSync(sidebarsJsPath, sidebarJsContent); + } + await app.generateDocs(project, options.outputDirectory); + }); +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..ffa7e9d --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "declaration": false, + "experimentalDecorators": true, + "lib": ["es2018", "dom"], + "module": "commonjs", + "moduleResolution": "node", + "noImplicitAny": false, + "noUnusedLocals": true, + "removeComments": false, + "sourceMap": false, + "strictNullChecks": true, + "target": "es2018", + "outDir": "dist" + } +} diff --git a/yarn.lock b/yarn.lock index 8e8cd1b..fe18057 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,173 +2,32 @@ # yarn lockfile v1 -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +"@actions/core@^1.2.6": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.2.6.tgz#a78d49f41a4def18e88ce47c2cac615d5694bf09" + integrity sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA== -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" +"@types/node@^14.14.35": + version "14.14.35" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.35.tgz#42c953a4e2b18ab931f72477e7012172f4ffa313" + integrity sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag== -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= +"@vercel/ncc@^0.28.5": + version "0.28.5" + resolved "https://registry.yarnpkg.com/@vercel/ncc/-/ncc-0.28.5.tgz#6d735379f81b70b708a9c3d2196507b2a841824f" + integrity sha512-ZSwD4EDCon2EsnPZ2/Qcigx4N2DiuBLV/rDnF04giEPFuDeBeUDdnSTyYYfX8KNic/prrJuS1vUEmAOHmj+fRg== -docusaurus-plugin-typedoc@^0.16.7: - version "0.16.7" - resolved "https://registry.yarnpkg.com/docusaurus-plugin-typedoc/-/docusaurus-plugin-typedoc-0.16.7.tgz#b23f22b8ec93d25d8d3e204684ab05e4636a6873" - integrity sha512-4V/Nw+cJDbcmA6getpweAKuu1tTyky3/gHliL75DLJntk2pR5wM/x4jNFaYiHOPsnP3d5CkBfK+mSSo4M9jtvA== +override-require@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/override-require/-/override-require-1.1.1.tgz#6ae22fadeb1f850ffb0cf4c20ff7b87e5eb650df" + integrity sha1-auIvresfhQ/7DPTCD/e4fl62UN8= -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= +tslib@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" + integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== -glob@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -handlebars@^4.7.7: - version "4.7.7" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" - integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== - dependencies: - minimist "^1.2.5" - neo-async "^2.6.0" - source-map "^0.6.1" - wordwrap "^1.0.0" - optionalDependencies: - uglify-js "^3.1.4" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -jsonc-parser@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.0.0.tgz#abdd785701c7e7eaca8a9ec8cf070ca51a745a22" - integrity sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA== - -lunr@^2.3.9: - version "2.3.9" - resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" - integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow== - -marked@^3.0.8: - version "3.0.8" - resolved "https://registry.yarnpkg.com/marked/-/marked-3.0.8.tgz#2785f0dc79cbdc6034be4bb4f0f0a396bd3f8aeb" - integrity sha512-0gVrAjo5m0VZSJb4rpL59K1unJAMb/hm8HRXqasD8VeC8m91ytDPMritgFSlKonfdt+rRYYpP/JfLxgIX8yoSw== - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -neo-async@^2.6.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -shiki@^0.9.12: - version "0.9.15" - resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.9.15.tgz#2481b46155364f236651319d2c18e329ead6fa44" - integrity sha512-/Y0z9IzhJ8nD9nbceORCqu6NgT9X6I8Fk8c3SICHI5NbZRLdZYFaB233gwct9sU0vvSypyaL/qaKvzyQGJBZSw== - dependencies: - jsonc-parser "^3.0.0" - vscode-oniguruma "^1.6.1" - vscode-textmate "5.2.0" - -source-map@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -typedoc-plugin-markdown@^3.11.11: - version "3.11.11" - resolved "https://registry.yarnpkg.com/typedoc-plugin-markdown/-/typedoc-plugin-markdown-3.11.11.tgz#5a7cdac2ebf4a11a622c2947484893decbbe54df" - integrity sha512-LyephgG2yHiSqJppuDVKy3dPLSbzP+ke/VBxGvH4I/+31NXzuEhLFhxx/X4UMqzh2XbUB44ttABtGd11biKr4Q== - dependencies: - handlebars "^4.7.7" - -typedoc@^0.22.10: - version "0.22.10" - resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.22.10.tgz#221e1a2b17bcb71817ef027dc4c4969d572e7620" - integrity sha512-hQYZ4WtoMZ61wDC6w10kxA42+jclWngdmztNZsDvIz7BMJg7F2xnT+uYsUa7OluyKossdFj9E9Ye4QOZKTy8SA== - dependencies: - glob "^7.2.0" - lunr "^2.3.9" - marked "^3.0.8" - minimatch "^3.0.4" - shiki "^0.9.12" - -typescript@^4.5.4: - version "4.5.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8" - integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg== - -uglify-js@^3.1.4: - version "3.14.5" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.14.5.tgz#cdabb7d4954231d80cb4a927654c4655e51f4859" - integrity sha512-qZukoSxOG0urUTvjc2ERMTcAy+BiFh3weWAkeurLwjrCba73poHmG3E36XEjd/JGukMzwTL7uCxZiAexj8ppvQ== - -vscode-oniguruma@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.6.1.tgz#2bf4dfcfe3dd2e56eb549a3068c8ee39e6c30ce5" - integrity sha512-vc4WhSIaVpgJ0jJIejjYxPvURJavX6QG41vu0mGhqywMkQqulezEqEQ3cO3gc8GvcOpX6ycmKGqRoROEMBNXTQ== - -vscode-textmate@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e" - integrity sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ== - -wordwrap@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +typescript@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3" + integrity sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==