inquirer-plugins 1.0.0-alpha.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.
- package/README.md +1 -0
- package/dist/_internal/plugins/table/table.d.ts +11 -0
- package/dist/_internal/plugins/table/table.js +59 -0
- package/dist/_internal/plugins/table/types.d.ts +45 -0
- package/dist/_internal/plugins/table/types.js +23 -0
- package/dist/_internal/plugins/table/utils.d.ts +3 -0
- package/dist/_internal/plugins/table/utils.js +22 -0
- package/dist/_internal/plugins/table.d.ts +49 -0
- package/dist/_internal/plugins/table.js +257 -0
- package/dist/_internal/plugins/test.d.ts +1 -0
- package/dist/_internal/plugins/test.js +47 -0
- package/dist/_internal/types/inquirer.d.ts +1 -0
- package/dist/_internal/types/inquirer.js +1 -0
- package/dist/_internal/types/parse-types.d.ts +6 -0
- package/dist/_internal/types/parse-types.js +5 -0
- package/dist/_internal/utils/chalk.d.ts +9 -0
- package/dist/_internal/utils/chalk.js +10 -0
- package/dist/_internal/utils/keypress.d.ts +3 -0
- package/dist/_internal/utils/keypress.js +14 -0
- package/dist/_internal/utils/parse-types.d.ts +3 -0
- package/dist/_internal/utils/parse-types.js +22 -0
- package/dist/modules/table.d.ts +2 -0
- package/dist/modules/table.js +2 -0
- package/dist/modules/types/inquirer.d.ts +1 -0
- package/dist/modules/types/inquirer.js +1 -0
- package/dist/modules/types/parse-types.d.ts +1 -0
- package/dist/modules/types/parse-types.js +1 -0
- package/package.json +86 -0
- package/src/_internal/plugins/table/table.ts +68 -0
- package/src/_internal/plugins/table/types.ts +71 -0
- package/src/_internal/plugins/table/utils.ts +25 -0
- package/src/_internal/plugins/table.ts +299 -0
- package/src/_internal/plugins/test.ts +58 -0
- package/src/_internal/types/inquirer.ts +1 -0
- package/src/_internal/types/parse-types.ts +7 -0
- package/src/_internal/utils/chalk.ts +13 -0
- package/src/_internal/utils/keypress.ts +16 -0
- package/src/_internal/utils/parse-types.ts +25 -0
- package/src/modules/table.ts +2 -0
- package/src/modules/types/inquirer.ts +1 -0
- package/src/modules/types/parse-types.ts +1 -0
- package/table/package.json +6 -0
- package/tsconfig.json +27 -0
- package/types/inquirer/package.json +6 -0
- package/types/parse-types/package.json +6 -0
package/package.json
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "inquirer-plugins",
|
|
3
|
+
"version": "1.0.0-alpha.1",
|
|
4
|
+
"main": "index.js",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"prepare": "husky",
|
|
8
|
+
"lint": "eslint .",
|
|
9
|
+
"lint:fix": "npm run lint -- --fix",
|
|
10
|
+
"_prettier": "prettier .",
|
|
11
|
+
"prettier:write": "npm run _prettier -- --write",
|
|
12
|
+
"prettier": "npm run prettier:write",
|
|
13
|
+
"prettier:check": "npm run _prettier -- --check",
|
|
14
|
+
"clean": "rimraf ./dist ./cli",
|
|
15
|
+
"tsc": "tsc -p tsconfig.publish.json && tsc-alias -p tsconfig.publish.json",
|
|
16
|
+
"generate": "tsx --tsconfig ./tsconfig.tsx.json ./tools/generate-alias.zx.ts",
|
|
17
|
+
"ci:update-version": "tsx --tsconfig ./tsconfig.tsx.json ./tools/update-version.zx.ts",
|
|
18
|
+
"md:generate": "tsx --tsconfig ./tsconfig.tsx.json ./tools/generate-md.ts",
|
|
19
|
+
"//--- test ---//": "",
|
|
20
|
+
"test": "run-s test:*",
|
|
21
|
+
"test:lint": "npm run lint",
|
|
22
|
+
"test:prettier": "npm run prettier:check",
|
|
23
|
+
"//--- build ---//": "",
|
|
24
|
+
"build": "run-s build:*",
|
|
25
|
+
"build:test": "npm run test",
|
|
26
|
+
"build:clean": "npm run clean",
|
|
27
|
+
"build:tsc": "npm run tsc",
|
|
28
|
+
"build:generate": "npm run generate",
|
|
29
|
+
"//--- publish ---//": "",
|
|
30
|
+
"publish:build": "run-s build:{clean,tsc,generate}",
|
|
31
|
+
"dry-run": "tsx --tsconfig ./tsconfig.tsx.json ./src/_internal/plugins/test.ts"
|
|
32
|
+
},
|
|
33
|
+
"author": "",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"description": "",
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=19.0.0"
|
|
38
|
+
},
|
|
39
|
+
"exports": {
|
|
40
|
+
".": "./dist/**/*.js",
|
|
41
|
+
"./table": "./dist/modules/table.js",
|
|
42
|
+
"./types/inquirer": "./dist/modules/types/inquirer.js",
|
|
43
|
+
"./types/parse-types": "./dist/modules/types/parse-types.js",
|
|
44
|
+
"./package.json": "./package.json"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@actions/core": "^1.10.1",
|
|
48
|
+
"@actions/exec": "^1.1.1",
|
|
49
|
+
"@actions/github": "^6.0.0",
|
|
50
|
+
"chalk": "^5.3.0",
|
|
51
|
+
"cli-cursor": "^4.0.0",
|
|
52
|
+
"cli-table3": "^0.6.5",
|
|
53
|
+
"inquirer": "^9.2.23",
|
|
54
|
+
"zx": "^8.1.2"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@eslint/js": "^8.57.0",
|
|
58
|
+
"@types/inquirer": "^9.0.7",
|
|
59
|
+
"@typescript-eslint/eslint-plugin": "^7.9.0",
|
|
60
|
+
"@typescript-eslint/parser": "^7.9.0",
|
|
61
|
+
"eslint": "^8.57.0",
|
|
62
|
+
"eslint-config-prettier": "^9.1.0",
|
|
63
|
+
"eslint-import-resolver-typescript": "^3.6.1",
|
|
64
|
+
"eslint-plugin-import": "^2.29.1",
|
|
65
|
+
"eslint-plugin-jest": "^28.5.0",
|
|
66
|
+
"eslint-plugin-unused-imports": "^3.2.0",
|
|
67
|
+
"husky": "^9.0.11",
|
|
68
|
+
"lint-staged": "^15.2.5",
|
|
69
|
+
"my-gadgetry": "^1.2.5",
|
|
70
|
+
"npm-run-all2": "^6.2.0",
|
|
71
|
+
"prettier": "^3.3.1",
|
|
72
|
+
"tsc-alias": "^1.8.10",
|
|
73
|
+
"tsx": "^4.14.1",
|
|
74
|
+
"typescript": "^5.4.5",
|
|
75
|
+
"typescript-eslint": "^7.12.0"
|
|
76
|
+
},
|
|
77
|
+
"files": [
|
|
78
|
+
"!**/__tests__",
|
|
79
|
+
"dist",
|
|
80
|
+
"types",
|
|
81
|
+
"table",
|
|
82
|
+
"src",
|
|
83
|
+
"package.json",
|
|
84
|
+
"tsconfig.json"
|
|
85
|
+
]
|
|
86
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { PARSE_TYPES } from '~types/parse-types.js'
|
|
2
|
+
import { trim } from '~utils/chalk.js'
|
|
3
|
+
import { parse } from '~utils/parse-types.js'
|
|
4
|
+
|
|
5
|
+
import { Column, Cell } from './types.js'
|
|
6
|
+
|
|
7
|
+
export class TableClass {
|
|
8
|
+
columns: Column[] = []
|
|
9
|
+
rows: string[][] = []
|
|
10
|
+
|
|
11
|
+
constructor(columns: Column[], rows: Cell[][]) {
|
|
12
|
+
this.columns = columns
|
|
13
|
+
this.rows = rows.map(columns => columns.map(value => `${value}`))
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
get header() {
|
|
17
|
+
return this.columns.map(({ name }) => `${name}`)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
getColumnType(columnIndex: number) {
|
|
21
|
+
if (!(columnIndex in this.columns)) {
|
|
22
|
+
return PARSE_TYPES.input
|
|
23
|
+
}
|
|
24
|
+
return this.columns[columnIndex].type
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
updateRow(rowIndex: number, columnIndex: number, value: string) {
|
|
28
|
+
if (!(rowIndex in this.rows)) {
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
const columns = this.rows[rowIndex]
|
|
32
|
+
if (!(columnIndex in columns)) {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
const validate = this.columns[columnIndex].validate || (() => true)
|
|
36
|
+
if (!validate(value)) {
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
const parser = this.columns[columnIndex].parser || ((txt: string) => txt)
|
|
40
|
+
const parsed = parser(value)
|
|
41
|
+
columns[columnIndex] = `${parsed}`
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
getValue(rowIndex: number, columnIndex: number) {
|
|
45
|
+
if (!(rowIndex in this.rows)) {
|
|
46
|
+
return ''
|
|
47
|
+
}
|
|
48
|
+
const columns = this.rows[rowIndex]
|
|
49
|
+
if (!(columnIndex in columns)) {
|
|
50
|
+
return ''
|
|
51
|
+
}
|
|
52
|
+
return columns[columnIndex]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
getResult() {
|
|
56
|
+
const result: Record<string, Cell>[] = []
|
|
57
|
+
for (let i = 0; i < this.rows.length; i++) {
|
|
58
|
+
result.push({})
|
|
59
|
+
for (let ii = 0; ii < (this.rows[i] || []).length; ii++) {
|
|
60
|
+
const { name: n, type, parser } = this.columns[ii]
|
|
61
|
+
const name = trim(n.toString())
|
|
62
|
+
const value = trim(this.rows[i][ii])
|
|
63
|
+
result[i][name] = parser ? parser(value) : parse(value, type)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return result
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import chalk, { ChalkInstance } from 'chalk'
|
|
2
|
+
|
|
3
|
+
import { ParseType } from '~types/parse-types.js'
|
|
4
|
+
import { hop, success, warn } from '~utils/chalk.js'
|
|
5
|
+
|
|
6
|
+
export const DEFAULT_PAGE_SIZE = 5
|
|
7
|
+
export const INDEX_ERRORS = Object.freeze({
|
|
8
|
+
excess: 'excess',
|
|
9
|
+
disabled: 'disabled',
|
|
10
|
+
} as const)
|
|
11
|
+
|
|
12
|
+
export interface DefaultOptions extends Required<Omit<TableQuestion, 'type' | 'name' | 'colors'>> {
|
|
13
|
+
colors: Colors
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const DEFAULT_OPTIONS: DefaultOptions = {
|
|
17
|
+
message: '',
|
|
18
|
+
description: '',
|
|
19
|
+
escapeMessage: chalk.red('Press ESC again to exit!'),
|
|
20
|
+
confirmMessage: chalk.red('Press ENTER again to confirm!'),
|
|
21
|
+
disableColumnIndexes: [],
|
|
22
|
+
colors: {
|
|
23
|
+
selected: warn,
|
|
24
|
+
editable: success,
|
|
25
|
+
editing: hop,
|
|
26
|
+
},
|
|
27
|
+
columns: [],
|
|
28
|
+
rows: [],
|
|
29
|
+
pageSize: DEFAULT_PAGE_SIZE,
|
|
30
|
+
validate: () => ({ isValid: true, message: '' }),
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface RequiredOptions extends Required<Omit<TableQuestion, 'colors'>> {
|
|
34
|
+
colors: Colors
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface Colors {
|
|
38
|
+
selected: ChalkInstance
|
|
39
|
+
editable: ChalkInstance
|
|
40
|
+
editing: ChalkInstance
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface ValidateResult {
|
|
44
|
+
isValid: boolean
|
|
45
|
+
message: string
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface TableQuestion {
|
|
49
|
+
type: string
|
|
50
|
+
name: string
|
|
51
|
+
message?: string | ChalkInstance
|
|
52
|
+
description?: string | ChalkInstance
|
|
53
|
+
escapeMessage?: string | ChalkInstance
|
|
54
|
+
confirmMessage?: string | ChalkInstance
|
|
55
|
+
disableColumnIndexes?: number[]
|
|
56
|
+
colors?: Partial<Colors>
|
|
57
|
+
columns: Column[]
|
|
58
|
+
rows: Cell[][]
|
|
59
|
+
validate?: (...args: any[]) => ValidateResult
|
|
60
|
+
pageSize?: number
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface Column {
|
|
64
|
+
name: string | ChalkInstance
|
|
65
|
+
value: string
|
|
66
|
+
type: ParseType
|
|
67
|
+
validate?: (input: string) => boolean
|
|
68
|
+
parser?: (input: any) => any
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export type Cell = number | string | boolean
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { INDEX_ERRORS } from '~internal/plugins/table/types.js'
|
|
2
|
+
|
|
3
|
+
export const isNoChoiceOfIndex = (maxIndex: number, disableIndexes: number[]) => {
|
|
4
|
+
return disableIndexes.length > maxIndex && [...Array(maxIndex).keys()].every(index => disableIndexes.includes(index))
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const gateValidateColumnIndexError = (index: number, maxIndex: number, disableIndexes: number[]) => {
|
|
8
|
+
if (index > maxIndex || index < 0) {
|
|
9
|
+
return INDEX_ERRORS.excess
|
|
10
|
+
}
|
|
11
|
+
if (disableIndexes.includes(index)) {
|
|
12
|
+
return INDEX_ERRORS.disabled
|
|
13
|
+
}
|
|
14
|
+
return false
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const getNextIndex = (index: number, maxIndex: number, num: number) => {
|
|
18
|
+
if (index > maxIndex) {
|
|
19
|
+
return 0
|
|
20
|
+
}
|
|
21
|
+
if (index < 0) {
|
|
22
|
+
return maxIndex
|
|
23
|
+
}
|
|
24
|
+
return index > maxIndex ? 0 : index + num
|
|
25
|
+
}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { Interface as ReadLineInterface, Key } from 'readline'
|
|
2
|
+
|
|
3
|
+
import { ChalkInstance } from 'chalk'
|
|
4
|
+
import cliCursor from 'cli-cursor'
|
|
5
|
+
import Table from 'cli-table3'
|
|
6
|
+
import { Question, Answers } from 'inquirer'
|
|
7
|
+
import Base from 'inquirer/lib/prompts/base.js'
|
|
8
|
+
import observe from 'inquirer/lib/utils/events.js'
|
|
9
|
+
import { map } from 'rxjs/operators'
|
|
10
|
+
|
|
11
|
+
import { Done } from '~types/inquirer.js'
|
|
12
|
+
import { dim, error } from '~utils/chalk.js'
|
|
13
|
+
import { getKeypressValue } from '~utils/keypress.js'
|
|
14
|
+
|
|
15
|
+
import { TableClass } from './table/table.js'
|
|
16
|
+
import { DEFAULT_OPTIONS, RequiredOptions, TableQuestion } from './table/types.js'
|
|
17
|
+
import { isNoChoiceOfIndex, gateValidateColumnIndexError, getNextIndex } from './table/utils.js'
|
|
18
|
+
|
|
19
|
+
export class TablePlugin extends Base {
|
|
20
|
+
table = new TableClass([], [])
|
|
21
|
+
options!: RequiredOptions
|
|
22
|
+
|
|
23
|
+
done!: Done
|
|
24
|
+
|
|
25
|
+
pointerIndexes = {
|
|
26
|
+
row: 0,
|
|
27
|
+
column: 0,
|
|
28
|
+
}
|
|
29
|
+
isNextCloses = {
|
|
30
|
+
escape: false,
|
|
31
|
+
}
|
|
32
|
+
editing = false
|
|
33
|
+
temporaryBackup: string | null = null
|
|
34
|
+
answers: Answers = []
|
|
35
|
+
|
|
36
|
+
constructor(question: Question<TableQuestion>, readLine: ReadLineInterface, answers: Answers) {
|
|
37
|
+
super({ ...question, validate: () => false } as Question, readLine, answers)
|
|
38
|
+
this.options = {
|
|
39
|
+
...DEFAULT_OPTIONS,
|
|
40
|
+
...(this.opt as any),
|
|
41
|
+
validate: question.validate || DEFAULT_OPTIONS.validate,
|
|
42
|
+
}
|
|
43
|
+
this.answers = answers
|
|
44
|
+
this.table = new TableClass(this.options.columns, this.options.rows)
|
|
45
|
+
|
|
46
|
+
if (isNoChoiceOfIndex(this.maxColumnIndex, this.options.disableColumnIndexes)) {
|
|
47
|
+
throw new Error('disableColumnIndexes contains all of index.')
|
|
48
|
+
}
|
|
49
|
+
this.pointerIndexes.row = 0
|
|
50
|
+
this.updateColumnIndex(1)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
getCurrentValues() {
|
|
54
|
+
return this.table.getResult()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
isEditable(index: number) {
|
|
58
|
+
return !this.options.disableColumnIndexes.includes(index)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
_run(callback: Done) {
|
|
62
|
+
this.done = callback
|
|
63
|
+
|
|
64
|
+
const events = observe(this.rl)
|
|
65
|
+
const validation = this.handleSubmitEvents(events.line.pipe(map(this.getCurrentValues.bind(this))))
|
|
66
|
+
validation.success.forEach(this.onEnd.bind(this))
|
|
67
|
+
validation.error.forEach(this.onError.bind(this))
|
|
68
|
+
|
|
69
|
+
events.keypress.forEach(({ key }) => {
|
|
70
|
+
if (key.name !== 'escape') {
|
|
71
|
+
this.isNextCloses.escape = false
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!this.editing) {
|
|
75
|
+
switch (key.name) {
|
|
76
|
+
case 'down':
|
|
77
|
+
return this.onDownKey()
|
|
78
|
+
|
|
79
|
+
case 'up':
|
|
80
|
+
return this.onUpKey()
|
|
81
|
+
|
|
82
|
+
case 'left':
|
|
83
|
+
return this.onLeftKey()
|
|
84
|
+
|
|
85
|
+
case 'right':
|
|
86
|
+
return this.onRightKey()
|
|
87
|
+
|
|
88
|
+
case 'escape':
|
|
89
|
+
if (!this.isNextCloses.escape) {
|
|
90
|
+
this.isNextCloses.escape = true
|
|
91
|
+
return this.render()
|
|
92
|
+
} else {
|
|
93
|
+
this.render()
|
|
94
|
+
return this.onEnd(false)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
default:
|
|
98
|
+
if (this.isEditable(this.pointerIndexes.column)) {
|
|
99
|
+
this.editing = true
|
|
100
|
+
this.onEditPress(key)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
return this.onEditPress(key)
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
cliCursor.hide()
|
|
109
|
+
this.render()
|
|
110
|
+
|
|
111
|
+
return this
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
get maxPageIndex() {
|
|
115
|
+
return this.options.pageSize - 1
|
|
116
|
+
}
|
|
117
|
+
get maxRowIndex() {
|
|
118
|
+
return this.table.rows.length - 1
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
get maxColumnIndex() {
|
|
122
|
+
return this.table.columns.length - 1
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
onDownKey() {
|
|
126
|
+
if (this.pointerIndexes.row < this.maxRowIndex) {
|
|
127
|
+
++this.pointerIndexes.row
|
|
128
|
+
}
|
|
129
|
+
this.render()
|
|
130
|
+
}
|
|
131
|
+
onUpKey() {
|
|
132
|
+
if (this.pointerIndexes.row > 0) {
|
|
133
|
+
--this.pointerIndexes.row
|
|
134
|
+
}
|
|
135
|
+
this.render()
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
updateColumnIndex(num: number) {
|
|
139
|
+
let index = this.pointerIndexes.column
|
|
140
|
+
for (let c = 0; c <= this.maxColumnIndex; c++) {
|
|
141
|
+
index = getNextIndex(index, this.maxColumnIndex, num)
|
|
142
|
+
const error = gateValidateColumnIndexError(index, this.maxColumnIndex, this.options.disableColumnIndexes)
|
|
143
|
+
if (!error) {
|
|
144
|
+
break
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
this.pointerIndexes.column = index
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
onLeftKey() {
|
|
151
|
+
this.updateColumnIndex(-1)
|
|
152
|
+
this.render()
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
onRightKey() {
|
|
156
|
+
this.updateColumnIndex(1)
|
|
157
|
+
this.render()
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
clear() {
|
|
161
|
+
this.temporaryBackup = null
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
onEnd(state: any) {
|
|
165
|
+
this.render(true)
|
|
166
|
+
this.clear()
|
|
167
|
+
this.status = 'answered'
|
|
168
|
+
this.screen.done()
|
|
169
|
+
cliCursor.show()
|
|
170
|
+
if (state) {
|
|
171
|
+
return this.done({
|
|
172
|
+
state,
|
|
173
|
+
result: this.table.getResult(),
|
|
174
|
+
})
|
|
175
|
+
} else {
|
|
176
|
+
return this.done({
|
|
177
|
+
state,
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
validate() {
|
|
183
|
+
return this.options.validate(this.getCurrentValues(), this.answers)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
onError(_state: any) {
|
|
187
|
+
this.clear()
|
|
188
|
+
if (this.editing) {
|
|
189
|
+
this.editing = false
|
|
190
|
+
this.render()
|
|
191
|
+
} else {
|
|
192
|
+
if (this.validate().isValid) {
|
|
193
|
+
return this.onEnd(true)
|
|
194
|
+
} else {
|
|
195
|
+
return this.render()
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
validateValue() {}
|
|
201
|
+
|
|
202
|
+
updateChoice(value: string) {
|
|
203
|
+
this.table.updateRow(this.pointerIndexes.row, this.pointerIndexes.column, value)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
get currentValue() {
|
|
207
|
+
return this.table.getValue(this.pointerIndexes.row, this.pointerIndexes.column)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
onEditPress(key: Key) {
|
|
211
|
+
let value = this.currentValue
|
|
212
|
+
if (this.temporaryBackup === null) {
|
|
213
|
+
this.temporaryBackup = value
|
|
214
|
+
value = ''
|
|
215
|
+
}
|
|
216
|
+
switch (key.name) {
|
|
217
|
+
case 'escape':
|
|
218
|
+
this.updateChoice(this.temporaryBackup)
|
|
219
|
+
this.editing = false
|
|
220
|
+
break
|
|
221
|
+
case 'delete':
|
|
222
|
+
this.updateChoice('')
|
|
223
|
+
break
|
|
224
|
+
case 'backspace': {
|
|
225
|
+
let currentValue = value
|
|
226
|
+
currentValue = currentValue.slice(0, -1)
|
|
227
|
+
this.updateChoice(currentValue)
|
|
228
|
+
break
|
|
229
|
+
}
|
|
230
|
+
default:
|
|
231
|
+
this.updateChoice(`${value}${getKeypressValue(key)}`)
|
|
232
|
+
break
|
|
233
|
+
}
|
|
234
|
+
this.render()
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
getShowRowIndex() {
|
|
238
|
+
const middleOfPage = Math.floor(this.options.pageSize / 2)
|
|
239
|
+
let rowIndexFrom = Math.max(0, this.pointerIndexes.row - middleOfPage)
|
|
240
|
+
const rowIndexTo = Math.min(this.maxRowIndex, rowIndexFrom + this.maxPageIndex)
|
|
241
|
+
rowIndexFrom = Math.min(rowIndexFrom, rowIndexTo - (this.options.pageSize - 1))
|
|
242
|
+
return { rowIndexFrom, rowIndexTo }
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
isSelected(rowIndex: number, columnIndex: number) {
|
|
246
|
+
return this.pointerIndexes.row === rowIndex && this.pointerIndexes.column === columnIndex
|
|
247
|
+
}
|
|
248
|
+
getColor(_value: string, isSelected: boolean, isEditable: boolean) {
|
|
249
|
+
const value = isEditable ? _value : dim(_value)
|
|
250
|
+
if (!isSelected) {
|
|
251
|
+
return value
|
|
252
|
+
}
|
|
253
|
+
if (this.editing) {
|
|
254
|
+
return isEditable ? this.options.colors.editing(value) : this.options.colors.selected(value)
|
|
255
|
+
}
|
|
256
|
+
return isEditable ? this.options.colors.editable(value) : this.options.colors.selected(value)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
render(isDisconnect = false) {
|
|
260
|
+
let content = this.getQuestion()
|
|
261
|
+
let bottomContent: string | ChalkInstance = ''
|
|
262
|
+
|
|
263
|
+
content += this.options.description ? `\n${this.options.description}` : ''
|
|
264
|
+
|
|
265
|
+
const { rowIndexFrom, rowIndexTo } = this.getShowRowIndex()
|
|
266
|
+
const table = new Table({
|
|
267
|
+
head: this.table.header,
|
|
268
|
+
})
|
|
269
|
+
for (let i = 0; i < this.table.rows.length; i++) {
|
|
270
|
+
if (i < rowIndexFrom || i > rowIndexTo) {
|
|
271
|
+
continue
|
|
272
|
+
}
|
|
273
|
+
const columnValues: string[] = []
|
|
274
|
+
for (let ii = 0; ii < (this.table.rows[i] || []).length; ii++) {
|
|
275
|
+
const isEditable = this.isEditable(ii)
|
|
276
|
+
const value = this.table.rows[i][ii]
|
|
277
|
+
columnValues.push(this.getColor(value, this.isSelected(i, ii), isEditable))
|
|
278
|
+
}
|
|
279
|
+
table.push(columnValues)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
content += '\n\n' + table.toString()
|
|
283
|
+
|
|
284
|
+
if (!isDisconnect) {
|
|
285
|
+
const validateResult = this.validate()
|
|
286
|
+
if (!this.editing && validateResult.isValid) {
|
|
287
|
+
bottomContent = this.options.confirmMessage
|
|
288
|
+
}
|
|
289
|
+
if (!validateResult.isValid) {
|
|
290
|
+
bottomContent = validateResult.message || error('Something went wrong.')
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (this.isNextCloses.escape) {
|
|
294
|
+
bottomContent = this.options.escapeMessage
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
this.screen.render(content, bottomContent as string)
|
|
298
|
+
}
|
|
299
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import chalk from 'chalk'
|
|
2
|
+
import inquirer from 'inquirer'
|
|
3
|
+
|
|
4
|
+
import { success, warn, hop, cyan } from '../utils/chalk.js'
|
|
5
|
+
|
|
6
|
+
import { TableQuestion } from './table/types.js'
|
|
7
|
+
import { TablePlugin } from './table.js'
|
|
8
|
+
|
|
9
|
+
const run = async () => {
|
|
10
|
+
inquirer.registerPrompt('table-input', TablePlugin)
|
|
11
|
+
const rows = [...Array(33).keys()].map(i => [cyan(`--path ${i}--`), '--id--', true, i + 100, '--lock--'])
|
|
12
|
+
const question: TableQuestion = {
|
|
13
|
+
type: 'table-input',
|
|
14
|
+
name: 'links',
|
|
15
|
+
message: chalk.red('GENERATE LINKS PATH SETTINGS'),
|
|
16
|
+
description: 'Edit setting.',
|
|
17
|
+
disableColumnIndexes: [0],
|
|
18
|
+
colors: {
|
|
19
|
+
selected: warn,
|
|
20
|
+
editable: success,
|
|
21
|
+
editing: hop,
|
|
22
|
+
},
|
|
23
|
+
columns: [
|
|
24
|
+
{ name: cyan.bold('filepath'), value: 'path', type: 'input' },
|
|
25
|
+
{ name: cyan.bold('id'), value: 'id', type: 'input', parser: () => 'aaa' },
|
|
26
|
+
{ name: cyan.bold('title'), value: 'title', type: 'confirm' },
|
|
27
|
+
{
|
|
28
|
+
name: cyan.bold('num'),
|
|
29
|
+
value: 'output',
|
|
30
|
+
type: 'number',
|
|
31
|
+
validate: (value: string) => /^\d*$/.test(value) || value === '0' || !value,
|
|
32
|
+
},
|
|
33
|
+
{ name: cyan.bold('lock'), value: 'lock', type: 'input' },
|
|
34
|
+
],
|
|
35
|
+
rows: rows,
|
|
36
|
+
validate: (inputs, _answers) => {
|
|
37
|
+
const isValid = inputs.every((i: any) => Object.values(i).every(v => `${v}`.length))
|
|
38
|
+
return {
|
|
39
|
+
isValid,
|
|
40
|
+
message: isValid ? '' : 'not allow empty input',
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
const answers = await inquirer.prompt([
|
|
45
|
+
// {
|
|
46
|
+
// type: 'confirm',
|
|
47
|
+
// name: 'id',
|
|
48
|
+
// message: 'type id',
|
|
49
|
+
// choices: ['aa', 'bb']
|
|
50
|
+
// },
|
|
51
|
+
question,
|
|
52
|
+
])
|
|
53
|
+
console.log('answers', JSON.stringify(answers, null, 2))
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
run().then(() => {
|
|
57
|
+
console.log('--- end ---')
|
|
58
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type Done = (value: any) => void
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import chalk from 'chalk'
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line no-control-regex
|
|
4
|
+
export const trim = (txt: string) => txt.replace(/\u001b\[[0-9;]*m/g, '')
|
|
5
|
+
|
|
6
|
+
export const success = chalk.green
|
|
7
|
+
export const warn = chalk.hex('#FFA500')
|
|
8
|
+
export const info = chalk.hex('#77CFF5')
|
|
9
|
+
export const error = chalk.red
|
|
10
|
+
export const hop = chalk.hex('#F577F5')
|
|
11
|
+
export const cyan = chalk.cyan
|
|
12
|
+
export const bold = chalk.bold
|
|
13
|
+
export const dim = chalk.dim
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Key } from 'readline'
|
|
2
|
+
|
|
3
|
+
export const getKeypressValue = (key: Key) => {
|
|
4
|
+
switch (key.name) {
|
|
5
|
+
case 'escape':
|
|
6
|
+
case 'delete':
|
|
7
|
+
case 'backspace':
|
|
8
|
+
case 'down':
|
|
9
|
+
case 'up':
|
|
10
|
+
case 'left':
|
|
11
|
+
case 'right':
|
|
12
|
+
return ''
|
|
13
|
+
default:
|
|
14
|
+
return key.sequence
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { PARSE_TYPES, ParseType } from '~types/parse-types.js'
|
|
2
|
+
|
|
3
|
+
const BOOL_VALUES = Object.freeze(['Y', 'y', 'yes', 'YES', 'x', 'v', 'o', 'true'])
|
|
4
|
+
|
|
5
|
+
export const parse = (value: string, type: ParseType) => {
|
|
6
|
+
switch (type) {
|
|
7
|
+
case PARSE_TYPES.number:
|
|
8
|
+
return value ? Number(value) : 0
|
|
9
|
+
case PARSE_TYPES.confirm:
|
|
10
|
+
return BOOL_VALUES.includes(value)
|
|
11
|
+
default:
|
|
12
|
+
return value
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const parseView = (value: string, type: ParseType) => {
|
|
17
|
+
switch (type) {
|
|
18
|
+
case PARSE_TYPES.number:
|
|
19
|
+
return value ? Number(value) : 0
|
|
20
|
+
case PARSE_TYPES.confirm:
|
|
21
|
+
return value === 'true'
|
|
22
|
+
default:
|
|
23
|
+
return value
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '~types/inquirer.js'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '~types/parse-types.js'
|