node-web-gpio 1.0.10 → 1.0.14
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.ts +98 -2
- package/dist/index.js +135 -23
- package/package.json +14 -6
package/dist/index.d.ts
CHANGED
|
@@ -1,24 +1,53 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { EventEmitter } from
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
/** ポート番号 */
|
|
3
4
|
declare type PortNumber = number;
|
|
5
|
+
/** ポート名 */
|
|
4
6
|
declare type PortName = string;
|
|
7
|
+
/** ピン名 */
|
|
5
8
|
declare type PinName = string;
|
|
6
|
-
|
|
9
|
+
/** 入出力方向 */
|
|
10
|
+
declare type DirectionMode = 'in' | 'out';
|
|
11
|
+
/** GPIO 値 0: LOW / 1: HIGH */
|
|
7
12
|
declare type GPIOValue = 0 | 1;
|
|
13
|
+
/**
|
|
14
|
+
* GPIO チェンジイベント
|
|
15
|
+
*/
|
|
8
16
|
interface GPIOChangeEvent {
|
|
17
|
+
/** 入出力値 */
|
|
9
18
|
readonly value: GPIOValue;
|
|
19
|
+
/** ポート */
|
|
10
20
|
readonly port: GPIOPort;
|
|
11
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* GPIO チェンジイベントハンドラ
|
|
24
|
+
*/
|
|
12
25
|
interface GPIOChangeEventHandler {
|
|
26
|
+
/** イベント */
|
|
13
27
|
(event: GPIOChangeEvent): void;
|
|
14
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* GPIO
|
|
31
|
+
*/
|
|
15
32
|
export declare class GPIOAccess extends EventEmitter {
|
|
33
|
+
/** ポート */
|
|
16
34
|
private readonly _ports;
|
|
35
|
+
/** GPIO チェンジイベントハンドラ */
|
|
17
36
|
onchange: GPIOChangeEventHandler | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Creates an instance of GPIOAccess.
|
|
39
|
+
* @param ports ポート番号
|
|
40
|
+
*/
|
|
18
41
|
constructor(ports?: GPIOPortMap);
|
|
42
|
+
/**
|
|
43
|
+
* ポート情報取得処理
|
|
44
|
+
* @return 現在のポート情報
|
|
45
|
+
*/
|
|
19
46
|
get ports(): GPIOPortMap;
|
|
20
47
|
/**
|
|
21
48
|
* Unexport all exported GPIO ports.
|
|
49
|
+
* 全てのポート開放をする
|
|
50
|
+
* @return ポート開放結果
|
|
22
51
|
*/
|
|
23
52
|
unexportAll(): Promise<void>;
|
|
24
53
|
}
|
|
@@ -27,30 +56,97 @@ export declare class GPIOAccess extends EventEmitter {
|
|
|
27
56
|
*/
|
|
28
57
|
export declare class GPIOPortMap extends Map<PortNumber, GPIOPort> {
|
|
29
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* GPIO ポート
|
|
61
|
+
*/
|
|
30
62
|
export declare class GPIOPort extends EventEmitter {
|
|
63
|
+
/** ポート番号 */
|
|
31
64
|
private readonly _portNumber;
|
|
65
|
+
/** ポーリング間隔 */
|
|
32
66
|
private readonly _pollingInterval;
|
|
67
|
+
/** 入出力方向 */
|
|
33
68
|
private _direction;
|
|
69
|
+
/** エクスポート */
|
|
34
70
|
private _exported;
|
|
71
|
+
/** エクスポートリトライ回数 */
|
|
35
72
|
private _exportRetry;
|
|
73
|
+
/** 入出力値 */
|
|
36
74
|
private _value;
|
|
75
|
+
/** タイムアウト値 */
|
|
37
76
|
private _timeout;
|
|
77
|
+
/** GPIO チェンジイベントハンドラ */
|
|
38
78
|
onchange: GPIOChangeEventHandler | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* Creates an instance of GPIOPort.
|
|
81
|
+
* @param portNumber ポート番号
|
|
82
|
+
*/
|
|
39
83
|
constructor(portNumber: PortNumber);
|
|
84
|
+
/**
|
|
85
|
+
* ポート番号取得処理
|
|
86
|
+
* @return 現在のポート番号
|
|
87
|
+
*/
|
|
40
88
|
get portNumber(): PortNumber;
|
|
89
|
+
/**
|
|
90
|
+
* ポート名取得処理
|
|
91
|
+
* @return 現在のポート名
|
|
92
|
+
*/
|
|
41
93
|
get portName(): PortName;
|
|
94
|
+
/**
|
|
95
|
+
* ピン名取得処理
|
|
96
|
+
* @return 現在のピン名
|
|
97
|
+
*/
|
|
42
98
|
get pinName(): PinName;
|
|
99
|
+
/**
|
|
100
|
+
* GPIO 入出力方向 getter
|
|
101
|
+
* @return 現在のGPIO 入出力方向
|
|
102
|
+
*/
|
|
43
103
|
get direction(): DirectionMode;
|
|
104
|
+
/**
|
|
105
|
+
* GPIO export の有無 getter
|
|
106
|
+
* @return 現在のGPIO 出力
|
|
107
|
+
*/
|
|
44
108
|
get exported(): boolean;
|
|
109
|
+
/**
|
|
110
|
+
* GPIO 出力処理
|
|
111
|
+
* @param direction GPIO 入出力方向
|
|
112
|
+
* @return export 処理の完了
|
|
113
|
+
*/
|
|
45
114
|
export(direction: DirectionMode): Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* Unexport exported GPIO ports.
|
|
117
|
+
* ポート開放をする
|
|
118
|
+
* @return ポート開放処理の完了
|
|
119
|
+
*/
|
|
46
120
|
unexport(): Promise<void>;
|
|
121
|
+
/**
|
|
122
|
+
* 入力値読み取り処理
|
|
123
|
+
* @return 読み取り処理の完了
|
|
124
|
+
*/
|
|
47
125
|
read(): Promise<GPIOValue>;
|
|
126
|
+
/**
|
|
127
|
+
* 出力値書き込み処理
|
|
128
|
+
* @return 読み取り処理の完了
|
|
129
|
+
*/
|
|
48
130
|
write(value: GPIOValue): Promise<void>;
|
|
49
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* 無効なアクセスエラー
|
|
134
|
+
*/
|
|
50
135
|
export declare class InvalidAccessError extends Error {
|
|
136
|
+
/**
|
|
137
|
+
* Creates an instance of InvalidAccessError.
|
|
138
|
+
* @param message エラーメッセージ
|
|
139
|
+
*/
|
|
51
140
|
constructor(message: string);
|
|
52
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* 操作エラー
|
|
144
|
+
*/
|
|
53
145
|
export declare class OperationError extends Error {
|
|
146
|
+
/**
|
|
147
|
+
* Creates an instance of OperationError.
|
|
148
|
+
* @param message エラーメッセージ
|
|
149
|
+
*/
|
|
54
150
|
constructor(message: string);
|
|
55
151
|
}
|
|
56
152
|
export declare function requestGPIOAccess(): Promise<GPIOAccess>;
|
package/dist/index.js
CHANGED
|
@@ -8,36 +8,68 @@ const path = require("path");
|
|
|
8
8
|
* Interval of file system polling, in milliseconds.
|
|
9
9
|
*/
|
|
10
10
|
const PollingInterval = 100;
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* GPIO パス
|
|
13
|
+
*/
|
|
14
|
+
const SysfsGPIOPath = '/sys/class/gpio';
|
|
15
|
+
/**
|
|
16
|
+
* GPIO ポートマップサイズ
|
|
17
|
+
*/
|
|
12
18
|
const GPIOPortMapSizeMax = 1024;
|
|
19
|
+
/**
|
|
20
|
+
* Uint16 Max サイズ
|
|
21
|
+
*/
|
|
13
22
|
const Uint16Max = 65535;
|
|
14
|
-
|
|
15
|
-
|
|
23
|
+
/**
|
|
24
|
+
*
|
|
25
|
+
* Uint16型変換処理
|
|
26
|
+
* @param parseString 変換文字列
|
|
27
|
+
* @return Uint16型変換値
|
|
28
|
+
*/
|
|
29
|
+
function parseUint16(parseString) {
|
|
30
|
+
const n = Number.parseInt(parseString, 10);
|
|
16
31
|
if (0 <= n && n <= Uint16Max)
|
|
17
32
|
return n;
|
|
18
33
|
else
|
|
19
34
|
throw new RangeError(`Must be between 0 and ${Uint16Max}.`);
|
|
20
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* GPIO
|
|
38
|
+
*/
|
|
21
39
|
class GPIOAccess extends events_1.EventEmitter {
|
|
40
|
+
/** ポート */
|
|
41
|
+
_ports;
|
|
42
|
+
/** GPIO チェンジイベントハンドラ */
|
|
43
|
+
onchange;
|
|
44
|
+
/**
|
|
45
|
+
* Creates an instance of GPIOAccess.
|
|
46
|
+
* @param ports ポート番号
|
|
47
|
+
*/
|
|
22
48
|
constructor(ports) {
|
|
23
49
|
super();
|
|
24
50
|
this._ports = ports == null ? new GPIOPortMap() : ports;
|
|
25
|
-
this._ports.forEach(port => port.on(
|
|
26
|
-
this.emit(
|
|
51
|
+
this._ports.forEach((port) => port.on('change', (event) => {
|
|
52
|
+
this.emit('change', event);
|
|
27
53
|
}));
|
|
28
|
-
this.on(
|
|
54
|
+
this.on('change', (event) => {
|
|
29
55
|
if (this.onchange !== undefined)
|
|
30
56
|
this.onchange(event);
|
|
31
57
|
});
|
|
32
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* ポート情報取得処理
|
|
61
|
+
* @return 現在のポート情報
|
|
62
|
+
*/
|
|
33
63
|
get ports() {
|
|
34
64
|
return this._ports;
|
|
35
65
|
}
|
|
36
66
|
/**
|
|
37
67
|
* Unexport all exported GPIO ports.
|
|
68
|
+
* 全てのポート開放をする
|
|
69
|
+
* @return ポート開放結果
|
|
38
70
|
*/
|
|
39
71
|
async unexportAll() {
|
|
40
|
-
await Promise.all([...this.ports.values()].map(port => port.exported ? port.unexport() : undefined));
|
|
72
|
+
await Promise.all([...this.ports.values()].map((port) => port.exported ? port.unexport() : undefined));
|
|
41
73
|
}
|
|
42
74
|
}
|
|
43
75
|
exports.GPIOAccess = GPIOAccess;
|
|
@@ -47,39 +79,87 @@ exports.GPIOAccess = GPIOAccess;
|
|
|
47
79
|
class GPIOPortMap extends Map {
|
|
48
80
|
}
|
|
49
81
|
exports.GPIOPortMap = GPIOPortMap;
|
|
82
|
+
/**
|
|
83
|
+
* GPIO ポート
|
|
84
|
+
*/
|
|
50
85
|
class GPIOPort extends events_1.EventEmitter {
|
|
86
|
+
/** ポート番号 */
|
|
87
|
+
_portNumber;
|
|
88
|
+
/** ポーリング間隔 */
|
|
89
|
+
_pollingInterval;
|
|
90
|
+
/** 入出力方向 */
|
|
91
|
+
_direction;
|
|
92
|
+
/** エクスポート */
|
|
93
|
+
_exported;
|
|
94
|
+
/** エクスポートリトライ回数 */
|
|
95
|
+
_exportRetry;
|
|
96
|
+
/** 入出力値 */
|
|
97
|
+
_value;
|
|
98
|
+
/** タイムアウト値 */
|
|
99
|
+
_timeout;
|
|
100
|
+
/** GPIO チェンジイベントハンドラ */
|
|
101
|
+
onchange;
|
|
102
|
+
/**
|
|
103
|
+
* Creates an instance of GPIOPort.
|
|
104
|
+
* @param portNumber ポート番号
|
|
105
|
+
*/
|
|
51
106
|
constructor(portNumber) {
|
|
52
107
|
super();
|
|
53
108
|
this._portNumber = parseUint16(portNumber.toString());
|
|
54
109
|
this._pollingInterval = PollingInterval;
|
|
55
|
-
this._direction = new OperationError(
|
|
56
|
-
this._exported = new OperationError(
|
|
110
|
+
this._direction = new OperationError('Unknown direction.');
|
|
111
|
+
this._exported = new OperationError('Unknown export.');
|
|
57
112
|
this._exportRetry = 0;
|
|
58
|
-
this.on(
|
|
113
|
+
this.on('change', (event) => {
|
|
59
114
|
if (this.onchange !== undefined)
|
|
60
115
|
this.onchange(event);
|
|
61
116
|
});
|
|
62
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* ポート番号取得処理
|
|
120
|
+
* @return 現在のポート番号
|
|
121
|
+
*/
|
|
63
122
|
get portNumber() {
|
|
64
123
|
return this._portNumber;
|
|
65
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* ポート名取得処理
|
|
127
|
+
* @return 現在のポート名
|
|
128
|
+
*/
|
|
66
129
|
get portName() {
|
|
67
130
|
return `gpio${this.portNumber}`;
|
|
68
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* ピン名取得処理
|
|
134
|
+
* @return 現在のピン名
|
|
135
|
+
*/
|
|
69
136
|
get pinName() {
|
|
70
137
|
// NOTE: Unknown pinName.
|
|
71
|
-
return
|
|
138
|
+
return '';
|
|
72
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* GPIO 入出力方向 getter
|
|
142
|
+
* @return 現在のGPIO 入出力方向
|
|
143
|
+
*/
|
|
73
144
|
get direction() {
|
|
74
145
|
if (this._direction instanceof OperationError)
|
|
75
146
|
throw this._direction;
|
|
76
147
|
return this._direction;
|
|
77
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* GPIO export の有無 getter
|
|
151
|
+
* @return 現在のGPIO 出力
|
|
152
|
+
*/
|
|
78
153
|
get exported() {
|
|
79
154
|
if (this._exported instanceof OperationError)
|
|
80
155
|
throw this._exported;
|
|
81
156
|
return this._exported;
|
|
82
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* GPIO 出力処理
|
|
160
|
+
* @param direction GPIO 入出力方向
|
|
161
|
+
* @return export 処理の完了
|
|
162
|
+
*/
|
|
83
163
|
async export(direction) {
|
|
84
164
|
if (!/^(in|out)$/.test(direction)) {
|
|
85
165
|
throw new InvalidAccessError(`Must be "in" or "out".`);
|
|
@@ -94,10 +174,10 @@ class GPIOPort extends events_1.EventEmitter {
|
|
|
94
174
|
try {
|
|
95
175
|
clearInterval(this._timeout);
|
|
96
176
|
if (!this.exported) {
|
|
97
|
-
await fs_1.promises.writeFile(path.join(SysfsGPIOPath,
|
|
177
|
+
await fs_1.promises.writeFile(path.join(SysfsGPIOPath, 'export'), String(this.portNumber));
|
|
98
178
|
}
|
|
99
|
-
await fs_1.promises.writeFile(path.join(SysfsGPIOPath, this.portName,
|
|
100
|
-
if (direction ===
|
|
179
|
+
await fs_1.promises.writeFile(path.join(SysfsGPIOPath, this.portName, 'direction'), direction);
|
|
180
|
+
if (direction === 'in') {
|
|
101
181
|
this._timeout = setInterval(
|
|
102
182
|
// eslint-disable-next-line
|
|
103
183
|
this.read.bind(this), this._pollingInterval);
|
|
@@ -106,7 +186,7 @@ class GPIOPort extends events_1.EventEmitter {
|
|
|
106
186
|
catch (error) {
|
|
107
187
|
if (this._exportRetry == 0) {
|
|
108
188
|
await sleep(100);
|
|
109
|
-
console.warn(
|
|
189
|
+
console.warn('May be the first time port access. Retry..');
|
|
110
190
|
++this._exportRetry;
|
|
111
191
|
await this.export(direction);
|
|
112
192
|
}
|
|
@@ -117,26 +197,35 @@ class GPIOPort extends events_1.EventEmitter {
|
|
|
117
197
|
this._direction = direction;
|
|
118
198
|
this._exported = true;
|
|
119
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* Unexport exported GPIO ports.
|
|
202
|
+
* ポート開放をする
|
|
203
|
+
* @return ポート開放処理の完了
|
|
204
|
+
*/
|
|
120
205
|
async unexport() {
|
|
121
206
|
clearInterval(this._timeout);
|
|
122
207
|
try {
|
|
123
|
-
await fs_1.promises.writeFile(path.join(SysfsGPIOPath,
|
|
208
|
+
await fs_1.promises.writeFile(path.join(SysfsGPIOPath, 'unexport'), String(this.portNumber));
|
|
124
209
|
}
|
|
125
210
|
catch (error) {
|
|
126
211
|
throw new OperationError(error);
|
|
127
212
|
}
|
|
128
213
|
this._exported = false;
|
|
129
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* 入力値読み取り処理
|
|
217
|
+
* @return 読み取り処理の完了
|
|
218
|
+
*/
|
|
130
219
|
async read() {
|
|
131
|
-
if (!(this.exported && this.direction ===
|
|
220
|
+
if (!(this.exported && this.direction === 'in')) {
|
|
132
221
|
throw new InvalidAccessError(`The exported must be true and value of direction must be "in".`);
|
|
133
222
|
}
|
|
134
223
|
try {
|
|
135
|
-
const buffer = await fs_1.promises.readFile(path.join(SysfsGPIOPath, this.portName,
|
|
224
|
+
const buffer = await fs_1.promises.readFile(path.join(SysfsGPIOPath, this.portName, 'value'));
|
|
136
225
|
const value = parseUint16(buffer.toString());
|
|
137
226
|
if (this._value !== value) {
|
|
138
227
|
this._value = value;
|
|
139
|
-
this.emit(
|
|
228
|
+
this.emit('change', { value, port: this });
|
|
140
229
|
}
|
|
141
230
|
return value;
|
|
142
231
|
}
|
|
@@ -144,12 +233,16 @@ class GPIOPort extends events_1.EventEmitter {
|
|
|
144
233
|
throw new OperationError(error);
|
|
145
234
|
}
|
|
146
235
|
}
|
|
236
|
+
/**
|
|
237
|
+
* 出力値書き込み処理
|
|
238
|
+
* @return 読み取り処理の完了
|
|
239
|
+
*/
|
|
147
240
|
async write(value) {
|
|
148
|
-
if (!(this.exported && this.direction ===
|
|
241
|
+
if (!(this.exported && this.direction === 'out')) {
|
|
149
242
|
throw new InvalidAccessError(`The exported must be true and value of direction must be "out".`);
|
|
150
243
|
}
|
|
151
244
|
try {
|
|
152
|
-
await fs_1.promises.writeFile(path.join(SysfsGPIOPath, this.portName,
|
|
245
|
+
await fs_1.promises.writeFile(path.join(SysfsGPIOPath, this.portName, 'value'), parseUint16(value.toString()).toString());
|
|
153
246
|
}
|
|
154
247
|
catch (error) {
|
|
155
248
|
throw new OperationError(error);
|
|
@@ -157,14 +250,28 @@ class GPIOPort extends events_1.EventEmitter {
|
|
|
157
250
|
}
|
|
158
251
|
}
|
|
159
252
|
exports.GPIOPort = GPIOPort;
|
|
253
|
+
/**
|
|
254
|
+
* 無効なアクセスエラー
|
|
255
|
+
*/
|
|
160
256
|
class InvalidAccessError extends Error {
|
|
257
|
+
/**
|
|
258
|
+
* Creates an instance of InvalidAccessError.
|
|
259
|
+
* @param message エラーメッセージ
|
|
260
|
+
*/
|
|
161
261
|
constructor(message) {
|
|
162
262
|
super(message);
|
|
163
263
|
this.name = this.constructor.name;
|
|
164
264
|
}
|
|
165
265
|
}
|
|
166
266
|
exports.InvalidAccessError = InvalidAccessError;
|
|
267
|
+
/**
|
|
268
|
+
* 操作エラー
|
|
269
|
+
*/
|
|
167
270
|
class OperationError extends Error {
|
|
271
|
+
/**
|
|
272
|
+
* Creates an instance of OperationError.
|
|
273
|
+
* @param message エラーメッセージ
|
|
274
|
+
*/
|
|
168
275
|
constructor(message) {
|
|
169
276
|
super(message);
|
|
170
277
|
this.name = this.constructor.name;
|
|
@@ -174,13 +281,18 @@ exports.OperationError = OperationError;
|
|
|
174
281
|
// Web GPIOの仕様に基づく意図的なasync関数の使用なので、ルールを無効化
|
|
175
282
|
// eslint-disable-next-line
|
|
176
283
|
async function requestGPIOAccess() {
|
|
177
|
-
const ports = new GPIOPortMap([...Array(GPIOPortMapSizeMax).keys()].map(portNumber => [
|
|
284
|
+
const ports = new GPIOPortMap([...Array(GPIOPortMapSizeMax).keys()].map((portNumber) => [
|
|
178
285
|
portNumber,
|
|
179
|
-
new GPIOPort(portNumber)
|
|
286
|
+
new GPIOPort(portNumber),
|
|
180
287
|
]));
|
|
181
288
|
return new GPIOAccess(ports);
|
|
182
289
|
}
|
|
183
290
|
exports.requestGPIOAccess = requestGPIOAccess;
|
|
291
|
+
/**
|
|
292
|
+
* 待機 関数
|
|
293
|
+
* @param ms スリープ時間(ミリ秒)
|
|
294
|
+
* @return 待機完了
|
|
295
|
+
*/
|
|
184
296
|
function sleep(ms) {
|
|
185
297
|
return new Promise((resolve) => {
|
|
186
298
|
return setTimeout(resolve, ms);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-web-gpio",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.14",
|
|
4
4
|
"description": "GPIO access with Node.js",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -14,16 +14,24 @@
|
|
|
14
14
|
"author": "Kohei Watanabe <kou029w@gmail.com>",
|
|
15
15
|
"license": "MIT",
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"@types/node": "^16.
|
|
18
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
19
|
-
"@typescript-eslint/parser": "^5.
|
|
20
|
-
"eslint": "^8.
|
|
17
|
+
"@types/node": "^16.11.11",
|
|
18
|
+
"@typescript-eslint/eslint-plugin": "^5.5.0",
|
|
19
|
+
"@typescript-eslint/parser": "^5.5.0",
|
|
20
|
+
"eslint": "^8.4.0",
|
|
21
|
+
"husky": "^7.0.4",
|
|
22
|
+
"lint-staged": "^12.1.2",
|
|
23
|
+
"prettier": "^2.5.1",
|
|
24
|
+
"typedoc": "^0.22.10",
|
|
21
25
|
"typescript": "^4.2.3"
|
|
22
26
|
},
|
|
23
27
|
"scripts": {
|
|
24
28
|
"build": "tsc",
|
|
25
29
|
"lint": "eslint index.ts",
|
|
26
|
-
"prepare": "rm -rf dist && npm run build"
|
|
30
|
+
"prepare": "husky install && rm -rf dist && npm run build",
|
|
31
|
+
"precommit": "lint-staged",
|
|
32
|
+
"docs": "npm run remove:docs && npm run typedoc -- --options typedoc.json --exclude '**/*.spec.ts' ./ README.md",
|
|
33
|
+
"typedoc": "typedoc",
|
|
34
|
+
"remove:docs": "rm -rf docs"
|
|
27
35
|
},
|
|
28
36
|
"keywords": [
|
|
29
37
|
"gpio",
|