Move documentation generation to TypeScript

Change-Type: patch
This commit is contained in:
Tim Perry 2017-12-21 18:40:13 +01:00
parent ffffd447f2
commit f25442c036
14 changed files with 342 additions and 160 deletions

114
capitanodoc.ts Normal file
View File

@ -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' ]
},
]
};

View File

@ -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

14
extras/capitanodoc/doc-types.d.ts vendored Normal file
View File

@ -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 };

View File

@ -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, '60-')
.replace(/>/g, '-62-')
.replace(/\[/g, '')
.replace(/\]/g, '-')
.replace(/--/g, '-')
.replace(/\.\.\./g, '')
.replace(/\|/g, '')
.toLowerCase()
}
return category
console.log(markdown.display(result))

View File

@ -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 = <Document> {};
result.title = capitanodoc.title;
result.introduction = capitanodoc.introduction;
result.categories = [];
for (let commandCategory of capitanodoc.categories) {
const category = <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));

View File

@ -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

View File

@ -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, '60-')
.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;
};

View File

@ -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)

View File

@ -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);
};

17
extras/tsconfig.json Normal file
View File

@ -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"
]
}

View File

@ -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: `\

View File

@ -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: `\

View File

@ -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",

31
typings/capitano.d.ts vendored
View File

@ -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<P = {}, O = {}> {
export interface CommandDefinition<P = {}, O = {}> {
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
};
}