@kdcloudjs/cli 0.0.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 (59) hide show
  1. package/README.MD +22 -0
  2. package/package.json +28 -0
  3. package/src/actions/env/auth/index.js +33 -0
  4. package/src/actions/env/auth/openapi.js +83 -0
  5. package/src/actions/env/auth/web.js +3 -0
  6. package/src/actions/env/config.js +102 -0
  7. package/src/actions/env/create.js +36 -0
  8. package/src/actions/env/info.js +28 -0
  9. package/src/actions/env/list.js +21 -0
  10. package/src/actions/env/remote.js +59 -0
  11. package/src/actions/env/remove.js +23 -0
  12. package/src/actions/env/resolveEnv.js +27 -0
  13. package/src/actions/env/setDefault.js +20 -0
  14. package/src/actions/project/constants.js +33 -0
  15. package/src/actions/project/create/createMetaXml.js +26 -0
  16. package/src/actions/project/create/index.js +24 -0
  17. package/src/actions/project/create/kwc.js +25 -0
  18. package/src/actions/project/create/page.js +42 -0
  19. package/src/actions/project/create/validate.js +45 -0
  20. package/src/actions/project/create/writeKwcFiles/index.js +15 -0
  21. package/src/actions/project/create/writeKwcFiles/lwc.js +25 -0
  22. package/src/actions/project/create/writeKwcFiles/react.js +49 -0
  23. package/src/actions/project/create/writeKwcFiles/vue.js +48 -0
  24. package/src/actions/project/deploy/collect.js +43 -0
  25. package/src/actions/project/deploy/context.js +26 -0
  26. package/src/actions/project/deploy/index.js +38 -0
  27. package/src/actions/project/deploy/projectRoot.js +32 -0
  28. package/src/actions/project/deploy/updateIsv.js +109 -0
  29. package/src/actions/project/deploy/upload.js +60 -0
  30. package/src/actions/project/deploy/validate.js +13 -0
  31. package/src/actions/project/init/index.js +42 -0
  32. package/src/actions/project/init/post.js +20 -0
  33. package/src/actions/project/init/prompts.js +50 -0
  34. package/src/api/index.js +99 -0
  35. package/src/api/uploader/index.js +7 -0
  36. package/src/api/uploader/updateKwcMeta.js +90 -0
  37. package/src/api/uploader/updatePageMeta.js +94 -0
  38. package/src/commands/env/auth.js +8 -0
  39. package/src/commands/env/create.js +2 -0
  40. package/src/commands/env/delete.js +2 -0
  41. package/src/commands/env/index.js +72 -0
  42. package/src/commands/env/info.js +2 -0
  43. package/src/commands/env/list.js +2 -0
  44. package/src/commands/env/remote.js +2 -0
  45. package/src/commands/env/set.js +2 -0
  46. package/src/commands/project/create.js +8 -0
  47. package/src/commands/project/deploy.js +2 -0
  48. package/src/commands/project/index.js +28 -0
  49. package/src/commands/project/init.js +5 -0
  50. package/src/index.js +24 -0
  51. package/src/utils/checkUpdate.js +18 -0
  52. package/src/utils/crypto.js +53 -0
  53. package/src/utils/download.js +21 -0
  54. package/src/utils/index.js +9 -0
  55. package/src/utils/log.js +20 -0
  56. package/src/utils/printTable.js +28 -0
  57. package/src/utils/projectConfig.js +32 -0
  58. package/src/utils/prompts.js +14 -0
  59. package/src/utils/validator.js +14 -0
package/README.MD ADDED
@@ -0,0 +1,22 @@
1
+ # kd
2
+ # 起步
3
+ #### 安装
4
+ ```
5
+ npm install -g @kdcloudjs/cli
6
+ # OR
7
+ yarn global add @kdcloudjs/cli
8
+ ```
9
+ #### 初始化项目:
10
+ ```
11
+ kd project init demo
12
+ ```
13
+
14
+ #### 创建组件
15
+ ```
16
+ kd project create kwcdemo --type kwc
17
+ ```
18
+
19
+ #### 创建页面元数据
20
+ ```
21
+ kd project create kwcdemo --type page
22
+ ```
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@kdcloudjs/cli",
3
+ "version": "0.0.1",
4
+ "description": "Kingdee CLI",
5
+ "scripts": {
6
+ "test": "echo \"Error: no test specified\" && exit 1"
7
+ },
8
+ "keywords": [
9
+ "cli",
10
+ "kd"
11
+ ],
12
+ "bin": {
13
+ "kd": "./src/index.js"
14
+ },
15
+ "author": "rubing_yan@kingdee.com",
16
+ "license": "ISC",
17
+ "dependencies": {
18
+ "axios": "^1.12.2",
19
+ "chalk": "4.1.2",
20
+ "commander": "12.1.0",
21
+ "download-git-repo": "^3.0.2",
22
+ "form-data": "^4.0.4",
23
+ "ora": "5.4.1",
24
+ "prompts": "2.4.2",
25
+ "update-notifier": "^7.3.1"
26
+ },
27
+ "type": "commonjs"
28
+ }
@@ -0,0 +1,33 @@
1
+
2
+
3
+
4
+ const { loadDefaultEnv, getEnvByName } = require('../config')
5
+ const webAuth = require('./web')
6
+ const openapiAuth = require('./openapi')
7
+ const { error } = require('../../../utils/log')
8
+
9
+ module.exports = async function doAuth(options ={}) {
10
+ let { type, env } = options
11
+
12
+ if (env === undefined) {
13
+ env = loadDefaultEnv()?.name
14
+ if (!env) {
15
+ error('❌ No environment specified and default environment is invalid, cannot authenticate') // 待产品提供
16
+ return
17
+ }
18
+ }
19
+
20
+ const envInfo = getEnvByName(env)
21
+
22
+ try {
23
+ if (type === 'web') {
24
+ return webAuth({ env: envInfo })
25
+ }
26
+
27
+ if (type === 'openapi') {
28
+ return openapiAuth({ env: envInfo })
29
+ }
30
+ } catch (e) {
31
+ error(`❌ Authentication failed: ${e.message}`)
32
+ }
33
+ }
@@ -0,0 +1,83 @@
1
+ const { loadEnv, saveEnv } = require('../config')
2
+ const { getAllDataCenters, getAccessToken, getIsv } = require('../../../api')
3
+ const { safePrompts } = require('../../../utils/prompts')
4
+ const { encrypt } = require('../../../utils/crypto')
5
+ const { isValidUrl } = require('../../../utils/validator')
6
+ const { error } = require('../../../utils/log')
7
+ module.exports = async function authOpenAPI(options = {}) {
8
+ const { env } = options
9
+
10
+ try {
11
+ const { url, name }= env || {}
12
+ if (!isValidUrl(url)) {
13
+ console.error('Invalid URL format:', url)
14
+ return
15
+ }
16
+
17
+ // 获取数据中心
18
+ let dataCenter
19
+ const dataCenters = await getAllDataCenters(url) || []
20
+ if (dataCenters.length === 0) return
21
+
22
+ const datacenterPrompt = {
23
+ type: 'select',
24
+ name: 'datacenterId',
25
+ message: 'Please select a data center',
26
+ choices: [...dataCenters]
27
+ }
28
+ const dcRes = await safePrompts(datacenterPrompt)
29
+ dataCenter = dataCenters.find(dc => dc.value === dcRes.datacenterId) || {}
30
+
31
+ // 获取client信息
32
+ const clientRes = await safePrompts([
33
+ {
34
+ type: 'text',
35
+ name: 'client_id',
36
+ message: '*Please enter OpenAPI third-party app client_id',
37
+ validate: v => !!v || 'OpenAPI third-party app client_id cannot be empty'
38
+ },
39
+ {
40
+ type: 'text',
41
+ name: 'client_secret',
42
+ message: '*Please enter OpenAPI third-party app client_secret',
43
+ validate: v => !!v || 'OpenAPI third-party app client_secret cannot be empty'
44
+ },
45
+ {
46
+ type: 'text',
47
+ name: 'username',
48
+ message: '*Please enter OpenAPI third-party app username',
49
+ validate: v => !!v || 'OpenAPI third-party app username cannot be empty'
50
+ }
51
+ ])
52
+
53
+ // 获取token
54
+ const getAccessTokenParams = {
55
+ client_id: clientRes.client_id,
56
+ client_secret: clientRes.client_secret,
57
+ username: clientRes.username,
58
+ accountId: dataCenter?.accountId
59
+ }
60
+ const tokenData = await getAccessToken(url, getAccessTokenParams) || {}
61
+ let token = tokenData.access_token || ''
62
+ if (!token) {
63
+ error('Failed to obtain access_token. Please check your credentials and reauthentication.')
64
+ return
65
+ }
66
+
67
+ // 获取isv
68
+ const { isv } = await getIsv(url, token) || {}
69
+ if (!isv) return
70
+
71
+ // 环境信息更新存储
72
+ const envs = loadEnv()
73
+ getAccessTokenParams.client_secret = encrypt(getAccessTokenParams.client_secret)
74
+ envs[name] = Object.assign({}, env, getAccessTokenParams, {
75
+ access_token: encrypt(token),
76
+ isv
77
+ })
78
+
79
+ saveEnv(envs)
80
+ } catch (error) {
81
+ console.error('auth error:', error)
82
+ }
83
+ }
@@ -0,0 +1,3 @@
1
+ module.exports = async function authWeb(options) {
2
+ console.log('Web authentication initiated with options:', options)
3
+ }
@@ -0,0 +1,102 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+ const os = require('os')
4
+ const { warn } = require('../../utils/log')
5
+
6
+ const KD_DIR = path.join(os.homedir(), '.kd')
7
+ const CONFIG_FILE = path.join(KD_DIR, 'config.json')
8
+
9
+ /**
10
+ * 确保 ~/.kd 目录存在
11
+ */
12
+ function ensureKdDir() {
13
+ if (!fs.existsSync(KD_DIR)) {
14
+ fs.mkdirSync(KD_DIR, { recursive: true })
15
+ }
16
+ }
17
+
18
+ /**
19
+ * 读取完整配置(容错)
20
+ */
21
+ function loadConfig() {
22
+ try {
23
+ if (!fs.existsSync(CONFIG_FILE)) {
24
+ return {}
25
+ }
26
+
27
+ const content = fs.readFileSync(CONFIG_FILE, 'utf-8').trim()
28
+ if (!content) {
29
+ return {}
30
+ }
31
+
32
+ return JSON.parse(content)
33
+ } catch (e) {
34
+ warn('⚠️ ~/.kd/config.json parse failed, using empty config')
35
+ return {}
36
+ }
37
+ }
38
+
39
+ /**
40
+ * 写入完整配置(原子性写入)
41
+ */
42
+ function saveConfig(config) {
43
+ try {
44
+ ensureKdDir()
45
+
46
+ const tmpFile = `${CONFIG_FILE}.tmp`
47
+
48
+ fs.writeFileSync(
49
+ tmpFile,
50
+ JSON.stringify(config, null, 2),
51
+ 'utf-8'
52
+ )
53
+
54
+ fs.renameSync(tmpFile, CONFIG_FILE)
55
+ } catch (e) {
56
+ warn('⚠️ Failed to save ~/.kd/config.json')
57
+ return {}
58
+ }
59
+ }
60
+
61
+ /**
62
+ * 读取 env 配置
63
+ */
64
+ function loadEnv() {
65
+ const config = loadConfig()
66
+ return config.env || {}
67
+ }
68
+
69
+ /**
70
+ * 读取 env 默认配置
71
+ */
72
+ function loadDefaultEnv() {
73
+ const envs = loadEnv()
74
+ const envsList = Object.values(envs) || []
75
+ return envsList.find(env => env.default) || {}
76
+ }
77
+
78
+ /**
79
+ * 根据环境名获取环境配置
80
+ */
81
+ function getEnvByName(name) {
82
+ const envs = loadEnv() || {}
83
+ return envs[name] || {}
84
+ }
85
+
86
+ /**
87
+ * 保存 env 配置(不破坏其他字段)
88
+ */
89
+ function saveEnv(env) {
90
+ const config = loadConfig()
91
+ config.env = env
92
+ saveConfig(config)
93
+ }
94
+
95
+ module.exports = {
96
+ loadConfig,
97
+ saveConfig,
98
+ loadEnv,
99
+ saveEnv,
100
+ loadDefaultEnv,
101
+ getEnvByName
102
+ }
@@ -0,0 +1,36 @@
1
+ const { loadEnv, saveEnv } = require('./config')
2
+ const { info, error } = require('../../utils/log')
3
+
4
+ module.exports = function createEnv(name, options) {
5
+ const url = options?.url
6
+ if (!url) {
7
+ error('--url is required')
8
+ return
9
+ }
10
+
11
+ // url 校验
12
+ const urlPattern = /^https?:\/\/.+/
13
+ if (!urlPattern.test(url)) {
14
+ error(`Invalid URL: ${url}`)
15
+ return
16
+ }
17
+
18
+ const envs = loadEnv()
19
+
20
+ if (envs[name]) {
21
+ error(`Environment ${name} already exists`)
22
+ return
23
+ }
24
+
25
+ const isFirst = Object.keys(envs).length === 0
26
+
27
+ envs[name] = {
28
+ name,
29
+ url,
30
+ default: isFirst
31
+ }
32
+
33
+ saveEnv(envs)
34
+
35
+ info(`✅ Environment ${name} created successfully${isFirst ? ' (set as default)' : ''}`)
36
+ }
@@ -0,0 +1,28 @@
1
+ const { loadEnv } = require('./config')
2
+ const { info, error } = require('../../utils/log')
3
+ const printTable = require('../../utils/printTable')
4
+
5
+ module.exports = function envInfo() {
6
+ const envs = loadEnv()
7
+ const envsList = Object.values(envs)
8
+ if (!envsList?.length) {
9
+ error('No environments configured')
10
+ return
11
+ }
12
+
13
+ const current = envsList.find(e => e.default)
14
+
15
+ if (!current) {
16
+ error('No default environment configured')
17
+ return
18
+ }
19
+
20
+ info('Current Environment:')
21
+ const headers = ['Name', 'URL', 'Default']
22
+ const rows = [current].map(env => [
23
+ env.name,
24
+ env.url || '',
25
+ env.default ? '★' : ''
26
+ ])
27
+ printTable(headers, rows)
28
+ }
@@ -0,0 +1,21 @@
1
+ const { loadEnv } = require('./config')
2
+ const { warn } = require('../../utils/log')
3
+ const printTable = require('../../utils/printTable')
4
+
5
+ module.exports = function listEnv() {
6
+ const envs = loadEnv()
7
+ const names = Object.keys(envs)
8
+
9
+ if (names.length === 0) {
10
+ warn('No environment configuration found')
11
+ return
12
+ }
13
+
14
+ const headers = ['Name', 'URL', 'Default']
15
+ const rows = names.map(name => [
16
+ name,
17
+ envs[name].url || '',
18
+ envs[name].default ? '★' : ''
19
+ ])
20
+ printTable(headers, rows)
21
+ }
@@ -0,0 +1,59 @@
1
+ const { exec } = require('child_process')
2
+ const { getEnvByName, loadDefaultEnv } = require('./config')
3
+ const { error, info } = require('../../utils/log')
4
+
5
+ module.exports = async function remote(envName, options) {
6
+ const { formId } = options
7
+
8
+ if (!formId) {
9
+ error('Error: --form-id (-f) is required')
10
+ return
11
+ }
12
+
13
+ let env
14
+ if (envName) {
15
+ env = getEnvByName(envName)
16
+ if (!env) {
17
+ error(`Error: Environment "${envName}" not found`)
18
+ return
19
+ }
20
+ } else {
21
+ env = loadDefaultEnv()
22
+ if (!env || !env.name) {
23
+ error('Error: No environment specified and no default environment found')
24
+ return
25
+ }
26
+ info(`Using default environment: ${env.name}`)
27
+ }
28
+
29
+ if (!env.url) {
30
+ error(`Error: Environment "${env.name}" has no URL configured`)
31
+ return
32
+ }
33
+
34
+ try {
35
+ const targetUrl = new URL(env.url)
36
+ targetUrl.searchParams.append('formId', formId)
37
+ targetUrl.searchParams.append('kdkwc_cdn', 'http://localhost:3333')
38
+
39
+ const finalUrl = targetUrl.toString()
40
+ info(`Opening: ${finalUrl}`)
41
+
42
+ let cmd
43
+ if (process.platform === 'win32') {
44
+ cmd = `start "" "${finalUrl}"`
45
+ } else if (process.platform === 'darwin') {
46
+ cmd = `open "${finalUrl}"`
47
+ } else {
48
+ cmd = `xdg-open "${finalUrl}"`
49
+ }
50
+
51
+ exec(cmd, (err) => {
52
+ if (err) {
53
+ error(`Failed to open browser: ${err.message}`)
54
+ }
55
+ })
56
+ } catch (e) {
57
+ error(`Invalid Environment URL: ${env.url}`)
58
+ }
59
+ }
@@ -0,0 +1,23 @@
1
+ const { loadEnv, saveEnv } = require('./config')
2
+ const { info, error } = require('../../utils/log')
3
+
4
+ module.exports = function removeEnv(name) {
5
+ const envs = loadEnv()
6
+
7
+ if (!envs[name]) {
8
+ error(`Environment ${name} does not exist`)
9
+ return
10
+ }
11
+
12
+ const wasDefault = envs[name].default
13
+ delete envs[name]
14
+
15
+ let first
16
+ if (wasDefault) {
17
+ first = Object.values(envs)[0]
18
+ if (first) first.default = true
19
+ }
20
+
21
+ saveEnv(envs)
22
+ info(`✅ Environment ${name} deleted${first ? `, default environment switched to ${first?.name || 'none'}` : ''}`)
23
+ }
@@ -0,0 +1,27 @@
1
+ const { loadDefaultEnv, getEnvByName } = require('./config')
2
+ const { error } = require('../../utils/log')
3
+
4
+ /**
5
+ * 根据环境名解析环境
6
+ * - 未传:使用默认环境
7
+ * - 已传:使用指定环境
8
+ */
9
+ module.exports = function resolveEnv(envName) {
10
+ let name = envName
11
+
12
+ if (name === undefined) {
13
+ name = loadDefaultEnv()?.name
14
+ if (!name) {
15
+ error('❌ No environment specified and no default environment exists')
16
+ return
17
+ }
18
+ }
19
+
20
+ const env = getEnvByName(name)
21
+ if (!env?.name) {
22
+ error(`❌ Environment ${name} does not exist`)
23
+ return
24
+ }
25
+
26
+ return { envName: name, env }
27
+ }
@@ -0,0 +1,20 @@
1
+ const { loadEnv, saveEnv } = require('./config')
2
+ const { info, error } = require('../../utils/log')
3
+
4
+ module.exports = function setDefault(name) {
5
+ const envs = loadEnv()
6
+
7
+ if (!envs[name]) {
8
+ error(`Environment ${name} does not exist`)
9
+ return
10
+ }
11
+
12
+ Object.values(envs).forEach(env => {
13
+ env.default = false
14
+ })
15
+
16
+ envs[name].default = true
17
+ saveEnv(envs)
18
+
19
+ info(`✅ ${name} has been set as the default environment`)
20
+ }
@@ -0,0 +1,33 @@
1
+ module.exports = {
2
+ PROJECT_TYPES: {
3
+ KWC: 'kwc',
4
+ PAGE: 'page'
5
+ },
6
+
7
+ TEMPLATES: {
8
+ lwc_js: 'direct:https://github.com/kingdee/cli-template.git#kwc-project',
9
+ react_ts: 'direct:https://github.com/kingdee/cli-template.git#kwc-project-react',
10
+ react_js: 'direct:https://github.com/kingdee/cli-template.git#kwc-project-react-js',
11
+ vue_ts: 'direct:https://github.com/kingdee/cli-template.git#kwc-project-vue',
12
+ vue_js: 'direct:https://github.com/kingdee/cli-template.git#kwc-project-vue-js'
13
+ },
14
+
15
+ INNER_TEMPLATES: {
16
+ lwc_js: 'direct:http://gitlab.kingdee.com/bos-cli-template/kd-custom-control-template.git#kwc-project',
17
+ react_ts: 'direct:http://gitlab.kingdee.com/bos-cli-template/kd-custom-control-template.git#kwc-project-react',
18
+ react_js: 'direct:http://gitlab.kingdee.com/bos-cli-template/kd-custom-control-template.git#kwc-project-react-js',
19
+ vue_ts: 'direct:http://gitlab.kingdee.com/bos-cli-template/kd-custom-control-template.git#kwc-project-vue',
20
+ vue_js: 'direct:http://gitlab.kingdee.com/bos-cli-template/kd-custom-control-template.git#kwc-project-vue-js'
21
+ },
22
+
23
+ FRAMEWORKS: {
24
+ React: 'react',
25
+ Vue: 'vue',
26
+ LWC: 'lwc'
27
+ },
28
+
29
+ LANGUAGES: {
30
+ TypeScript: 'ts',
31
+ JavaScript: 'js'
32
+ }
33
+ }
@@ -0,0 +1,26 @@
1
+ module.exports = function createMetaXml({ name, moduleId, framework }) {
2
+ return `<?xml version="1.0" encoding="UTF-8"?>
3
+ <KingdeeComponentBundle
4
+ xmlns="http://dev.kingdee.com/2025/10/metadata"
5
+ >
6
+ <version></version>
7
+ <name>${name}</name>
8
+ <masterLabel>${name}</masterLabel>
9
+ <isv></isv>
10
+ <moduleid>${moduleId}</moduleid>
11
+ <framework>${framework}</framework>
12
+ <targets>
13
+ <target>BaseFormModel</target>
14
+ <target>BillFormModel</target>
15
+ <target>DynamicFormModel</target>
16
+ <target>MobileBillFormModel</target>
17
+ <target>MobileFormModel</target>
18
+ <target>KWCFormModel</target>
19
+ </targets>
20
+ <targetConfigs>
21
+ <targetConfig>
22
+ <targets>BaseFormModel,BillFormModel,DynamicFormModel,MobileBillFormModel,MobileFormModel,KWCFormModel</targets>
23
+ </targetConfig>
24
+ </targetConfigs>
25
+ </KingdeeComponentBundle>`
26
+ }
@@ -0,0 +1,24 @@
1
+ const { PROJECT_TYPES } = require('../constants')
2
+ const validate = require('./validate')
3
+ const createKwc = require('./kwc')
4
+ const createPage = require('./page')
5
+ const { error } = require('../../../utils/log')
6
+ const { getConfig } = require('../../../utils/projectConfig')
7
+
8
+ module.exports = async function create({ name, type }) {
9
+ const cwd = process.cwd()
10
+ const config = getConfig(cwd) || {}
11
+ validate({ name, type, ...config })
12
+
13
+ try {
14
+ if (type === PROJECT_TYPES.KWC) {
15
+ return createKwc(name, cwd, config)
16
+ }
17
+
18
+ if (type === PROJECT_TYPES.PAGE) {
19
+ return createPage(name, cwd)
20
+ }
21
+ } catch (e) {
22
+ error(`❌ Failed to create: ${e.message}`)
23
+ }
24
+ }
@@ -0,0 +1,25 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+ const { info } = require('../../../utils/log')
4
+ const writeKwcFiles = require('./writeKwcFiles')
5
+
6
+ module.exports = function createKwc(name, cwd, config) {
7
+ const kwcRoot = path.join(cwd, 'app', 'kwc')
8
+ const dir = path.join(kwcRoot, name)
9
+
10
+ if (!fs.existsSync(kwcRoot)) {
11
+ throw new Error('Directory app/kwc not found')
12
+ }
13
+ if (fs.existsSync(dir)) {
14
+ throw new Error(`Component ${name} already exists`)
15
+ }
16
+
17
+ console.time('🕒 KWC component creation time')
18
+ fs.mkdirSync(dir, { recursive: true })
19
+
20
+ writeKwcFiles({ dir, name, ...config })
21
+
22
+ info(`✅ KWC Component ${name} created successfully`)
23
+ console.timeEnd('🕒 KWC component creation time')
24
+ }
25
+
@@ -0,0 +1,42 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+ const { info } = require('../../../utils/log')
4
+
5
+ module.exports = function createPage(name, cwd) {
6
+ const pagesDir = path.join(cwd, 'app/pages')
7
+
8
+ if (!fs.existsSync(pagesDir)) {
9
+ throw new Error('Directory app/pages not found')
10
+ }
11
+
12
+ const file = path.join(pagesDir, `${name}.page-meta.kwp`)
13
+ if (fs.existsSync(file)) {
14
+ throw new Error(`Page ${name} already exists`)
15
+ }
16
+
17
+ console.time(`🕒 Page ${name} creation time`)
18
+ fs.writeFileSync(file, createPageXml(name))
19
+
20
+ info(`✅ Page ${name} created successfully`)
21
+ console.timeEnd(`🕒 Page ${name} creation time`)
22
+ }
23
+
24
+ function createPageXml(name) {
25
+ return `<?xml version="1.0" encoding="UTF-8"?>
26
+
27
+ <Page>
28
+ <name>${name}</name>
29
+ <masterLabel>${name}</masterLabel>
30
+ <template>oneregion</template>
31
+ <app></app>
32
+ <isv></isv>
33
+ <version>1</version>
34
+ <regions>
35
+ <region>
36
+ <name>region1</name>
37
+ <controls>
38
+ </controls>
39
+ </region>
40
+ </regions>
41
+ </Page>`
42
+ }