@liuli-util/cli 3.14.0 → 3.17.1

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 (64) hide show
  1. package/CHANGELOG.md +100 -80
  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.map +1 -1
  22. package/dist/commands/generate/GenerateProgram.d.ts.map +1 -1
  23. package/dist/commands/sync/SyncProgram.d.ts.map +1 -1
  24. package/dist/index.esm.js +1 -1
  25. package/dist/index.esm.js.map +2 -2
  26. package/dist/index.js +2 -2
  27. package/dist/index.js.map +2 -2
  28. package/dist/utils/nodeCacheDir.d.ts +2 -0
  29. package/dist/utils/nodeCacheDir.d.ts.map +1 -0
  30. package/package.json +73 -66
  31. package/src/bin.ts +3 -2
  32. package/src/commands/deploy/DeployService.ts +174 -0
  33. package/src/commands/deploy/__tests__/DeployService.test.ts +75 -0
  34. package/src/commands/deploy/__tests__/FileLock.test.ts +27 -0
  35. package/src/commands/deploy/__tests__/conf.test.ts +29 -0
  36. package/src/commands/deploy/__tests__/simpleGit.test.ts +34 -0
  37. package/src/commands/deploy/__tests__/util/deployGhPageWorker.ts +16 -0
  38. package/src/commands/deploy/deploy.ts +48 -0
  39. package/src/commands/deploy/index.ts +8 -0
  40. package/src/commands/deploy/util/FileLock.ts +31 -0
  41. package/src/commands/deploy/util/PromiseUtil.ts +34 -0
  42. package/src/commands/deploy/util/createArchive.ts +30 -0
  43. package/src/commands/deploy/util/execPromise.ts +13 -0
  44. package/src/commands/deploy/util/wait.ts +23 -0
  45. package/src/commands/esbuild/ESBuildProgram.ts +1 -1
  46. package/src/commands/esbuild/__tests__/.temp/getDeps/package.json +1 -0
  47. package/src/commands/generate/__tests__/.temp/test-cli/CHANGELOG.md +1 -0
  48. package/src/commands/generate/__tests__/.temp/test-cli/README.md +1 -0
  49. package/src/commands/generate/__tests__/.temp/test-cli/bin.js +3 -0
  50. package/src/commands/generate/__tests__/.temp/test-cli/package.json +44 -0
  51. package/src/commands/generate/__tests__/.temp/test-cli/src/bin.ts +13 -0
  52. package/src/commands/generate/__tests__/.temp/test-cli/src/index.ts +1 -0
  53. package/src/commands/generate/__tests__/.temp/test-cli/tsconfig.json +28 -0
  54. package/src/commands/sync/SyncProgram.ts +15 -41
  55. package/src/commands/sync/__tests__/SyncProgram.test.ts +13 -1
  56. package/src/utils/__tests__/nodeCacheDir.test.ts +6 -0
  57. package/src/utils/nodeCacheDir.ts +54 -0
  58. package/templates/cli/package.json +4 -10
  59. package/templates/cli/tsconfig.json +28 -28
  60. package/templates/lib/package.json +2 -8
  61. package/templates/lib/tsconfig.json +28 -28
  62. package/tsconfig.json +34 -34
  63. package/src/commands/sync/__tests__/.temp/lerna.json +0 -6
  64. 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
  * 获取所有依赖
@@ -0,0 +1 @@
1
+ {"devDependencies":{"@types/node":"16"},"dependencies":{"ora":"^6"},"peerDependencies":{"typescript":"^4"}}
@@ -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
+ }
@@ -13,13 +13,9 @@ import { PathUtil } from '../../PathUtil'
13
13
 
14
14
  export async function mergeJson(base: string, json: object): Promise<void> {
15
15
  const pkgJsonFilePath = path.resolve(base, './package.json')
16
- await writeJson(
17
- pkgJsonFilePath,
18
- merge(await readJson(pkgJsonFilePath), json),
19
- {
20
- spaces: 2,
21
- },
22
- )
16
+ await writeJson(pkgJsonFilePath, merge(await readJson(pkgJsonFilePath), json), {
17
+ spaces: 2,
18
+ })
23
19
  }
24
20
 
25
21
  export type SyncConfigType =
@@ -68,10 +64,7 @@ export class SyncProgram {
68
64
  } as PackageJson)
69
65
  },
70
66
  async when(): Promise<boolean> {
71
- return (
72
- (await isNpmPackage()) &&
73
- ((await isYarnRoot()) || !(await isYarnSubModule()))
74
- )
67
+ return (await isNpmPackage()) && ((await isYarnRoot()) || !(await isYarnSubModule()))
75
68
  },
76
69
  },
77
70
  {
@@ -91,23 +84,14 @@ export class SyncProgram {
91
84
  } as PackageJson)
92
85
  },
93
86
  async when(): Promise<boolean> {
94
- return (
95
- (await isNpmPackage()) &&
96
- ((await isYarnRoot()) || !(await isYarnSubModule()))
97
- )
87
+ return (await isNpmPackage()) && ((await isYarnRoot()) || !(await isYarnSubModule()))
98
88
  },
99
89
  },
100
90
  {
101
91
  type: 'gitignore',
102
92
  handler: async () => {
103
93
  const gitignorePath = path.resolve(this.base, '.gitignore')
104
- await writeFile(
105
- gitignorePath,
106
- await readFile(
107
- path.resolve(PathUtil.RootPath, '_gitignore'),
108
- 'utf-8',
109
- ),
110
- )
94
+ await writeFile(gitignorePath, await readFile(path.resolve(PathUtil.RootPath, '_gitignore'), 'utf-8'))
111
95
  },
112
96
  },
113
97
  {
@@ -123,11 +107,7 @@ export class SyncProgram {
123
107
  } as PackageJson)
124
108
  },
125
109
  async when(): Promise<boolean> {
126
- return (
127
- (await isNpmPackage()) &&
128
- !(await isIncludeDep(['vue'])) &&
129
- !(await isIncludeDep(['react']))
130
- )
110
+ return (await isNpmPackage()) && !(await isIncludeDep(['vue'])) && !(await isIncludeDep(['react']))
131
111
  },
132
112
  },
133
113
  {
@@ -154,6 +134,10 @@ export class SyncProgram {
154
134
  preset: 'ts-jest',
155
135
  testMatch: ['<rootDir>/src/**/__tests__/*.test.ts'],
156
136
  },
137
+ devDependencies: {
138
+ jest: '^27.4.3',
139
+ 'ts-jest': '^27.0.7',
140
+ },
157
141
  })
158
142
  },
159
143
  },
@@ -171,10 +155,7 @@ export class SyncProgram {
171
155
  }
172
156
  let config = {
173
157
  scripts: {
174
- postinstall: appendScript(
175
- json?.scripts?.postinstall,
176
- 'npx simple-git-hooks',
177
- ),
158
+ postinstall: appendScript(json?.scripts?.postinstall, 'npx simple-git-hooks'),
178
159
  },
179
160
  'simple-git-hooks': {
180
161
  'pre-commit': 'yarn lint-staged',
@@ -197,26 +178,19 @@ export class SyncProgram {
197
178
  await mergeJson(this.base, config as PackageJson)
198
179
  },
199
180
  async when(): Promise<boolean> {
200
- return (
201
- (await isNpmPackage()) &&
202
- ((await isYarnRoot()) || !(await isYarnSubModule()))
203
- )
181
+ return (await isNpmPackage()) && ((await isYarnRoot()) || !(await isYarnSubModule()))
204
182
  },
205
183
  },
206
184
  ]
207
185
 
208
186
  async sync(): Promise<void> {
209
- const { sync } = (await readJson(
210
- path.resolve(this.base, 'package.json'),
211
- )) as {
187
+ const { sync } = (await readJson(path.resolve(this.base, 'package.json'))) as {
212
188
  sync?: SyncConfigType[]
213
189
  }
214
190
  if (!sync) {
215
191
  return
216
192
  }
217
- const syncConfigs = this.syncConfigs.filter((config) =>
218
- sync.includes(config.type),
219
- )
193
+ const syncConfigs = this.syncConfigs.filter((config) => sync.includes(config.type))
220
194
  for (const syncConfig of syncConfigs) {
221
195
  await syncConfig.handler()
222
196
  }
@@ -30,7 +30,7 @@ describe('测试 SyncProgram', () => {
30
30
  workspaces,
31
31
  } as PackageJson)
32
32
  await syncProgram.sync()
33
- }, 100_000)
33
+ })
34
34
 
35
35
  it.skip('测试初始化同步配置', async () => {
36
36
  await writeJson(path.resolve(tempPath, 'lerna.json'), {})
@@ -42,6 +42,18 @@ describe('测试 SyncProgram', () => {
42
42
  await syncProgram.init()
43
43
  expect(((await readJson(file)).sync as string[]).length).toBeGreaterThan(0)
44
44
  }, 100_000)
45
+
46
+ it('测试同步 jest', async () => {
47
+ const jsonPath = path.resolve(tempPath, 'package.json')
48
+ await writeJson(jsonPath, {
49
+ name: 'temp',
50
+ sync: ['jest'] as SyncConfigType[],
51
+ } as PackageJson)
52
+ await syncProgram.sync()
53
+ const json = (await readJson(jsonPath)) as PackageJson
54
+ const devDeps = Object.keys(json.devDependencies!)
55
+ expect(devDeps.includes('jest') && devDeps.includes('ts-jest')).toBeTruthy()
56
+ })
45
57
  })
46
58
 
47
59
  it('测试 lodash-es.merge', () => {
@@ -0,0 +1,6 @@
1
+ import { nodeCacheDir } from '../nodeCacheDir'
2
+
3
+ it('测试 nodeCacheDir', () => {
4
+ const res = nodeCacheDir('liuli-cli')
5
+ console.log(res)
6
+ })