@steedos/service-package-registry 2.1.10 → 2.1.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/main/default/manager/registry.js +1 -1
- package/main/default/objects/steedos_packages/buttons/install_purchased_packages.button.js +42 -32
- package/main/default/objects/steedos_packages/buttons/uninstall.button.js +1 -1
- package/main/default/objects/steedos_packages/fields/metadata.$.type.field.yml +3 -1
- package/main/default/util/events.js +73 -0
- package/main/default/util/exec.js +91 -0
- package/main/default/util/hooks.js +243 -0
- package/main/default/util/i18n.js +234 -0
- package/main/default/util/index.js +81 -0
- package/main/default/util/log.js +233 -0
- package/main/default/util/util.js +987 -0
- package/package.json +8 -4
- package/package.service.js +50 -16
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {exec,log,events} = require("
|
|
1
|
+
const {exec,log,events} = require("../util");
|
|
2
2
|
const child_process = require('child_process');
|
|
3
3
|
const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
4
4
|
const yarnCommand = process.platform === 'win32' ? 'yarn.cmd' : 'yarn';
|
|
@@ -1,56 +1,66 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
install_purchased_packages: function (object_name, record_id) {
|
|
3
|
-
const
|
|
4
|
-
if(
|
|
3
|
+
const result = Steedos.authRequest(Steedos.absoluteUrl('service/api/~packages-project-server/cloud/saas/packages/purchased'), {async: false, type: 'get'});
|
|
4
|
+
if(result && result.packages.length === 0){
|
|
5
5
|
return toastr.info('您还未购买任何软件包')
|
|
6
6
|
}else{
|
|
7
|
+
toastr.info('安装中,请稍后...', '', {
|
|
8
|
+
timeOut: 0,
|
|
9
|
+
progressBar: true,
|
|
10
|
+
})
|
|
7
11
|
Steedos.authRequest(Steedos.absoluteUrl('service/api/~packages-project-server/cloud/saas/packages/purchased'), {type: 'post', error: function(XMLHttpRequest, textStatus, errorThrown){
|
|
8
|
-
|
|
12
|
+
toastr.clear()
|
|
9
13
|
if (XMLHttpRequest.responseJSON && XMLHttpRequest.responseJSON.error) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
14
|
+
toastr.error(XMLHttpRequest.responseJSON.error)
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
toastr.error(XMLHttpRequest.responseJSON)
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
success: function(result){
|
|
21
|
+
try {
|
|
22
|
+
toastr.clear()
|
|
23
|
+
const installErrors = result.installErrors;
|
|
24
|
+
let errorsHtml = '';
|
|
25
|
+
let index = 0;
|
|
26
|
+
_.each(installErrors, function(v, k){
|
|
27
|
+
index ++
|
|
28
|
+
errorsHtml = `${errorsHtml}<li class="py-4">
|
|
29
|
+
<div class="flex space-x-3">
|
|
30
|
+
<div class="flex-1 space-y-1">
|
|
31
|
+
<div class="flex items-center justify-between">
|
|
32
|
+
<h3 class="text-sm font-medium"><b>${k}</b></h3>
|
|
33
|
+
<p class="text-sm text-gray-500"><span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-pink-100 text-pink-800">
|
|
34
|
+
Error ${index}
|
|
35
|
+
</span></p>
|
|
27
36
|
</div>
|
|
28
|
-
|
|
29
|
-
|
|
37
|
+
<p class="text-sm text-gray-500">${v}</p>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</li>`
|
|
41
|
+
})
|
|
42
|
+
if(!_.isEmpty(installErrors)){
|
|
30
43
|
swal({
|
|
31
44
|
title: "安装软件包异常",
|
|
32
45
|
text: `<div>
|
|
33
46
|
<ul role="list" class="divide-y divide-gray-200">
|
|
34
47
|
${errorsHtml}
|
|
35
48
|
</ul>
|
|
36
|
-
|
|
49
|
+
</div>`,
|
|
37
50
|
html: true,
|
|
38
51
|
showCancelButton: false,
|
|
39
52
|
closeOnConfirm: false,
|
|
40
53
|
cancelButtonText: t('Cancel'),
|
|
41
54
|
confirmButtonText: t('OK')
|
|
42
55
|
});
|
|
43
|
-
}
|
|
44
|
-
toastr.
|
|
56
|
+
}else{
|
|
57
|
+
toastr.success('安装完成')
|
|
45
58
|
}
|
|
59
|
+
FlowRouter.reload();
|
|
60
|
+
} catch (error) {
|
|
61
|
+
toastr.error(XMLHttpRequest.responseJSON.error)
|
|
46
62
|
}
|
|
47
|
-
|
|
48
|
-
toastr.error(XMLHttpRequest.responseJSON)
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
success: function(){
|
|
52
|
-
toastr.info('安装完成')
|
|
53
|
-
FlowRouter.reload();
|
|
63
|
+
|
|
54
64
|
}
|
|
55
65
|
});
|
|
56
66
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright JS Foundation and other contributors, http://js.foundation
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
**/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Runtime events
|
|
19
|
+
* @mixin @node-red/util_events
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const events = new (require("events")).EventEmitter();
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
const deprecatedEvents = {
|
|
26
|
+
"nodes-stopped": "flows:stopped",
|
|
27
|
+
"nodes-started": "flows:started"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function wrapEventFunction(obj,func) {
|
|
31
|
+
events["_"+func] = events[func];
|
|
32
|
+
return function(eventName, listener) {
|
|
33
|
+
if (deprecatedEvents.hasOwnProperty(eventName)) {
|
|
34
|
+
const log = require("@node-red/util").log;
|
|
35
|
+
const stack = (new Error().stack).split("\n")[2].split("(")[1].slice(0,-1);
|
|
36
|
+
log.warn(`[RED.events] Deprecated use of "${eventName}" event from "${stack}". Use "${deprecatedEvents[eventName]}" instead.`)
|
|
37
|
+
}
|
|
38
|
+
return events["_"+func].call(events,eventName,listener)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
events.on = wrapEventFunction(events,"on");
|
|
44
|
+
events.once = wrapEventFunction(events,"once");
|
|
45
|
+
events.addListener = events.on;
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
module.exports = events;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Runtime events emitter
|
|
53
|
+
* @mixin @node-red/util_events
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Register an event listener for a runtime event
|
|
58
|
+
* @name on
|
|
59
|
+
* @function
|
|
60
|
+
* @memberof @node-red/util_events
|
|
61
|
+
* @param {String} eventName - the name of the event to listen to
|
|
62
|
+
* @param {Function} listener - the callback function for the event
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Emit an event to all of its registered listeners
|
|
67
|
+
* @name emit
|
|
68
|
+
* @function
|
|
69
|
+
* @memberof @node-red/util_events
|
|
70
|
+
* @param {String} eventName - the name of the event to emit
|
|
71
|
+
* @param {any} ...args - the arguments to pass in the event
|
|
72
|
+
* @return {Boolean} - whether the event had listeners or not
|
|
73
|
+
*/
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright JS Foundation and other contributors, http://js.foundation
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
**/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Run system commands with event-log integration
|
|
19
|
+
* @mixin @node-red/util_exec
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const child_process = require('child_process');
|
|
23
|
+
const events = require("./events");
|
|
24
|
+
const util = require('./util');
|
|
25
|
+
|
|
26
|
+
function logLines(id,type,data) {
|
|
27
|
+
events.emit("event-log", {id:id,payload:{ts: Date.now(),data:data,type:type}});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = {
|
|
31
|
+
/**
|
|
32
|
+
* Run a system command with stdout/err being emitted as 'event-log' events
|
|
33
|
+
* on the @node-red/util/events handler.
|
|
34
|
+
*
|
|
35
|
+
* The main arguments to this function are the same as passed to `child_process.spawn`
|
|
36
|
+
*
|
|
37
|
+
* @param {String} command - the command to run
|
|
38
|
+
* @param {Array} args - arguments for the command
|
|
39
|
+
* @param {Object} options - options to pass child_process.spawn
|
|
40
|
+
* @param {Boolean} emit - whether to emit events to the event-log for each line of stdout/err
|
|
41
|
+
* @return {Promise} A promise that resolves (rc=0) or rejects (rc!=0) when the command completes. The value
|
|
42
|
+
* of the promise is an object of the form:
|
|
43
|
+
*
|
|
44
|
+
* {
|
|
45
|
+
* code: <exit code>,
|
|
46
|
+
* stdout: <standard output from the command>,
|
|
47
|
+
* stderr: <standard error from the command>
|
|
48
|
+
* }
|
|
49
|
+
|
|
50
|
+
* @memberof @node-red/util_exec
|
|
51
|
+
*/
|
|
52
|
+
run: function(command,args,options,emit) {
|
|
53
|
+
var invocationId = util.generateId();
|
|
54
|
+
|
|
55
|
+
emit && events.emit("event-log", {ts: Date.now(),id:invocationId,payload:{ts: Date.now(),data:command+" "+args.join(" ")}});
|
|
56
|
+
|
|
57
|
+
return new Promise((resolve, reject) => {
|
|
58
|
+
let stdout = "";
|
|
59
|
+
let stderr = "";
|
|
60
|
+
const child = child_process.spawn(command,args,options);
|
|
61
|
+
child.stdout.on('data', (data) => {
|
|
62
|
+
const str = ""+data;
|
|
63
|
+
stdout += str;
|
|
64
|
+
emit && logLines(invocationId,"out",str);
|
|
65
|
+
});
|
|
66
|
+
child.stderr.on('data', (data) => {
|
|
67
|
+
const str = ""+data;
|
|
68
|
+
stderr += str;
|
|
69
|
+
emit && logLines(invocationId,"err",str);
|
|
70
|
+
});
|
|
71
|
+
child.on('error', function(err) {
|
|
72
|
+
stderr = err.toString();
|
|
73
|
+
emit && logLines(invocationId,"err",stderr);
|
|
74
|
+
})
|
|
75
|
+
child.on('close', (code) => {
|
|
76
|
+
let result = {
|
|
77
|
+
code: code,
|
|
78
|
+
stdout: stdout,
|
|
79
|
+
stderr: stderr
|
|
80
|
+
}
|
|
81
|
+
emit && events.emit("event-log", {id:invocationId,payload:{ts: Date.now(),data:"rc="+code}});
|
|
82
|
+
|
|
83
|
+
if (code === 0) {
|
|
84
|
+
resolve(result)
|
|
85
|
+
} else {
|
|
86
|
+
reject(result);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
const Log = require("./log.js");
|
|
2
|
+
|
|
3
|
+
const VALID_HOOKS = [
|
|
4
|
+
// Message Routing Path
|
|
5
|
+
"onSend",
|
|
6
|
+
"preRoute",
|
|
7
|
+
"preDeliver",
|
|
8
|
+
"postDeliver",
|
|
9
|
+
"onReceive",
|
|
10
|
+
"postReceive",
|
|
11
|
+
"onComplete",
|
|
12
|
+
// Module install hooks
|
|
13
|
+
"preInstall",
|
|
14
|
+
"postInstall",
|
|
15
|
+
"preUninstall",
|
|
16
|
+
"postUninstall"
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
// Flags for what hooks have handlers registered
|
|
21
|
+
let states = { }
|
|
22
|
+
|
|
23
|
+
// Doubly-LinkedList of hooks by id.
|
|
24
|
+
// - hooks[id] points to head of list
|
|
25
|
+
// - each list item looks like:
|
|
26
|
+
// {
|
|
27
|
+
// cb: the callback function
|
|
28
|
+
// location: filename/line of code that added the hook
|
|
29
|
+
// previousHook: reference to previous hook in list
|
|
30
|
+
// nextHook: reference to next hook in list
|
|
31
|
+
// removed: a flag that is set if the item was removed
|
|
32
|
+
// }
|
|
33
|
+
let hooks = { }
|
|
34
|
+
|
|
35
|
+
// Hooks by label
|
|
36
|
+
let labelledHooks = { }
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Runtime hooks engine
|
|
40
|
+
*
|
|
41
|
+
* The following hooks can be used:
|
|
42
|
+
*
|
|
43
|
+
* Message sending
|
|
44
|
+
* - `onSend` - passed an array of `SendEvent` objects. The messages inside these objects are exactly what the node has passed to `node.send` - meaning there could be duplicate references to the same message object.
|
|
45
|
+
* - `preRoute` - passed a `SendEvent`
|
|
46
|
+
* - `preDeliver` - passed a `SendEvent`. The local router has identified the node it is going to send to. At this point, the message has been cloned if needed.
|
|
47
|
+
* - `postDeliver` - passed a `SendEvent`. The message has been dispatched to be delivered asynchronously (unless the sync delivery flag is set, in which case it would be continue as synchronous delivery)
|
|
48
|
+
* - `onReceive` - passed a `ReceiveEvent` when a node is about to receive a message
|
|
49
|
+
* - `postReceive` - passed a `ReceiveEvent` when the message has been given to the node's `input` handler(s)
|
|
50
|
+
* - `onComplete` - passed a `CompleteEvent` when the node has completed with a message or logged an error
|
|
51
|
+
*
|
|
52
|
+
* @mixin @node-red/util_hooks
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Register a handler to a named hook
|
|
57
|
+
* @memberof @node-red/util_hooks
|
|
58
|
+
* @param {String} hookId - the name of the hook to attach to
|
|
59
|
+
* @param {Function} callback - the callback function for the hook
|
|
60
|
+
*/
|
|
61
|
+
function add(hookId, callback) {
|
|
62
|
+
let [id, label] = hookId.split(".");
|
|
63
|
+
if (VALID_HOOKS.indexOf(id) === -1) {
|
|
64
|
+
throw new Error(`Invalid hook '${id}'`);
|
|
65
|
+
}
|
|
66
|
+
if (label && labelledHooks[label] && labelledHooks[label][id]) {
|
|
67
|
+
throw new Error("Hook "+hookId+" already registered")
|
|
68
|
+
}
|
|
69
|
+
// Get location of calling code
|
|
70
|
+
const stack = new Error().stack;
|
|
71
|
+
const callModule = stack.split("\n")[2].split("(")[1].slice(0,-1);
|
|
72
|
+
Log.debug(`Adding hook '${hookId}' from ${callModule}`);
|
|
73
|
+
|
|
74
|
+
const hookItem = {cb:callback, location: callModule, previousHook: null, nextHook: null }
|
|
75
|
+
|
|
76
|
+
let tailItem = hooks[id];
|
|
77
|
+
if (tailItem === undefined) {
|
|
78
|
+
hooks[id] = hookItem;
|
|
79
|
+
} else {
|
|
80
|
+
while(tailItem.nextHook !== null) {
|
|
81
|
+
tailItem = tailItem.nextHook
|
|
82
|
+
}
|
|
83
|
+
tailItem.nextHook = hookItem;
|
|
84
|
+
hookItem.previousHook = tailItem;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (label) {
|
|
88
|
+
labelledHooks[label] = labelledHooks[label]||{};
|
|
89
|
+
labelledHooks[label][id] = hookItem;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// TODO: get rid of this;
|
|
93
|
+
states[id] = true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Remove a handled from a named hook
|
|
98
|
+
* @memberof @node-red/util_hooks
|
|
99
|
+
* @param {String} hookId - the name of the hook event to remove - must be `name.label`
|
|
100
|
+
*/
|
|
101
|
+
function remove(hookId) {
|
|
102
|
+
let [id,label] = hookId.split(".");
|
|
103
|
+
if ( !label) {
|
|
104
|
+
throw new Error("Cannot remove hook without label: "+hookId)
|
|
105
|
+
}
|
|
106
|
+
Log.debug(`Removing hook '${hookId}'`);
|
|
107
|
+
if (labelledHooks[label]) {
|
|
108
|
+
if (id === "*") {
|
|
109
|
+
// Remove all hooks for this label
|
|
110
|
+
let hookList = Object.keys(labelledHooks[label]);
|
|
111
|
+
for (let i=0;i<hookList.length;i++) {
|
|
112
|
+
removeHook(hookList[i],labelledHooks[label][hookList[i]])
|
|
113
|
+
}
|
|
114
|
+
delete labelledHooks[label];
|
|
115
|
+
} else if (labelledHooks[label][id]) {
|
|
116
|
+
removeHook(id,labelledHooks[label][id])
|
|
117
|
+
delete labelledHooks[label][id];
|
|
118
|
+
if (Object.keys(labelledHooks[label]).length === 0){
|
|
119
|
+
delete labelledHooks[label];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function removeHook(id,hookItem) {
|
|
126
|
+
let previousHook = hookItem.previousHook;
|
|
127
|
+
let nextHook = hookItem.nextHook;
|
|
128
|
+
|
|
129
|
+
if (previousHook) {
|
|
130
|
+
previousHook.nextHook = nextHook;
|
|
131
|
+
} else {
|
|
132
|
+
hooks[id] = nextHook;
|
|
133
|
+
}
|
|
134
|
+
if (nextHook) {
|
|
135
|
+
nextHook.previousHook = previousHook;
|
|
136
|
+
}
|
|
137
|
+
hookItem.removed = true;
|
|
138
|
+
if (!previousHook && !nextHook) {
|
|
139
|
+
delete hooks[id];
|
|
140
|
+
delete states[id];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
function trigger(hookId, payload, done) {
|
|
146
|
+
let hookItem = hooks[hookId];
|
|
147
|
+
if (!hookItem) {
|
|
148
|
+
if (done) {
|
|
149
|
+
done();
|
|
150
|
+
return;
|
|
151
|
+
} else {
|
|
152
|
+
return Promise.resolve();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (!done) {
|
|
156
|
+
return new Promise((resolve,reject) => {
|
|
157
|
+
invokeStack(hookItem,payload,function(err) {
|
|
158
|
+
if (err !== undefined && err !== false) {
|
|
159
|
+
if (!(err instanceof Error)) {
|
|
160
|
+
err = new Error(err);
|
|
161
|
+
}
|
|
162
|
+
err.hook = hookId
|
|
163
|
+
reject(err);
|
|
164
|
+
} else {
|
|
165
|
+
resolve(err);
|
|
166
|
+
}
|
|
167
|
+
})
|
|
168
|
+
});
|
|
169
|
+
} else {
|
|
170
|
+
invokeStack(hookItem,payload,done)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function invokeStack(hookItem,payload,done) {
|
|
174
|
+
function callNextHook(err) {
|
|
175
|
+
if (!hookItem || err) {
|
|
176
|
+
done(err);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (hookItem.removed) {
|
|
180
|
+
hookItem = hookItem.nextHook;
|
|
181
|
+
callNextHook();
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const callback = hookItem.cb;
|
|
185
|
+
if (callback.length === 1) {
|
|
186
|
+
try {
|
|
187
|
+
let result = callback(payload);
|
|
188
|
+
if (result === false) {
|
|
189
|
+
// Halting the flow
|
|
190
|
+
done(false);
|
|
191
|
+
return
|
|
192
|
+
}
|
|
193
|
+
if (result && typeof result.then === 'function') {
|
|
194
|
+
result.then(handleResolve, callNextHook)
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
hookItem = hookItem.nextHook;
|
|
198
|
+
callNextHook();
|
|
199
|
+
} catch(err) {
|
|
200
|
+
done(err);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
} else {
|
|
204
|
+
try {
|
|
205
|
+
callback(payload,handleResolve)
|
|
206
|
+
} catch(err) {
|
|
207
|
+
done(err);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function handleResolve(result) {
|
|
213
|
+
if (result === undefined) {
|
|
214
|
+
hookItem = hookItem.nextHook;
|
|
215
|
+
callNextHook();
|
|
216
|
+
} else {
|
|
217
|
+
done(result);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
callNextHook();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function clear() {
|
|
224
|
+
hooks = {}
|
|
225
|
+
labelledHooks = {}
|
|
226
|
+
states = {}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function has(hookId) {
|
|
230
|
+
let [id, label] = hookId.split(".");
|
|
231
|
+
if (label) {
|
|
232
|
+
return !!(labelledHooks[label] && labelledHooks[label][id])
|
|
233
|
+
}
|
|
234
|
+
return !!states[id]
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
module.exports = {
|
|
238
|
+
has,
|
|
239
|
+
clear,
|
|
240
|
+
add,
|
|
241
|
+
remove,
|
|
242
|
+
trigger
|
|
243
|
+
}
|