This repository has been archived by the owner on Nov 3, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
/
cli.js
executable file
·155 lines (143 loc) · 4.55 KB
/
cli.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import updateNotifier from 'update-notifier'
import meow from 'meow'
import processFiles from './process-files'
import normalizeNewline from 'normalize-newline'
import relative from 'relative'
import normalizePath from 'normalize-path'
import chalk from 'chalk'
import fs from 'fs'
import path from 'path'
import test from 'tape'
import tapDiff from 'mos-tap-diff'
import readPkgUp from 'mos-read-pkg-up'
import rcfile from 'rcfile'
import mos from 'mos-processor'
import defaultPlugins from './default-plugins'
import resolveFrom from 'resolve-from'
const cwd = process.cwd()
const stdout = process.stdout
const cli = meow([
'Usage',
' mos [test] [files]',
'',
'Options',
' --init Add mos to your project',
' --help, -h Display usage',
' --version, -v Display version',
' --tap Generate TAP output when testing markdown files',
'',
' -x="<exclude-pattern>"',
' Exclude pattern',
'',
'Examples',
' mos',
' mos test',
' mos test README.md',
' mos --init',
' mos --init README.md',
'',
'Tips:',
' Add `mos test` to your `scripts.test` property in `package.json`',
].join('\n'), {
alias: {
help: 'h',
version: 'v',
},
})
updateNotifier({pkg: cli.pkg}).notify()
if (cli.flags.init) {
require('mos-init')()
} else {
const highlightPath = chalk.bgBlack.yellow
const isTest = ~['test', 't'].indexOf((cli.input[0] || '').toLowerCase())
const processMD = md => readPkgUp({ cwd: md.filePath })
.then(result => {
const pkg = result.pkg
const config = rcfile('mos', { cwd: path.dirname(md.filePath) })
const allDeps = new Set([
...Object.keys(pkg.dependencies || {}),
...Object.keys(pkg.devDependencies || {}),
])
const pkgPlugins = (config.plugins || [])
.map(plugin => plugin instanceof Array
? { name: plugin[0], options: plugin[1] || {} }
: { name: plugin, options: {} }
)
.map(plugin => {
const namespacedName = 'mos-plugin-' + plugin.name
if (allDeps.has(namespacedName)) {
return {...plugin, name: namespacedName}
}
if (allDeps.has(plugin.name)) {
return plugin
}
throw new Error(`${plugin.name} is not in the dependencies`)
})
.map(plugin => ({...plugin, path: resolveFrom(path.dirname(md.filePath), plugin.name)}))
.map(plugin => ({...plugin, path: normalizePath(plugin.path)}))
.map(plugin => ({...plugin, register: require(plugin.path)}))
const defaultPluginsWithOpts = defaultPlugins.reduce((defPlugins, defPlugin) => {
const defPluginName = defPlugin.attributes.pkg && defPlugin.attributes.pkg.name || defPlugin.attributes.name
const options = config[defPluginName] || config[defPluginName.replace(/^mos-plugin-/, '')]
if (options === false) {
return defPlugins
}
return [
...defPlugins,
{
register: defPlugin,
options: options,
},
]
}, [])
return mos(md, [...defaultPluginsWithOpts, ...pkgPlugins])
})
.then(processor => processor.process())
const mdExtensions = ['markdown', 'mdown', 'mkdn', 'mkd', 'md']
const files = cli.input[isTest ? 1 : 0]
const pattern = files
? path.resolve(cwd, files)
: path.resolve(cwd, `{/**/,/}*.{${mdExtensions.join()}}`)
const ignorePattern = cli.flags.x
? path.resolve(cwd, cli.flags.x)
: null
if (isTest) {
if (cli.flags.tap !== true) {
test.createStream()
.pipe(tapDiff())
.pipe(stdout)
}
test('markdown', t => {
processFiles({
process: processMD,
pattern,
ignorePattern,
afterEachRender (opts) {
const relativePath = normalizePath(getRelativePath(opts.filePath))
t.equal(normalizeNewline(opts.newMD), normalizeNewline(opts.currentMD), relativePath)
},
})
.then(() => t.end())
.catch(err => { throw err })
})
} else {
processFiles({
process: processMD,
pattern,
ignorePattern,
afterEachRender (opts) {
if (normalizeNewline(opts.newMD) !== normalizeNewline(opts.currentMD)) {
fs.writeFileSync(opts.filePath, opts.newMD, {
encoding: 'utf8',
})
const relativePath = normalizePath(getRelativePath(opts.filePath))
console.log('updated', highlightPath(relativePath))
}
},
})
.catch(err => { throw err })
}
}
function getRelativePath (filePath) {
return relative(cwd, filePath)
}