@weig_3078/cli-demo 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/.eslintignore +1 -0
  2. package/.eslintrc +73 -0
  3. package/README.md +1 -0
  4. package/bin/mvc.js +14 -0
  5. package/dist/mvc.js +135771 -0
  6. package/ejs-demo.js +29 -0
  7. package/lib/ConfigTransform.js +40 -0
  8. package/lib/Creator.js +29 -0
  9. package/lib/Generator.js +307 -0
  10. package/lib/PromptModuleAPI.js +13 -0
  11. package/lib/create.js +328 -0
  12. package/lib/generator/babel/index.js +15 -0
  13. package/lib/generator/linter/index.js +55 -0
  14. package/lib/generator/linter/template/.eslintrc.js +30 -0
  15. package/lib/generator/router/index.js +17 -0
  16. package/lib/generator/router/template/src/App.vue +33 -0
  17. package/lib/generator/router/template/src/router/index.js +30 -0
  18. package/lib/generator/router/template/src/views/About.vue +5 -0
  19. package/lib/generator/router/template/src/views/Home.vue +18 -0
  20. package/lib/generator/vue/index.js +20 -0
  21. package/lib/generator/vue/template/public/favicon.ico +0 -0
  22. package/lib/generator/vue/template/public/index.html +19 -0
  23. package/lib/generator/vue/template/src/App.vue +29 -0
  24. package/lib/generator/vue/template/src/assets/logo.png +0 -0
  25. package/lib/generator/vue/template/src/components/HelloWorld.vue +110 -0
  26. package/lib/generator/vue/template/src/main.js +8 -0
  27. package/lib/generator/vuex/index.js +13 -0
  28. package/lib/generator/vuex/template/src/store/index.js +15 -0
  29. package/lib/generator/webpack/index.js +27 -0
  30. package/lib/generator/webpack/template/build/base.config.js +68 -0
  31. package/lib/generator/webpack/template/build/dev.config.js +19 -0
  32. package/lib/generator/webpack/template/build/pro.config.js +16 -0
  33. package/lib/promptModules/babel.js +10 -0
  34. package/lib/promptModules/linter.js +48 -0
  35. package/lib/promptModules/router.js +19 -0
  36. package/lib/promptModules/vuex.js +8 -0
  37. package/lib/utils/clearConsole.js +13 -0
  38. package/lib/utils/codemods/injectImports.js +31 -0
  39. package/lib/utils/codemods/injectOptions.js +27 -0
  40. package/lib/utils/configTransforms.js +49 -0
  41. package/lib/utils/executeCommand.js +33 -0
  42. package/lib/utils/normalizeFilePaths.js +11 -0
  43. package/lib/utils/sortObject.js +32 -0
  44. package/lib/utils/stringifyJS.js +12 -0
  45. package/lib/utils/writeFileTree.js +12 -0
  46. package/package.json +53 -0
  47. package/rollup.config.cjs +43 -0
  48. package/scripts/verify-commit.js +24 -0
@@ -0,0 +1,110 @@
1
+ <template>
2
+ <div class="hello">
3
+ <h1>{{ msg }}</h1>
4
+ <p>
5
+ For a guide and recipes on how to configure / customize this
6
+ project,<br />
7
+ check out the
8
+ <a href="https://cli.vuejs.org" target="_blank" rel="noopener"
9
+ >vue-cli documentation</a
10
+ >.
11
+ </p>
12
+ <h3>Essential Links</h3>
13
+ <ul>
14
+ <li>
15
+ <a href="https://vuejs.org" target="_blank" rel="noopener"
16
+ >Core Docs</a
17
+ >
18
+ </li>
19
+ <li>
20
+ <a href="https://forum.vuejs.org" target="_blank" rel="noopener"
21
+ >Forum</a
22
+ >
23
+ </li>
24
+ <li>
25
+ <a href="https://chat.vuejs.org" target="_blank" rel="noopener"
26
+ >Community Chat</a
27
+ >
28
+ </li>
29
+ <li>
30
+ <a
31
+ href="https://twitter.com/vuejs"
32
+ target="_blank"
33
+ rel="noopener"
34
+ >Twitter</a
35
+ >
36
+ </li>
37
+ <li>
38
+ <a href="https://news.vuejs.org" target="_blank" rel="noopener"
39
+ >News</a
40
+ >
41
+ </li>
42
+ </ul>
43
+ <h3>Ecosystem</h3>
44
+ <ul>
45
+ <li>
46
+ <a
47
+ href="https://router.vuejs.org"
48
+ target="_blank"
49
+ rel="noopener"
50
+ >vue-router</a
51
+ >
52
+ </li>
53
+ <li>
54
+ <a href="https://vuex.vuejs.org" target="_blank" rel="noopener"
55
+ >vuex</a
56
+ >
57
+ </li>
58
+ <li>
59
+ <a
60
+ href="https://github.com/vuejs/vue-devtools#vue-devtools"
61
+ target="_blank"
62
+ rel="noopener"
63
+ >vue-devtools</a
64
+ >
65
+ </li>
66
+ <li>
67
+ <a
68
+ href="https://vue-loader.vuejs.org"
69
+ target="_blank"
70
+ rel="noopener"
71
+ >vue-loader</a
72
+ >
73
+ </li>
74
+ <li>
75
+ <a
76
+ href="https://github.com/vuejs/awesome-vue"
77
+ target="_blank"
78
+ rel="noopener"
79
+ >awesome-vue</a
80
+ >
81
+ </li>
82
+ </ul>
83
+ </div>
84
+ </template>
85
+
86
+ <script>
87
+ export default {
88
+ name: 'HelloWorld',
89
+ props: {
90
+ msg: String
91
+ }
92
+ }
93
+ </script>
94
+
95
+ <style scoped>
96
+ h3 {
97
+ margin: 40px 0 0;
98
+ }
99
+ ul {
100
+ list-style-type: none;
101
+ padding: 0;
102
+ }
103
+ li {
104
+ display: inline-block;
105
+ margin: 0 10px;
106
+ }
107
+ a {
108
+ color: #42b983;
109
+ }
110
+ </style>
@@ -0,0 +1,8 @@
1
+ import Vue from 'vue'
2
+ import App from './App.vue'
3
+
4
+ Vue.config.productionTip = false
5
+
6
+ new Vue({
7
+ render: (h) => h(App),
8
+ }).$mount('#app')
@@ -0,0 +1,13 @@
1
+ module.exports = (generator) => {
2
+ generator.injectImports(generator.entryFile, `import store from './store'`)
3
+
4
+ generator.injectRootOptions(generator.entryFile, `store`)
5
+
6
+ generator.extendPackage({
7
+ dependencies: {
8
+ vuex: '^3.6.2',
9
+ },
10
+ })
11
+
12
+ generator.render('./template', {})
13
+ }
@@ -0,0 +1,15 @@
1
+ import Vue from 'vue'
2
+ import Vuex from 'vuex'
3
+
4
+ Vue.use(Vuex)
5
+
6
+ export default new Vuex.Store({
7
+ state: {
8
+ },
9
+ mutations: {
10
+ },
11
+ actions: {
12
+ },
13
+ modules: {
14
+ },
15
+ })
@@ -0,0 +1,27 @@
1
+ module.exports = (generator, options = {}) => {
2
+ generator.extendPackage({
3
+ scripts: {
4
+ dev: 'webpack-dev-server --config ./build/dev.config.js',
5
+ build: 'webpack --config ./build/pro.config.js',
6
+ },
7
+ devDependencies: {
8
+ 'clean-webpack-plugin': '^3.0.0',
9
+ 'css-loader': '^5.0.2',
10
+ 'file-loader': '^6.2.0',
11
+ 'url-loader': '^4.1.1',
12
+ 'html-webpack-plugin': '^4.5.1',
13
+ 'style-loader': '^2.0.0',
14
+ 'vue-loader': '^15.9.6',
15
+ webpack: '^4.32.2',
16
+ 'webpack-cli': '^3.3.11',
17
+ 'webpack-dev-server': '^3.11.2',
18
+ 'webpack-merge': '^4.2.1',
19
+ webpackbar: '^4.0.0',
20
+ },
21
+ })
22
+
23
+ generator.render('./template', {
24
+ hasBabel: options.features.includes('babel'),
25
+ lintOnSave: options.lintOn.includes('save'),
26
+ })
27
+ }
@@ -0,0 +1,68 @@
1
+ const path = require('path')
2
+ const { VueLoaderPlugin } = require('vue-loader')
3
+ const HtmlWebpackPlugin = require('html-webpack-plugin')
4
+ const { CleanWebpackPlugin } = require('clean-webpack-plugin')
5
+ const WebpackBar = require('webpackbar')
6
+
7
+ const resolve = (filePath) => path.resolve(__dirname, filePath)
8
+
9
+ module.exports = {
10
+ entry: resolve('../src/main.js'),
11
+ resolve: {
12
+ extensions: ['.js', '.vue', '.json', '.css'],
13
+ alias: {
14
+ '@': resolve('../src'),
15
+ },
16
+ },
17
+ module: {
18
+ rules: [
19
+ <%_ if (lintOnSave) { _%>
20
+ {
21
+ enforce: 'pre',
22
+ test: /\.(js|vue)$/,
23
+ loader: 'eslint-loader',
24
+ exclude: /node_modules/
25
+ },
26
+ <%_ } _%>
27
+ {
28
+ test: /\.vue$/,
29
+ loader: 'vue-loader',
30
+ exclude: /node_modules/,
31
+ },
32
+ <%_ if (hasBabel) { _%>
33
+ {
34
+ test: /\.js$/,
35
+ loader: 'babel-loader',
36
+ exclude: /node_modules/,
37
+ },
38
+ <%_ } _%>
39
+ {
40
+ test: /\.(png|svg|jpg|gif|ico)$/,
41
+ use: [{
42
+ loader: 'file-loader',
43
+ options: {
44
+ esModule: false,
45
+ },
46
+ }],
47
+ },
48
+ {
49
+ test: /\.(woff|eot|ttf)\??.*$/,
50
+ loader: 'url-loader?name=fonts/[name].[md5:hash:hex:7].[ext]',
51
+ },
52
+ {
53
+ test: /\.css$/,
54
+ use: ['style-loader', 'css-loader'],
55
+ },
56
+ ],
57
+ },
58
+ plugins: [
59
+ new WebpackBar(),
60
+ new VueLoaderPlugin(),
61
+ new CleanWebpackPlugin(),
62
+ new HtmlWebpackPlugin({
63
+ title: 'My App',
64
+ template: resolve('../public/index.html'),
65
+ favicon: resolve('../public/favicon.ico'),
66
+ }),
67
+ ],
68
+ }
@@ -0,0 +1,19 @@
1
+ const path = require('path')
2
+ const merge = require('webpack-merge')
3
+ const base = require('./base.config')
4
+
5
+ const resolve = (filePath) => path.resolve(__dirname, filePath)
6
+
7
+ module.exports = merge(base, {
8
+ mode: 'development',
9
+ devtool: 'inline-source-map',
10
+ devServer: {
11
+ contentBase: resolve('../dist'),
12
+ hot: true,
13
+ port: 8080,
14
+ },
15
+ output: {
16
+ filename: '[name].bundle.js',
17
+ path: resolve('../dist'),
18
+ },
19
+ })
@@ -0,0 +1,16 @@
1
+ const path = require('path')
2
+ const merge = require('webpack-merge')
3
+ const base = require('./base.config')
4
+
5
+ const resolve = (filePath) => path.resolve(__dirname, filePath)
6
+
7
+ module.exports = merge(base, {
8
+ mode: 'production',
9
+ devtool: 'source-map',
10
+ output: {
11
+ path: resolve('../dist'),
12
+ publicPath: './',
13
+ filename: '[name].[contenthash].js',
14
+ chunkFilename: '[name].[contenthash].js',
15
+ },
16
+ })
@@ -0,0 +1,10 @@
1
+ module.exports = (api) => {
2
+ api.injectFeature({
3
+ name: 'Babel',
4
+ value: 'babel',
5
+ short: 'Babel',
6
+ description: 'Transpile modern JavaScript to older versions (for compatibility)',
7
+ link: 'https://babeljs.io/',
8
+ checked: true,
9
+ })
10
+ }
@@ -0,0 +1,48 @@
1
+ module.exports = (api) => {
2
+ api.injectFeature({
3
+ name: 'Linter / Formatter',
4
+ value: 'linter',
5
+ short: 'Linter',
6
+ description: 'Check and enforce code quality with ESLint or Prettier',
7
+ link: 'https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint',
8
+ checked: true,
9
+ })
10
+
11
+ api.injectPrompt({
12
+ name: 'eslintConfig',
13
+ when: answers => answers.features.includes('linter'),
14
+ type: 'list',
15
+ message: 'Pick a linter / formatter config:',
16
+ description: 'Checking code errors and enforcing an homogeoneous code style is recommended.',
17
+ choices: () => [
18
+ {
19
+ name: 'ESLint + Airbnb config',
20
+ value: 'airbnb',
21
+ short: 'Airbnb',
22
+ },
23
+ {
24
+ name: 'ESLint + Standard config',
25
+ value: 'standard',
26
+ short: 'Standard',
27
+ },
28
+ ],
29
+ })
30
+
31
+ api.injectPrompt({
32
+ name: 'lintOn',
33
+ message: 'Pick additional lint features:',
34
+ when: answers => answers.features.includes('linter'),
35
+ type: 'checkbox',
36
+ choices: [
37
+ {
38
+ name: 'Lint on save',
39
+ value: 'save',
40
+ checked: true,
41
+ },
42
+ {
43
+ name: 'Lint and fix on commit',
44
+ value: 'commit',
45
+ },
46
+ ],
47
+ })
48
+ }
@@ -0,0 +1,19 @@
1
+ const chalk = require('chalk')
2
+
3
+ module.exports = (api) => {
4
+ api.injectFeature({
5
+ name: 'Router',
6
+ value: 'router',
7
+ description: 'Structure the app with dynamic pages',
8
+ link: 'https://router.vuejs.org/',
9
+ })
10
+
11
+ api.injectPrompt({
12
+ name: 'historyMode',
13
+ when: answers => answers.features.includes('router'),
14
+ type: 'confirm',
15
+ message: `Use history mode for router? ${chalk.yellow(`(Requires proper server setup for index fallback in production)`)}`,
16
+ description: `By using the HTML5 History API, the URLs don't need the '#' character anymore.`,
17
+ link: 'https://router.vuejs.org/guide/essentials/history-mode.html',
18
+ })
19
+ }
@@ -0,0 +1,8 @@
1
+ module.exports = (api) => {
2
+ api.injectFeature({
3
+ name: 'Vuex',
4
+ value: 'vuex',
5
+ description: 'Manage the app state with a centralized store',
6
+ link: 'https://vuex.vuejs.org/',
7
+ })
8
+ }
@@ -0,0 +1,13 @@
1
+ const readline = require('readline')
2
+ // 清空控制台
3
+ module.exports = function clearConsole(title) {
4
+ if (process.stdout.isTTY) {
5
+ const blank = '\n'.repeat(process.stdout.rows)
6
+ console.log(blank)
7
+ readline.cursorTo(process.stdout, 0, 0)
8
+ readline.clearScreenDown(process.stdout)
9
+ if (title) {
10
+ console.log(title)
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,31 @@
1
+ // https://github.com/facebook/jscodeshift
2
+ // 对代码进行解析得到 AST,再将参数 imports 中的语句插入
3
+ module.exports = function injectImports(fileInfo, api, { imports }) {
4
+ const j = api.jscodeshift
5
+ const root = j(fileInfo.source)
6
+
7
+ const toImportAST = i => j(`${i}\n`).nodes()[0].program.body[0]
8
+ const toImportHash = node => JSON.stringify({
9
+ specifiers: node.specifiers.map(s => s.local.name),
10
+ source: node.source.raw,
11
+ })
12
+
13
+ const declarations = root.find(j.ImportDeclaration)
14
+ const importSet = new Set(declarations.nodes().map(toImportHash))
15
+ const nonDuplicates = node => !importSet.has(toImportHash(node))
16
+
17
+ const importASTNodes = imports.map(toImportAST).filter(nonDuplicates)
18
+
19
+ if (declarations.length) {
20
+ declarations
21
+ .at(-1)
22
+ // a tricky way to avoid blank line after the previous import
23
+ .forEach(({ node }) => delete node.loc)
24
+ .insertAfter(importASTNodes)
25
+ } else {
26
+ // no pre-existing import declarations
27
+ root.get().node.program.body.unshift(...importASTNodes)
28
+ }
29
+
30
+ return root.toSource()
31
+ }
@@ -0,0 +1,27 @@
1
+ // https://github.com/facebook/jscodeshift
2
+ // 对代码进行解析得到 AST,再将参数 injections 中的语句插入
3
+ module.exports = function injectOptions(fileInfo, api, { injections }) {
4
+ const j = api.jscodeshift
5
+ const root = j(fileInfo.source)
6
+
7
+ const toPropertyAST = i => j(`({${i}})`).nodes()[0].program.body[0].expression.properties[0]
8
+
9
+ const properties = root
10
+ .find(j.NewExpression, {
11
+ callee: { name: 'Vue' },
12
+ arguments: [{ type: 'ObjectExpression' }],
13
+ })
14
+ .map(path => path.get('arguments', 0))
15
+ .get()
16
+ .node
17
+ .properties
18
+
19
+ const toPropertyHash = p => `${p.key.name}: ${j(p.value).toSource()}`
20
+ const propertySet = new Set(properties.map(toPropertyHash))
21
+ const nonDuplicates = p => !propertySet.has(toPropertyHash(p))
22
+
23
+ // inject at index length - 1 as it's usually the render fn
24
+ properties.splice(-1, 0, ...injections.map(toPropertyAST).filter(nonDuplicates))
25
+
26
+ return root.toSource()
27
+ }
@@ -0,0 +1,49 @@
1
+ const stringifyJS = require('./stringifyJS')
2
+ const merge = require('deepmerge')
3
+
4
+ const mergeArrayWithDedupe = (a, b) => Array.from(new Set([...a, ...b]))
5
+ const mergeOptions = {
6
+ arrayMerge: mergeArrayWithDedupe,
7
+ }
8
+
9
+ const transformJS = {
10
+ read: ({ filename, context }) => {
11
+ try {
12
+ return require(`./${filename}`, context, true)
13
+ } catch (e) {
14
+ return null
15
+ }
16
+ },
17
+ write: ({ value }) => `module.exports = ${stringifyJS(value, null, 4)}`,
18
+ }
19
+
20
+ const transformJSON = {
21
+ read: ({ source }) => JSON.parse(source),
22
+ write: ({ value, existing }) => JSON.stringify(merge(existing, value, mergeOptions), null, 4),
23
+ }
24
+
25
+ const transformYAML = {
26
+ read: ({ source }) => require('js-yaml').safeLoad(source),
27
+ write: ({ value, existing }) => require('js-yaml').safeDump(merge(existing, value, mergeOptions), {
28
+ skipInvalid: true,
29
+ }),
30
+ }
31
+
32
+ const transformLines = {
33
+ read: ({ source }) => source.split('\n'),
34
+ write: ({ value, existing }) => {
35
+ if (existing) {
36
+ value = existing.concat(value)
37
+ // Dedupe
38
+ value = value.filter((item, index) => value.indexOf(item) === index)
39
+ }
40
+ return value.join('\n')
41
+ },
42
+ }
43
+
44
+ module.exports = {
45
+ js: transformJS,
46
+ json: transformJSON,
47
+ yaml: transformYAML,
48
+ lines: transformLines,
49
+ }
@@ -0,0 +1,33 @@
1
+ const execa = require('execa')
2
+ module.exports = function executeCommand(command, cwd) {
3
+ return new Promise((resolve, reject) => {
4
+ const child = execa.command(command, {
5
+ cwd,
6
+ /*
7
+ 三个选项分别对应:
8
+ stdin = 'inherit': 子进程直接用用户的输入
9
+ stdout = 'pipe':把子进程的正常输出“接到一根管子里”给 Node 程序
10
+ stderr = 'inherit':子进程的错误输出直接显示到当前终端
11
+ 不用你自己监听 child.stderr,报错会直接出现在屏幕上
12
+ */
13
+ stdio: ['inherit', 'pipe', 'inherit'],
14
+ })
15
+
16
+ child.stdout.on('data', buffer => {
17
+ process.stdout.write(buffer)
18
+ })
19
+
20
+ child.on('close', code => {
21
+ /*
22
+ 子进程结束时触发
23
+ code是退出码:一般0 表示成功,非0表示失败
24
+ */
25
+ if (code !== 0) {
26
+ reject(new Error(`command failed: ${command}`))
27
+ return
28
+ }
29
+
30
+ resolve()
31
+ })
32
+ })
33
+ }
@@ -0,0 +1,11 @@
1
+ module.exports = function normalizeFilePaths(files) {
2
+ Object.keys(files).forEach(file => {
3
+ const normalized = file.replace(/\\/g, '/')
4
+ if (file !== normalized) {
5
+ files[normalized] = files[file]
6
+ delete files[file]
7
+ }
8
+ })
9
+
10
+ return files
11
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * 对对象 key 排序并返回新对象。
3
+ * - 先按 keyOrder 指定的顺序放置(若存在)
4
+ * - 剩余 key 默认按 Unicode 字典序排序(可关闭)
5
+ *
6
+ * @param {Record<string, any>} obj 要排序的对象(会被 delete 已提取的 key)
7
+ * @param {string[]} [keyOrder] 优先排序的 key 列表
8
+ * @param {boolean} [dontSortByUnicode] 为 true 时不对剩余 key 做 keys.sort()
9
+ * @returns {Record<string, any> | undefined} 排序后的新对象;obj 为空时返回 undefined
10
+ */
11
+ module.exports = function sortObject(obj, keyOrder, dontSortByUnicode) {
12
+ if (!obj) return
13
+ const res = {}
14
+
15
+ if (keyOrder) {
16
+ keyOrder.forEach(key => {
17
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
18
+ res[key] = obj[key]
19
+ delete obj[key]
20
+ }
21
+ })
22
+ }
23
+
24
+ const keys = Object.keys(obj)
25
+
26
+ !dontSortByUnicode && keys.sort()
27
+ keys.forEach(key => {
28
+ res[key] = obj[key]
29
+ })
30
+
31
+ return res
32
+ }
@@ -0,0 +1,12 @@
1
+ // 递归的序列化代码
2
+ module.exports = function stringifyJS(value) {
3
+ const { stringify } = require('javascript-stringify')
4
+ // eslint-disable-next-line no-shadow
5
+ return stringify(value, (val, indent, stringify) => {
6
+ if (val && val.__expression) {
7
+ return val.__expression
8
+ }
9
+
10
+ return stringify(val)
11
+ }, 4)
12
+ }
@@ -0,0 +1,12 @@
1
+ const fs = require('fs-extra')
2
+ const path = require('path')
3
+
4
+ module.exports = async function writeFileTree(dir, files, options = {}) {
5
+ const { overwrite = true } = options
6
+ Object.keys(files).forEach((name) => {
7
+ const filePath = path.join(dir, name)
8
+ fs.ensureDirSync(path.dirname(filePath))
9
+ if (!overwrite && name !== 'package.json' && fs.existsSync(filePath)) return
10
+ fs.writeFileSync(filePath, files[name])
11
+ })
12
+ }
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@weig_3078/cli-demo",
3
+ "version": "0.1.0",
4
+ "description": "脚手架 demo",
5
+ "private": false,
6
+ "main": "index.js",
7
+ "bin": {
8
+ "mvc": "./dist/mvc.js"
9
+ },
10
+ "scripts": {
11
+ "build": "rollup -c rollup.config.cjs",
12
+ "test": "echo \"Error: no test specified\" && exit 1"
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/weige3078/cli-demo.git"
17
+ },
18
+ "husky": {
19
+ "hooks": {
20
+ "commit-msg": "node scripts/verify-commit.js"
21
+ }
22
+ },
23
+ "keywords": [],
24
+ "author": "",
25
+ "license": "ISC",
26
+ "dependencies": {
27
+ "chalk": "^4.1.2",
28
+ "commander": "^7.0.0",
29
+ "download-git-repo": "^3.0.2",
30
+ "ejs": "^3.1.6",
31
+ "execa": "^5.0.0",
32
+ "fs-extra": "^9.1.0",
33
+ "globby": "^11.0.2",
34
+ "inquirer": "^7.3.3",
35
+ "isbinaryfile": "^4.0.6",
36
+ "javascript-stringify": "^2.0.1",
37
+ "js-yaml": "^4.1.0",
38
+ "readline": "^1.3.0",
39
+ "recast": "^0.20.4",
40
+ "vue-codemod": "0.0.5"
41
+ },
42
+ "devDependencies": {
43
+ "@rollup/plugin-commonjs": "^29.0.2",
44
+ "@rollup/plugin-json": "^6.1.0",
45
+ "@rollup/plugin-node-resolve": "^16.0.3",
46
+ "deepmerge": "^4.3.1",
47
+ "eslint": "^7.20.0",
48
+ "eslint-config-airbnb-base": "^14.2.1",
49
+ "eslint-plugin-import": "^2.22.1",
50
+ "husky": "^4.3.0",
51
+ "rollup": "^4.60.0"
52
+ }
53
+ }