Skip to content
This repository has been archived by the owner on Apr 21, 2022. It is now read-only.

Commit

Permalink
feat: readme generator work
Browse files Browse the repository at this point in the history
  • Loading branch information
jdx committed Feb 6, 2018
1 parent c021099 commit fa21751
Show file tree
Hide file tree
Showing 7 changed files with 1,121 additions and 63 deletions.
1 change: 1 addition & 0 deletions .circleci/config.yml
Expand Up @@ -38,6 +38,7 @@ jobs:
- restore_cache: *restore_cache
- run: yarn global add @anycli/semantic-release@1 semantic-release@12
- run: yarn --frozen-lockfile
- run: yarn link
- run: |
export PATH=/usr/local/share/.config/yarn/global/node_modules/.bin:$PATH
semantic-release -e @anycli/semantic-release
Expand Down
2 changes: 1 addition & 1 deletion README.md
@@ -1,7 +1,7 @@
@anycli/dev-cli
===============


helpers for anycli CLIs

[![Version](https://img.shields.io/npm/v/@anycli/dev-cli.svg)](https://npmjs.org/package/@anycli/dev-cli)
[![CircleCI](https://circleci.com/gh/anycli/dev-cli/tree/master.svg?style=svg)](https://circleci.com/gh/anycli/dev-cli/tree/master)
Expand Down
23 changes: 16 additions & 7 deletions package.json
@@ -1,10 +1,15 @@
{
"name": "@anycli/dev-cli",
"description": "helpers for anycli CLIs",
"version": "0.2.2",
"author": "Jeff Dickey @jdxcode",
"anycli": {
"commands": "./lib/commands",
"bin": "anycli-dev",
"devPlugins": [
"@heroku-cli/plugin-apps",
"@anycli/plugin-plugins"
],
"plugins": [
"@anycli/plugin-help"
]
Expand All @@ -14,19 +19,23 @@
},
"bugs": "https://github.com/anycli/dev-cli/issues",
"dependencies": {
"@anycli/command": "^1.2.9",
"@anycli/config": "^1.3.10",
"@anycli/errors": "^0.2.0",
"@anycli/plugin-help": "^0.6.4"
"@anycli/command": "^1.2.10",
"@anycli/config": "^1.3.15",
"@anycli/errors": "^0.2.1",
"@anycli/plugin-help": "^0.6.7",
"lodash.template": "^4.4.0",
"normalize-package-data": "^2.4.0"
},
"devDependencies": {
"@anycli/dev-cli": "^0.2.1",
"@anycli/plugin-plugins": "^0.2.13",
"@anycli/test": "^0.10.11",
"@anycli/tslint": "^0.2.6",
"@anycli/tslint": "^0.2.7",
"@heroku-cli/plugin-apps": "^2.4.23",
"@types/chai": "^4.1.2",
"@types/fs-extra": "^5.0.0",
"@types/lodash.template": "^4.4.3",
"@types/mocha": "^2.2.48",
"@types/node": "^9.4.0",
"@types/node": "^9.4.1",
"chai": "^4.1.2",
"concurrently": "^3.5.1",
"fs-extra": "^5.0.0",
Expand Down
2 changes: 1 addition & 1 deletion src/commands/manifest.ts
Expand Up @@ -6,7 +6,7 @@ import * as fs from 'fs'
import * as path from 'path'

export default class Manifest extends Command {
static title = 'generates plugin manifest json'
static description = 'generates plugin manifest json'
static args = [
{name: 'path', description: 'path to plugin', default: '.'}
]
Expand Down
101 changes: 101 additions & 0 deletions src/commands/readme.ts
@@ -0,0 +1,101 @@
// tslint:disable no-implicit-dependencies

import {Command} from '@anycli/command'
import * as Config from '@anycli/config'
import Help from '@anycli/plugin-help'
import * as fs from 'fs-extra'
import * as path from 'path'

import {compact, sortBy, uniqBy} from '../util'

const normalize = require('normalize-package-data')

export default class Readme extends Command {
static description = 'adds commands to readme'

static aliases = ['c', 'd']

async run() {
const config = Config.load({root: process.cwd()})
try {
let p = require.resolve('@anycli/plugin-legacy')
config.plugins.push(new Config.Plugin({root: p}))
} catch {}
await config.runHook('init', {id: 'readme', argv: this.argv})
let readme = await fs.readFile('README.md', 'utf8')
// if (readme.includes('<!-- toc -->')) {
// } else this.warn('<!-- toc --> not found in README')
readme = this.commands(config, readme)

console.log(readme)
}

commands(config: Config.IConfig, readme: string): string {
const help = new Help(config, {stripAnsi: true, maxWidth: 120})
const build = (): string => {
let commands = this.config.commands
commands = commands.filter(c => !c.hidden)
commands = uniqBy(commands, c => c.id)
commands = sortBy(commands, c => c.id)
const renderCommand = (level: number) => (c: Config.Command): string => {
const header = () => '#'.repeat(level) + ` ${c.id}`
const code = () => {
let pluginName = c.pluginName
if (!pluginName) return
let plugin = config.plugins.concat([config]).find(p => p.name === c.pluginName)
if (!plugin) return
normalize(plugin.pjson)
let repo = plugin.pjson.repository
let commandsDir = plugin.pjson.anycli.commands
if (!repo || !repo.url || !commandsDir) return
commandsDir = commandsDir.replace(/\.\//, '')
if (plugin.name === this.config.name) pluginName = path.join(__dirname, '../..')
let commandPath = require.resolve(`${pluginName}/${commandsDir}/${c.id.replace(/:/g, '/')}`)
commandPath = commandPath.replace(path.dirname(require.resolve(`${pluginName}/package.json`)) + '/', '')
if (plugin.pjson.devDependencies.typescript) {
commandPath = commandPath.replace(/^lib\//, 'src/')
commandPath = commandPath.replace(/\.js$/, '.ts')
}
repo = repo.url.split('+')[1].replace(/\.git$/, '')
return `_See code: [${plugin.name}](${repo}/blob/master/${commandPath})_`
// return `_From plugin: [${plugin.name}](${plugin.pjson.homepage})_`
}
const subcommands = (): string | undefined => {
return commands
.filter(sc => sc.id.startsWith(c.id) && sc.id !== c.id)
.map(renderCommand(level + 1))
.map(c => c.trim())
.join('\n\n')
}
return compact([
header(),
'```\n' + help.command(c).trim() + '\n```',
code(),
subcommands(),
]).join('\n\n')
}
let rootCommands = commands.filter(c => !c.id.includes(':'))

return [
'<!-- commands -->',
'# Commands\n',
...commands.map(c => {
return `* [${c.id}](#${c.id.replace(/:/g, '')})`
}),
...rootCommands.map(renderCommand(2)).map(s => s.trim() + '\n'),
'<!-- commandsstop -->',
].join('\n').trim()
}
if (readme.includes('<!-- commands -->')) {
if (readme.includes('<!-- commandsstop -->')) {
// clear out current commands
readme = readme.replace(/<!-- commands -->(.|\n)*<!-- commandsstop -->/m, '<!-- commands -->')
}
readme = readme.replace(/<!-- commands -->/, build())
} else {
// add commands to end
readme += `\n${build()}`
}
return readme
}
}
43 changes: 43 additions & 0 deletions src/util.ts
@@ -0,0 +1,43 @@
import Template = require('lodash.template')

export function castArray<T>(input?: T | T[]): T[] {
if (input === undefined) return []
return Array.isArray(input) ? input : [input]
}

export function uniqBy<T>(arr: T[], fn: (cur: T) => any): T[] {
return arr.filter((a, i) => {
let aVal = fn(a)
return !arr.find((b, j) => j !== i && fn(b) === aVal)
})
}

export function compact<T>(a: (T | undefined)[]): T[] {
return a.filter((a): a is T => !!a)
}

export function sortBy<T>(arr: T[], fn: (i: T) => sort.Types | sort.Types[]): T[] {
function compare(a: sort.Types | sort.Types[], b: sort.Types | sort.Types[]): number {
a = a === undefined ? 0 : a
b = b === undefined ? 0 : b

if (Array.isArray(a) && Array.isArray(b)) {
if (a.length === 0 && b.length === 0) return 0
let diff = compare(a[0], b[0])
if (diff !== 0) return diff
return compare(a.slice(1), b.slice(1))
}

if (a < b) return -1
if (a > b) return 1
return 0
}

return arr.sort((a, b) => compare(fn(a), fn(b)))
}

export namespace sort {
export type Types = string | number | undefined | boolean
}

export const template = (context: any) => (t: string | undefined): string => Template(t || '')(context)

0 comments on commit fa21751

Please sign in to comment.