From f25442c036e4805909992b3726bdc1519ca723ab Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Thu, 21 Dec 2017 18:40:13 +0100 Subject: [PATCH] Move documentation generation to TypeScript Change-Type: patch --- capitanodoc.ts | 114 +++++++++++++++++++++++++++++ doc/cli.markdown | 18 ++--- extras/capitanodoc/doc-types.d.ts | 14 ++++ extras/capitanodoc/index.coffee | 46 ------------ extras/capitanodoc/index.ts | 33 +++++++++ extras/capitanodoc/markdown.coffee | 66 ----------------- extras/capitanodoc/markdown.ts | 90 +++++++++++++++++++++++ extras/capitanodoc/utils.coffee | 26 ------- extras/capitanodoc/utils.ts | 35 +++++++++ extras/tsconfig.json | 17 +++++ lib/actions/info.ts | 4 +- lib/actions/settings.ts | 4 +- package.json | 4 +- typings/capitano.d.ts | 31 ++++++-- 14 files changed, 342 insertions(+), 160 deletions(-) create mode 100644 capitanodoc.ts create mode 100644 extras/capitanodoc/doc-types.d.ts delete mode 100644 extras/capitanodoc/index.coffee create mode 100644 extras/capitanodoc/index.ts delete mode 100644 extras/capitanodoc/markdown.coffee create mode 100644 extras/capitanodoc/markdown.ts delete mode 100644 extras/capitanodoc/utils.coffee create mode 100644 extras/capitanodoc/utils.ts create mode 100644 extras/tsconfig.json diff --git a/capitanodoc.ts b/capitanodoc.ts new file mode 100644 index 00000000..9cda44b9 --- /dev/null +++ b/capitanodoc.ts @@ -0,0 +1,114 @@ +export = { + title: 'Resin CLI Documentation', + introduction: `\ +This tool allows you to interact with the resin.io api from the comfort of your command line. + +Please make sure your system meets the requirements as specified in the [README](https://github.com/resin-io/resin-cli). + +To get started download the CLI from npm. + + $ npm install resin-cli -g + +Then authenticate yourself: + + $ resin login + +Now you have access to all the commands referenced below. + +## Proxy support + +The CLI does support HTTP(S) proxies. + +You can configure the proxy using several methods (in order of their precedence): + +* set the \`RESINRC_PROXY\` environment variable in the URL format (with protocol, host, port, and optionally the basic auth), +* use the [resin config file](https://www.npmjs.com/package/resin-settings-client#documentation) (project-specific or user-level) +and set the \`proxy\` setting. This can be: + * a string in the URL format, + * or an object following [this format](https://www.npmjs.com/package/global-tunnel-ng#options), which allows more control, +* or set the conventional \`https_proxy\` / \`HTTPS_PROXY\` / \`http_proxy\` / \`HTTP_PROXY\` +environment variable (in the same standard URL format).\ +`, + + categories: [ + { + title: 'Application', + files: [ 'build/actions/app.js' ] + }, + { + title: 'Authentication', + files: [ 'build/actions/auth.js' ] + }, + { + title: 'Device', + files: [ 'build/actions/device.js' ] + }, + { + title: 'Environment Variables', + files: [ 'build/actions/environment-variables.js' ] + }, + { + title: 'Help', + files: [ 'build/actions/help.js' ] + }, + { + title: 'Information', + files: [ 'build/actions/info.js' ] + }, + { + title: 'Keys', + files: [ 'build/actions/keys.js' ] + }, + { + title: 'Logs', + files: [ 'build/actions/logs.js' ] + }, + { + title: 'Sync', + files: [ 'build/actions/sync.js' ] + }, + { + title: 'SSH', + files: [ 'build/actions/ssh.js' ] + }, + { + title: 'Notes', + files: [ 'build/actions/notes.js' ] + }, + { + title: 'OS', + files: [ 'build/actions/os.js' ] + }, + { + title: 'Config', + files: [ 'build/actions/config.js' ] + }, + { + title: 'Preload', + files: [ 'build/actions/preload.js' ] + }, + { + title: 'Settings', + files: [ 'build/actions/settings.js' ] + }, + { + title: 'Wizard', + files: [ 'build/actions/wizard.js' ] + }, + { + title: 'Local', + files: [ 'build/actions/local/index.js' ] + }, + { + title: 'Deploy', + files: [ + 'build/actions/build.js', + 'build/actions/deploy.js' + ] + }, + { + title: 'Utilities', + files: [ 'build/actions/util.js' ] + }, + ] +}; diff --git a/doc/cli.markdown b/doc/cli.markdown index 3cb7a2cc..9caea2f0 100644 --- a/doc/cli.markdown +++ b/doc/cli.markdown @@ -254,7 +254,7 @@ web-based login credential-based login -#### --email, --e,u, --e,u <email> +#### --email, -e, -u <email> email @@ -310,7 +310,7 @@ Examples: ### Options -#### --application, --a,app, --a,app <application> +#### --application, -a, --app <application> application name @@ -464,7 +464,7 @@ Examples: ### Options -#### --application, --a,app, --a,app <application> +#### --application, -a, --app <application> application name @@ -482,7 +482,7 @@ Examples: ### Options -#### --application, --a,app, --a,app <application> +#### --application, -a, --app <application> application name @@ -529,7 +529,7 @@ Example: ### Options -#### --application, --a,app, --a,app <application> +#### --application, -a, --app <application> application name @@ -589,7 +589,7 @@ Examples: ### Options -#### --application, --a,app, --a,app <application> +#### --application, -a, --app <application> application name @@ -845,7 +845,7 @@ Examples: ### Options -#### --device, --d,dev, --d,dev <device> +#### --device, -d, --dev <device> device uuid @@ -937,7 +937,7 @@ Examples: show advanced configuration options -#### --application, --a,app, --a,app <application> +#### --application, -a, --app <application> application name @@ -1081,7 +1081,7 @@ Examples: ### Options -#### --application, --a,app, --a,app <application> +#### --application, -a, --app <application> application name diff --git a/extras/capitanodoc/doc-types.d.ts b/extras/capitanodoc/doc-types.d.ts new file mode 100644 index 00000000..536cf6c8 --- /dev/null +++ b/extras/capitanodoc/doc-types.d.ts @@ -0,0 +1,14 @@ +import { CommandDefinition } from 'capitano'; + +export interface Document { + title: string; + introduction: string; + categories: Category[]; +} + +export interface Category { + title: string; + commands: CommandDefinition[]; +} + +export { CommandDefinition as Command }; diff --git a/extras/capitanodoc/index.coffee b/extras/capitanodoc/index.coffee deleted file mode 100644 index c2f2223b..00000000 --- a/extras/capitanodoc/index.coffee +++ /dev/null @@ -1,46 +0,0 @@ -_ = require('lodash') -path = require('path') -capitanodoc = require('../../capitanodoc') -markdown = require('./markdown') - -result = {} -result.title = capitanodoc.title -result.introduction = capitanodoc.introduction -result.categories = [] - -for commandCategory in capitanodoc.categories - category = {} - category.title = commandCategory.title - category.commands = [] - - for file in commandCategory.files - actions = require(path.join(process.cwd(), file)) - - if actions.signature? - category.commands.push(_.omit(actions, 'action')) - else - for actionName, actionCommand of actions - category.commands.push(_.omit(actionCommand, 'action')) - - result.categories.push(category) - -result.toc = _.cloneDeep(result.categories) -result.toc = _.map result.toc, (category) -> - category.commands = _.map category.commands, (command) -> - return { - signature: command.signature - anchor: '#' + command.signature - .replace(/\s/g,'-') - .replace(//g, '-62-') - .replace(/\[/g, '') - .replace(/\]/g, '-') - .replace(/--/g, '-') - .replace(/\.\.\./g, '') - .replace(/\|/g, '') - .toLowerCase() - } - - return category - -console.log(markdown.display(result)) diff --git a/extras/capitanodoc/index.ts b/extras/capitanodoc/index.ts new file mode 100644 index 00000000..4346a41a --- /dev/null +++ b/extras/capitanodoc/index.ts @@ -0,0 +1,33 @@ +import capitanodoc = require('../../capitanodoc'); +import * as _ from 'lodash'; +import * as path from 'path'; +import * as markdown from './markdown'; +import { Document, Category } from './doc-types'; + +const result = {}; +result.title = capitanodoc.title; +result.introduction = capitanodoc.introduction; +result.categories = []; + +for (let commandCategory of capitanodoc.categories) { + const category = {}; + category.title = commandCategory.title; + category.commands = []; + + for (let file of commandCategory.files) { + const actions: any = require(path.join(process.cwd(), file)); + + if (actions.signature != null) { + category.commands.push(_.omit(actions, 'action')); + } else { + for (let actionName in actions) { + const actionCommand = actions[actionName]; + category.commands.push(_.omit(actionCommand, 'action')); + } + } + } + + result.categories.push(category); +} + +console.log(markdown.render(result)); diff --git a/extras/capitanodoc/markdown.coffee b/extras/capitanodoc/markdown.coffee deleted file mode 100644 index 85c0d6e1..00000000 --- a/extras/capitanodoc/markdown.coffee +++ /dev/null @@ -1,66 +0,0 @@ -_ = require('lodash') -ent = require('ent') -utils = require('./utils') - -exports.command = (command) -> - result = """ - ## #{ent.encode(command.signature)} - - #{command.help}\n - """ - - if not _.isEmpty(command.options) - result += '\n### Options' - - for option in command.options - result += """ - \n\n#### #{utils.parseSignature(option)} - - #{option.description} - """ - - result += '\n' - - return result - -exports.category = (category) -> - result = """ - # #{category.title}\n - """ - - for command in category.commands - result += '\n' + exports.command(command) - - return result - -exports.toc = (toc) -> - result = ''' - # Table of contents\n - ''' - - for category in toc - - result += """ - \n- #{category.title}\n\n - """ - - for command in category.commands - result += """ - \t- [#{ent.encode(command.signature)}](#{command.anchor})\n - """ - - return result - -exports.display = (doc) -> - result = """ - # #{doc.title} - - #{doc.introduction} - - #{exports.toc(doc.toc)} - """ - - for category in doc.categories - result += '\n' + exports.category(category) - - return result diff --git a/extras/capitanodoc/markdown.ts b/extras/capitanodoc/markdown.ts new file mode 100644 index 00000000..6a272d1b --- /dev/null +++ b/extras/capitanodoc/markdown.ts @@ -0,0 +1,90 @@ +import * as _ from 'lodash'; +import * as ent from 'ent'; +import * as utils from './utils'; +import { Document, Category, Command } from './doc-types'; + +export function renderCommand(command: Command) { + let result = `\ +## ${ent.encode(command.signature)} + +${command.help}\n\ +`; + + if (!_.isEmpty(command.options)) { + result += '\n### Options'; + + for (let option of command.options!) { + result += `\ +\n\n#### ${utils.parseSignature(option)} + +${option.description}\ +`; + } + + result += '\n'; + } + + return result; +}; + +export function renderCategory(category: Category) { + let result = `\ +# ${category.title}\n\ +`; + + for (let command of category.commands) { + result += `\n${renderCommand(command)}`; + } + + return result; +}; + +function getAnchor(command: Command) { + return '#' + command.signature + .replace(/\s/g,'-') + .replace(//g, '-62-') + .replace(/\[/g, '') + .replace(/\]/g, '-') + .replace(/--/g, '-') + .replace(/\.\.\./g, '') + .replace(/\|/g, '') + .toLowerCase(); +} + +export function renderToc(categories: Category[]) { + let result = `\ +# Table of contents\n\ +`; + + for (let category of categories) { + + result += `\ +\n- ${category.title}\n\n\ +`; + + for (let command of category.commands) { + result += `\ +\t- [${ent.encode(command.signature)}](${getAnchor(command)})\n\ +`; + } + } + + return result; +}; + +export function render(doc: Document) { + let result = `\ +# ${doc.title} + +${doc.introduction} + +${renderToc(doc.categories)}\ +`; + + for (let category of doc.categories) { + result += `\n${renderCategory(category)}`; + } + + return result; +}; diff --git a/extras/capitanodoc/utils.coffee b/extras/capitanodoc/utils.coffee deleted file mode 100644 index 84eac0dc..00000000 --- a/extras/capitanodoc/utils.coffee +++ /dev/null @@ -1,26 +0,0 @@ -_ = require('lodash') -ent = require('ent') - -exports.getOptionPrefix = (signature) -> - if signature.length > 1 - return '--' - else - return '-' - -exports.getOptionSignature = (signature) -> - return "#{exports.getOptionPrefix(signature)}#{signature}" - -exports.parseSignature = (option) -> - result = exports.getOptionSignature(option.signature) - - if not _.isEmpty(option.alias) - if _.isString(option.alias) - result += ", #{exports.getOptionSignature(option.alias)}" - else - for alias in option.alias - result += ", #{exports.getOptionSignature(option.alias)}" - - if option.parameter? - result += " <#{option.parameter}>" - - return ent.encode(result) diff --git a/extras/capitanodoc/utils.ts b/extras/capitanodoc/utils.ts new file mode 100644 index 00000000..bda4c343 --- /dev/null +++ b/extras/capitanodoc/utils.ts @@ -0,0 +1,35 @@ +import { OptionDefinition } from 'capitano'; +import * as _ from 'lodash'; +import * as ent from 'ent'; + +export function getOptionPrefix(signature: string) { + if (signature.length > 1) { + return '--'; + } else { + return '-'; + } +}; + +export function getOptionSignature(signature: string) { + return `${getOptionPrefix(signature)}${signature}`; +} + +export function parseSignature(option: OptionDefinition) { + let result = getOptionSignature(option.signature); + + if (!_.isEmpty(option.alias)) { + if (_.isString(option.alias)) { + result += `, ${getOptionSignature(option.alias)}`; + } else { + for (let alias of option.alias!) { + result += `, ${getOptionSignature(alias)}`; + } + } + } + + if (option.parameter != null) { + result += ` <${option.parameter}>`; + } + + return ent.encode(result); +}; diff --git a/extras/tsconfig.json b/extras/tsconfig.json new file mode 100644 index 00000000..2fbc2f6e --- /dev/null +++ b/extras/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "outDir": "build", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "preserveConstEnums": true, + "removeComments": true, + "sourceMap": true + }, + "include": [ + "../typings/*.d.ts", + "./**/*.ts" + ] +} diff --git a/lib/actions/info.ts b/lib/actions/info.ts index c55e74b5..f9ed173f 100644 --- a/lib/actions/info.ts +++ b/lib/actions/info.ts @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { Command } from "capitano"; +import { CommandDefinition } from "capitano"; -export const version: Command = { +export const version: CommandDefinition = { signature: 'version', description: 'output the version number', help: `\ diff --git a/lib/actions/settings.ts b/lib/actions/settings.ts index 5981cd30..1832a06c 100644 --- a/lib/actions/settings.ts +++ b/lib/actions/settings.ts @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { Command } from "capitano"; +import { CommandDefinition } from "capitano"; -export const list: Command = { +export const list: CommandDefinition = { signature: 'settings', description: 'print current settings', help: `\ diff --git a/package.json b/package.json index 65258af4..7315b653 100644 --- a/package.json +++ b/package.json @@ -31,13 +31,13 @@ "scripts": { "prebuild": "rimraf build/ build-bin/ build-zip/", "build": "npm run build:src && npm run build:bin", - "build:src": "gulp build && tsc && npm run doc", + "build:src": "gulp build && tsc && npm run build:doc", + "build:doc": "mkdirp doc/ && ts-node extras/capitanodoc/index.ts > doc/cli.markdown", "build:bin": "ts-node --type-check -P automation automation/build-bin.ts", "release": "npm run build && ts-node --type-check -P automation automation/deploy-bin.ts", "pretest": "npm run build", "test": "gulp test", "ci": "npm run test && catch-uncommitted", - "doc": "mkdirp doc/ && coffee extras/capitanodoc/index.coffee > doc/cli.markdown", "watch": "gulp watch", "lint": "gulp lint", "prepublish": "require-npm4-to-publish", diff --git a/typings/capitano.d.ts b/typings/capitano.d.ts index 25e33697..e1c63547 100644 --- a/typings/capitano.d.ts +++ b/typings/capitano.d.ts @@ -7,7 +7,7 @@ declare module 'capitano' { global: {}; } - export interface CommandOption { + export interface OptionDefinition { signature: string; description: string; parameter?: string; @@ -15,22 +15,39 @@ declare module 'capitano' { alias?: string | string[]; } - export interface Command

{ + export interface CommandDefinition

{ signature: string; description: string; help: string; - options?: CommandOption[], + options?: OptionDefinition[], permission?: 'user', action(params: P, options: O, done: () => void): void; } - export interface BuiltCommand { - signature: {} + export interface Command { + signature: Signature; + options: Option[]; + isWildcard(): boolean; } - export function command(command: Command): void; + export interface Signature { + hasParameters(): boolean; + hasVariadicParameters(): boolean; + isWildcard(): boolean; + allowsStdin(): boolean; + } + + export interface Option { + signature: Signature; + alias: string | string[]; + boolean: boolean; + parameter: string; + required: boolean | string; + } + + export function command(command: CommandDefinition): void; export const state: { - getMatchCommand: (signature: string, callback: (e: Error, cmd: BuiltCommand) => void) => void + getMatchCommand: (signature: string, callback: (e: Error, cmd: Command) => void) => void }; }