mirta 0.1.1 → 0.2.0

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/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { Event } from '@mirta/basics';
1
+ import { OnEvent } from '@mirta/basics';
2
2
  export * from '@mirta/basics';
3
3
 
4
4
  type DeviceType = 'wired' | 'virtual' | 'zigbee';
@@ -65,9 +65,9 @@ type StrictWhenSpecified<TObject, TKey extends keyof TObject, TReturn> = IsSpeci
65
65
  * Устанавливает указанное свойство в readonly при выполнении указанного условия.
66
66
  * @since 0.1.0
67
67
  **/
68
- type ReadonlyPropWhen<TObject, K extends keyof TObject, TCondition extends boolean | undefined> = TCondition extends true ? Omit<TObject, K> & {
68
+ type ReadonlyPropWhen<TObject, K extends keyof TObject, TCondition extends boolean | undefined> = TCondition extends true ? Expand<Omit<TObject, K> & {
69
69
  +readonly [P in K]-?: TObject[P];
70
- } : TObject;
70
+ }> : TObject;
71
71
  /**
72
72
  * Проверяет, что указанный тип объекта имеет хотя бы одно свойство заданного типа.
73
73
  * Применяется для работы с дженериками.
@@ -86,14 +86,66 @@ type HasPropertyOfType<TObject extends object, TProperty> = {
86
86
  [K in keyof TObject as TObject[K] extends TProperty ? K : never]: unknown;
87
87
  } extends infer R ? {} extends R ? false : true : never;
88
88
 
89
+ /**
90
+ * Набор политик, управляющих доступностью смены значения контрола.
91
+ *
92
+ * @since 0.2.0
93
+ *
94
+ **/
95
+ declare enum ChangePolicies {
96
+ /**
97
+ * Политика по умолчанию.
98
+ *
99
+ * - Применяет {@link Public} к контролам типа `switch`, `pushbutton`, `range` и `rgb`;
100
+ *
101
+ * - Применяет {@link Script} к остальным типам контролов.
102
+ *
103
+ **/
104
+ Default = "default",
105
+ /**
106
+ * Установка значения возможна как скриптами wb-rules, так и сторонними службами.
107
+ *
108
+ * Применимо к контролам виртуальных устройств.
109
+ *
110
+ **/
111
+ Public = "public",
112
+ /**
113
+ * Установка значения возможна только скриптами wb-rules.
114
+ *
115
+ * Применимо к контролам виртуальных устройств.
116
+ *
117
+ **/
118
+ Script = "script",
119
+ /**
120
+ * Полный запрет записи, значение доступно только для чтения.
121
+ *
122
+ * Применимо к контролам реальных устройств.
123
+ *
124
+ **/
125
+ ReadOnly = "read-only"
126
+ }
127
+ /**
128
+ * Определяет политику установки значений реальных устройств.
129
+ *
130
+ * @since 0.2.0
131
+ *
132
+ **/
133
+ type ChangePolicy = `${Exclude<ChangePolicies, ChangePolicies.Public | ChangePolicies.Script>}`;
134
+ /**
135
+ * Определяет политику установки значений контролов виртуальных устройств.
136
+ *
137
+ * @since 0.2.0
138
+ *
139
+ **/
140
+ type VirtualChangePolicy = `${Exclude<ChangePolicies, ChangePolicies.ReadOnly>}`;
89
141
  type ValueEventHandler<TValue> = (newValue: TValue, oldValue: TValue) => void;
90
142
  interface Control<TValue> {
91
143
  /** Актуальное значение контрола. */
92
144
  value: TValue;
93
145
  /** Событие, происходящее когда поступило новое значение. */
94
- valueReceived: Event<ValueEventHandler<TValue>>;
146
+ onValueReceived: OnEvent<ValueEventHandler<TValue>>;
95
147
  /** Событие, происходящее когда значение изменилось. */
96
- valueChanged: Event<ValueEventHandler<TValue>>;
148
+ onValueChanged: OnEvent<ValueEventHandler<TValue>>;
97
149
  }
98
150
  type MaybeReadonlyControl<TValue, TReadonly extends boolean | undefined> = ReadonlyPropWhen<Control<TValue>, 'value', TReadonly>;
99
151
 
@@ -117,8 +169,8 @@ type VirtualTypeMapper<K extends keyof WbRules.TypeMappings = keyof WbRules.Type
117
169
  interface BaseControlDef {
118
170
  /** Идентификатор контрола. Если не указан, используется название свойства. */
119
171
  controlId?: string;
120
- /** Если `true`, то значение доступно только для чтения. */
121
- isReadonly?: boolean;
172
+ /** Политика доступа на запись значения. */
173
+ changePolicy?: VirtualChangePolicy | ChangePolicy;
122
174
  }
123
175
  /**
124
176
  * Определения основных контролов.
@@ -166,7 +218,7 @@ type StrictVirtualControls<TControls extends VirtualControls> = TControls & Virt
166
218
  * при описании устройства в `defineDevice()`.
167
219
  **/
168
220
  type CreatedControls<TControls extends Controls | VirtualControls> = {
169
- [K in keyof TControls]: Expand<MaybeReadonlyControl<StrictWhenSpecified<TControls[K], 'defaultValue', WbRules.TypeMappings[TControls[K]['type']]>, TControls[K]['isReadonly']>>;
221
+ [K in keyof TControls]: Expand<MaybeReadonlyControl<StrictWhenSpecified<TControls[K], 'defaultValue', WbRules.TypeMappings[TControls[K]['type']]>, TControls[K]['changePolicy'] extends ChangePolicies.ReadOnly ? true : false>>;
170
222
  };
171
223
  /** Используется для извлечения типа значения из значения по умолчанию. */
172
224
  type InferDefaultType<TProp> = [TProp] extends [{
@@ -431,5 +483,5 @@ declare function getControlSafe(context: DeviceContext, controlId: string): Cont
431
483
  **/
432
484
  declare function getControlSafe(deviceId: string, controlId: string, isReadyFunc: () => boolean): ControlSafe;
433
485
 
434
- export { defineVirtualDevice, defineWiredDevice, defineZigbeeDevice, getControlSafe, getDeviceSafe };
486
+ export { ChangePolicies, defineVirtualDevice, defineWiredDevice, defineZigbeeDevice, getControlSafe, getDeviceSafe };
435
487
  export type { ControlSafe, DeviceContext, DeviceType, PropType, TrackCallback };
package/dist/index.mjs CHANGED
@@ -23,6 +23,45 @@ function getControlSafe(context, controlId, isReadyFunc = () => true) {
23
23
  };
24
24
  }
25
25
 
26
+ /**
27
+ * Набор политик, управляющих доступностью смены значения контрола.
28
+ *
29
+ * @since 0.2.0
30
+ *
31
+ **/
32
+ var ChangePolicies;
33
+ (function (ChangePolicies) {
34
+ /**
35
+ * Политика по умолчанию.
36
+ *
37
+ * - Применяет {@link Public} к контролам типа `switch`, `pushbutton`, `range` и `rgb`;
38
+ *
39
+ * - Применяет {@link Script} к остальным типам контролов.
40
+ *
41
+ **/
42
+ ChangePolicies["Default"] = "default";
43
+ /**
44
+ * Установка значения возможна как скриптами wb-rules, так и сторонними службами.
45
+ *
46
+ * Применимо к контролам виртуальных устройств.
47
+ *
48
+ **/
49
+ ChangePolicies["Public"] = "public";
50
+ /**
51
+ * Установка значения возможна только скриптами wb-rules.
52
+ *
53
+ * Применимо к контролам виртуальных устройств.
54
+ *
55
+ **/
56
+ ChangePolicies["Script"] = "script";
57
+ /**
58
+ * Полный запрет записи, значение доступно только для чтения.
59
+ *
60
+ * Применимо к контролам реальных устройств.
61
+ *
62
+ **/
63
+ ChangePolicies["ReadOnly"] = "read-only";
64
+ })(ChangePolicies || (ChangePolicies = {}));
26
65
  const typeMappings = {
27
66
  'text': 'string',
28
67
  'value': 'number',
@@ -35,10 +74,11 @@ const typeMappings = {
35
74
  /**
36
75
  * Создаёт контрол устройства.
37
76
  * @since 0.1.0
77
+ *
38
78
  **/
39
79
  function createControl(context, controlId, options) {
40
80
  const { deviceType, deviceId } = context;
41
- const { type, isReadonly } = options;
81
+ const { type, changePolicy = ChangePolicies.Default } = options;
42
82
  const defaultValue = 'defaultValue' in options
43
83
  ? options['defaultValue']
44
84
  : void 0;
@@ -61,6 +101,7 @@ function createControl(context, controlId, options) {
61
101
  * Устанавливает новое значение, если оно отличается от существующего.
62
102
  * @param newValue Устанавливаемое значение.
63
103
  * @param preventEmit Предотвращает отправку значения в устройство.
104
+ *
64
105
  **/
65
106
  function setValue(newValue, preventEmit = false) {
66
107
  const oldValue = localValue;
@@ -102,16 +143,14 @@ function createControl(context, controlId, options) {
102
143
  return localValue;
103
144
  },
104
145
  set value(newValue) {
105
- if (isReadonly) {
106
- log.warning(`Value of '${deviceId}/${controlId}' is readonly`);
146
+ if (changePolicy === ChangePolicies.ReadOnly) {
147
+ log.warning(`A new value of '${deviceId}/${controlId}' has been rejected: control is readonly.`);
107
148
  return;
108
149
  }
109
150
  setValue(newValue);
110
151
  },
111
- valueReceived: valueReceived
112
- .withoutRaise(),
113
- valueChanged: valueChanged
114
- .withoutRaise(),
152
+ onValueReceived: valueReceived.on,
153
+ onValueChanged: valueChanged.on,
115
154
  };
116
155
  }
117
156
 
@@ -141,6 +180,9 @@ function createContext(deviceType, deviceId, state) {
141
180
  };
142
181
  return context;
143
182
  }
183
+ const extendWithReadonly = (changePolicy) => changePolicy && changePolicy !== ChangePolicies.Default
184
+ ? { readonly: changePolicy === ChangePolicies.Script || changePolicy === ChangePolicies.ReadOnly }
185
+ : {};
144
186
  function configureControls(deviceId, controls) {
145
187
  const device = getDevice(deviceId);
146
188
  if (!device)
@@ -154,8 +196,7 @@ function configureControls(deviceId, controls) {
154
196
  device.removeControl(controlId);
155
197
  device.addControl(controlId, assign({}, control, {
156
198
  value: control.defaultValue,
157
- readonly: control.isReadonly,
158
- }));
199
+ }, extendWithReadonly(control.changePolicy)));
159
200
  });
160
201
  }
161
202
  function configureContext(type, deviceId, controls, title) {
@@ -182,9 +223,10 @@ function configureContext(type, deviceId, controls, title) {
182
223
  if (type === 'virtual') {
183
224
  const cells = {};
184
225
  Object.keys(controls).forEach((key) => {
185
- const cell = assign({}, controls[key], {
186
- value: controls[key]['defaultValue'],
187
- }, controls[key]['isReadonly'] ? { readonly: true } : {});
226
+ const control = controls[key];
227
+ const cell = assign({}, control, {
228
+ value: control['defaultValue'],
229
+ }, extendWithReadonly(control['changePolicy']));
188
230
  cells[key] = cell;
189
231
  });
190
232
  global.defineVirtualDevice(deviceId, {
@@ -219,8 +261,8 @@ function createDevice(deviceType, deviceId, propDefs, props, options) {
219
261
  const controlId = controlDef.controlId ?? key;
220
262
  const control = createControl({ deviceType, deviceId, isReady: true }, controlId, {
221
263
  type: controlDef.type,
264
+ changePolicy: controlDef.changePolicy ?? ChangePolicies.Default,
222
265
  defaultValue: controlDef.defaultValue,
223
- isReadonly: controlDef.isReadonly,
224
266
  forceDefault: controlDef.forceDefault,
225
267
  lazyInit: controlDef.lazyInit,
226
268
  });
@@ -322,4 +364,4 @@ function getDeviceSafe(deviceId, isReadyFunc = () => true) {
322
364
  };
323
365
  }
324
366
 
325
- export { defineVirtualDevice, defineWiredDevice, defineZigbeeDevice, getControlSafe, getDeviceSafe };
367
+ export { ChangePolicies, defineVirtualDevice, defineWiredDevice, defineZigbeeDevice, getControlSafe, getDeviceSafe };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mirta",
3
3
  "description": "The powerful framework to write smart home automation scripts.",
4
- "version": "0.1.1",
4
+ "version": "0.2.0",
5
5
  "license": "Unlicense",
6
6
  "keywords": [
7
7
  "mirta",
@@ -36,9 +36,9 @@
36
36
  "url": "https://pay.cloudtips.ru/p/58512cca"
37
37
  },
38
38
  "dependencies": {
39
- "@mirta/basics": "0.1.1",
40
- "@mirta/polyfills": "0.1.1",
41
- "@mirta/globals": "0.1.1"
39
+ "@mirta/globals": "0.2.0",
40
+ "@mirta/basics": "0.2.0",
41
+ "@mirta/polyfills": "0.2.0"
42
42
  },
43
43
  "publishConfig": {
44
44
  "access": "public"