@liuli-util/cli 3.9.0 → 3.11.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 (82) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +3 -3
  3. package/_gitignore +33 -0
  4. package/dist/PathUtil.d.ts +7 -0
  5. package/dist/PathUtil.d.ts.map +1 -0
  6. package/dist/bin.d.ts +1 -1
  7. package/dist/bin.js +116 -1
  8. package/dist/bin.js.map +7 -1
  9. package/dist/commands/esbuild/ESBuildProgram.d.ts +71 -0
  10. package/dist/commands/esbuild/ESBuildProgram.d.ts.map +1 -0
  11. package/dist/commands/esbuild/index.d.ts +3 -0
  12. package/dist/commands/esbuild/index.d.ts.map +1 -0
  13. package/dist/commands/esbuild/util/debounce.d.ts +15 -0
  14. package/dist/commands/esbuild/util/debounce.d.ts.map +1 -0
  15. package/dist/commands/esbuild/util/esbuildPlugins.d.ts +16 -0
  16. package/dist/commands/esbuild/util/esbuildPlugins.d.ts.map +1 -0
  17. package/dist/commands/generate/GenerateProgram.d.ts +18 -0
  18. package/dist/commands/generate/GenerateProgram.d.ts.map +1 -0
  19. package/dist/commands/generate/index.d.ts +3 -0
  20. package/dist/commands/generate/index.d.ts.map +1 -0
  21. package/dist/commands/sync/SyncProgram.d.ts +15 -0
  22. package/dist/commands/sync/SyncProgram.d.ts.map +1 -0
  23. package/dist/commands/sync/index.d.ts +3 -0
  24. package/dist/commands/sync/index.d.ts.map +1 -0
  25. package/dist/commands/sync/when.d.ts +21 -0
  26. package/dist/commands/sync/when.d.ts.map +1 -0
  27. package/dist/index.d.ts +3 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.esm.js +5 -1
  30. package/dist/index.esm.js.map +7 -1
  31. package/dist/index.js +5 -1
  32. package/dist/index.js.map +7 -1
  33. package/dist/utils/AsyncArray.d.ts +21 -0
  34. package/dist/utils/AsyncArray.d.ts.map +1 -0
  35. package/dist/utils/appendScript.d.ts +7 -0
  36. package/dist/utils/appendScript.d.ts.map +1 -0
  37. package/dist/utils/arrayToMap.d.ts +3 -0
  38. package/dist/utils/arrayToMap.d.ts.map +1 -0
  39. package/dist/utils/findParent.d.ts +8 -0
  40. package/dist/utils/findParent.d.ts.map +1 -0
  41. package/dist/utils/index.d.ts +5 -0
  42. package/dist/utils/index.d.ts.map +1 -0
  43. package/package.json +34 -22
  44. package/src/@types/global.d.ts +8 -0
  45. package/src/PathUtil.ts +8 -0
  46. package/src/bin.ts +5 -5
  47. package/src/commands/esbuild/ESBuildProgram.ts +288 -0
  48. package/src/commands/esbuild/__tests__/ESBuildProgram.test.ts +125 -0
  49. package/src/commands/esbuild/__tests__/spinnies.test.ts +11 -0
  50. package/src/commands/esbuild/index.ts +32 -0
  51. package/src/commands/esbuild/util/debounce.ts +29 -0
  52. package/src/commands/esbuild/util/esbuildPlugins.ts +82 -0
  53. package/src/commands/generate/GenerateProgram.ts +115 -0
  54. package/src/commands/generate/__tests__/GenerateProgram.test.ts +51 -0
  55. package/src/commands/generate/index.ts +26 -0
  56. package/src/commands/sync/SyncProgram.ts +247 -0
  57. package/src/commands/sync/__tests__/SyncProgram.test.ts +50 -0
  58. package/src/commands/sync/__tests__/when.test.ts +46 -0
  59. package/src/commands/sync/index.ts +15 -0
  60. package/src/commands/sync/when.ts +67 -0
  61. package/src/index.ts +3 -1
  62. package/src/utils/AsyncArray.ts +144 -0
  63. package/src/utils/__tests__/appendScript.test.ts +15 -0
  64. package/src/utils/__tests__/arrayToMap.test.ts +37 -0
  65. package/src/utils/__tests__/findParent.test.ts +15 -0
  66. package/src/utils/appendScript.ts +17 -0
  67. package/src/utils/arrayToMap.ts +27 -0
  68. package/src/utils/findParent.ts +36 -0
  69. package/src/utils/index.ts +4 -0
  70. package/templates/cli/CHANGELOG.md +1 -0
  71. package/templates/cli/README.md +1 -0
  72. package/templates/cli/package.json +44 -0
  73. package/templates/cli/src/bin.ts +13 -0
  74. package/templates/cli/src/index.ts +1 -0
  75. package/templates/cli/tsconfig.json +28 -0
  76. package/templates/lib/CHANGELOG.md +1 -0
  77. package/templates/lib/README.md +1 -0
  78. package/templates/lib/package.json +32 -0
  79. package/templates/lib/src/__tests__/hello.test.ts +5 -0
  80. package/templates/lib/src/index.ts +3 -0
  81. package/templates/lib/tsconfig.json +28 -0
  82. package/tsconfig.json +34 -28
package/src/index.ts CHANGED
@@ -1 +1,3 @@
1
- export {}
1
+ export * from './commands/esbuild/ESBuildProgram'
2
+ export * from './commands/generate/GenerateProgram'
3
+ export * from './commands/sync/SyncProgram'
@@ -0,0 +1,144 @@
1
+ import { IterableElement } from 'type-fest'
2
+
3
+ enum ActionTypeEnum {
4
+ Filter = 'filter',
5
+ Map = 'map',
6
+ ForEach = 'forEach',
7
+ Reduce = 'reduce',
8
+ FlatMap = 'flatMap',
9
+ }
10
+
11
+ class Action {
12
+ public static Type = ActionTypeEnum
13
+
14
+ constructor(
15
+ public readonly type: ActionTypeEnum,
16
+ public readonly args: any[],
17
+ ) {
18
+ this.type = type
19
+ this.args = args
20
+ }
21
+ }
22
+
23
+ /**
24
+ * 异步数组,支持静态方法和链式调用
25
+ */
26
+ export class AsyncArray<T> implements PromiseLike<T[]> {
27
+ static reduce<T extends any[], R>(
28
+ arr: T,
29
+ fn: (res: R, item: IterableElement<T>, index: number) => Promise<R>,
30
+ res: R,
31
+ ): Promise<R> {
32
+ return arr.reduce(
33
+ (res: Promise<R>, item: IterableElement<T>, index: number) =>
34
+ res.then((r) => fn(r, item, index)),
35
+ Promise.resolve(res),
36
+ )
37
+ }
38
+
39
+ static map<T, R>(
40
+ arr: T[],
41
+ fn: (item: T, index: number) => Promise<R>,
42
+ ): Promise<R[]> {
43
+ return Promise.all(arr.map((item, index) => fn(item, index)))
44
+ }
45
+
46
+ static async filter<T>(
47
+ arr: T[],
48
+ fn: (item: T, index: number) => Promise<boolean>,
49
+ ): Promise<T[]> {
50
+ const res: T[] = []
51
+ await AsyncArray.map(arr, async (item, index) => {
52
+ if (await fn(item, index)) {
53
+ res.push(item)
54
+ }
55
+ })
56
+ return res
57
+ }
58
+
59
+ static async flatMap<T, R>(
60
+ arr: T[],
61
+ fn: (item: T, index: number) => Promise<R[]>,
62
+ ): Promise<R[]> {
63
+ return (
64
+ await Promise.all(arr.map((item, index) => fn(item, index)))
65
+ ).flatMap((r) => r)
66
+ }
67
+
68
+ static async forEach<T extends any[]>(
69
+ arr: T,
70
+ fn: (item: IterableElement<T>, index: number) => Promise<void>,
71
+ ): Promise<void> {
72
+ await AsyncArray.map(arr, fn)
73
+ }
74
+
75
+ private tasks: Action[] = []
76
+
77
+ constructor(private readonly arr: T[]) {}
78
+
79
+ map<R>(fn: (item: T, index: number) => Promise<R>): AsyncArray<R> {
80
+ this.tasks.push(new Action(ActionTypeEnum.Map, [fn]))
81
+ return this as any
82
+ }
83
+
84
+ flatMap<R>(fn: (item: T, index: number) => Promise<R[]>): AsyncArray<R> {
85
+ this.tasks.push(new Action(ActionTypeEnum.FlatMap, [fn]))
86
+ return this as any
87
+ }
88
+
89
+ filter(fn: (item: T, index: number) => Promise<boolean>): this {
90
+ this.tasks.push(new Action(ActionTypeEnum.Filter, [fn]))
91
+ return this
92
+ }
93
+
94
+ async forEach<R>(fn: (item: T, index: number) => Promise<R>): Promise<void> {
95
+ this.tasks.push(new Action(ActionTypeEnum.Map, [fn]))
96
+ await this
97
+ }
98
+
99
+ then<TResult1 = T[], TResult2 = never>(
100
+ resolve?:
101
+ | ((value: T[]) => PromiseLike<TResult1> | TResult1)
102
+ | undefined
103
+ | null,
104
+ reject?:
105
+ | ((reason: any) => PromiseLike<TResult2> | TResult2)
106
+ | undefined
107
+ | null,
108
+ ): PromiseLike<TResult1 | TResult2> {
109
+ const res = this.value()
110
+ res
111
+ .then((r) => {
112
+ resolve && resolve(res as any)
113
+ return r
114
+ })
115
+ .catch((e) => {
116
+ reject && reject(e as any)
117
+ throw e
118
+ })
119
+ return res as any
120
+ }
121
+
122
+ private async value(): Promise<any> {
123
+ let res = this.arr
124
+ for (const task of this.tasks) {
125
+ switch (task.type) {
126
+ case ActionTypeEnum.Filter:
127
+ res = await AsyncArray.filter(res, task.args[0])
128
+ break
129
+ case ActionTypeEnum.Map:
130
+ res = await AsyncArray.map(res, task.args[0])
131
+ break
132
+ case ActionTypeEnum.FlatMap:
133
+ res = await AsyncArray.flatMap(res, task.args[0])
134
+ break
135
+ case ActionTypeEnum.ForEach:
136
+ await AsyncArray.forEach(res, task.args[0])
137
+ return
138
+ case ActionTypeEnum.Reduce:
139
+ return await AsyncArray.reduce(res, task.args[0], task.args[1])
140
+ }
141
+ }
142
+ return res
143
+ }
144
+ }
@@ -0,0 +1,15 @@
1
+ import { appendScript } from '../appendScript'
2
+
3
+ describe('测试 appendScript', () => {
4
+ const newScript = 'liuli-cli sync'
5
+ it('脚本不存在', () => {
6
+ expect(appendScript(undefined, newScript)).toBe(newScript)
7
+ })
8
+ it('脚本存在但不包含新的脚本', () => {
9
+ expect(appendScript('tsc', newScript)).toBe('tsc && ' + newScript)
10
+ })
11
+ it('脚本存在且包含新的脚本', () => {
12
+ const oldScript = `${newScript} && tsc`
13
+ expect(appendScript(oldScript, newScript)).toBe(oldScript)
14
+ })
15
+ })
@@ -0,0 +1,37 @@
1
+ import { arrayToMap } from '../arrayToMap'
2
+
3
+ /**
4
+ * @test {arrayToMap}
5
+ */
6
+ describe('test arrayToMap', () => {
7
+ it('arrayToMap [1, 2, 3] to equals Map({1 => 1, 2 => 2, 3 => 3})', () => {
8
+ const arr = [1, 2, 3]
9
+ expect(arrayToMap(arr, (i: any) => i)).toEqual(
10
+ new Map().set(1, 1).set(2, 2).set(3, 3),
11
+ )
12
+ })
13
+ it('use vFn', () => {
14
+ const arr = [1, 2, 3]
15
+ expect(
16
+ arrayToMap(
17
+ arr,
18
+ (v) => v,
19
+ (i) => i * 2 + '',
20
+ ),
21
+ ).toEqual(new Map().set(1, '2').set(2, '4').set(3, '6'))
22
+ })
23
+ it('use string k/v field', () => {
24
+ class User {
25
+ constructor(public id: number, public name: string) {}
26
+ }
27
+
28
+ const arr = [new User(1, 'rx'), new User(2, '琉璃'), new User(3, '楚轩')]
29
+ expect(
30
+ arrayToMap(
31
+ arr,
32
+ (item) => item.id,
33
+ (item) => item.name,
34
+ ),
35
+ ).toEqual(new Map().set(1, 'rx').set(2, '琉璃').set(3, '楚轩'))
36
+ })
37
+ })
@@ -0,0 +1,15 @@
1
+ import { findParent } from '../findParent'
2
+ import { mkdir, remove } from 'fs-extra'
3
+ import path from 'path'
4
+
5
+ describe('测试 findParent', () => {
6
+ it('基本示例', async () => {
7
+ const tempPath = path.resolve(__dirname, 'temp')
8
+ await mkdir(tempPath)
9
+ expect(findParent(tempPath, (dir) => dir === __dirname)).toBe(__dirname)
10
+ await remove(tempPath)
11
+ })
12
+ it('测试找不到的情况', () => {
13
+ expect(findParent(__dirname, () => false)).toBeNull()
14
+ })
15
+ })
@@ -0,0 +1,17 @@
1
+ /**
2
+ * 在之前的脚本中追加新的脚本
3
+ * @param oldScript
4
+ * @param newScript
5
+ */
6
+ export function appendScript(
7
+ oldScript: string | undefined,
8
+ newScript: string,
9
+ ): string {
10
+ if (!oldScript) {
11
+ return newScript
12
+ }
13
+ if (oldScript.includes(newScript)) {
14
+ return oldScript
15
+ }
16
+ return oldScript + ' && ' + newScript
17
+ }
@@ -0,0 +1,27 @@
1
+ export function arrayToMap<T, K>(
2
+ arr: T[],
3
+ kFn: (item: T, index: number, arr: T[]) => K,
4
+ ): Map<K, T>
5
+ export function arrayToMap<T, K, V>(
6
+ arr: T[],
7
+ kFn: (item: T, index: number, arr: T[]) => K,
8
+ vFn: (item: T, index: number, arr: T[]) => V,
9
+ ): Map<K, V>
10
+ /**
11
+ * 将数组映射为 Map
12
+ * @param arr 数组
13
+ * @param kFn 产生 Map 元素唯一标识的函数
14
+ * @param vFn 产生 Map 值的函数,默认为返回数组的元素
15
+ * @returns 映射产生的 map 集合
16
+ */
17
+ export function arrayToMap<T, K, V>(
18
+ arr: T[],
19
+ kFn: (item: T, index: number, arr: T[]) => K,
20
+ vFn: (item: T, index: number, arr: T[]) => V = (v) => v as any,
21
+ ): Map<K, V> {
22
+ return arr.reduce(
23
+ (res, item, index, arr) =>
24
+ res.set(kFn(item, index, arr), vFn(item, index, arr)),
25
+ new Map<K, V>(),
26
+ )
27
+ }
@@ -0,0 +1,36 @@
1
+ import path from 'path'
2
+
3
+ /**
4
+ * 向上查找目录
5
+ * @param cwd
6
+ * @param predicate
7
+ */
8
+ export function findParent(
9
+ cwd: string,
10
+ predicate: (dir: string) => boolean,
11
+ ): string | null
12
+ export function findParent(
13
+ cwd: string,
14
+ predicate: (dir: string) => Promise<boolean>,
15
+ ): Promise<string | null>
16
+ export function findParent<
17
+ T extends (dir: string) => boolean | Promise<boolean>,
18
+ R extends string | null,
19
+ >(
20
+ cwd: string,
21
+ predicate: T,
22
+ ): ReturnType<T> extends Promise<any> ? Promise<R> : R {
23
+ const res = predicate(cwd)
24
+ function f(res: boolean): string | null {
25
+ if (res) {
26
+ return cwd
27
+ }
28
+ const parent = path.dirname(cwd)
29
+ if (parent === cwd) {
30
+ return null
31
+ }
32
+ return findParent(parent, predicate as any)
33
+ }
34
+
35
+ return res instanceof Promise ? res.then(f) : (f(res) as any)
36
+ }
@@ -0,0 +1,4 @@
1
+ export * from './arrayToMap'
2
+ export * from './appendScript'
3
+ export * from './findParent'
4
+ export * from './AsyncArray'
@@ -0,0 +1 @@
1
+ # CHANGELOG
@@ -0,0 +1 @@
1
+ # @liuli-util/cli-template
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@liuli-util/cli-template",
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": "dist/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.0",
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 @@
1
+ export {}
@@ -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
+ }
@@ -0,0 +1 @@
1
+ # CHANGELOG
@@ -0,0 +1 @@
1
+ # @liuli-util/lib-template
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@liuli-util/lib-template",
3
+ "private": true,
4
+ "version": "0.1.0",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.esm.js",
7
+ "types": "dist/index.d.ts",
8
+ "license": "MIT",
9
+ "scripts": {
10
+ "build": "rimraf dist && liuli-cli build pkg",
11
+ "dev": "liuli-cli build pkg -w",
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
+ "jest": {
18
+ "preset": "ts-jest"
19
+ },
20
+ "devDependencies": {
21
+ "@liuli-util/cli": "^3.11.0",
22
+ "@types/jest": "^27.0.2",
23
+ "esno": "^0.9.1",
24
+ "gh-pages": "^3.2.3",
25
+ "jest": "^27.2.1",
26
+ "rimraf": "^3.0.2",
27
+ "ts-jest": "^27.0.5",
28
+ "type-fest": "^2.3.4",
29
+ "typedoc": "^0.22.4",
30
+ "typescript": "^4.4.3"
31
+ }
32
+ }
@@ -0,0 +1,5 @@
1
+ import { hello } from '../index'
2
+
3
+ it('测试 hello', () => {
4
+ expect(hello('liuli')).toBe('hello liuli')
5
+ })
@@ -0,0 +1,3 @@
1
+ export function hello(name: string) {
2
+ return `hello ${name}`
3
+ }
@@ -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
+ }
package/tsconfig.json CHANGED
@@ -1,28 +1,34 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES6",
4
- "lib": ["ESNext"],
5
- "outDir": "./dist",
6
- "skipLibCheck": true,
7
- "esModuleInterop": true,
8
- "strict": true,
9
- "module": "ESNext",
10
- "moduleResolution": "node",
11
- "sourceMap": true,
12
- "declaration": true,
13
- "declarationMap": true,
14
- "resolveJsonModule": true
15
- },
16
- "include": ["src"],
17
- "typedocOptions": {
18
- "entryPoints": ["src/index.ts"],
19
- "out": "docs",
20
- "readme": "README.md",
21
- "gitRemote": "origin"
22
- },
23
- "ts-node": {
24
- "compilerOptions": {
25
- "module": "CommonJS"
26
- }
27
- }
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
+ "resolveJsonModule": true
17
+ },
18
+ "include": [
19
+ "src"
20
+ ],
21
+ "typedocOptions": {
22
+ "entryPoints": [
23
+ "src/index.ts"
24
+ ],
25
+ "out": "docs",
26
+ "readme": "README.md",
27
+ "gitRemote": "origin"
28
+ },
29
+ "ts-node": {
30
+ "compilerOptions": {
31
+ "module": "CommonJS"
32
+ }
33
+ }
34
+ }