@liuli-util/cli 3.13.1 → 3.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. package/CHANGELOG.md +100 -74
  2. package/LICENSE +21 -0
  3. package/dist/bin.js +96 -77
  4. package/dist/bin.js.map +3 -3
  5. package/dist/commands/deploy/DeployService.d.ts +52 -0
  6. package/dist/commands/deploy/DeployService.d.ts.map +1 -0
  7. package/dist/commands/deploy/deploy.d.ts +3 -0
  8. package/dist/commands/deploy/deploy.d.ts.map +1 -0
  9. package/dist/commands/deploy/index.d.ts +3 -0
  10. package/dist/commands/deploy/index.d.ts.map +1 -0
  11. package/dist/commands/deploy/util/FileLock.d.ts +14 -0
  12. package/dist/commands/deploy/util/FileLock.d.ts.map +1 -0
  13. package/dist/commands/deploy/util/PromiseUtil.d.ts +14 -0
  14. package/dist/commands/deploy/util/PromiseUtil.d.ts.map +1 -0
  15. package/dist/commands/deploy/util/createArchive.d.ts +10 -0
  16. package/dist/commands/deploy/util/createArchive.d.ts.map +1 -0
  17. package/dist/commands/deploy/util/execPromise.d.ts +4 -0
  18. package/dist/commands/deploy/util/execPromise.d.ts.map +1 -0
  19. package/dist/commands/deploy/util/wait.d.ts +9 -0
  20. package/dist/commands/deploy/util/wait.d.ts.map +1 -0
  21. package/dist/commands/esbuild/ESBuildProgram.d.ts +1 -2
  22. package/dist/commands/esbuild/ESBuildProgram.d.ts.map +1 -1
  23. package/dist/commands/generate/GenerateProgram.d.ts.map +1 -1
  24. package/dist/commands/sync/SyncProgram.d.ts.map +1 -1
  25. package/dist/index.esm.js +1 -1
  26. package/dist/index.esm.js.map +2 -2
  27. package/dist/index.js +2 -2
  28. package/dist/index.js.map +2 -2
  29. package/dist/utils/nodeCacheDir.d.ts +2 -0
  30. package/dist/utils/nodeCacheDir.d.ts.map +1 -0
  31. package/package.json +73 -66
  32. package/src/bin.ts +3 -2
  33. package/src/commands/deploy/DeployService.ts +174 -0
  34. package/src/commands/deploy/__tests__/DeployService.test.ts +75 -0
  35. package/src/commands/deploy/__tests__/FileLock.test.ts +27 -0
  36. package/src/commands/deploy/__tests__/conf.test.ts +29 -0
  37. package/src/commands/deploy/__tests__/simpleGit.test.ts +34 -0
  38. package/src/commands/deploy/__tests__/util/deployGhPageWorker.ts +16 -0
  39. package/src/commands/deploy/deploy.ts +48 -0
  40. package/src/commands/deploy/index.ts +8 -0
  41. package/src/commands/deploy/util/FileLock.ts +31 -0
  42. package/src/commands/deploy/util/PromiseUtil.ts +34 -0
  43. package/src/commands/deploy/util/createArchive.ts +30 -0
  44. package/src/commands/deploy/util/execPromise.ts +13 -0
  45. package/src/commands/deploy/util/wait.ts +23 -0
  46. package/src/commands/esbuild/ESBuildProgram.ts +3 -12
  47. package/src/commands/esbuild/__tests__/.temp/getDeps/package.json +1 -0
  48. package/src/commands/esbuild/__tests__/ESBuildProgram.test.ts +0 -1
  49. package/src/commands/generate/GenerateProgram.ts +3 -1
  50. package/src/commands/generate/__tests__/.temp/test-cli/CHANGELOG.md +1 -0
  51. package/src/commands/generate/__tests__/.temp/test-cli/README.md +1 -0
  52. package/src/commands/generate/__tests__/.temp/test-cli/bin.js +3 -0
  53. package/src/commands/generate/__tests__/.temp/test-cli/package.json +44 -0
  54. package/src/commands/generate/__tests__/.temp/test-cli/src/bin.ts +13 -0
  55. package/src/commands/generate/__tests__/.temp/test-cli/src/index.ts +1 -0
  56. package/src/commands/generate/__tests__/.temp/test-cli/tsconfig.json +28 -0
  57. package/src/commands/generate/__tests__/GenerateProgram.test.ts +17 -17
  58. package/src/commands/sync/SyncProgram.ts +15 -41
  59. package/src/commands/sync/__tests__/SyncProgram.test.ts +13 -1
  60. package/src/utils/__tests__/nodeCacheDir.test.ts +6 -0
  61. package/src/utils/nodeCacheDir.ts +54 -0
  62. package/templates/cli/package.json +4 -10
  63. package/templates/cli/tsconfig.json +28 -28
  64. package/templates/lib/package.json +2 -8
  65. package/templates/lib/tsconfig.json +28 -28
  66. package/tsconfig.json +34 -34
  67. package/src/commands/sync/__tests__/.temp/lerna.json +0 -6
  68. package/src/commands/sync/__tests__/.temp/package.json +0 -58
@@ -0,0 +1,75 @@
1
+ import * as path from 'path'
2
+ import { mkdirp, remove, writeFile } from 'fs-extra'
3
+ import { GhPagesDeployService, SftpDeployOptions, SftpDeployService } from '../DeployService'
4
+ import { execPromise } from '../util/execPromise'
5
+
6
+ const tempPath = path.resolve(__dirname, '.temp')
7
+ beforeAll(async () => {
8
+ const distPath = path.resolve(tempPath, 'dist')
9
+ await remove(tempPath)
10
+ await mkdirp(distPath)
11
+
12
+ await writeFile(
13
+ path.resolve(distPath, 'index.html'),
14
+ `<!DOCTYPE html>
15
+ <html lang="en">
16
+ <head>
17
+ <meta charset="UTF-8" />
18
+ <title>测试部署</title>
19
+ </head>
20
+ <body>
21
+ <h1>测试部署</h1>
22
+ </body>
23
+ </html>
24
+ `,
25
+ )
26
+ })
27
+
28
+ describe('测试 SftpDeployService', () => {
29
+ const options: SftpDeployOptions = {
30
+ cwd: tempPath,
31
+ dest: 'dist',
32
+ remote: '/home/pinefield/apps/test',
33
+ sshConfig: {
34
+ host: '10.8.2.4',
35
+ username: 'pinefield',
36
+ },
37
+ }
38
+ it('基本示例', async () => {
39
+ const sftpDeployService = new SftpDeployService(options)
40
+ await sftpDeployService.deploy()
41
+ })
42
+ describe('测试校验', () => {
43
+ it('正确情况', () => {
44
+ const [isValid] = new SftpDeployService(options).validate()
45
+ expect(isValid).toBeTruthy()
46
+ })
47
+ it('缺少字段', () => {
48
+ const [isValid, errorText] = new SftpDeployService({
49
+ cwd: tempPath,
50
+ } as SftpDeployOptions).validate()
51
+ expect(isValid).toBeFalsy()
52
+ console.log(errorText)
53
+ })
54
+ })
55
+ })
56
+
57
+ describe('测试 GhPagesDeployService', () => {
58
+ const ghPagesDeployService = new GhPagesDeployService({
59
+ cwd: tempPath,
60
+ dest: 'dist',
61
+ remote: 'examples/test-app',
62
+ })
63
+ it('基本示例', async () => {
64
+ await ghPagesDeployService.deploy().on('process', (title) => console.log(title))
65
+ }, 10_000)
66
+ //TODO 无法使用单元测试
67
+ it.skip('并发推送', async () => {
68
+ const scriptPath = path.resolve(__dirname, './util/deployGhPageWorker.ts').replace(/\\/g, '/')
69
+ await Promise.all(
70
+ [1, 2].map(async () => {
71
+ await execPromise(`esno ${scriptPath}`)
72
+ }),
73
+ )
74
+ }, 10_000)
75
+ })
@@ -0,0 +1,27 @@
1
+ import * as path from 'path'
2
+ import { FileLock } from '../util/FileLock'
3
+ import { AsyncArray } from '../../../utils'
4
+ import { wait } from '../util/wait'
5
+
6
+ describe('测试文件锁', () => {
7
+ const tempPath = path.resolve(__dirname, '.temp/test.lock')
8
+ it('基本示例', async () => {
9
+ const fileLock = new FileLock(tempPath)
10
+ expect(await fileLock.lock()).toBeTruthy()
11
+ expect(await fileLock.lock()).toBeFalsy()
12
+ await fileLock.unlock()
13
+ expect(await fileLock.lock()).toBeTruthy()
14
+ await fileLock.unlock()
15
+ })
16
+ it('测试并发调用', async () => {
17
+ const start = Date.now()
18
+ await AsyncArray.forEach(Array(10).fill(0), async () => {
19
+ const fileLock = new FileLock(tempPath)
20
+ await wait(() => fileLock.lock())
21
+ await wait(100)
22
+ await fileLock.unlock()
23
+ })
24
+ const time = Date.now() - start
25
+ expect(time).toBeLessThan(3000)
26
+ })
27
+ })
@@ -0,0 +1,29 @@
1
+ import Conf from 'conf'
2
+ import { wait } from '../util/wait'
3
+ import { writeJson } from 'fs-extra'
4
+ import * as path from 'path'
5
+
6
+ describe('测试 conf', () => {
7
+ const conf = new Conf<{ lock: boolean }>({ projectName: '@liuli-util/test' })
8
+ beforeEach(() => {
9
+ conf.clear()
10
+ })
11
+ it('测试并发模式', async () => {
12
+ await Promise.all([
13
+ wait(() => conf.store.lock),
14
+ wait(1000).then(() => {
15
+ conf.set('lock', true)
16
+ }),
17
+ ])
18
+ expect(conf.store.lock).toBeTruthy()
19
+ })
20
+ it('测试直接修改文件', async () => {
21
+ await Promise.all([
22
+ wait(() => conf.store.lock),
23
+ wait(1000).then(async () => {
24
+ await writeJson(conf.path, { lock: true })
25
+ }),
26
+ ])
27
+ expect(conf.store.lock).toBeTruthy()
28
+ })
29
+ })
@@ -0,0 +1,34 @@
1
+ import simpleGit, { SimpleGit } from 'simple-git'
2
+ import * as path from 'path'
3
+ import { mkdirp, remove } from 'fs-extra'
4
+
5
+ describe('测试 simple-git', () => {
6
+ async function getOriginRemote() {
7
+ const git = simpleGit()
8
+ const remotes = await git.getRemotes(true)
9
+ return remotes.find((item) => item.name === 'origin')
10
+ }
11
+ let git: SimpleGit
12
+ const tempPath = path.resolve(__dirname, '.temp')
13
+ beforeEach(async () => {
14
+ git = simpleGit()
15
+ await remove(tempPath)
16
+ await mkdirp(tempPath)
17
+ })
18
+ it('测试获取当前项目的远端地址', async () => {
19
+ const originRemote = await getOriginRemote()
20
+ console.log('git.getRemotes', originRemote)
21
+ expect(originRemote).not.toBeUndefined()
22
+ })
23
+ it('克隆项目', async () => {
24
+ const originRemote = (await getOriginRemote())!
25
+ console.log('获取当前项目远端配置: ', originRemote)
26
+ const originRepoName = originRemote.refs.fetch.replace(new RegExp('[/:]', 'g'), '_')
27
+ await git.clone(originRemote.refs.fetch, path.resolve(tempPath, originRepoName), { '--branch': 'gh-pages' })
28
+ }, 100_000)
29
+ it('测试 git status', async () => {
30
+ await git.add('-A')
31
+ const status = await git.status()
32
+ console.log('status: ', status.files)
33
+ })
34
+ })
@@ -0,0 +1,16 @@
1
+ import { GhPagesDeployService } from '../../DeployService'
2
+ import * as path from 'path'
3
+
4
+ async function deployGhPages() {
5
+ const tempPath = path.resolve(__dirname, '../.temp/')
6
+ const ghPagesDeployService = new GhPagesDeployService({
7
+ cwd: tempPath,
8
+ dest: 'dist',
9
+ remote: 'examples/test-app',
10
+ })
11
+ const now = Date.now()
12
+ await ghPagesDeployService.deploy().on('process', (title) => console.log(`[${now}] ${title}`))
13
+ }
14
+
15
+ // noinspection JSIgnoredPromiseFromCall
16
+ deployGhPages()
@@ -0,0 +1,48 @@
1
+ import {
2
+ BaseDeployOptions,
3
+ DeployTypeEnum,
4
+ GhPagesDeployService,
5
+ IDeployService,
6
+ SftpDeployOptions,
7
+ SftpDeployService,
8
+ } from './DeployService'
9
+ import * as path from 'path'
10
+ import { pathExists, readJson } from 'fs-extra'
11
+
12
+ async function getOptions(cwd: string): Promise<BaseDeployOptions> {
13
+ const pkgJsonPath = path.resolve(cwd, 'package.json')
14
+ if (await pathExists(pkgJsonPath)) {
15
+ const config = (await readJson(pkgJsonPath)).deploy
16
+ if (!config) {
17
+ throw new Error('找不到配置')
18
+ }
19
+ return config
20
+ }
21
+ throw new Error('找不到配置')
22
+ }
23
+
24
+ export async function deploy(options: Omit<BaseDeployOptions, 'type'>): Promise<void> {
25
+ const deployOptions = await getOptions(options.cwd)
26
+ let service: IDeployService
27
+ const _options = {
28
+ ...options,
29
+ ...deployOptions,
30
+ } as unknown as SftpDeployOptions
31
+ switch (deployOptions.type) {
32
+ case DeployTypeEnum.Sftp:
33
+ service = new SftpDeployService(_options)
34
+ break
35
+ case DeployTypeEnum.GhPages:
36
+ service = new GhPagesDeployService(_options)
37
+ break
38
+ default:
39
+ throw new Error('未知的部署预设类型 ' + deployOptions.type)
40
+ }
41
+ const [isValidate, errorText] = service.validate()
42
+ if (!isValidate) {
43
+ throw new Error(errorText)
44
+ }
45
+ await service.deploy().on('process', (title) => {
46
+ console.info(title)
47
+ })
48
+ }
@@ -0,0 +1,8 @@
1
+ import { Command } from 'commander'
2
+ import { deploy } from './deploy'
3
+ import * as path from 'path'
4
+
5
+ export const deployCommand = new Command('deploy')
6
+ .description('部署项目到远端')
7
+ .option('--debug', '是否开启调试模式')
8
+ .action((options: { debug?: boolean }) => deploy({ cwd: path.resolve(), debug: !!options.debug }))
@@ -0,0 +1,31 @@
1
+ import { close, open, remove } from 'fs-extra'
2
+ import path from 'path'
3
+
4
+ export class FileLock {
5
+ constructor(private readonly lockFilePath: string) {}
6
+
7
+ private lockId?: number
8
+
9
+ /**
10
+ * 加锁
11
+ */
12
+ async lock(): Promise<boolean> {
13
+ try {
14
+ this.lockId = await open(path.resolve(this.lockFilePath), 'wx')
15
+ return true
16
+ } catch (e) {
17
+ return false
18
+ }
19
+ }
20
+
21
+ /**
22
+ * 解锁
23
+ */
24
+ async unlock(): Promise<void> {
25
+ if (!this.lockId) {
26
+ throw new Error('未加锁')
27
+ }
28
+ await remove(path.resolve(this.lockFilePath))
29
+ close(this.lockId)
30
+ }
31
+ }
@@ -0,0 +1,34 @@
1
+ import { ConditionalKeys, PromiseValue } from 'type-fest'
2
+
3
+ type VoidFunc = ((...args: any[]) => void) | undefined
4
+
5
+ export type EventExtPromise<T, E> = Promise<T> & {
6
+ on<K extends ConditionalKeys<E, VoidFunc>>(type: K, callback: E[K]): EventExtPromise<T, E>
7
+ }
8
+
9
+ export class PromiseUtil {
10
+ /**
11
+ * 创建一个支持 on* 事件的 Promise 实例
12
+ * @param executor
13
+ */
14
+ static wrapOnEvent<
15
+ F extends (events: any) => Promise<any>,
16
+ E extends Parameters<F>[0],
17
+ K extends ConditionalKeys<E, VoidFunc>,
18
+ >(executor: F): EventExtPromise<PromiseValue<ReturnType<F>>, E> {
19
+ const events: Partial<Pick<E, K>> = {}
20
+ const res = new Promise(async (resolve, reject) => {
21
+ await new Promise((resolve) => setTimeout(resolve, 0))
22
+ try {
23
+ resolve(await executor(events))
24
+ } catch (e) {
25
+ reject(e)
26
+ }
27
+ })
28
+ Reflect.set(res, 'on', (type: K, callback: E[K]) => {
29
+ events[type] = callback
30
+ return res
31
+ })
32
+ return res as any
33
+ }
34
+ }
@@ -0,0 +1,30 @@
1
+ import { create, CreateOptions } from 'tar'
2
+ import { promise } from 'glob-promise'
3
+ import * as path from 'path'
4
+
5
+ export type ArchiveOptions = {
6
+ // sourceDir 源目录,一般设置为 dist
7
+ sourceDir: string
8
+ // destPath 目标位置,可能是 <packageName>.jpl
9
+ destPath: string
10
+ }
11
+
12
+ /**
13
+ * 创建 jpl 压缩文件
14
+ * @param options
15
+ */
16
+ export async function createArchive(options: ArchiveOptions): Promise<void> {
17
+ const sourceDir = path.resolve(options.sourceDir)
18
+ const destPath = path.resolve(options.destPath)
19
+ const distFiles = (await promise(`${sourceDir}/**/*`, { nodir: true })).map((f) => f.substr(sourceDir.length + 1))
20
+ await create(
21
+ {
22
+ strict: true,
23
+ portable: true,
24
+ file: destPath,
25
+ cwd: sourceDir,
26
+ sync: true,
27
+ } as Partial<CreateOptions>,
28
+ distFiles,
29
+ )
30
+ }
@@ -0,0 +1,13 @@
1
+ import { exec, ExecOptions } from 'child_process'
2
+
3
+ export function execPromise(command: string, options?: ExecOptions): Promise<string | Buffer> {
4
+ return new Promise((resolve, reject) => {
5
+ exec(command, options, (error, stdout) => {
6
+ if (error) {
7
+ reject(error)
8
+ return
9
+ }
10
+ resolve(stdout)
11
+ })
12
+ })
13
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * 等待指定的时间/等待指定表达式成立
3
+ * 如果未指定等待条件则立刻执行
4
+ * 注: 此实现在 nodejs 10- 会存在宏任务与微任务的问题,切记 async-await 本质上还是 Promise 的语法糖,实际上并非真正的同步函数!!!即便在浏览器,也不要依赖于这种特性。
5
+ * @param param 等待时间/等待条件
6
+ * @returns Promise 对象
7
+ */
8
+ export function wait(param?: number | (() => boolean | Promise<boolean>)): Promise<void> {
9
+ return new Promise((resolve) => {
10
+ if (typeof param === 'number') {
11
+ setTimeout(resolve, param)
12
+ } else if (typeof param === 'function') {
13
+ const timer = setInterval(async () => {
14
+ if (await param()) {
15
+ clearInterval(timer)
16
+ resolve()
17
+ }
18
+ }, 100)
19
+ } else {
20
+ resolve()
21
+ }
22
+ })
23
+ }
@@ -31,7 +31,7 @@ export class ESBuildProgram {
31
31
  this.options.isWatch = isWatch
32
32
  }
33
33
 
34
- static readonly globalExternal = ['esbuild', 'pnpapi', 'ts-morph']
34
+ static readonly globalExternal = ['esbuild', 'pnpapi', 'ts-morph', 'ssh2']
35
35
 
36
36
  /**
37
37
  * 获取所有依赖
@@ -146,22 +146,14 @@ export class ESBuildProgram {
146
146
  * @param platform
147
147
  * @param plugins
148
148
  */
149
- getBuildIifeOption({
150
- deps,
151
- platform,
152
- globalName,
153
- }: {
154
- deps: string[]
155
- platform: Platform
156
- globalName: string
157
- }): BuildOptions {
149
+ getBuildIifeOption({ platform, globalName }: { platform: Platform; globalName: string }): BuildOptions {
158
150
  return {
159
151
  entryPoints: [path.resolve(this.options.base, './src/index.ts')],
160
152
  outfile: path.resolve(this.options.base, './dist/index.iife.js'),
161
153
  format: 'iife',
162
154
  sourcemap: true,
163
155
  bundle: true,
164
- external: [...ESBuildProgram.globalExternal, ...deps],
156
+ external: [...ESBuildProgram.globalExternal],
165
157
  platform: platform,
166
158
  minify: !this.options.isWatch,
167
159
  incremental: this.options.isWatch,
@@ -239,7 +231,6 @@ export class ESBuildProgram {
239
231
  task: async () => {
240
232
  return await this.build(
241
233
  this.getBuildIifeOption({
242
- deps: deps,
243
234
  platform: platform,
244
235
  globalName: getPkgGlobalName(
245
236
  ((await readJson(path.resolve(this.options.base, './package.json'))) as PackageJson).name!,
@@ -0,0 +1 @@
1
+ {"devDependencies":{"@types/node":"16"},"dependencies":{"ora":"^6"},"peerDependencies":{"typescript":"^4"}}
@@ -93,7 +93,6 @@ describe('测试 ESBuildProgram', () => {
93
93
  })
94
94
  it('测试 getBuildIifeOption', async () => {
95
95
  const option = program.getBuildIifeOption({
96
- deps: deps,
97
96
  platform: platform,
98
97
  globalName: 'test',
99
98
  })
@@ -64,7 +64,9 @@ export class GenerateProgram {
64
64
  }
65
65
  }
66
66
  await remove(destFile)
67
- await copy(srcFile, destFile)
67
+ await copy(srcFile, destFile, {
68
+ filter: (source) => path.basename(source) !== 'node_modules',
69
+ })
68
70
  await GenerateProgram.updatePackageJSON(destFile)
69
71
  await GenerateProgram.updateReadme(destFile)
70
72
  if (config.initSync) {
@@ -0,0 +1 @@
1
+ # @liuli-util/cli-test-cli
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ // eslint-disable-next-line no-undef
3
+ require('./dist/bin.js')
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "test-cli",
3
+ "version": "0.1.0",
4
+ "main": "dist/index.js",
5
+ "module": "dist/index.esm.js",
6
+ "types": "dist/index.d.ts",
7
+ "license": "MIT",
8
+ "scripts": {
9
+ "build": "rimraf dist && liuli-cli build cli",
10
+ "dev": "liuli-cli build cli -w",
11
+ "start": "esno src/bin.ts",
12
+ "docs:server": "live-server docs",
13
+ "docs:dev": "typedoc --watch",
14
+ "docs:build": "rimraf docs && typedoc",
15
+ "docs:deploy": "yarn docs:build && gh-pages -d docs/ -e / -a"
16
+ },
17
+ "bin": {
18
+ "cli-name": "./bin.js"
19
+ },
20
+ "jest": {
21
+ "preset": "ts-jest"
22
+ },
23
+ "dependencies": {
24
+ "commander": "^8.2.0",
25
+ "fs-extra": "^10.0.0",
26
+ "inquirer": "^8.1.5"
27
+ },
28
+ "devDependencies": {
29
+ "@liuli-util/cli": "^3.11.1",
30
+ "@types/fs-extra": "^9.0.13",
31
+ "@types/inquirer": "^8.1.2",
32
+ "@types/jest": "^27.0.2",
33
+ "@types/lodash": "^4.14.173",
34
+ "@types/node": "^16.9.6",
35
+ "esno": "^0.9.1",
36
+ "gh-pages": "^3.2.3",
37
+ "jest": "^27.2.1",
38
+ "rimraf": "^3.0.2",
39
+ "ts-jest": "^27.0.5",
40
+ "type-fest": "^2.3.4",
41
+ "typedoc": "^0.22.4",
42
+ "typescript": "^4.4.3"
43
+ }
44
+ }
@@ -0,0 +1,13 @@
1
+ import { Command } from 'commander'
2
+ import { prompt } from 'inquirer'
3
+
4
+ new Command()
5
+ .action(async () => {
6
+ const { name } = await prompt<{ name: string }>({
7
+ type: 'input',
8
+ name: 'name',
9
+ message: '请输入名字',
10
+ })
11
+ console.log(`hello ${name}`)
12
+ })
13
+ .parse()
@@ -0,0 +1,28 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "lib": [
5
+ "ESNext"
6
+ ],
7
+ "outDir": "./dist",
8
+ "skipLibCheck": true,
9
+ "esModuleInterop": true,
10
+ "strict": true,
11
+ "module": "ESNext",
12
+ "moduleResolution": "node",
13
+ "sourceMap": true,
14
+ "declaration": true,
15
+ "declarationMap": true
16
+ },
17
+ "include": [
18
+ "src"
19
+ ],
20
+ "typedocOptions": {
21
+ "entryPoints": [
22
+ "src/index.ts"
23
+ ],
24
+ "out": "docs",
25
+ "readme": "README.md",
26
+ "gitRemote": "origin"
27
+ }
28
+ }
@@ -1,19 +1,11 @@
1
1
  import { GenerateProgram, TemplateTypeEnum } from '../GenerateProgram'
2
2
  import path from 'path'
3
- import {
4
- mkdir,
5
- pathExists,
6
- readFile,
7
- readJson,
8
- remove,
9
- writeFile,
10
- writeJson,
11
- } from 'fs-extra'
3
+ import { mkdir, pathExists, readFile, readJson, remove, writeFile, writeJson } from 'fs-extra'
12
4
  import { PackageJson } from 'type-fest'
13
5
 
14
6
  describe('测试 InitProgram', () => {
15
7
  const initProgram = new GenerateProgram()
16
- const tempPath = path.resolve(__dirname, 'temp')
8
+ const tempPath = path.resolve(__dirname, '.temp')
17
9
  it('生成项目', async () => {
18
10
  const dest = path.resolve(tempPath, 'lib-demo')
19
11
  await remove(dest)
@@ -22,7 +14,7 @@ describe('测试 InitProgram', () => {
22
14
  dest,
23
15
  })
24
16
  expect(await pathExists(dest)).toBeTruthy()
25
- }, 100_000)
17
+ })
26
18
  describe('测试一些钩子', () => {
27
19
  beforeAll(async () => {
28
20
  await remove(tempPath)
@@ -34,18 +26,26 @@ describe('测试 InitProgram', () => {
34
26
  name: '@liuli-util/template',
35
27
  })
36
28
  await GenerateProgram.updatePackageJSON(tempPath)
37
- expect(
38
- ((await readJson(jsonPath)) as PackageJson).name?.endsWith('temp'),
39
- ).toBeTruthy()
29
+ expect(((await readJson(jsonPath)) as PackageJson).name?.endsWith('temp')).toBeTruthy()
40
30
  })
41
31
  it('测试修改 readme', async () => {
42
32
  const readmePath = path.resolve(tempPath, 'README.md')
43
33
  await writeFile(readmePath, `# @liuli-util/template`)
44
34
  await GenerateProgram.updateReadme(tempPath)
45
35
  console.log('readme: ', await readFile(readmePath, 'utf-8'))
46
- expect(
47
- (await readFile(readmePath, 'utf-8')).endsWith('temp'),
48
- ).toBeTruthy()
36
+ expect((await readFile(readmePath, 'utf-8')).endsWith('temp')).toBeTruthy()
37
+ })
38
+ })
39
+ describe('测试错误修复', () => {
40
+ it('修复 monorepo 中使用 cli 会复制 node_modules 的错误', async () => {
41
+ const program = new GenerateProgram()
42
+ const destPath = path.resolve(tempPath, 'test-cli')
43
+ await program.generate({
44
+ template: TemplateTypeEnum.Cli,
45
+ dest: destPath,
46
+ initSync: false,
47
+ })
48
+ expect(await pathExists(path.resolve(destPath, 'node_modules'))).toBeFalsy()
49
49
  })
50
50
  })
51
51
  })