@ray-js/lamp-schedule-core 1.0.1-beta-10 → 1.0.2-beta-2

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 (37) hide show
  1. package/lib/conflict/ConflictResolver.js +48 -21
  2. package/lib/conflict/__test__/ConflictResolver.test.js +49 -0
  3. package/lib/conflict/__test__/scheduleDataManager.test.js +66 -0
  4. package/lib/conflict/__test__/transform.test.js +5 -1
  5. package/lib/conflict/index.js +27 -7
  6. package/lib/conflict/scheduleDataManager.js +28 -33
  7. package/lib/context/rhythms/actions.d.ts +13 -17
  8. package/lib/context/rhythms/reducer.d.ts +2 -23
  9. package/lib/context/rhythms/reducer.js +7 -8
  10. package/lib/context/schedule/reducer.d.ts +5 -2
  11. package/lib/dpParser/__test__/autoDispatch.test.d.ts +1 -0
  12. package/lib/dpParser/__test__/autoDispatch.test.js +45 -0
  13. package/lib/dpParser/__test__/rhythms.test.js +90 -14
  14. package/lib/dpParser/__test__/rtcTimer.test.js +35 -0
  15. package/lib/dpParser/__test__/sleep.test.js +17 -0
  16. package/lib/dpParser/__test__/wakeup.test.js +17 -4
  17. package/lib/dpParser/__test__/wakeupSigmesh.test.d.ts +1 -0
  18. package/lib/dpParser/__test__/wakeupSigmesh.test.js +126 -0
  19. package/lib/hooks/__test__/useBaseLightDp.test.d.ts +1 -0
  20. package/lib/hooks/__test__/useBaseLightDp.test.js +251 -0
  21. package/lib/hooks/__test__/useCommonSupport.test.d.ts +1 -0
  22. package/lib/hooks/__test__/useCommonSupport.test.js +204 -0
  23. package/lib/hooks/__test__/useTimerFlushList.test.d.ts +1 -0
  24. package/lib/hooks/__test__/useTimerFlushList.test.js +117 -0
  25. package/lib/hooks/__test__/useTimerOperate.test.js +239 -5
  26. package/lib/hooks/__test__/useTimerOperateLocal.test.js +161 -53
  27. package/lib/hooks/useCommonSupport.js +16 -19
  28. package/lib/types/rhythms.d.ts +25 -13
  29. package/lib/types/ty.d.ts +3 -0
  30. package/lib/utils/ScheduleDataSync.js +4 -1
  31. package/lib/utils/ScheduleLogger.js +1 -1
  32. package/lib/utils/__test__/ScheduleDataSync.test.d.ts +11 -0
  33. package/lib/utils/__test__/ScheduleDataSync.test.js +137 -0
  34. package/lib/utils/__test__/ScheduleEmit.test.d.ts +1 -0
  35. package/lib/utils/__test__/ScheduleEmit.test.js +35 -0
  36. package/lib/utils/__test__/ScheduleSupport.test.js +288 -154
  37. package/package.json +1 -1
@@ -1,55 +1,69 @@
1
1
  import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
+ /* eslint-disable no-bitwise */
2
3
  import { Support, DeviceCapability, getBitValue } from '../ScheduleSupport';
3
- import { setScheduleCache, getScheduleCache } from '../ScheduleCache';
4
- import { getDpCodeByDpId, getDpIdByDpCode } from '../ScheduleUtils';
5
-
6
- // 模拟依赖
4
+ import { setScheduleCache, getScheduleCache, devIdOrGroupIdCache } from '../ScheduleCache';
5
+ import { setDpState } from '../dpState';
6
+ import { getDpCodeByDpId } from '../ScheduleUtils';
7
+ import { getDeviceInfo, getGroupInfo } from '@ray-js/ray';
8
+ jest.mock('@ray-js/ray', () => ({
9
+ getDeviceInfo: jest.fn(),
10
+ getGroupInfo: jest.fn()
11
+ }));
7
12
  jest.mock('../ScheduleCache', () => ({
8
13
  setScheduleCache: jest.fn(),
9
14
  getScheduleCache: jest.fn(),
10
- clearScheduleCache: jest.fn()
15
+ devIdOrGroupIdCache: {
16
+ set: jest.fn(),
17
+ get: jest.fn().mockReturnValue({
18
+ devId: '',
19
+ groupId: ''
20
+ })
21
+ }
11
22
  }));
12
23
  jest.mock('../dpState', () => ({
13
- setDpState: jest.fn(),
14
- clearDpState: jest.fn()
24
+ setDpState: jest.fn()
15
25
  }));
16
26
  jest.mock('../ScheduleUtils', () => ({
17
- getDpCodeByDpId: jest.fn(),
18
- getDpIdByDpCode: jest.fn()
27
+ getDpCodeByDpId: jest.fn()
28
+ }));
29
+ jest.mock('../ScheduleLogger', () => ({
30
+ scheduleLogger: {
31
+ debug: jest.fn(),
32
+ info: jest.fn(),
33
+ warn: jest.fn(),
34
+ error: jest.fn()
35
+ }
19
36
  }));
20
37
  describe('ScheduleSupport', () => {
21
38
  beforeEach(() => {
22
- jest.clearAllMocks();
39
+ jest.resetAllMocks();
23
40
  });
24
41
  describe('getBitValue', () => {
25
- it('应该正确获取数字指定位的值', () => {
26
- expect(getBitValue(0b1010, 0)).toBe(0); // 第0位是0
27
- expect(getBitValue(0b1010, 1)).toBe(1); // 第1位是1
28
- expect(getBitValue(0b1010, 2)).toBe(0); // 第2位是0
29
- expect(getBitValue(0b1010, 3)).toBe(1); // 第3位是1
30
- expect(getBitValue(0b1010, 4)).toBe(0); // 第4位是0(超出范围)
42
+ it('returns the specific bit value', () => {
43
+ expect(getBitValue(0b1011, 0)).toBe(1);
44
+ expect(getBitValue(0b1011, 1)).toBe(1);
45
+ expect(getBitValue(0b1011, 2)).toBe(0);
46
+ expect(getBitValue(0b1011, 3)).toBe(1);
31
47
  });
32
- it('当数字为0时应该返回0', () => {
33
- expect(getBitValue(0, 0)).toBe(0);
34
- expect(getBitValue(0, 1)).toBe(0);
35
- expect(getBitValue(0, 10)).toBe(0);
48
+ it('returns 0 when bit not set', () => {
49
+ expect(getBitValue(0, 5)).toBe(0);
36
50
  });
37
51
  });
38
- describe('DeviceCapability枚举', () => {
39
- it('应该定义了正确的设备能力枚举值', () => {
52
+ describe('DeviceCapability enum', () => {
53
+ it('contains expected bit definitions', () => {
40
54
  expect(DeviceCapability.WIFI).toBe(0);
41
55
  expect(DeviceCapability.ZIGBEE).toBe(12);
42
56
  expect(DeviceCapability.SIGMESH).toBe(15);
43
57
  expect(DeviceCapability.BLUETOOTH).toBe(10);
44
58
  });
45
59
  });
46
- describe('Support', () => {
47
- let support;
48
- const mockDevInfo = {
49
- devId: 'test-device-id',
50
- capability: 12,
60
+ describe('Support class', () => {
61
+ const baseDevInfo = {
62
+ devId: 'dev-1',
63
+ capability: 0,
51
64
  dps: {
52
- 1: true
65
+ 1: true,
66
+ 2: false
53
67
  },
54
68
  schema: [{
55
69
  id: 1,
@@ -57,154 +71,274 @@ describe('ScheduleSupport', () => {
57
71
  }, {
58
72
  id: 2,
59
73
  code: 'bright_value'
60
- }]
74
+ }],
75
+ panelConfig: {
76
+ bic: [{
77
+ code: 'timer',
78
+ selected: true
79
+ }]
80
+ },
81
+ isMatter: false,
82
+ isTripartiteMatter: false
61
83
  };
62
- const mockGroupInfo = {
63
- groupId: 'test-group-id',
64
- capability: DeviceCapability.ZIGBEE,
84
+ const baseGroupInfo = {
85
+ groupId: 'group-1',
86
+ capability: 0,
65
87
  dps: {
66
88
  1: true
67
89
  },
68
- schema: [{
69
- id: 1,
70
- code: 'switch_led'
71
- }, {
72
- id: 2,
73
- code: 'bright_value'
74
- }]
90
+ deviceList: [],
91
+ panelConfig: {
92
+ bic: [{
93
+ code: 'timer',
94
+ selected: true
95
+ }]
96
+ }
97
+ };
98
+ const setCachedDevInfo = info => {
99
+ getScheduleCache.mockReturnValue(info);
75
100
  };
76
- beforeEach(() => {
77
- support = new Support({
78
- devId: 'test-device-id'
101
+ describe('init workflow', () => {
102
+ it('fails when neither devId nor groupId provided', async () => {
103
+ const support = new Support({
104
+ devId: '',
105
+ groupId: ''
106
+ });
107
+ await expect(support.init()).rejects.toThrow('devId and groupId are undefined');
79
108
  });
80
- // 模拟getScheduleCache返回null,表示缓存中没有数据
81
- getScheduleCache.mockReturnValue(null);
82
- });
83
- describe('初始化', () => {
84
- it('应该正确初始化设备信息', () => {
85
- support.setDevInfo(mockDevInfo);
86
- expect(setScheduleCache).toHaveBeenCalledWith('devInfo', mockDevInfo);
109
+ it('initializes device info when devId provided', async () => {
110
+ const support = new Support({
111
+ devId: 'dev-1',
112
+ groupId: undefined
113
+ });
114
+ const deviceInfo = _objectSpread(_objectSpread({}, baseDevInfo), {}, {
115
+ capability: 1 << DeviceCapability.WIFI
116
+ });
117
+ getDpCodeByDpId.mockReturnValue('switch_led');
118
+ getDeviceInfo.mockImplementation(_ref => {
119
+ let {
120
+ success
121
+ } = _ref;
122
+ return success(deviceInfo);
123
+ });
124
+ await expect(support.init()).resolves.toBe(true);
125
+ expect(setScheduleCache).toHaveBeenCalledWith('devInfo', deviceInfo);
126
+ expect(setDpState).toHaveBeenCalledWith('switch_led', true);
127
+ expect(devIdOrGroupIdCache.set).toHaveBeenCalledWith('dev-1', '');
128
+ });
129
+ it('initializes group info when groupId provided', async () => {
130
+ const support = new Support({
131
+ devId: '',
132
+ groupId: 'group-1'
133
+ });
134
+ const groupInfo = _objectSpread(_objectSpread({}, baseGroupInfo), {}, {
135
+ dps: {
136
+ 1: true
137
+ },
138
+ deviceList: []
139
+ });
140
+ getDpCodeByDpId.mockReturnValue('switch_led');
141
+ getGroupInfo.mockImplementation(_ref2 => {
142
+ let {
143
+ success
144
+ } = _ref2;
145
+ return success(groupInfo);
146
+ });
147
+ await expect(support.init()).resolves.toBe(true);
148
+ expect(setScheduleCache).toHaveBeenCalledWith('devInfo', groupInfo);
149
+ expect(setDpState).toHaveBeenCalledWith('switch_led', true);
150
+ expect(devIdOrGroupIdCache.set).toHaveBeenCalledWith('', 'group-1');
87
151
  });
88
- it('应该正确初始化群组信息', () => {
89
- support.setGroupDevInfo(mockGroupInfo);
90
- expect(setScheduleCache).toHaveBeenCalledWith('devInfo', mockGroupInfo);
152
+ it('propagates device info failure', async () => {
153
+ const support = new Support({
154
+ devId: 'dev-1',
155
+ groupId: undefined
156
+ });
157
+ getDeviceInfo.mockImplementation(_ref3 => {
158
+ let {
159
+ fail
160
+ } = _ref3;
161
+ setTimeout(() => fail(new Error('boom')), 0);
162
+ });
163
+ await expect(support.init()).rejects.toThrow('get dev info fail');
91
164
  });
92
- });
93
- describe('设备信息获取', () => {
94
- it('getCachedDevInfo应该返回缓存的设备信息', () => {
95
- getScheduleCache.mockReturnValue(mockDevInfo);
96
- const result = support.getCachedDevInfo();
97
- expect(result).toEqual(mockDevInfo);
98
- expect(getScheduleCache).toHaveBeenCalledWith('devInfo');
99
- });
100
- it('getDevInfo应该返回设备信息', () => {
101
- getScheduleCache.mockReturnValue(mockDevInfo);
102
- const result = support.getDevInfo();
103
- expect(result).toEqual(mockDevInfo);
104
- });
105
- it('getGroupDevInfo应该返回群组信息', () => {
106
- support.setGroupDevInfo('mock-group-id');
107
- const result = support.getGroupDevInfo();
108
- expect(result).toEqual(mockGroupInfo);
165
+ it('propagates group info failure', async () => {
166
+ const support = new Support({
167
+ devId: '',
168
+ groupId: 'group-1'
169
+ });
170
+ getGroupInfo.mockImplementation(_ref4 => {
171
+ let {
172
+ fail
173
+ } = _ref4;
174
+ setTimeout(() => fail(new Error('boom')), 0);
175
+ });
176
+ await expect(support.init()).rejects.toThrow('get group info fail');
109
177
  });
110
178
  });
111
- describe('设备类型判断', () => {
112
- beforeEach(() => {
113
- getScheduleCache.mockReturnValue(mockDevInfo);
114
- });
115
- it('isWifiDevice应该正确判断WIFI设备', () => {
116
- // 修改capability
117
- getScheduleCache.mockReturnValue(_objectSpread(_objectSpread({}, mockDevInfo), {}, {
118
- capability: 1 << DeviceCapability.WIFI
179
+ describe('capability checks', () => {
180
+ it('hasCapability reads cached info when no argument provided', () => {
181
+ const support = new Support({
182
+ devId: 'dev-1'
183
+ });
184
+ const capabilityMask = 1 << DeviceCapability.WIFI | 1 << DeviceCapability.ZIGBEE;
185
+ setCachedDevInfo(_objectSpread(_objectSpread({}, baseDevInfo), {}, {
186
+ capability: capabilityMask
119
187
  }));
120
- expect(support.isWifiDevice()).toBe(true);
188
+ expect(support.hasCapability(DeviceCapability.WIFI)).toBe(true);
189
+ expect(support.hasCapability(DeviceCapability.ZIGBEE)).toBe(true);
190
+ expect(support.hasCapability(DeviceCapability.SIGMESH)).toBe(false);
121
191
  });
122
- it('isZigbeeDevice应该正确判断ZIGBEE设备', () => {
123
- // 修改capability
124
- getScheduleCache.mockReturnValue(_objectSpread(_objectSpread({}, mockDevInfo), {}, {
125
- capability: 1 << DeviceCapability.ZIGBEE
126
- }));
127
- expect(support.isZigbeeDevice()).toBe(true);
128
- });
129
- it('isSigMeshDevice应该正确判断SIGMESH设备', () => {
130
- expect(support.isSigMeshDevice()).toBe(false);
131
-
132
- // 修改capability
133
- getScheduleCache.mockReturnValue(_objectSpread(_objectSpread({}, mockDevInfo), {}, {
134
- capability: 1 << DeviceCapability.SIGMESH
135
- }));
136
- expect(support.isSigMeshDevice()).toBe(true);
137
- });
138
- it('isBleDevice应该正确判断BLE设备', () => {
139
- expect(support.isBleDevice()).toBe(false);
140
-
141
- // 修改capability
142
- getScheduleCache.mockReturnValue(_objectSpread(_objectSpread({}, mockDevInfo), {}, {
143
- capability: 1 << DeviceCapability.BLUETOOTH
192
+ it('isBleDevice returns true when any BLE related bit is set', () => {
193
+ const support = new Support({
194
+ devId: 'dev-1'
195
+ });
196
+ setCachedDevInfo(_objectSpread(_objectSpread({}, baseDevInfo), {}, {
197
+ capability: 1 << DeviceCapability.BLEMESH
144
198
  }));
145
199
  expect(support.isBleDevice()).toBe(true);
146
200
  });
201
+ it('isMatter device helpers work with either argument or cached info', () => {
202
+ const support = new Support({
203
+ devId: 'dev-1'
204
+ });
205
+ const devInfo = _objectSpread(_objectSpread({}, baseDevInfo), {}, {
206
+ isMatter: true,
207
+ isTripartiteMatter: false
208
+ });
209
+ expect(support.isMatterDevice(devInfo)).toBe(true);
210
+ expect(support.isTuyaMatterDevice(devInfo)).toBe(true);
211
+ expect(support.isTripartiteMatter(_objectSpread(_objectSpread({}, devInfo), {}, {
212
+ isTripartiteMatter: true
213
+ }))).toBe(true);
214
+ setCachedDevInfo(devInfo);
215
+ expect(support.isMatterDevice()).toBe(true);
216
+ });
147
217
  });
148
- describe('设备能力判断', () => {
149
- it('hasCapability应该正确判断设备能力', () => {
150
- getScheduleCache.mockReturnValue(_objectSpread(_objectSpread({}, mockDevInfo), {}, {
151
- capability: 1 << DeviceCapability.WIFI | 1 << DeviceCapability.ZIGBEE
152
- }));
153
- expect(support.hasCapability(DeviceCapability.WIFI)).toBe(true);
154
- expect(support.hasCapability(DeviceCapability.ZIGBEE)).toBe(true);
155
- expect(support.hasCapability(DeviceCapability.SIGMESH)).toBe(false);
218
+ describe('isSupportCloudTimer', () => {
219
+ it('returns true when panelConfig contains selected timer', () => {
220
+ const support = new Support({
221
+ devId: 'dev-1'
222
+ });
223
+ expect(support.isSupportCloudTimer(_objectSpread({}, baseDevInfo))).toBe(true);
156
224
  });
157
- it('isGroupDevice应该正确判断是否为群组设备', () => {
158
- // 没有groupId时返回false
159
- getScheduleCache.mockReturnValue(mockDevInfo);
160
- expect(support.isGroupDevice()).toBe(false);
161
-
162
- // 有groupId时返回true
163
- getScheduleCache.mockReturnValue(mockGroupInfo);
164
- expect(support.isGroupDevice()).toBe(true);
225
+ it('returns false when device list contains unsupported member', () => {
226
+ const support = new Support({
227
+ devId: '',
228
+ groupId: 'group-1'
229
+ });
230
+ const groupInfo = _objectSpread(_objectSpread({}, baseGroupInfo), {}, {
231
+ deviceList: [{
232
+ panelConfig: {
233
+ bic: [{
234
+ code: 'timer',
235
+ selected: true
236
+ }]
237
+ }
238
+ }, {
239
+ panelConfig: {
240
+ bic: [{
241
+ code: 'timer',
242
+ selected: false
243
+ }]
244
+ }
245
+ }]
246
+ });
247
+ expect(support.isSupportCloudTimer(groupInfo)).toBe(false);
165
248
  });
166
- it('isSupportCloudTimer应该正确判断是否支持云端定时', () => {
167
- // 设置支持云端定时的设备信息
168
- getScheduleCache.mockReturnValue(_objectSpread(_objectSpread({}, mockDevInfo), {}, {
169
- panelConfig: {
170
- bic: [{
171
- code: 'timer',
172
- selected: true
173
- }]
174
- }
175
- }));
176
- expect(support.isSupportCloudTimer()).toBe(true);
177
-
178
- // 测试不支持云端定时的情况
179
- getScheduleCache.mockReturnValue(_objectSpread(_objectSpread({}, mockDevInfo), {}, {
180
- panelConfig: {
181
- bic: [{
182
- code: 'timer',
183
- selected: false
184
- }]
249
+ it('returns true only when all group members support timer', () => {
250
+ const support = new Support({
251
+ devId: '',
252
+ groupId: 'group-1'
253
+ });
254
+ const groupInfo = _objectSpread(_objectSpread({}, baseGroupInfo), {}, {
255
+ deviceList: [{
256
+ panelConfig: {
257
+ bic: [{
258
+ code: 'timer',
259
+ selected: true
260
+ }]
261
+ }
262
+ }, {
263
+ panelConfig: {
264
+ bic: [{
265
+ code: 'timer',
266
+ selected: true
267
+ }]
268
+ }
269
+ }]
270
+ });
271
+ expect(support.isSupportCloudTimer(groupInfo)).toBe(true);
272
+ });
273
+ });
274
+ describe('supportDp & isSupportDp', () => {
275
+ const support = new Support({
276
+ devId: 'dev-1'
277
+ });
278
+ beforeEach(() => {
279
+ support.isInit = true;
280
+ setCachedDevInfo(_objectSpread({}, baseDevInfo));
281
+ });
282
+ it('supports schema array lookup', () => {
283
+ expect(support.supportDp('switch_led', baseDevInfo)).toBe(true);
284
+ expect(support.supportDp('not_exist', baseDevInfo)).toBe(false);
285
+ });
286
+ it('supports schema object lookup', () => {
287
+ const devInfoObjectSchema = _objectSpread(_objectSpread({}, baseDevInfo), {}, {
288
+ schema: {
289
+ switch_led: {},
290
+ another: {}
185
291
  }
292
+ });
293
+ expect(support.supportDp('switch_led', devInfoObjectSchema)).toBe(true);
294
+ expect(support.supportDp('not_exist', devInfoObjectSchema)).toBe(false);
295
+ });
296
+ it('isSupportDp caches results when not forced', () => {
297
+ const devInfo = _objectSpread(_objectSpread({}, baseDevInfo), {}, {
298
+ schema: [{
299
+ code: 'cached_dp'
300
+ }]
301
+ });
302
+ expect(support.isSupportDp('cached_dp', false, devInfo)).toBe(true);
303
+ // After caching, flip schema to empty but expect true without isForce
304
+ setCachedDevInfo(_objectSpread(_objectSpread({}, baseDevInfo), {}, {
305
+ schema: []
186
306
  }));
187
- expect(support.isSupportCloudTimer()).toBe(false);
307
+ expect(support.isSupportDp('cached_dp')).toBe(true);
308
+ // Forcing bypasses cache
309
+ expect(support.isSupportDp('cached_dp', true)).toBe(false);
310
+ });
311
+ it('returns false when not initialized', () => {
312
+ const notInitSupport = new Support({
313
+ devId: 'dev-1'
314
+ });
315
+ notInitSupport.isInit = false;
316
+ expect(notInitSupport.isSupportDp('switch_led')).toBe(false);
188
317
  });
189
318
  });
190
- describe('DP点支持判断', () => {
191
- beforeEach(() => {
192
- getScheduleCache.mockReturnValue(mockDevInfo);
193
- getDpCodeByDpId.mockImplementation(dpId => {
194
- if (dpId === 1) return 'switch_led';
195
- if (dpId === 2) return 'bright_value';
196
- return null;
197
- });
198
- getDpIdByDpCode.mockImplementation(dpCode => {
199
- if (dpCode === 'switch_led') return 1;
200
- if (dpCode === 'bright_value') return 2;
201
- return null;
202
- });
203
- });
204
- it('supportDp应该正确判断是否支持DP点(通过dpCode)', () => {
205
- expect(support.supportDp('switch_led')).toBe(true);
206
- expect(support.supportDp('bright_value')).toBe(true);
207
- expect(support.supportDp('unsupported_dp')).toBe(false);
319
+ describe('getMergeDevInfo & group detection', () => {
320
+ it('merges cached dev and group info', () => {
321
+ const support = new Support({
322
+ devId: 'dev-1'
323
+ });
324
+ setCachedDevInfo(baseDevInfo);
325
+ support.groupDevInfo = baseGroupInfo;
326
+ const merged = support.getMergeDevInfo();
327
+ expect(merged.devId).toBe('dev-1');
328
+ expect(support.groupDevInfo.groupId).toBe('group-1');
329
+ });
330
+ it('isGroupDevice uses cached info when argument omitted', () => {
331
+ const support = new Support({
332
+ devId: 'dev-1'
333
+ });
334
+ setCachedDevInfo(_objectSpread(_objectSpread({}, baseDevInfo), {}, {
335
+ groupId: 'group-1'
336
+ }));
337
+ expect(support.isGroupDevice()).toBe(true);
338
+ setCachedDevInfo(_objectSpread(_objectSpread({}, baseDevInfo), {}, {
339
+ groupId: undefined
340
+ }));
341
+ expect(support.isGroupDevice()).toBe(false);
208
342
  });
209
343
  });
210
344
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ray-js/lamp-schedule-core",
3
- "version": "1.0.1-beta-10",
3
+ "version": "1.0.2-beta-2",
4
4
  "description": "照明计划模块核心能力",
5
5
  "main": "./lib/index.js",
6
6
  "files": [