1. 'use strict'
    2. const fs = require('fs')
    3. const inquirer = require('inquirer')
    4. const fse = require('fs-extra')
    5. const semver = require('semver')
    6. const Command = require('@haha-cli-dev/command')
    7. const log = require('@haha-cli-dev/log')
    8. const TYPE_PROJECT = 'project'
    9. const TYPE_COMPONENT = 'component'
    10. class initCommand extends Command {
    11. init() {
    12. this.projectName = this._argv[0]
    13. console.log('projectName', this.projectName)
    14. }
    15. exec() {
    16. try {
    17. //1、准备阶段
    18. this.prepare()
    19. //2、下载模板
    20. //3、安装模板
    21. } catch (error) {
    22. log.error(error.message)
    23. }
    24. }
    25. async prepare() {
    26. //当前执行node命令时候的文件夹地址 ——工作目录
    27. const localPath = process.cwd()
    28. const force = this._argv[1]?.force
    29. let isContinue = false
    30. if (this.isCmdEmpty(localPath)) {
    31. //1.1 询问是否继续创建
    32. if (!force) {
    33. const res = await inquirer.prompt({
    34. type: 'confirm',
    35. name: 'isContinue',
    36. message: '当前文件夹内容不为空,是否在此继续创建项目?',
    37. default: false
    38. })
    39. isContinue = res.isContinue
    40. if (!isContinue) {
    41. return false
    42. }
    43. }
    44. }
    45. // 2.是否启动强制安装
    46. if (isContinue || force) {
    47. const { isDelete } = await inquirer.prompt({
    48. type: 'confirm',
    49. name: 'isDelete',
    50. message: '是否清空当前目录下的文件?',
    51. default: false
    52. })
    53. if (isDelete) {
    54. // 清空当前目录
    55. fse.emptyDirSync(localPath)
    56. }
    57. }
    58. return this.getBaseInfo()
    59. }
    60. //3、选择创建项目或组件
    61. async getBaseInfo() {
    62. const { type } = await inquirer.prompt({
    63. type: 'list',
    64. message: '请选择初始化类型',
    65. name: 'type',
    66. default: TYPE_PROJECT,
    67. choices: [
    68. {
    69. name: '项目',
    70. value: TYPE_PROJECT
    71. },
    72. {
    73. name: '组件',
    74. value: TYPE_COMPONENT
    75. }
    76. ]
    77. })
    78. if (type === TYPE_COMPONENT) {
    79. }
    80. if (type === TYPE_PROJECT) {
    81. const { project, version } = await inquirer.prompt([
    82. {
    83. type: 'input',
    84. message: '请输入项目名称',
    85. name: 'project',
    86. default: 'haha-demo',
    87. validate: function (val) {
    88. //检查项目名称和版本号的合法性
    89. const done = this.async()
    90. setTimeout(function () {
    91. //1、必须首字母大写,
    92. //2、尾字符必须为英文或者数字,不能为字符
    93. //3、字符仅允许'-_'
    94. //类型合法有:a a-b a_b a-b-c a_b_c a1_b1_c1 a1 a1-b1-c1
    95. if (!/^[a-zA-Z]+([-][a-zA-Z0-9]|[_][a-zA-Z0-9]|[a-zA-Z0-9])*$/.test(val)) {
    96. done('请输入合法的项目名称(要求英文字母开头,数字或字母结尾,字符只允许使用 - 以及 _)')
    97. return
    98. }
    99. done(null, true)
    100. }, 0)
    101. }
    102. },
    103. {
    104. type: 'input',
    105. message: '请输入项目版本号',
    106. name: 'version',
    107. default: '1.0.0',
    108. validate: function (val) {
    109. const done = this.async()
    110. setTimeout(function () {
    111. //!!semver.valid(val) !!转成Boolean类型
    112. if (!!!semver.valid(val)) {
    113. done('请输入合法的版本号')
    114. return
    115. }
    116. done(null, true)
    117. }, 0)
    118. },
    119. filter: val => {
    120. if (!!semver.valid(val)) {
    121. return semver.valid(val)
    122. }
    123. return val
    124. }
    125. }
    126. ])
    127. //4、获取项目的基本信息
    128. return {
    129. type,
    130. project,
    131. version
    132. }
    133. }
    134. }
    135. //判断当前路径是否不为空
    136. isCmdEmpty(localPath) {
    137. let fileList = fs.readdirSync(localPath)
    138. fileList = fileList.filter(item => !item.startsWith('.') && item !== 'node_modules')
    139. return fileList && fileList.length > 0
    140. }
    141. }
    142. function init(argv) {
    143. return new initCommand(argv)
    144. }
    145. module.exports = init
    146. module.exports.initCommand = initCommand