@kdcloudjs/cli 0.0.2 → 0.0.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kdcloudjs/cli",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Kingdee CLI",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -17,6 +17,7 @@
17
17
  "dependencies": {
18
18
  "axios": "^1.12.2",
19
19
  "chalk": "4.1.2",
20
+ "cli-table3": "^0.6.5",
20
21
  "commander": "12.1.0",
21
22
  "download-git-repo": "^3.0.2",
22
23
  "form-data": "^4.0.4",
@@ -87,16 +87,19 @@ module.exports = async function debug(options = {}) {
87
87
 
88
88
  // 6. Open Browser & Start Debug
89
89
  // Start server first
90
- const { promise: serverPromise, child } = runDebug(root)
90
+ const { serverPromise, serverChild, buildPromise, buildReadyPromise } = runDebug(root)
91
91
 
92
92
  try {
93
- info('Waiting for debug server to be ready...')
94
- await waitForPort(3333, child)
93
+ info('Waiting for debug server and build watcher...')
94
+ await Promise.all([
95
+ waitForPort(3333, serverChild),
96
+ buildReadyPromise
97
+ ])
95
98
  info(`Opening: ${finalUrl}`)
96
99
  openBrowser(finalUrl)
97
100
  } catch (e) {
98
- error(`Server start failed: ${e.message}`)
101
+ error(`Start failed: ${e.message}`)
99
102
  }
100
103
 
101
- await serverPromise
104
+ await Promise.all([serverPromise, buildPromise])
102
105
  }
@@ -1,3 +1,5 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
1
3
  const { spawn } = require('child_process')
2
4
  const { info } = require('../../utils/log')
3
5
 
@@ -17,19 +19,62 @@ function installDeps(root) {
17
19
  }
18
20
 
19
21
  function runDebug(root) {
20
- info('Starting debug server...')
21
- let childProcess
22
- const promise = new Promise((resolve, reject) => {
22
+ info('Starting build watcher...')
23
+ let buildChild
24
+ let buildReadyResolve
25
+ const buildReadyPromise = new Promise(resolve => {
26
+ buildReadyResolve = resolve
27
+ })
28
+
29
+ // Poll dist/kwc for content
30
+ const checkInterval = setInterval(() => {
31
+ const distDir = path.join(root, 'dist/kwc')
32
+ if (fs.existsSync(distDir)) {
33
+ try {
34
+ const files = fs.readdirSync(distDir)
35
+ if (files.length > 0) {
36
+ clearInterval(checkInterval)
37
+ buildReadyResolve()
38
+ }
39
+ } catch (e) {
40
+ // ignore
41
+ }
42
+ }
43
+ }, 1000)
44
+
45
+ const buildPromise = new Promise((resolve, reject) => {
23
46
  const child = spawn('npm', ['run', 'debug'], {
24
47
  cwd: root,
25
48
  stdio: 'inherit',
26
49
  shell: true
27
50
  })
28
- childProcess = child
51
+ buildChild = child
52
+
53
+ child.on('close', (code) => {
54
+ clearInterval(checkInterval)
55
+ buildReadyResolve()
56
+ resolve(code)
57
+ })
58
+ child.on('error', (err) => {
59
+ clearInterval(checkInterval)
60
+ buildReadyResolve()
61
+ reject(err)
62
+ })
63
+ })
64
+
65
+ info('Starting debug server...')
66
+ let serverChild
67
+ const serverPromise = new Promise((resolve, reject) => {
68
+ const child = spawn('npm', ['run', 'server'], {
69
+ cwd: root,
70
+ stdio: 'inherit',
71
+ shell: true
72
+ })
73
+ serverChild = child
29
74
  child.on('close', resolve)
30
75
  child.on('error', reject)
31
76
  })
32
- return { promise, child: childProcess }
77
+ return { serverPromise, serverChild, buildPromise, buildChild, buildReadyPromise }
33
78
  }
34
79
 
35
80
  module.exports = {
@@ -24,5 +24,7 @@ module.exports = function envInfo() {
24
24
  env.url || '',
25
25
  env.default ? '★' : ''
26
26
  ])
27
- printTable(headers, rows)
27
+ printTable(headers, rows, {
28
+ colWidths: [20, 50, 10]
29
+ })
28
30
  }
@@ -17,5 +17,7 @@ module.exports = function listEnv() {
17
17
  envs[name].url || '',
18
18
  envs[name].default ? '★' : ''
19
19
  ])
20
- printTable(headers, rows)
20
+ printTable(headers, rows, {
21
+ colWidths: [20, 50, 10]
22
+ })
21
23
  }
@@ -10,16 +10,47 @@ module.exports = function createMetaXml({ name, moduleId, framework }) {
10
10
  <moduleid>${moduleId}</moduleid>
11
11
  <framework>${framework}</framework>
12
12
  <targets>
13
- <target>BaseFormModel</target>
14
- <target>BillFormModel</target>
15
- <target>DynamicFormModel</target>
16
- <target>MobileBillFormModel</target>
17
- <target>MobileFormModel</target>
18
13
  <target>KWCFormModel</target>
19
14
  </targets>
20
15
  <targetConfigs>
21
16
  <targetConfig>
22
- <targets>BaseFormModel,BillFormModel,DynamicFormModel,MobileBillFormModel,MobileFormModel,KWCFormModel</targets>
17
+ <targets>KWCFormModel</targets>
18
+ <!-- <property
19
+ description="文本类型属性"
20
+ name="StringValue"
21
+ caption="文本类型属性"
22
+ type="String"
23
+ length="25"
24
+ default="默认值">
25
+ </property>
26
+ <property
27
+ name="IntValue"
28
+ type="Integer"
29
+ caption="数值类型属性"
30
+ description="数值类型属性"
31
+ max="10"
32
+ min="2"
33
+ default="2"
34
+ ></property>
35
+ <property
36
+ name="ComboValue"
37
+ type="Combo"
38
+ default="0"
39
+ caption="下拉列表类型属性"
40
+ description="下拉列表类型属性" >
41
+ <items>
42
+ <item id="0" name="默认名称" />
43
+ <item id="1" name="选项1" />
44
+ <item id="2" name="选项2" />
45
+ </items>
46
+ </property>
47
+
48
+ <property name="BooleanValue"
49
+ type="Boolean"
50
+ caption="布尔类型属性"
51
+ description="布尔类型属性"
52
+ default="true" >
53
+ </property> -->
23
54
  </targetConfig>
24
55
  </targetConfigs>
25
56
  </KingdeeComponentBundle>`
@@ -35,6 +35,17 @@ function createPageXml(name) {
35
35
  <region>
36
36
  <name>region1</name>
37
37
  <controls>
38
+ <!-- <control>
39
+ <type>ReactDemoAp</type>
40
+ <name>ReactDemo</name>
41
+ <label>测试组件名称</label>
42
+ <propertys>
43
+ <property>
44
+ <name>StringValue</name>
45
+ <value>3333</value>
46
+ </property>
47
+ </propertys>
48
+ </control> -->
38
49
  </controls>
39
50
  </region>
40
51
  </regions>
@@ -27,8 +27,8 @@ module.exports = function validate({ name, type, framework }) {
27
27
  }
28
28
  break
29
29
  case FRAMEWORKS.React:
30
- if (!/^[A-Z][a-zA-Z0-9]*$/.test(name) && !/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(name)) {
31
- error('React component name must follow PascalCase (start with uppercase) or kebab-case (hyphen-separated)')
30
+ if (!/^[A-Z][a-zA-Z0-9]*$/.test(name)) {
31
+ error('React component name must follow PascalCase (start with uppercase)')
32
32
  process.exit(1)
33
33
  }
34
34
  break
@@ -50,11 +50,17 @@ exports.upload = async function upload(files, env) {
50
50
  const headers = ['Type', 'File', 'Status', 'Message']
51
51
  const rows = results.map(file => [
52
52
  file.type,
53
- file.path,
53
+ path.relative(process.cwd(), file.path),
54
54
  file.status === 'success' ? '✔' : '✖',
55
- file.status === 'failed' ? `Failed: ${file.message}` : 'Success'
55
+ file.status === 'failed' ? `${file.message}` : 'Success'
56
56
  ])
57
- printTable(headers, rows)
57
+
58
+ const hasFailed = results.some(r => r.status === 'failed')
59
+ const colWidths = hasFailed ? [10, 30, 10, 50] : [10, 50, 10, 30]
60
+
61
+ printTable(headers, rows, {
62
+ colWidths
63
+ })
58
64
  console.timeEnd(`🕒 Upload duration`)
59
65
  return results
60
66
  }
@@ -8,15 +8,15 @@ const { TEMPLATES, INNER_TEMPLATES } = require('../constants')
8
8
 
9
9
  module.exports = async function initProject({ projectName: _projectName, source }) {
10
10
  try {
11
+ if (fs.existsSync(path.resolve(process.cwd(), _projectName))) {
12
+ error(`Directory already exists: ${_projectName}`)
13
+ return
14
+ }
15
+
11
16
  const { projectName, moduleId, framework, language } = await collectInitInfo(_projectName) || {}
12
17
 
13
18
  const targetDir = path.resolve(process.cwd(), projectName)
14
19
 
15
- if (fs.existsSync(targetDir)) {
16
- error(`Directory already exists: ${projectName}`)
17
- return
18
- }
19
-
20
20
  tip(`\n🚀 Creating project: ${projectName}\n`)
21
21
  console.time('🕒 Project initialization')
22
22
 
package/src/api/index.js CHANGED
@@ -18,17 +18,17 @@ async function getAllDataCenters (url) {
18
18
  value: d.accountId
19
19
  })
20
20
  } else {
21
- error(`⚠ 数据中心返回异常,请检查url: ${url} 是否正确`)
21
+ error(`⚠ Data center response error, please check if url: ${url} is correct`)
22
22
  }
23
23
  }
24
24
  } else {
25
- error(`⚠ 数据中心列表为空,请检查url: ${url} 是否正确`)
25
+ error(`⚠ Data center list is empty, please check if url: ${url} is correct`)
26
26
  }
27
27
  } else {
28
- error(`⚠ 请求失败,请检查url: ${url} 是否正确。error message: ${resp?.statusText}`)
28
+ error(`⚠ Request failed, please check if url: ${url} is correct. error message: ${resp?.statusText}`)
29
29
  }
30
30
  } catch (e) {
31
- error(`⚠ 请求失败,请检查url: ${url} 是否正确。error message: ${e?.message}`)
31
+ error(`⚠ Request failed, please check if url: ${url} is correct. error message: ${e?.message}`)
32
32
  }
33
33
  return res
34
34
  }
@@ -58,13 +58,13 @@ async function getAccessToken (url, params) {
58
58
  if (respData?.status) {
59
59
  res = respData?.data || {}
60
60
  } else {
61
- error(`⚠ 获取access_token失败,请检查urlclient_idclient_secretusername是否正确。errormessage: ${respData?.message}`)
61
+ error(`⚠ Failed to get access_token, please check url, client_id, client_secret, username. error message: ${respData?.message}`)
62
62
  }
63
63
  } else {
64
- error(`⚠ 获取access_token失败,请检查urlclient_idclient_secretusername是否正确, response status: ${resp?.status}`)
64
+ error(`⚠ Failed to get access_token, please check url, client_id, client_secret, username. response status: ${resp?.status}`)
65
65
  }
66
66
  } catch (e) {
67
- error(`⚠ 获取access_token失败,请检查urlclient_idclient_secretusername是否正确。error message: ${e?.message}`)
67
+ error(`⚠ Failed to get access_token, please check url, client_id, client_secret, username. error message: ${e?.message}`)
68
68
  }
69
69
  return res
70
70
  }
@@ -85,13 +85,13 @@ async function getIsv (url, access_token) {
85
85
  if (respData?.status) {
86
86
  res = respData?.data || {}
87
87
  } else {
88
- error(`⚠ get isv failpls check url and credentials info, errormessage: ${respData?.message}`)
88
+ error(`⚠ get isv fail, pls check url and credentials info, errormessage: ${respData?.message}`)
89
89
  }
90
90
  } else {
91
- error(`⚠ get isv failpls check url and credentials info, response status: ${resp?.status}`)
91
+ error(`⚠ get isv fail, pls check url and credentials info, response status: ${resp?.status}`)
92
92
  }
93
93
  } catch (err) {
94
- error(`⚠ getIsv failerror message: ${err.message}`)
94
+ error(`⚠ getIsv fail. error message: ${err.message}`)
95
95
  }
96
96
  return res
97
97
  }
@@ -9,7 +9,7 @@ const { decrypt } = require('../../utils/crypto')
9
9
  module.exports.updateKwcMeta = async function updateKwcMeta(filePath, env = {}) {
10
10
  // TODO: 调用真实接口
11
11
  if (!fs.existsSync(filePath)) {
12
- throw new Error(`❌ 未找到文件: ${filePath}`)
12
+ throw new Error(`❌ File not found: ${filePath}`)
13
13
  }
14
14
 
15
15
  const { url: backendUrl, client_id, client_secret, username, accountId, access_token } = env
@@ -62,7 +62,7 @@ module.exports.updateKwcMeta = async function updateKwcMeta(filePath, env = {})
62
62
  return res
63
63
  }
64
64
  } catch (err) {
65
- console.warn(`⚠ 文本上传失败,尝试文件上传方式: ${err.message}`)
65
+ console.warn(`⚠ Text upload failed, trying file upload: ${err.message}`)
66
66
  }
67
67
 
68
68
  // ============ 第二阶段:FormData 文件流上传 ============
@@ -85,6 +85,6 @@ module.exports.updateKwcMeta = async function updateKwcMeta(filePath, env = {})
85
85
  }
86
86
  throw new Error(`File upload failed: ${res?.data?.message || res.status}`)
87
87
  } catch (err) {
88
- throw new Error(`元数据上传失败:${err.message}`)
88
+ throw new Error(`${err.message}`)
89
89
  }
90
90
  }
@@ -14,7 +14,7 @@ const { decrypt } = require('../../utils/crypto')
14
14
  module.exports.updatePageMeta = async function updatePageMeta(filePath, env = {}) {
15
15
  // TODO: 调用真实接口
16
16
  if (!fs.existsSync(filePath)) {
17
- throw new Error(`❌ 未找到文件: ${filePath}`)
17
+ throw new Error(`❌ File not found: ${filePath}`)
18
18
  }
19
19
 
20
20
  const { url: backendUrl, client_id, client_secret, username, accountId, access_token } = env
@@ -66,7 +66,7 @@ module.exports.updatePageMeta = async function updatePageMeta(filePath, env = {}
66
66
  return res
67
67
  }
68
68
  } catch (err) {
69
- console.warn(`⚠ 文本上传失败,尝试文件上传方式: ${err.message}`)
69
+ console.warn(`⚠ Text upload failed, trying file upload: ${err.message}`)
70
70
  }
71
71
 
72
72
  // ============ 第二阶段:FormData 文件流上传 ============
@@ -89,6 +89,6 @@ module.exports.updatePageMeta = async function updatePageMeta(filePath, env = {}
89
89
  }
90
90
  throw new Error(`File upload failed: ${res?.data?.message || res.status}`)
91
91
  } catch (err) {
92
- throw new Error(`元数据上传失败:${err.message}`)
92
+ throw new Error(`${err.message}`)
93
93
  }
94
94
  }
@@ -1,7 +1,12 @@
1
+ const KdHelp = require('../../utils/help')
2
+
1
3
  module.exports = function registerEnv(program) {
2
4
  const env = program
3
5
  .command('env')
4
6
  .description('Environment management')
7
+ .usage('[command] [options]')
8
+
9
+ env.createHelp = () => new KdHelp(env.configureHelp())
5
10
 
6
11
  env
7
12
  .command('create <name>')
@@ -11,9 +16,14 @@ module.exports = function registerEnv(program) {
11
16
  require('./create')(name, options)
12
17
  )
13
18
 
14
- env
19
+ const set = env
15
20
  .command('set')
16
21
  .description('Set environment config')
22
+ .usage('[command] [options]')
23
+
24
+ set.createHelp = () => new KdHelp(set.configureHelp())
25
+
26
+ set
17
27
  .command('target-env <name>')
18
28
  .description('Set default environment')
19
29
  .action(name =>
@@ -1,7 +1,12 @@
1
+ const KdHelp = require('../../utils/help')
2
+
1
3
  module.exports = function registerProject(program) {
2
4
  const project = program
3
5
  .command('project')
4
6
  .description('Project management')
7
+ .usage('[command] [options]')
8
+
9
+ project.createHelp = () => new KdHelp(project.configureHelp())
5
10
 
6
11
  project
7
12
  .command('init <name>')
@@ -0,0 +1,52 @@
1
+ const { execSync } = require('child_process')
2
+ const os = require('os')
3
+ const ora = require('ora')
4
+ const chalk = require('chalk')
5
+ const { info, success, error } = require('../utils/log')
6
+ const pkg = require('../../package.json')
7
+
8
+ module.exports = async () => {
9
+ const spinner = ora('Checking for updates...').start()
10
+
11
+ try {
12
+ // Check latest version
13
+ let latestVersion
14
+ try {
15
+ latestVersion = execSync(`npm view ${pkg.name} version`, { encoding: 'utf8', cwd: os.homedir() }).trim()
16
+ } catch (e) {
17
+ spinner.stop()
18
+ error('Failed to check for updates. Please check your network connection.')
19
+ return
20
+ }
21
+
22
+ if (latestVersion === pkg.version) {
23
+ spinner.stop()
24
+ success(`You are already using the latest version (${chalk.green(pkg.version)}).`)
25
+ return
26
+ }
27
+
28
+ spinner.stop()
29
+ info(`New version available: ${chalk.green(latestVersion)} (current: ${chalk.yellow(pkg.version)})`)
30
+ spinner.start('Updating...')
31
+
32
+ try {
33
+ // Execute update
34
+ // Use os.homedir() as cwd to avoid reading project-specific .npmrc which might cause warnings
35
+ execSync(`npm install -g ${pkg.name}@latest`, { stdio: 'inherit', cwd: os.homedir() })
36
+ spinner.stop()
37
+ success(`Successfully updated to version ${chalk.green(latestVersion)}`)
38
+ } catch (err) {
39
+ spinner.stop()
40
+ error('Update failed')
41
+ console.log(chalk.red('\nPlease try running the following command manually:'))
42
+ console.log(chalk.cyan(`npm install -g ${pkg.name}@latest`))
43
+ if (process.platform !== 'win32') {
44
+ console.log(chalk.dim('(You may need to use sudo)'))
45
+ }
46
+ }
47
+ } catch (error) {
48
+ spinner.stop()
49
+ error('An error occurred during update')
50
+ console.error(error)
51
+ }
52
+ }
package/src/index.js CHANGED
@@ -3,15 +3,20 @@
3
3
  const { Command } = require('commander')
4
4
  const pkg = require('../package.json')
5
5
  const checkUpdate = require('./utils/checkUpdate')
6
+ const KdHelp = require('./utils/help')
6
7
 
7
8
  const program = new Command()
9
+ program.createHelp = () => new KdHelp(program.configureHelp())
8
10
 
9
- checkUpdate()
11
+ if (!process.argv.includes('update')) {
12
+ checkUpdate()
13
+ }
10
14
 
11
15
  program
12
16
  .name('kd')
17
+ .usage('[command] [options]')
13
18
  .description('Kingdee CLI')
14
- .version(pkg.version)
19
+ .version(pkg.version, '-v, --version')
15
20
 
16
21
  program
17
22
  .command('update')
@@ -0,0 +1,18 @@
1
+ const { Help } = require('commander')
2
+
3
+ class KdHelp extends Help {
4
+ subcommandTerm(cmd) {
5
+ if (cmd.name() === 'init') {
6
+ return 'init <name> [options]'
7
+ }
8
+ if (cmd.name() === 'create') {
9
+ return 'create <name> [options]'
10
+ }
11
+ if (cmd.name() === 'target-env') {
12
+ return 'target-env <name> [options]'
13
+ }
14
+ return super.subcommandTerm(cmd)
15
+ }
16
+ }
17
+
18
+ module.exports = KdHelp
@@ -1,28 +1,98 @@
1
- function pad(str, len) {
2
- str = String(str)
3
- return str + ' '.repeat(Math.max(len - str.length, 0))
1
+ const Table = require('cli-table3')
2
+
3
+ let stringWidth
4
+ try {
5
+ const m = require('string-width')
6
+ stringWidth = m.default || m
7
+ } catch (e) {
8
+ // Fallback (simple approximation) if string-width is not available
9
+ stringWidth = (str) => {
10
+ let width = 0
11
+ for (let i = 0; i < str.length; i++) {
12
+ width += str.charCodeAt(i) > 255 ? 2 : 1
13
+ }
14
+ return width
15
+ }
16
+ }
17
+
18
+ function wrapText(text, width) {
19
+ if (width <= 0) return text
20
+ const lines = []
21
+ let line = ''
22
+ let lineWidth = 0
23
+
24
+ for (const char of text) {
25
+ const cw = stringWidth(char)
26
+ if (lineWidth + cw > width) {
27
+ lines.push(line)
28
+ line = char
29
+ lineWidth = cw
30
+ } else {
31
+ line += char
32
+ lineWidth += cw
33
+ }
34
+ }
35
+ lines.push(line)
36
+ return lines.join('\n')
4
37
  }
5
38
 
6
- module.exports = function printTable(headers, rows) {
7
- const colWidths = headers.map((h, i) =>
8
- Math.max(
9
- h.length,
10
- ...rows.map(r => String(r[i] ?? '').length)
11
- )
12
- )
13
-
14
- const line = headers
15
- .map((h, i) => pad(h, colWidths[i]))
16
- .join(' ')
17
-
18
- console.log(line)
19
- console.log(
20
- colWidths.map(w => '-'.repeat(w)).join(' ')
21
- )
22
-
23
- rows.forEach(row => {
24
- console.log(
25
- row.map((cell, i) => pad(cell ?? '', colWidths[i])).join(' ')
26
- )
39
+ module.exports = function printTable(headers, rows, options = {}) {
40
+ const MAX_LENGTH = 500
41
+
42
+ // Pre-process rows to handle flattening, truncation, and manual wrapping
43
+ const processedRows = rows.map(row => {
44
+ return row.map((cell, colIndex) => {
45
+ if (typeof cell !== 'string') return cell
46
+
47
+ let text = cell
48
+
49
+ // 1. Truncate: Limit total length first to avoid processing huge strings
50
+ if (text.length > MAX_LENGTH) {
51
+ text = text.slice(0, MAX_LENGTH) + '... (truncated)'
52
+ }
53
+
54
+ // 2. Manual Wrap: If colWidth is provided, wrap manually to avoid cli-table3 CJK bugs
55
+ // We must handle existing newlines by wrapping each line individually
56
+ const colWidth = options.colWidths ? options.colWidths[colIndex] : null
57
+ if (colWidth && typeof colWidth === 'number') {
58
+ // cli-table3 default padding is 1 left + 1 right = 2
59
+ // We use a larger safety margin (3 or 4) to ensure we NEVER exceed the width
60
+ // due to potential width calculation mismatches between string-width versions
61
+ const padding = 2
62
+ const safetyMargin = 2
63
+ const contentWidth = colWidth - padding - safetyMargin
64
+
65
+ if (contentWidth > 0) {
66
+ // Split by existing newlines, wrap each segment, then rejoin
67
+ text = text.split('\n').map(line => wrapText(line, contentWidth)).join('\n')
68
+ }
69
+ }
70
+
71
+ return text
72
+ })
27
73
  })
74
+
75
+ const table = new Table({
76
+ head: headers,
77
+ // Keep internal and horizontal borders, but remove left and right outer borders
78
+ chars: {
79
+ 'top': '─', 'top-mid': '┬', 'top-left': '', 'top-right': '',
80
+ 'bottom': '─', 'bottom-mid': '┴', 'bottom-left': '', 'bottom-right': '',
81
+ 'left': '', 'left-mid': '', 'mid': '─', 'mid-mid': '┼',
82
+ 'right': '', 'right-mid': '', 'middle': '│'
83
+ },
84
+ style: {
85
+ head: ['cyan'],
86
+ border: ['grey']
87
+ },
88
+ // Disable cli-table3's wordWrap if we have explicit column widths (since we manually wrapped)
89
+ // Otherwise enable it to let cli-table3 handle auto-sizing
90
+ wordWrap: !options.colWidths,
91
+ wrapOnWordBoundary: false,
92
+ colWidths: options.colWidths
93
+ })
94
+
95
+ processedRows.forEach(row => table.push(row))
96
+
97
+ console.log(table.toString())
28
98
  }
@@ -5,7 +5,7 @@ function getConfig(root) {
5
5
  const configPath = path.join(root, '.kd', 'config.json')
6
6
 
7
7
  if (!fs.existsSync(configPath)) {
8
- throw new Error('未找到 .kd/config.json')
8
+ throw new Error('.kd/config.json not found')
9
9
  }
10
10
 
11
11
  return JSON.parse(fs.readFileSync(configPath, 'utf-8'))
@@ -15,7 +15,7 @@ function getConfigValue(root, key) {
15
15
  const config = getConfig(root)
16
16
 
17
17
  if (!config[key]) {
18
- throw new Error(`config.json 中缺少 ${key}`)
18
+ throw new Error(`${key} is missing in config.json`)
19
19
  }
20
20
 
21
21
  return config[key]