neo-cmp-cli 1.2.15 → 1.2.17

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": "neo-cmp-cli",
3
- "version": "1.2.15",
3
+ "version": "1.2.17",
4
4
  "description": "前端脚手架:自定义组件开发工具,支持react 和 vue2.0技术栈。",
5
5
  "keywords": [
6
6
  "neo-cli",
@@ -110,9 +110,9 @@ module.exports = {
110
110
  curConfig.webpack.plugins &&
111
111
  Array.isArray(curConfig.webpack.plugins)
112
112
  ) {
113
- curConfig.webpack.plugins.push(new AddNeoRequirePlugin({verbose: true}));
113
+ curConfig.webpack.plugins.push(new AddNeoRequirePlugin({ verbose: true }));
114
114
  } else {
115
- curConfig.webpack.plugins = [new AddNeoRequirePlugin({verbose: true})];
115
+ curConfig.webpack.plugins = [new AddNeoRequirePlugin({ verbose: true })];
116
116
  }
117
117
 
118
118
  // 添加 内置 Neo 的 externals 配置
@@ -197,7 +197,10 @@ module.exports = {
197
197
  curCmpTypes = cmpTypes;
198
198
  } else {
199
199
  // 自动生成入口文件(并自动创建对应的注册文件)
200
- const { widgetEntries, cmpTypes } = getEntriesWithAutoRegister(curConfig.componentsDir, cmpType);
200
+ const { widgetEntries, cmpTypes } = getEntriesWithAutoRegister(
201
+ curConfig.componentsDir,
202
+ cmpType
203
+ );
201
204
  entries = widgetEntries;
202
205
  curCmpTypes = cmpTypes;
203
206
  }
@@ -230,9 +233,9 @@ module.exports = {
230
233
  curConfig.webpack.plugins &&
231
234
  Array.isArray(curConfig.webpack.plugins)
232
235
  ) {
233
- curConfig.webpack.plugins.push(new AddNeoRequirePlugin({verbose: true}));
236
+ curConfig.webpack.plugins.push(new AddNeoRequirePlugin({ verbose: true }));
234
237
  } else {
235
- curConfig.webpack.plugins = [new AddNeoRequirePlugin({verbose: true})];
238
+ curConfig.webpack.plugins = [new AddNeoRequirePlugin({ verbose: true })];
236
239
  }
237
240
 
238
241
  // 添加 内置 Neo 的 externals 配置
@@ -251,7 +254,9 @@ module.exports = {
251
254
  Object.keys(curConfig.build2lib.entry).forEach((name) => {
252
255
  // 判断不是以Model结尾的文件
253
256
  if (!name.endsWith('Model')) {
254
- curConfig.build2lib.entry[name] = [commonModulesFilePath].concat(curConfig.build2lib.entry[name]);
257
+ curConfig.build2lib.entry[name] = [commonModulesFilePath].concat(
258
+ curConfig.build2lib.entry[name]
259
+ );
255
260
  }
256
261
  });
257
262
  }
@@ -1,6 +1,7 @@
1
1
  const { aliBOS, baiduBOS } = require('akfun');
2
2
  const fs = require('fs');
3
3
  const path = require('path');
4
+ const _ = require('lodash');
4
5
  const { catchCurPackageJson } = require('../utils/pathUtils');
5
6
  const getConfigObj = require('../utils/getConfigObj');
6
7
  const updatePublishLog = require('../cmpUtils/updatePublishLog');
@@ -185,13 +186,25 @@ const getResultFilesByWidgetName = (files) => {
185
186
  return;
186
187
  }
187
188
  let widgetName = file.widgetName;
189
+ const curCmpInfo = {
190
+ 'cmpType': _.kebabCase(widgetName),
191
+ }
192
+
188
193
  if (widgetName.includes('Model')) {
189
194
  widgetName = widgetName.replace('Model', '');
195
+ curCmpInfo.cmpType = _.kebabCase(widgetName),
196
+ curCmpInfo.modelAsset = !file.success ? `${file.error}[${file.ossPath}]` : file.ossPath;
197
+ } else if (file.fileName.endsWith('.css')) {
198
+ curCmpInfo.cssAsset = !file.success ? `${file.error}[${file.ossPath}]` : file.ossPath;
199
+ } else {
200
+ curCmpInfo.asset = !file.success ? `${file.error}[${file.ossPath}]` : file.ossPath;
190
201
  }
202
+
191
203
  if (widgetFilesMap[widgetName]) {
192
- widgetFilesMap[widgetName].push(getResultFile(file));
204
+ widgetFilesMap[widgetName] = Object.assign(widgetFilesMap[widgetName], curCmpInfo);
193
205
  } else {
194
- widgetFilesMap[widgetName] = [getResultFile(file)];
206
+ // widgetFilesMap[widgetName] = [getResultFile(file)];
207
+ widgetFilesMap[widgetName] = curCmpInfo;
195
208
  }
196
209
  });
197
210
 
@@ -31,14 +31,14 @@ class AddNeoRequirePlugin {
31
31
  return true;
32
32
  }
33
33
  }
34
-
34
+
35
35
  // 检查文件名模式
36
36
  for (const pattern of this.options.skipPatterns) {
37
37
  if (pattern.test(filename)) {
38
38
  return true;
39
39
  }
40
40
  }
41
-
41
+
42
42
  return false;
43
43
  }
44
44
 
@@ -49,10 +49,12 @@ class AddNeoRequirePlugin {
49
49
  if (!content || typeof content !== 'string') {
50
50
  return false;
51
51
  }
52
-
52
+
53
53
  // 检查是否包含注入的标识
54
- return content.includes('NeoCustomCmpFileFactory(window.neoRequire)') &&
55
- content.includes('if (!window.neoRequire)');
54
+ return (
55
+ content.includes('NeoCustomCmpFileFactory(window.neoRequire)') &&
56
+ content.includes('if (!window.neoRequire)')
57
+ );
56
58
  }
57
59
 
58
60
  /**
@@ -62,12 +64,12 @@ class AddNeoRequirePlugin {
62
64
  if (!content || typeof content !== 'string') {
63
65
  return false;
64
66
  }
65
-
67
+
66
68
  // 检查文件是否为空或只包含空白字符
67
69
  if (content.trim().length === 0) {
68
70
  return false;
69
71
  }
70
-
72
+
71
73
  return true;
72
74
  }
73
75
 
@@ -77,7 +79,7 @@ class AddNeoRequirePlugin {
77
79
  log(message, level = 'info') {
78
80
  if (this.options.verbose || level === 'error') {
79
81
  const prefix = `[AddNeoRequirePlugin]`;
80
- console[level](`/n${prefix} ${message}`);
82
+ console[level](`${prefix} ${message}`);
81
83
  }
82
84
  }
83
85
 
@@ -90,7 +92,7 @@ class AddNeoRequirePlugin {
90
92
  },
91
93
  (assets) => {
92
94
  this.log('开始处理资源文件...');
93
-
95
+
94
96
  let processedCount = 0;
95
97
  let skippedCount = 0;
96
98
  let errorCount = 0;
@@ -126,9 +128,8 @@ class AddNeoRequirePlugin {
126
128
  // 执行注入
127
129
  this.injectNeoRequire(compilation, filename, content);
128
130
  processedCount++;
129
-
130
- this.log(`成功处理文件: ${filename}`);
131
131
 
132
+ this.log(`成功处理文件: ${filename}`);
132
133
  } catch (error) {
133
134
  errorCount++;
134
135
  this.log(`处理文件失败: ${filename}, 错误: ${error.message}`, 'error');
@@ -137,8 +138,10 @@ class AddNeoRequirePlugin {
137
138
  }
138
139
 
139
140
  // 输出处理统计
140
- this.log(`处理完成 - 成功: ${processedCount}, 跳过: ${skippedCount}, 错误: ${errorCount}`);
141
-
141
+ this.log(
142
+ `处理完成 - 成功: ${processedCount}, 跳过: ${skippedCount}, 错误: ${errorCount}`
143
+ );
144
+
142
145
  if (errorCount > 0) {
143
146
  this.log(`警告: 有 ${errorCount} 个文件处理失败`, 'warn');
144
147
  }
@@ -164,7 +167,7 @@ class AddNeoRequirePlugin {
164
167
 
165
168
  // 创建新的资源
166
169
  const newSource = new ConcatSource(Header, content, Footer);
167
-
170
+
168
171
  // 更新资源
169
172
  compilation.updateAsset(filename, newSource);
170
173
  }
@@ -47,7 +47,7 @@
47
47
  "@commitlint/config-conventional": "^9.1.1",
48
48
  "@types/react": "^16.9.11",
49
49
  "@types/react-dom": "^16.9.15",
50
- "neo-cmp-cli": "^1.2.15",
50
+ "neo-cmp-cli": "^1.2.17",
51
51
  "husky": "^4.2.5",
52
52
  "lint-staged": "^10.2.9",
53
53
  "prettier": "^2.0.5"
@@ -51,7 +51,7 @@
51
51
  "@types/react": "^16.9.11",
52
52
  "@types/react-dom": "^16.9.15",
53
53
  "@types/axios": "^0.14.0",
54
- "neo-cmp-cli": "^1.2.15",
54
+ "neo-cmp-cli": "^1.2.17",
55
55
  "husky": "^4.2.5",
56
56
  "lint-staged": "^10.2.9",
57
57
  "prettier": "^2.0.5"
@@ -47,7 +47,7 @@
47
47
  "@commitlint/config-conventional": "^9.1.1",
48
48
  "@types/react": "^16.9.11",
49
49
  "@types/react-dom": "^16.9.15",
50
- "neo-cmp-cli": "^1.2.15",
50
+ "neo-cmp-cli": "^1.2.17",
51
51
  "husky": "^4.2.5",
52
52
  "lint-staged": "^10.2.9",
53
53
  "prettier": "^2.0.5",
@@ -101,6 +101,7 @@ module.exports = {
101
101
  },
102
102
  publish2oss: {
103
103
  // 用于构建并发布至 OSS 的相关配置
104
+ cssExtract: true, // 不额外提取css文件
104
105
  /*
105
106
  【特别说明】以下配置项都自带默认值,非必填。如需自定义请自行配置。
106
107
  NODE_ENV: 'production',
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo-custom-cmp-template",
3
- "version": "1.1.1",
3
+ "version": "1.1.6",
4
4
  "description": "neo自定义组件模板(react&ts技术栈)",
5
5
  "keywords": [
6
6
  "自定义组件模板",
@@ -44,7 +44,7 @@
44
44
  "axios": "^0.27.2",
45
45
  "antd": "^4.9.4",
46
46
  "lodash": "^4.17.21",
47
- "neo-open-api": "^1.0.8"
47
+ "neo-open-api": "^1.0.11"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@commitlint/cli": "^8.3.5",
@@ -52,7 +52,7 @@
52
52
  "@types/react": "^16.9.11",
53
53
  "@types/react-dom": "^16.9.15",
54
54
  "@types/axios": "^0.14.0",
55
- "neo-cmp-cli": "^1.2.15",
55
+ "neo-cmp-cli": "^1.2.17",
56
56
  "husky": "^4.2.5",
57
57
  "lint-staged": "^10.2.9",
58
58
  "prettier": "^2.0.5"
@@ -28,6 +28,7 @@ interface EntityDetailProps {
28
28
  xObjectDetailApi?: {
29
29
  xObjectApiKey: string;
30
30
  objectId: string;
31
+ fieldDescList?: any[];
31
32
  };
32
33
  columnCount?: number;
33
34
  showTitle?: boolean;
@@ -85,7 +86,7 @@ export default class EntityDetail extends React.PureComponent<
85
86
  const { xObjectDetailApi } = this.props;
86
87
  if (!xObjectDetailApi?.xObjectApiKey || !xObjectDetailApi?.objectId) {
87
88
  this.setState({
88
- error: '缺少必要参数:实体类型或数据ID',
89
+ error: '缺少必要参数:实体类型或业务数据ID',
89
90
  loading: false,
90
91
  });
91
92
  return;
@@ -95,9 +96,16 @@ export default class EntityDetail extends React.PureComponent<
95
96
  }
96
97
 
97
98
  async loadFieldDescriptions() {
98
- const { xObjectDetailApi } = this.props;
99
- if (!xObjectDetailApi?.xObjectApiKey) return;
99
+ const { xObjectDetailApi } = this.props || {};
100
+
101
+ // 方式一:直接从 props.xObjectDetailApi 中获取字段描述
102
+ if (xObjectDetailApi && xObjectDetailApi.fieldDescList) {
103
+ this.setState({ fieldDescriptions: xObjectDetailApi.fieldDescList });
104
+ }
100
105
 
106
+ /*
107
+ // 方式二:自行通过 OpenAPI SDK 获取字段描述
108
+ if (!xObjectDetailApi.xObjectApiKey) return;
101
109
  try {
102
110
  const result = await xObject.getDesc(xObjectDetailApi.xObjectApiKey);
103
111
  if (result?.status) {
@@ -107,6 +115,7 @@ export default class EntityDetail extends React.PureComponent<
107
115
  } catch (error: any) {
108
116
  console.error('获取字段描述失败:', error);
109
117
  }
118
+ */
110
119
  }
111
120
 
112
121
  async loadEntityDetail() {
@@ -116,10 +125,7 @@ export default class EntityDetail extends React.PureComponent<
116
125
  this.setState({ loading: true, error: null });
117
126
 
118
127
  try {
119
- const result = await xObject.get(
120
- xObjectDetailApi.xObjectApiKey,
121
- xObjectDetailApi.objectId,
122
- );
128
+ const result = await xObject.get(xObjectDetailApi);
123
129
 
124
130
  if (result?.status) {
125
131
  const data = result.data || {};
@@ -266,6 +272,7 @@ export default class EntityDetail extends React.PureComponent<
266
272
  const { loading, error } = this.state;
267
273
  const curAmisData = this.props.data || {};
268
274
  const systemInfo = curAmisData.__NeoSystemInfo || {};
275
+ console.log('this.props:', this.props);
269
276
 
270
277
  return (
271
278
  <div className="entity-detail-container">
@@ -26,7 +26,7 @@ export class ObjectCardListModel {
26
26
  label: '数据卡片列表',
27
27
  xObjectDataApi: {
28
28
  xObjectApiKey: 'customContact__c',
29
- fields: ['id', 'name', 'phone__c'],
29
+ fields: ['name', 'phone__c'],
30
30
  },
31
31
  };
32
32
 
@@ -52,6 +52,13 @@ export class ObjectCardListModel {
52
52
  name: 'xObjectDataApi',
53
53
  label: '实体数据源',
54
54
  placeholder: '请选择实体数据源',
55
+ /*
56
+ // 返回的数值格式:
57
+ value: {
58
+ xObjectApiKey: 'customContact__c',
59
+ fields: ['name', 'phone__c'],
60
+ },
61
+ */
55
62
  },
56
63
  ];
57
64
 
@@ -31,6 +31,8 @@ import {
31
31
  import moment from 'moment';
32
32
  // @ts-ignore
33
33
  import { xObject } from 'neo-open-api'; // Neo Open API
34
+ // @ts-ignore
35
+ import isEqual from 'lodash/isEqual';
34
36
  import './style.scss';
35
37
 
36
38
  const { Option } = Select;
@@ -43,6 +45,9 @@ interface XObjectTableProps {
43
45
  xObjectDataApi: {
44
46
  xObjectApiKey: string;
45
47
  fields: string[];
48
+ fieldDescList?: any[];
49
+ pageSize?: number;
50
+ page?: number;
46
51
  };
47
52
  /** Neo 平台传递的数据,包含系统信息等 */
48
53
  data?: any;
@@ -120,7 +125,7 @@ export default class XObjectTable extends React.PureComponent<
120
125
  constructor(props: XObjectTableProps) {
121
126
  super(props);
122
127
  const { xObjectDataApi } = props;
123
- const { xObjectApiKey, fields } = xObjectDataApi || {};
128
+ const { xObjectApiKey, fields, page, pageSize } = xObjectDataApi || {};
124
129
 
125
130
  // 初始化组件状态
126
131
  this.state = {
@@ -129,8 +134,8 @@ export default class XObjectTable extends React.PureComponent<
129
134
  loading: false,
130
135
  error: null,
131
136
  pagination: {
132
- current: 1,
133
- pageSize: 10,
137
+ current: page || 1,
138
+ pageSize: pageSize || 10,
134
139
  total: 0,
135
140
  },
136
141
  isModalVisible: false,
@@ -143,10 +148,10 @@ export default class XObjectTable extends React.PureComponent<
143
148
  if (xObjectApiKey) {
144
149
  // 初始化字段列表、加载数据和业务类型列表
145
150
  this.getEntityTypeList(xObjectApiKey);
146
- this.loadFieldList(xObjectApiKey);
151
+ this.loadFieldList();
147
152
 
148
153
  if (fields) {
149
- this.loadData();
154
+ this.loadData(page, pageSize);
150
155
  }
151
156
  }
152
157
 
@@ -165,16 +170,29 @@ export default class XObjectTable extends React.PureComponent<
165
170
  * 当 xObjectApiKey 发生变化时重新加载数据
166
171
  */
167
172
  async componentDidUpdate(prevProps: XObjectTableProps) {
168
- const { xObjectApiKey } = this.props.xObjectDataApi || {};
169
- const { xObjectApiKey: prevXObjectApiKey } = prevProps.xObjectDataApi || {};
170
- if (xObjectApiKey !== prevXObjectApiKey) {
173
+ const { xObjectApiKey, fields, page, pageSize } =
174
+ this.props.xObjectDataApi || {};
175
+ const {
176
+ xObjectApiKey: prevXObjectApiKey,
177
+ fields: prevFields,
178
+ page: prevPage,
179
+ pageSize: prevPageSize,
180
+ } = prevProps.xObjectDataApi || {};
181
+ if (
182
+ xObjectApiKey !== prevXObjectApiKey ||
183
+ !isEqual(fields, prevFields) ||
184
+ page !== prevPage ||
185
+ pageSize !== prevPageSize
186
+ ) {
171
187
  if (xObjectApiKey) {
172
- this.loadData();
173
- this.getEntityTypeList(xObjectApiKey);
174
- this.loadFieldList(xObjectApiKey);
188
+ // 先加载字段列表,等待完成后再加载数据,确保字段信息已更新
189
+ await this.loadFieldList();
190
+ await this.getEntityTypeList(xObjectApiKey);
191
+ this.loadData(page, pageSize);
175
192
  } else {
176
193
  this.setState({
177
194
  dataSource: [],
195
+ fieldList: [],
178
196
  });
179
197
  }
180
198
  }
@@ -200,19 +218,26 @@ export default class XObjectTable extends React.PureComponent<
200
218
  * 加载字段列表
201
219
  * 从 Neo 平台获取 XObject 的字段描述信息
202
220
  */
203
- async loadFieldList(xObjectApiKey?: string) {
204
- if (!xObjectApiKey) return;
205
-
206
- try {
207
- const resultData = await xObject.getDesc(xObjectApiKey);
208
- if (resultData && resultData.status) {
209
- const result = resultData.data || {};
210
- const fieldList = result.fields || [];
211
- this.setState({ fieldList, title: result.label });
221
+ async loadFieldList() {
222
+ const { xObjectDataApi } = this.props || {};
223
+
224
+ // 方式一:直接从 props.xObjectDetailApi 中获取字段描述
225
+ if (xObjectDataApi && xObjectDataApi.fieldDescList) {
226
+ this.setState({ fieldList: xObjectDataApi.fieldDescList });
227
+ } else {
228
+ // 方式二:自行通过 OpenAPI SDK 获取字段描述
229
+ if (!xObjectDataApi.xObjectApiKey) return;
230
+ try {
231
+ const resultData = await xObject.getDesc(xObjectDataApi.xObjectApiKey);
232
+ if (resultData && resultData.status) {
233
+ const result = resultData.data || {};
234
+ const fieldList = result.fields || [];
235
+ this.setState({ fieldList, title: result.label });
236
+ }
237
+ } catch (error) {
238
+ console.error('获取字段列表失败:', error);
239
+ message.error('获取字段列表失败');
212
240
  }
213
- } catch (error) {
214
- console.error('获取字段列表失败:', error);
215
- message.error('获取字段列表失败');
216
241
  }
217
242
  }
218
243
 
@@ -292,19 +317,14 @@ export default class XObjectTable extends React.PureComponent<
292
317
  * @param pageSize 每页条数,默认为 10
293
318
  */
294
319
  async loadData(page = 1, pageSize = 10) {
295
- const { xObjectApiKey, fields } = this.props.xObjectDataApi || {};
320
+ const { xObjectApiKey } = this.props.xObjectDataApi || {};
296
321
  if (!xObjectApiKey) return;
297
322
 
298
323
  this.setState({ loading: true, error: null });
299
324
 
300
325
  try {
301
326
  // 获取所有字段的 API Key=
302
- const result = await xObject.query({
303
- xObjectApiKey,
304
- fields,
305
- page,
306
- pageSize,
307
- });
327
+ const result = await xObject.query(this.props.xObjectDataApi);
308
328
 
309
329
  if (result && result.status) {
310
330
  const records = result.data || [];
@@ -661,6 +681,7 @@ export default class XObjectTable extends React.PureComponent<
661
681
  const systemInfo = curAmisData.__NeoSystemInfo || {};
662
682
  const { xObjectApiKey } = this.props.xObjectDataApi || {};
663
683
  const columns = this.generateColumns();
684
+ console.log('this.props:', this.props);
664
685
 
665
686
  return (
666
687
  <div className="xobject-table-container">
@@ -718,6 +739,7 @@ export default class XObjectTable extends React.PureComponent<
718
739
  />
719
740
  ) : (
720
741
  <Table
742
+ key={`${xObjectApiKey}-${columns.length}`}
721
743
  columns={columns}
722
744
  dataSource={dataSource}
723
745
  rowKey="id"
@@ -13,7 +13,7 @@ export class XObjectTableModel {
13
13
  // cmpType: string = 'xobject-table';
14
14
 
15
15
  /** 组件名称,用于设置在编辑器左侧组件面板中展示的名称 */
16
- label: string = '实体对象数据';
16
+ label: string = '实体数据表格';
17
17
 
18
18
  /** 组件描述,用于设置在编辑器左侧组件面板中展示的描述 */
19
19
  description: string = '基于 XObject 的数据表格组件,支持增删改查操作';
@@ -32,17 +32,13 @@ export class XObjectTableModel {
32
32
  showDeleteButton: true,
33
33
  xObjectDataApi: {
34
34
  xObjectApiKey: 'customContact__c',
35
- fields: ['id', 'name', 'phone__c'],
35
+ fields: ['name', 'phone__c'],
36
36
  },
37
37
  };
38
38
 
39
39
  /** 设计器端预览时展示的默认数据 */
40
40
  previewComProps = {
41
41
  title: '实体数据表格',
42
- xObjectDataApi: {
43
- xObjectApiKey: 'customContact__c',
44
- fields: ['id', 'name', 'phone__c'],
45
- },
46
42
  };
47
43
 
48
44
  /**
@@ -100,7 +96,7 @@ export class XObjectTableModel {
100
96
  label: '实体数据源',
101
97
  value: {
102
98
  xObjectApiKey: 'customContact__c',
103
- fields: ['id', 'name', 'phone__c'],
99
+ fields: ['name', 'phone__c'],
104
100
  },
105
101
  placeholder: '请选择实体数据源',
106
102
  custom: true,
@@ -44,7 +44,7 @@
44
44
  "devDependencies": {
45
45
  "@commitlint/cli": "^8.3.5",
46
46
  "@commitlint/config-conventional": "^9.1.1",
47
- "neo-cmp-cli": "^1.2.15",
47
+ "neo-cmp-cli": "^1.2.17",
48
48
  "husky": "^4.2.5",
49
49
  "lint-staged": "^10.2.9",
50
50
  "prettier": "^2.0.5"
@@ -46,7 +46,7 @@
46
46
  "@commitlint/config-conventional": "^9.1.1",
47
47
  "@types/react": "^16.9.11",
48
48
  "@types/react-dom": "^16.9.15",
49
- "neo-cmp-cli": "^1.2.15",
49
+ "neo-cmp-cli": "^1.2.17",
50
50
  "husky": "^4.2.5",
51
51
  "lint-staged": "^10.2.9",
52
52
  "prettier": "^2.0.5"
@@ -44,7 +44,7 @@
44
44
  "devDependencies": {
45
45
  "@commitlint/cli": "^8.3.5",
46
46
  "@commitlint/config-conventional": "^9.1.1",
47
- "neo-cmp-cli": "^1.2.15",
47
+ "neo-cmp-cli": "^1.2.17",
48
48
  "husky": "^4.2.5",
49
49
  "lint-staged": "^10.2.9",
50
50
  "prettier": "^2.0.5",