@miot-rn/common-component 1.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 (40) hide show
  1. package/README.md +9 -0
  2. package/dist/index.d.ts +0 -0
  3. package/dist/index.js +0 -0
  4. package/dist/resources/i18n.d.ts +55 -0
  5. package/dist/resources/i18n.js +212 -0
  6. package/dist/service/specs/error-code.d.ts +19 -0
  7. package/dist/service/specs/error-code.js +41 -0
  8. package/dist/service/specs/index.d.ts +95 -0
  9. package/dist/service/specs/index.js +412 -0
  10. package/dist/service/specs/spec.d.ts +10 -0
  11. package/dist/service/specs/spec.js +109 -0
  12. package/dist/service/specs/specCache.d.ts +85 -0
  13. package/dist/service/specs/specCache.js +421 -0
  14. package/dist/service/specs/std-spec.d.ts +5 -0
  15. package/dist/service/specs/std-spec.js +228 -0
  16. package/dist/service/specs/subject.d.ts +20 -0
  17. package/dist/service/specs/subject.js +145 -0
  18. package/dist/service/specs/utils.d.ts +28 -0
  19. package/dist/service/specs/utils.js +46 -0
  20. package/dist/specs/i18n-parser.d.ts +10 -0
  21. package/dist/specs/i18n-parser.js +300 -0
  22. package/dist/specs/instance-parser.d.ts +26 -0
  23. package/dist/specs/instance-parser.js +706 -0
  24. package/dist/store/useGlobalSpecManager.d.ts +320 -0
  25. package/dist/store/useGlobalSpecManager.js +867 -0
  26. package/dist/types/index.d.ts +23 -0
  27. package/dist/types/index.js +1 -0
  28. package/dist/utils/fns.d.ts +12 -0
  29. package/dist/utils/fns.js +308 -0
  30. package/dist/utils/get-value-or-default.d.ts +1 -0
  31. package/dist/utils/get-value-or-default.js +4 -0
  32. package/dist/utils/i18n.d.ts +1 -0
  33. package/dist/utils/i18n.js +141 -0
  34. package/dist/utils/objects.d.ts +2 -0
  35. package/dist/utils/objects.js +222 -0
  36. package/dist/utils/spec.d.ts +8 -0
  37. package/dist/utils/spec.js +171 -0
  38. package/dist/utils/types.d.ts +3 -0
  39. package/dist/utils/types.js +25 -0
  40. package/package.json +27 -0
@@ -0,0 +1,222 @@
1
+ import { getType } from "./types";
2
+ const ReactSpecialKeys = new Set(['_owner', '__v', '__o']); // 预定义需跳过的特殊属性
3
+
4
+ /**
5
+ * 判断基础类型
6
+ * @param v
7
+ * @returns {boolean}
8
+ */
9
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
+ function isPrimary(v) {
11
+ if (v === null || v === undefined) {
12
+ return true;
13
+ }
14
+ return ['number', 'string', 'boolean', 'symbol'].includes(typeof v);
15
+ }
16
+
17
+ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types */
18
+ const TypeHandlers = {
19
+ '[object Array]': {
20
+ related: false,
21
+ create: () => {
22
+ return [];
23
+ },
24
+ forEach: (src, fn) => {
25
+ src.forEach((v, i) => fn(v, i));
26
+ },
27
+ map: (src, fn) => {
28
+ return src.map((v, i) => fn(v, i));
29
+ },
30
+ set: (src, key, value) => {
31
+ src[key] = value;
32
+ }
33
+ },
34
+ '[object Object]': {
35
+ related: true,
36
+ create: () => {
37
+ return {};
38
+ },
39
+ forEach: (src, fn) => {
40
+ Object.entries(src).forEach(([k, v]) => fn(v, k));
41
+ },
42
+ map: (src, fn) => {
43
+ return Object.entries(src).map(([k, v]) => fn(v, k));
44
+ },
45
+ set: (src, key, value) => {
46
+ src[key] = value;
47
+ }
48
+ },
49
+ '[object Set]': {
50
+ related: false,
51
+ create: () => {
52
+ return new Set();
53
+ },
54
+ forEach: (src, fn) => {
55
+ src.forEach(v => fn(v));
56
+ },
57
+ map: (src, fn) => {
58
+ return Array.from(src.entries()).map(vs => fn(vs[0]));
59
+ },
60
+ set: (src, key, value) => {
61
+ src.add(value);
62
+ }
63
+ },
64
+ '[object Map]': {
65
+ related: true,
66
+ create: () => {
67
+ return new Map();
68
+ },
69
+ forEach: (src, fn) => {
70
+ src.forEach((v, k) => fn(v, k));
71
+ },
72
+ map: (src, fn) => {
73
+ return Array.from(src.entries()).map(([k, v]) => fn(v, k));
74
+ },
75
+ set: (src, key, value) => {
76
+ src.set(key, value);
77
+ }
78
+ }
79
+ };
80
+ /* eslint-enable @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types */
81
+
82
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
83
+ function _copy(value, memo) {
84
+ if (isPrimary(value) || value instanceof Function) {
85
+ return value;
86
+ }
87
+ let newValue = memo.get(value);
88
+ if (newValue) {
89
+ return newValue;
90
+ }
91
+ const type = TypeHandlers[Object.prototype.toString.call(value)];
92
+ if (type !== undefined) {
93
+ newValue = type.create();
94
+ memo.set(value, newValue);
95
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
96
+ type.forEach(value, (v, k) => {
97
+ type.set(newValue, k, _copy(v, memo));
98
+ });
99
+ } else {
100
+ // 不认识的类型默认处理
101
+ newValue = JSON.parse(JSON.stringify(value));
102
+ }
103
+ return newValue;
104
+ }
105
+
106
+ /**
107
+ * 深度拷贝函数
108
+ * 1 基础类型:直接返回原值
109
+ * 2 数组 or 对象:深copy,支持 Object, Array, Map, Set, Function
110
+ * @returns {*}
111
+ * @param value
112
+ */
113
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
114
+ export function copy(value) {
115
+ return _copy(value, new Map());
116
+ }
117
+
118
+ /**
119
+ * @description 深度比较两个对象是否相等(优化版)基础版本来源:https://github.com/FormidableLabs/react-fast-compare
120
+ * @author guhao
121
+ * @param {any} a
122
+ * @param {any} b
123
+ * @returns {boolean}
124
+ */
125
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
126
+ export function deepEqual(a, b) {
127
+ // 快速相等(包括 +0/-0 和 NaN 处理)
128
+ if (Object.is(a, b)) return true;
129
+
130
+ // 类型检查
131
+ const typeA = getType(a);
132
+ const typeB = getType(b);
133
+ if (typeA !== typeB) return false;
134
+
135
+ // 处理非对象类型
136
+ if (!a || !b || typeof a !== 'object') {
137
+ return typeA === 'Date' ? a.getTime() === b.getTime() : false;
138
+ }
139
+
140
+ // 构造函数一致性检查
141
+ if (a.constructor !== b.constructor) return false;
142
+
143
+ // 分类型处理
144
+ switch (typeA) {
145
+ // 数组处理(反向遍历优化)
146
+ case 'Array':
147
+ {
148
+ if (a.length !== b.length) return false;
149
+ for (let i = a.length - 1; i >= 0; i--) {
150
+ if (!deepEqual(a[i], b[i])) return false;
151
+ }
152
+ return true;
153
+ }
154
+
155
+ // Date 处理(时间戳比对)
156
+ case 'Date':
157
+ return a.getTime() === b.getTime();
158
+
159
+ // RegExp 处理(源和标志比对)
160
+ case 'RegExp':
161
+ return a.source === b.source && a.flags === b.flags;
162
+
163
+ // Map 处理(合并两次遍历为一次)
164
+ case 'Map':
165
+ {
166
+ if (a.size !== b.size) return false;
167
+ for (const [key, val] of a) {
168
+ if (!b.has(key) || !deepEqual(val, b.get(key))) return false;
169
+ }
170
+ return true;
171
+ }
172
+
173
+ // Set 处理(值存在性检查)
174
+ case 'Set':
175
+ {
176
+ if (a.size !== b.size) return false;
177
+ for (const val of a) {
178
+ if (!b.has(val)) return false;
179
+ }
180
+ return true;
181
+ }
182
+
183
+ // ArrayBuffer 视图处理(直接内存比对)
184
+ case 'ArrayBufferView':
185
+ {
186
+ const viewA = new DataView(a.buffer, a.byteOffset, a.byteLength);
187
+ const viewB = new DataView(b.buffer, b.byteOffset, b.byteLength);
188
+ if (viewA.byteLength !== viewB.byteLength) return false;
189
+ for (let i = 0; i < viewA.byteLength; i++) {
190
+ if (viewA.getUint8(i) !== viewB.getUint8(i)) return false;
191
+ }
192
+ return true;
193
+ }
194
+
195
+ // 通用对象处理
196
+ case 'Object':
197
+ {
198
+ const keysA = Object.keys(a);
199
+ const keysB = Object.keys(b);
200
+ if (keysA.length !== keysB.length) return false;
201
+
202
+ // 使用 Set 优化属性存在性检查
203
+ const keysBSet = new Set(keysB);
204
+ for (const key of keysA) {
205
+ if (!keysBSet.has(key)) return false;
206
+ }
207
+
208
+ // 深度比较属性值(跳过 React 特殊属性)
209
+ for (const key of keysA) {
210
+ // @ts-ignore
211
+ // eslint-disable-next-line no-continue
212
+ if (ReactSpecialKeys.has(key) && a.$$typeof) continue;
213
+ if (!deepEqual(a[key], b[key])) return false;
214
+ }
215
+ return true;
216
+ }
217
+
218
+ // 其他未处理类型默认返回 false
219
+ default:
220
+ return false;
221
+ }
222
+ }
@@ -0,0 +1,8 @@
1
+ import { Spec } from '../types';
2
+ export declare function isSpecProp(prop: any): boolean;
3
+ export declare function encodeProp(prop: Spec): string;
4
+ export declare function decodeProp(key: string): any;
5
+ export declare function encodeSceneKey(o: Spec): string;
6
+ export declare function encodeIidsKey(o: Spec): string;
7
+ export declare function specAccess(prop: Spec, type: string): boolean;
8
+ export declare function specsToSubscribeKeys(specs?: Spec[]): string[];
@@ -0,0 +1,171 @@
1
+ // @ts-ignore
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ import { Device } from 'miot';
4
+ export function isSpecProp(prop) {
5
+ return !!(prop && prop.siid && typeof prop.siid === 'number');
6
+ }
7
+
8
+ /**
9
+ * 需要和服务端保持一致
10
+ * @param prop
11
+ * @returns {string}
12
+ */
13
+ export function encodeProp(prop) {
14
+ const {
15
+ miid,
16
+ siid,
17
+ piid,
18
+ aiid,
19
+ eiid
20
+ } = prop || {};
21
+ if (eiid !== null && eiid !== undefined) {
22
+ return miid ? `event.${miid}.${siid}.${eiid}` : `event.${siid}.${eiid}`;
23
+ }
24
+ if (aiid !== null && aiid !== undefined) {
25
+ return miid ? `action.${miid}.${siid}.${aiid}` : `action.${siid}.${aiid}`;
26
+ } // if (piid !== null && piid !== undefined) {
27
+ return miid ? `prop.${miid}.${siid}.${piid}` : `prop.${siid}.${piid}`;
28
+ }
29
+
30
+ /**
31
+ * 需要和服务端保持一致
32
+ * @returns { { siid, piid, aiid, eiid } |null}
33
+ * @param key
34
+ */
35
+ export function decodeProp(key) {
36
+ const res = {};
37
+ const parts = key.split('.');
38
+ if (parts.length === 3) {
39
+ const type = parts[0];
40
+ const sNumber = parseInt(parts[1], 10);
41
+ // 2 for '.'
42
+ const suffix = key.slice(parts[0].length + parts[1].length + 2);
43
+ const isNotSpec = isNaN(sNumber);
44
+ const siid = isNotSpec ? parts[1] : sNumber;
45
+ const xiid = isNotSpec ? suffix : parseInt(suffix, 10);
46
+ if (type === 'event') {
47
+ return {
48
+ siid,
49
+ eiid: xiid
50
+ };
51
+ }
52
+ if (type === 'action') {
53
+ return {
54
+ siid,
55
+ aiid: xiid
56
+ };
57
+ }
58
+ if (type === 'prop') {
59
+ return {
60
+ siid,
61
+ piid: xiid
62
+ };
63
+ }
64
+ } else if (parts.length >= 4) {
65
+ const type = parts[0];
66
+ const mNumber = parseInt(parts[1], 10);
67
+ const sNumber = parseInt(parts[2], 10);
68
+ const suffix = key.slice(parts[0].length + parts[1].length + parts[2].length + 3); // 3 for '.'
69
+ const isNotSpec = isNaN(sNumber);
70
+ const miid = isNotSpec ? parts[1] : mNumber;
71
+ const siid = isNotSpec ? parts[2] : sNumber;
72
+ const xiid = isNotSpec ? suffix : parseInt(suffix, 10);
73
+ if (type === 'event') {
74
+ return {
75
+ miid,
76
+ siid,
77
+ eiid: xiid
78
+ };
79
+ }
80
+ if (type === 'action') {
81
+ return {
82
+ miid,
83
+ siid,
84
+ aiid: xiid
85
+ };
86
+ }
87
+ if (type === 'prop') {
88
+ return {
89
+ miid,
90
+ siid,
91
+ piid: xiid
92
+ };
93
+ }
94
+ }
95
+ return res;
96
+ }
97
+
98
+ /**
99
+ * 根据spec 获取智能场景的key
100
+ * @param {object} o
101
+ * @returns {string}
102
+ */
103
+ export function encodeSceneKey(o) {
104
+ if (!o) {
105
+ return '';
106
+ }
107
+ const {
108
+ miid,
109
+ siid,
110
+ piid,
111
+ aiid,
112
+ eiid
113
+ } = o;
114
+ const type = eiid ? 'event' : aiid ? 'action' : piid ? 'prop' : '';
115
+ if (!type || !siid) {
116
+ return '';
117
+ }
118
+ return miid ? `${type}.${Device.model}.${miid}.${siid}.${eiid || aiid || piid}` : `${type}.${Device.model}.${siid}.${eiid || aiid || piid}`;
119
+ }
120
+
121
+ /**
122
+ * 根据spec 获取iids 组装的key
123
+ * @param {object} o
124
+ * @returns {string}
125
+ */
126
+ export function encodeIidsKey(o) {
127
+ if (!o) {
128
+ return '';
129
+ }
130
+ const {
131
+ miid,
132
+ siid,
133
+ piid,
134
+ aiid,
135
+ eiid
136
+ } = o;
137
+ const xiid = eiid || aiid || piid;
138
+ if (!xiid || !siid) {
139
+ return '';
140
+ }
141
+ return miid ? `${miid}.${siid}.${xiid}` : `${siid}.${xiid}`;
142
+ }
143
+ export function specAccess(prop, type) {
144
+ if (!prop) {
145
+ return false;
146
+ }
147
+ const access = prop.access || prop.prop?.access || undefined;
148
+ const gattAccess = prop['gatt-access'] || prop.prop?.['gatt-access'] || undefined;
149
+ if (
150
+ // gatt-access 匹配(蓝牙网关上报、插件代报)
151
+ gattAccess && gattAccess.includes(type) ||
152
+ // access 匹配时
153
+ access && access.includes(type)) {
154
+ return true;
155
+ }
156
+ return false;
157
+ }
158
+
159
+ /**
160
+ * 根据spec的订阅key
161
+ * @param {Array<object>} o
162
+ * @returns {Array<string>}
163
+ */
164
+ export function specsToSubscribeKeys(specs = []) {
165
+ const keys = specs.filter(prop => {
166
+ return prop && (prop.eiid || specAccess(prop, 'notify')) && (!prop.dataSource || prop.dataSource === 1);
167
+ }).map(s => {
168
+ return encodeProp(s);
169
+ });
170
+ return keys;
171
+ }
@@ -0,0 +1,3 @@
1
+ export declare const getType: (value: any) => string;
2
+ export declare const isTypeOf: (type: string | string[], value: any) => boolean;
3
+ export declare const isArrayValue: (value: any) => boolean;
@@ -0,0 +1,25 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
2
+ export const getType = value => Object.prototype.toString.call(value).match(/\[object (.*)\]/)[1];
3
+ /**
4
+ * 判断 value 的类型
5
+ * @param {string|Array<string>} type
6
+ * @param {any} value
7
+ * @returns
8
+ */
9
+ export const isTypeOf = (type, value) => {
10
+ const valueType = getType(value);
11
+ if (Array.isArray(type)) {
12
+ return type.includes(valueType);
13
+ }
14
+ return valueType === type;
15
+ };
16
+
17
+ /**
18
+ * @description value是否为array
19
+ * @param {any} value
20
+ * @returns {boolean}
21
+ */
22
+ export const isArrayValue = value => {
23
+ const valueType = getType(value);
24
+ return valueType === 'Array';
25
+ };
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@miot-rn/common-component",
3
+ "version": "1.0.1",
4
+ "scripts": {
5
+ "build": "rm -rf dist && rm -f tsconfig.tsbuildinfo && tsc && babel src -d dist --config-file ../../babel.config.js --extensions '.ts,.tsx' --verbose",
6
+ "lint": "eslint src/**/*.ts",
7
+ "lint:fix": "eslint src/**/*.ts --fix",
8
+ "tsc": "rm -f tsconfig.tsbuildinfo && tsc",
9
+ "format": "prettier --write src/**/*.ts"
10
+ },
11
+ "main": "./dist/index.js",
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "min_sdk_api_level": 10115,
19
+ "peerDependencies": {
20
+ "@types/react": "^16.14.0",
21
+ "@types/react-native": "^0.61.23",
22
+ "react": "^16.14.0",
23
+ "react-native": "0.61.0",
24
+ "zustand": "^4.4.1"
25
+ },
26
+ "gitHead": "3e6285821f0cebb8cdce54ea0e2a6fa624453ef6"
27
+ }