monocart-reporter 1.6.36 → 1.7.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.
- package/README.md +97 -16
- package/lib/cli.js +6 -3
- package/lib/default/options.js +2 -2
- package/lib/generate-report.js +1 -1
- package/lib/index.d.ts +122 -0
- package/lib/index.js +38 -7
- package/lib/index.mjs +5 -2
- package/lib/plugins/coverage/coverage.js +45 -53
- package/lib/plugins/coverage/istanbul/istanbul.js +27 -7
- package/lib/plugins/coverage/v8/source-map.js +5 -12
- package/lib/plugins/coverage/v8/v8-summary.js +2 -2
- package/lib/plugins/coverage/v8/v8.js +2 -19
- package/lib/plugins/state/client.js +153 -0
- package/lib/plugins/state/state.js +178 -0
- package/lib/runtime/monocart-reporter.js +1 -1
- package/lib/runtime/monocart-vendor.js +18 -62
- package/lib/utils/util.js +3 -0
- package/package.json +10 -7
|
@@ -28,11 +28,14 @@ const saveIstanbulReport = (coverageData, fileSources, options) => {
|
|
|
28
28
|
data = {};
|
|
29
29
|
Object.keys(coverageData).forEach((sourcePath) => {
|
|
30
30
|
const d = coverageData[sourcePath];
|
|
31
|
-
const
|
|
32
|
-
|
|
31
|
+
const s = fileSources[sourcePath];
|
|
32
|
+
const newSourcePath = options.sourcePath(sourcePath);
|
|
33
|
+
if (newSourcePath && newSourcePath !== sourcePath) {
|
|
33
34
|
sourcePath = newSourcePath;
|
|
35
|
+
// related updates
|
|
36
|
+
fileSources[sourcePath] = s;
|
|
37
|
+
d.path = sourcePath;
|
|
34
38
|
}
|
|
35
|
-
d.path = sourcePath;
|
|
36
39
|
data[sourcePath] = d;
|
|
37
40
|
});
|
|
38
41
|
}
|
|
@@ -40,6 +43,12 @@ const saveIstanbulReport = (coverageData, fileSources, options) => {
|
|
|
40
43
|
|
|
41
44
|
const coverageMap = istanbulLibCoverage.createCoverageMap(data);
|
|
42
45
|
|
|
46
|
+
const { watermarks, defaultSummarizer } = options;
|
|
47
|
+
const istanbulOptions = {
|
|
48
|
+
watermarks,
|
|
49
|
+
defaultSummarizer
|
|
50
|
+
};
|
|
51
|
+
|
|
43
52
|
// https://github.com/istanbuljs/istanbuljs/tree/master/packages/istanbul-lib-report
|
|
44
53
|
const contextOptions = {
|
|
45
54
|
watermarks: {
|
|
@@ -52,7 +61,7 @@ const saveIstanbulReport = (coverageData, fileSources, options) => {
|
|
|
52
61
|
// values can be nested/flat/pkg. Defaults to 'pkg'
|
|
53
62
|
defaultSummarizer: 'nested',
|
|
54
63
|
|
|
55
|
-
...
|
|
64
|
+
... istanbulOptions,
|
|
56
65
|
|
|
57
66
|
dir: options.htmlDir,
|
|
58
67
|
sourceFinder: (filePath) => {
|
|
@@ -87,7 +96,7 @@ const saveIstanbulReport = (coverageData, fileSources, options) => {
|
|
|
87
96
|
// create a context for report generation
|
|
88
97
|
const context = istanbulLibReport.createContext(contextOptions);
|
|
89
98
|
|
|
90
|
-
const htmlReport = istanbulReports.create('html', {});
|
|
99
|
+
const htmlReport = istanbulReports.create('html-spa', {});
|
|
91
100
|
htmlReport.execute(context);
|
|
92
101
|
|
|
93
102
|
const htmlPath = Util.relativePath(path.resolve(options.htmlDir, 'index.html'));
|
|
@@ -181,14 +190,25 @@ const convertV8ToIstanbul = async (v8list, options) => {
|
|
|
181
190
|
return p;
|
|
182
191
|
};
|
|
183
192
|
|
|
193
|
+
let failed = false;
|
|
184
194
|
await v8toIstanbul.load().catch((e) => {
|
|
185
|
-
EC.logRed(`[MCR] ${item.
|
|
195
|
+
EC.logRed(`[MCR] ${item.sourcePath} v8toIstanbul.load:`, e.message);
|
|
196
|
+
failed = true;
|
|
186
197
|
});
|
|
187
198
|
|
|
199
|
+
if (failed) {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
|
|
188
203
|
try {
|
|
189
204
|
v8toIstanbul.applyCoverage(item.functions);
|
|
190
205
|
} catch (e) {
|
|
191
|
-
EC.logRed(`[MCR] ${item.
|
|
206
|
+
EC.logRed(`[MCR] ${item.sourcePath} v8toIstanbul.applyCoverage:`, e.message);
|
|
207
|
+
failed = true;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (failed) {
|
|
211
|
+
continue;
|
|
192
212
|
}
|
|
193
213
|
|
|
194
214
|
const istanbulData = v8toIstanbul.toIstanbul();
|
|
@@ -99,7 +99,7 @@ const findOriginalEndPosition = (consumer, eLoc, generatedMapping, range) => {
|
|
|
99
99
|
|
|
100
100
|
// =========================================================================================================
|
|
101
101
|
|
|
102
|
-
const getOriginalMappings = (
|
|
102
|
+
const getOriginalMappings = (consumer, options) => {
|
|
103
103
|
|
|
104
104
|
// source filter
|
|
105
105
|
let sourceList = consumer.sources;
|
|
@@ -152,7 +152,7 @@ const unpackJsSourceMap = async (item, v8list, options) => {
|
|
|
152
152
|
|
|
153
153
|
const generatedMapping = new PositionMapping(item.source);
|
|
154
154
|
const consumer = await new SourceMapConsumer(sourceMap);
|
|
155
|
-
const originalMappings = getOriginalMappings(
|
|
155
|
+
const originalMappings = getOriginalMappings(consumer, options);
|
|
156
156
|
|
|
157
157
|
// generated ranges to original ranges
|
|
158
158
|
item.ranges.forEach((range) => {
|
|
@@ -388,10 +388,6 @@ const saveSourceFile = async (filePath, data) => {
|
|
|
388
388
|
|
|
389
389
|
const collectSourceMaps = async (v8list, options, inlineSourceMap) => {
|
|
390
390
|
|
|
391
|
-
if (!options.unpackSourceMap) {
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
391
|
if (inlineSourceMap) {
|
|
396
392
|
await collectInlineSourceMaps(v8list);
|
|
397
393
|
return;
|
|
@@ -419,7 +415,9 @@ const filterSourceMapList = (v8list, options) => {
|
|
|
419
415
|
return;
|
|
420
416
|
}
|
|
421
417
|
|
|
422
|
-
|
|
418
|
+
// do not remove in debug mode
|
|
419
|
+
if (!options.debug) {
|
|
420
|
+
// remove dist file if found sourceMap
|
|
423
421
|
indexes.reverse();
|
|
424
422
|
indexes.forEach((i) => {
|
|
425
423
|
v8list.splice(i, 1);
|
|
@@ -432,11 +430,6 @@ const filterSourceMapList = (v8list, options) => {
|
|
|
432
430
|
// requires ranges before unpack
|
|
433
431
|
const unpackSourceMaps = async (v8list, options) => {
|
|
434
432
|
|
|
435
|
-
// collect source maps
|
|
436
|
-
if (!options.unpackSourceMap) {
|
|
437
|
-
return;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
433
|
const sourceMapList = filterSourceMapList(v8list, options);
|
|
441
434
|
if (!sourceMapList) {
|
|
442
435
|
// nothing to unpack
|
|
@@ -17,7 +17,7 @@ const getCssSummary = (item) => {
|
|
|
17
17
|
const uncovered = total - covered;
|
|
18
18
|
|
|
19
19
|
return {
|
|
20
|
-
name: item.
|
|
20
|
+
name: item.sourcePath,
|
|
21
21
|
type: item.type,
|
|
22
22
|
url: item.url,
|
|
23
23
|
total,
|
|
@@ -59,7 +59,7 @@ const getJsSummary = (item) => {
|
|
|
59
59
|
const covered = total - uncovered;
|
|
60
60
|
|
|
61
61
|
return {
|
|
62
|
-
name: item.
|
|
62
|
+
name: item.sourcePath,
|
|
63
63
|
type: item.type,
|
|
64
64
|
url: item.url,
|
|
65
65
|
total,
|
|
@@ -3,8 +3,8 @@ const EC = require('eight-colors');
|
|
|
3
3
|
const Util = require('../../../utils/util.js');
|
|
4
4
|
const { getV8Summary } = require('./v8-summary.js');
|
|
5
5
|
const { dedupeRanges } = require('./dedupe.js');
|
|
6
|
-
const { getSourcePath
|
|
7
|
-
const { collectSourceMaps
|
|
6
|
+
const { getSourcePath } = require('../coverage-utils.js');
|
|
7
|
+
const { collectSourceMaps } = require('./source-map.js');
|
|
8
8
|
const { mergeScriptCovs } = require('../../../runtime/monocart-coverage.js');
|
|
9
9
|
|
|
10
10
|
|
|
@@ -70,22 +70,6 @@ const initV8ListAndSourcemap = async (v8list, options, inlineSourceMap) => {
|
|
|
70
70
|
|
|
71
71
|
// ========================================================================================================
|
|
72
72
|
|
|
73
|
-
const unpackV8List = async (v8list, options) => {
|
|
74
|
-
v8list.forEach((item, i) => {
|
|
75
|
-
if (item.type === 'js') {
|
|
76
|
-
item.ranges = convertFunctionsToRanges(item.functions);
|
|
77
|
-
delete item.functions;
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
// requires ranges before unpack
|
|
82
|
-
await unpackSourceMaps(v8list, options);
|
|
83
|
-
|
|
84
|
-
// console.log(v8list.length);
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
// ========================================================================================================
|
|
88
|
-
|
|
89
73
|
// force to async
|
|
90
74
|
const mergeCssRanges = (itemList) => {
|
|
91
75
|
return new Promise((resolve) => {
|
|
@@ -262,7 +246,6 @@ const saveV8Report = async (v8list, options) => {
|
|
|
262
246
|
|
|
263
247
|
module.exports = {
|
|
264
248
|
initV8ListAndSourcemap,
|
|
265
|
-
unpackV8List,
|
|
266
249
|
mergeV8Coverage,
|
|
267
250
|
saveV8Report
|
|
268
251
|
};
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
const EC = require('eight-colors');
|
|
2
|
+
const { WebSocket } = require('../../runtime/monocart-vendor.js');
|
|
3
|
+
const Util = require('../../utils/util.js');
|
|
4
|
+
|
|
5
|
+
const getServerUrl = (options = {}) => {
|
|
6
|
+
return `ws://${options.host}:${options.port}`;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
class Client {
|
|
10
|
+
|
|
11
|
+
constructor(clientOptions) {
|
|
12
|
+
this.options = clientOptions;
|
|
13
|
+
this.requests = new Map();
|
|
14
|
+
this.resolves = [];
|
|
15
|
+
|
|
16
|
+
const serverUrl = getServerUrl(clientOptions);
|
|
17
|
+
|
|
18
|
+
// https://github.com/websockets/ws/blob/master/doc/ws.md
|
|
19
|
+
const ws = new WebSocket(serverUrl);
|
|
20
|
+
|
|
21
|
+
ws.on('error', (err) => {
|
|
22
|
+
|
|
23
|
+
// socket hang up: the port is exists but not websocket server
|
|
24
|
+
// connect ECONNREFUSED: websocket server unavailable
|
|
25
|
+
|
|
26
|
+
if (Util.isList(this.resolves)) {
|
|
27
|
+
this.resolves.forEach((item) => {
|
|
28
|
+
item.reject(err);
|
|
29
|
+
});
|
|
30
|
+
this.resolves = null;
|
|
31
|
+
} else {
|
|
32
|
+
EC.logRed(`[SWS] websocket error: ${err.message}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
ws.on('message', (data) => {
|
|
38
|
+
this.onMessage(data);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
ws.on('open', () => {
|
|
42
|
+
this.ws = ws;
|
|
43
|
+
if (Util.isList(this.resolves)) {
|
|
44
|
+
this.resolves.forEach((item) => {
|
|
45
|
+
item.resolve(ws);
|
|
46
|
+
});
|
|
47
|
+
this.resolves = null;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
connect() {
|
|
53
|
+
return new Promise((resolve, reject) => {
|
|
54
|
+
|
|
55
|
+
if (this.ws) {
|
|
56
|
+
resolve(this.ws);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (this.resolves) {
|
|
61
|
+
this.resolves.push({
|
|
62
|
+
resolve,
|
|
63
|
+
reject
|
|
64
|
+
});
|
|
65
|
+
} else {
|
|
66
|
+
reject(new Error('[SWS] an error occurs when connecting websocket server'));
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
onMessage(buf) {
|
|
72
|
+
const message = JSON.parse(buf.toString());
|
|
73
|
+
if (!message) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const { id, data } = message;
|
|
77
|
+
if (!id) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const req = this.requests.get(id);
|
|
82
|
+
if (!req) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
this.requests.delete(id);
|
|
87
|
+
|
|
88
|
+
clearTimeout(req.timeout_id);
|
|
89
|
+
req.resolve(data);
|
|
90
|
+
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async execute(data) {
|
|
94
|
+
|
|
95
|
+
let err;
|
|
96
|
+
const ws = await this.connect().catch((e) => {
|
|
97
|
+
err = e;
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
|
|
102
|
+
if (!ws) {
|
|
103
|
+
reject(err);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const id = Util.uid();
|
|
108
|
+
const timeout = this.options.timeout;
|
|
109
|
+
const timeout_id = setTimeout(() => {
|
|
110
|
+
this.requests.delete(id);
|
|
111
|
+
reject(new Error(`[SWS] Timed out receiving message from websocket server: ${timeout}ms`));
|
|
112
|
+
}, timeout);
|
|
113
|
+
|
|
114
|
+
this.requests.set(id, {
|
|
115
|
+
resolve,
|
|
116
|
+
timeout_id
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const message = JSON.stringify({
|
|
120
|
+
id,
|
|
121
|
+
data
|
|
122
|
+
});
|
|
123
|
+
ws.send(message);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
state() {
|
|
128
|
+
return {
|
|
129
|
+
get: (... args) => {
|
|
130
|
+
return this.execute(['get', ... args]);
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
set: (... args) => {
|
|
134
|
+
return this.execute(['set', ... args]);
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
remove: (... args) => {
|
|
138
|
+
return this.execute(['remove', ... args]);
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
send: (... args) => {
|
|
142
|
+
return this.execute(['send', ... args]);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
module.exports = {
|
|
151
|
+
getServerUrl,
|
|
152
|
+
Client
|
|
153
|
+
};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
const EC = require('eight-colors');
|
|
2
|
+
const { WebSocketServer } = require('../../runtime/monocart-vendor.js');
|
|
3
|
+
const Util = require('../../utils/util.js');
|
|
4
|
+
const { getServerUrl, Client } = require('./client.js');
|
|
5
|
+
|
|
6
|
+
// https://github.com/websockets/ws/blob/master/doc/ws.md
|
|
7
|
+
const defaultServerOptions = {
|
|
8
|
+
host: 'localhost',
|
|
9
|
+
port: 8130
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const defaultClientOptions = {
|
|
13
|
+
... defaultServerOptions,
|
|
14
|
+
timeout: 3000
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const defaultStateOptions = {
|
|
18
|
+
|
|
19
|
+
server: defaultServerOptions,
|
|
20
|
+
|
|
21
|
+
// onReceive: function(... args) {
|
|
22
|
+
// console.log('receive on server', args);
|
|
23
|
+
// return ['custom response', ... args];
|
|
24
|
+
// },
|
|
25
|
+
|
|
26
|
+
// onClose: function(data, config) {
|
|
27
|
+
// Object.assign(config.metadata, data);
|
|
28
|
+
// },
|
|
29
|
+
|
|
30
|
+
// key-value state data
|
|
31
|
+
data: {}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// ===============================================================================
|
|
35
|
+
|
|
36
|
+
const clientMap = new Map();
|
|
37
|
+
const useState = (options = {}) => {
|
|
38
|
+
const clientOptions = {
|
|
39
|
+
... defaultClientOptions,
|
|
40
|
+
... options
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const clientKey = Object.keys(defaultClientOptions).map((k) => clientOptions[k]).join('-');
|
|
44
|
+
// console.log('client key', clientKey);
|
|
45
|
+
|
|
46
|
+
let client = clientMap.get(clientKey);
|
|
47
|
+
if (!client) {
|
|
48
|
+
client = new Client(clientOptions);
|
|
49
|
+
clientMap.set(clientKey, client);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return client.state();
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// ===============================================================================
|
|
56
|
+
|
|
57
|
+
const getActions = (stateData) => {
|
|
58
|
+
return {
|
|
59
|
+
get: (... args) => {
|
|
60
|
+
if (args.length) {
|
|
61
|
+
const values = args.map((k) => stateData[k]);
|
|
62
|
+
if (args.length === 1) {
|
|
63
|
+
return values[0];
|
|
64
|
+
}
|
|
65
|
+
return values;
|
|
66
|
+
}
|
|
67
|
+
return stateData;
|
|
68
|
+
},
|
|
69
|
+
set: (... args) => {
|
|
70
|
+
if (args.length) {
|
|
71
|
+
const first = args[0];
|
|
72
|
+
if (args.length === 1 && typeof first === 'object') {
|
|
73
|
+
Object.keys(first).forEach((key) => {
|
|
74
|
+
stateData[key] = first[key];
|
|
75
|
+
});
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
stateData[first] = args[1];
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
remove: (... args) => {
|
|
82
|
+
if (args.length) {
|
|
83
|
+
args.forEach((k) => {
|
|
84
|
+
if (Util.hasOwn(stateData, k)) {
|
|
85
|
+
delete stateData[k];
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const onMessage = async (ws, buf, options) => {
|
|
94
|
+
const message = JSON.parse(buf.toString());
|
|
95
|
+
if (!message) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const { id, data } = message;
|
|
99
|
+
if (!id || !Array.isArray(data)) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// first argument is action name always
|
|
104
|
+
const action = data.shift();
|
|
105
|
+
|
|
106
|
+
let resData;
|
|
107
|
+
if (action === 'send') {
|
|
108
|
+
// send handler
|
|
109
|
+
if (typeof options.onReceive === 'function') {
|
|
110
|
+
resData = await options.onReceive.apply(options, data);
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
// get/set/remove handler
|
|
114
|
+
const actions = getActions(options.data);
|
|
115
|
+
const handler = actions[action];
|
|
116
|
+
if (handler) {
|
|
117
|
+
resData = handler.apply(options, data);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const response = JSON.stringify({
|
|
122
|
+
id,
|
|
123
|
+
data: resData
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// always response, like send action
|
|
127
|
+
// otherwise the request will be timeout
|
|
128
|
+
ws.send(response);
|
|
129
|
+
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const createStateServer = (stateOptions) => {
|
|
133
|
+
|
|
134
|
+
const options = Util.mergeOption(defaultStateOptions, stateOptions);
|
|
135
|
+
|
|
136
|
+
if (!options.data || typeof options.data !== 'object') {
|
|
137
|
+
options.data = {};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const serverOptions = options.server;
|
|
141
|
+
|
|
142
|
+
const wss = new WebSocketServer(serverOptions);
|
|
143
|
+
|
|
144
|
+
wss.on('error', (e) => {
|
|
145
|
+
EC.logRed(`[SWS] websocket server error: ${e.message}`);
|
|
146
|
+
});
|
|
147
|
+
wss.on('wsClientError', (e) => {
|
|
148
|
+
EC.logRed(`[SWS] websocket client error: ${e.message}`);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
wss.on('connection', (ws) => {
|
|
152
|
+
|
|
153
|
+
// data {Buffer|ArrayBuffer|Buffer[]}
|
|
154
|
+
ws.on('message', (data) => {
|
|
155
|
+
// console.log(data, isBinary);
|
|
156
|
+
onMessage(ws, data, options);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
wss.on('listening', () => {
|
|
161
|
+
const serverUrl = getServerUrl(serverOptions);
|
|
162
|
+
console.log(`[SWS] state websocket server listening on ${EC.cyan(serverUrl)}`);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
close: async (config) => {
|
|
167
|
+
wss.close();
|
|
168
|
+
if (typeof options.onClose === 'function') {
|
|
169
|
+
await options.onClose.call(options, options.data, config);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
module.exports = {
|
|
176
|
+
createStateServer,
|
|
177
|
+
useState
|
|
178
|
+
};
|