diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 60be90db..fa208344 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -17,12 +17,12 @@ jobs:
strategy:
matrix:
- node-version: [16.x]
+ node-version: [18.x]
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v2
+ uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install -g codecov
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 5d365709..062fbddf 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -12,11 +12,11 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v4
- name: Setup Node
- uses: actions/setup-node@v2
+ uses: actions/setup-node@v4
with:
- node-version: '16.x'
+ node-version: '18.x'
registry-url: 'https://registry.npmjs.org'
- name: Build licia
run: npm i && npm link && npm run build
diff --git a/DOC.md b/DOC.md
index 96023acb..039035b0 100644
--- a/DOC.md
+++ b/DOC.md
@@ -751,6 +751,78 @@ c.remove('content-type');
c.has('content-type'); // -> false
```
+## Channel
+
+Interconnectable Message channel.
+
+
+Type Definition
+
+```typescript
+class Channel extends Emitter {
+ send(msg: any): void;
+ connect(channel: Channel): void;
+ disconnect(channel: Channel): void;
+ isConnected(channel: Channel): boolean;
+ destroy(): void;
+}
+```
+
+
+
+### send
+
+Send a message to all connected channels.
+
+|Name|Desc |
+|----|---------------|
+|msg |Message to send|
+
+### connect
+
+Connect to another channel.
+
+|Name |Desc |
+|-------|------------------|
+|channel|Channel to connect|
+
+### disconnect
+
+Disconnect from another channel.
+
+|Name |Desc |
+|-------|---------------------|
+|channel|Channel to disconnect|
+
+### isConnected
+
+Check if a channel is connected to another channel.
+
+|Name |Desc |
+|-------|----------------------|
+|channel|Channel to check |
+|return |Whether it's connected|
+
+### destroy
+
+Destroy the channel, disconnect from all connected channels.
+
+```javascript
+const channelA = new Channel();
+const channelB = new Channel();
+channelA.connect(channelB);
+channelB.on('message', msg => {
+ console.log(msg); // -> 'hello'
+});
+channelA.send('hello');
+channelA.on('message', msg => {
+ console.log(msg); // -> 'world'
+});
+channelB.send('world');
+channelA.isConnected(channelB); // -> true
+channelB.isConnected(channelA); // -> true
+```
+
## Class
Create JavaScript class.
diff --git a/DOC_CN.md b/DOC_CN.md
index 1ae77198..0dc47d64 100644
--- a/DOC_CN.md
+++ b/DOC_CN.md
@@ -745,6 +745,78 @@ c.remove('content-type');
c.has('content-type'); // -> false
```
+## Channel
+
+可以相互连接的消息通道。
+
+
+类型定义
+
+```typescript
+class Channel extends Emitter {
+ send(msg: any): void;
+ connect(channel: Channel): void;
+ disconnect(channel: Channel): void;
+ isConnected(channel: Channel): boolean;
+ destroy(): void;
+}
+```
+
+
+
+### send
+
+发送消息给所有连接的通道。
+
+|参数名|说明|
+|-----|---|
+|msg|要发送的消息|
+
+### connect
+
+连接到指定通道。
+
+|参数名|说明|
+|-----|---|
+|channel|要连接的通道|
+
+### disconnect
+
+断开与指定通道的连接。
+
+|参数名|说明|
+|-----|---|
+|channel|要断开的通道|
+
+### isConnected
+
+检查两个通道是否连接。
+
+|参数名|说明|
+|-----|---|
+|channel|目标通道|
+|返回值|是否连接|
+
+### destroy
+
+销毁通道,断开所有连接的通道。
+
+```javascript
+const channelA = new Channel();
+const channelB = new Channel();
+channelA.connect(channelB);
+channelB.on('message', msg => {
+ console.log(msg); // -> 'hello'
+});
+channelA.send('hello');
+channelA.on('message', msg => {
+ console.log(msg); // -> 'world'
+});
+channelB.send('world');
+channelA.isConnected(channelB); // -> true
+channelB.isConnected(channelA); // -> true
+```
+
## Class
创建 JavaScript 类。
diff --git a/cspell.json b/cspell.json
index 2f7cd763..805f8304 100644
--- a/cspell.json
+++ b/cspell.json
@@ -57,6 +57,7 @@
"castPath",
"centerAlign",
"cgroup",
+ "Channel",
"char",
"chunk",
"clamp",
diff --git a/i18n/Channel.md b/i18n/Channel.md
new file mode 100644
index 00000000..390fe504
--- /dev/null
+++ b/i18n/Channel.md
@@ -0,0 +1,40 @@
+## CN
+
+可以相互连接的消息通道。
+
+### send
+
+发送消息给所有连接的通道。
+
+|参数名|说明|
+|-----|---|
+|msg|要发送的消息|
+
+### connect
+
+连接到指定通道。
+
+|参数名|说明|
+|-----|---|
+|channel|要连接的通道|
+
+### disconnect
+
+断开与指定通道的连接。
+
+|参数名|说明|
+|-----|---|
+|channel|要断开的通道|
+
+### isConnected
+
+检查两个通道是否连接。
+
+|参数名|说明|
+|-----|---|
+|channel|目标通道|
+|返回值|是否连接|
+
+### destroy
+
+销毁通道,断开所有连接的通道。
diff --git a/index.json b/index.json
index 31bb0c15..1a112ecf 100644
--- a/index.json
+++ b/index.json
@@ -266,6 +266,24 @@
"browser"
]
},
+ "Channel": {
+ "dependencies": [
+ "Emitter",
+ "each",
+ "remove",
+ "some"
+ ],
+ "description": "Interconnectable Message channel.",
+ "env": [
+ "node",
+ "browser",
+ "miniprogram"
+ ],
+ "test": [
+ "node",
+ "browser"
+ ]
+ },
"Class": {
"demo": true,
"dependencies": [
diff --git a/src/Channel.js b/src/Channel.js
new file mode 100644
index 00000000..79ffdaef
--- /dev/null
+++ b/src/Channel.js
@@ -0,0 +1,114 @@
+/* Interconnectable Message channel.
+ *
+ * ### send
+ *
+ * Send a message to all connected channels.
+ *
+ * |Name|Desc |
+ * |----|---------------|
+ * |msg |Message to send|
+ *
+ * ### connect
+ *
+ * Connect to another channel.
+ *
+ * |Name |Desc |
+ * |-------|------------------|
+ * |channel|Channel to connect|
+ *
+ * ### disconnect
+ *
+ * Disconnect from another channel.
+ *
+ * |Name |Desc |
+ * |-------|---------------------|
+ * |channel|Channel to disconnect|
+ *
+ * ### isConnected
+ *
+ * Check if a channel is connected to another channel.
+ *
+ * |Name |Desc |
+ * |-------|----------------------|
+ * |channel|Channel to check |
+ * |return |Whether it's connected|
+ *
+ * ### destroy
+ *
+ * Destroy the channel, disconnect from all connected channels.
+ */
+
+/* example
+ * const channelA = new Channel();
+ * const channelB = new Channel();
+ * channelA.connect(channelB);
+ * channelB.on('message', msg => {
+ * console.log(msg); // -> 'hello'
+ * });
+ * channelA.send('hello');
+ * channelA.on('message', msg => {
+ * console.log(msg); // -> 'world'
+ * });
+ * channelB.send('world');
+ * channelA.isConnected(channelB); // -> true
+ * channelB.isConnected(channelA); // -> true
+ */
+
+/* module
+ * env: all
+ */
+
+/* typescript
+ * export declare class Channel extends Emitter {
+ * send(msg: any): void;
+ * connect(channel: Channel): void;
+ * disconnect(channel: Channel): void;
+ * isConnected(channel: Channel): boolean;
+ * destroy(): void;
+ * }
+ */
+
+_('Emitter each remove some');
+
+exports = Emitter.extend({
+ initialize: function Channel() {
+ this._connections = [];
+
+ this.callSuper(Emitter, 'initialize');
+ },
+ send(msg) {
+ each(this._connections, connection => {
+ connection.emit('message', msg, this);
+ });
+ },
+ connect(connection) {
+ if (this.isConnected(connection)) {
+ return;
+ }
+
+ this._connections.push(connection);
+
+ connection.connect(this);
+ },
+ disconnect(connection) {
+ if (!this.isConnected(connection)) {
+ return;
+ }
+
+ remove(this._connections, item => item === connection);
+
+ connection.disconnect(this);
+ },
+ isConnected(connection) {
+ if (connection === this) {
+ throw new Error('Connection cannot be connected to itself.');
+ }
+
+ return some(this._connections, item => item === connection);
+ },
+ destroy() {
+ each(this._connections, connection => {
+ this.disconnect(connection);
+ });
+ }
+});
diff --git a/test/Channel.js b/test/Channel.js
new file mode 100644
index 00000000..b76f44c3
--- /dev/null
+++ b/test/Channel.js
@@ -0,0 +1,27 @@
+const a = new Channel();
+const b = new Channel();
+
+a.connect(b);
+b.on('message', msg => {
+ expect(msg).to.equal('hello');
+});
+a.send('hello');
+a.on('message', msg => {
+ expect(msg).to.equal('world');
+});
+b.send('world');
+
+expect(a.isConnected(b)).to.be.true;
+expect(b.isConnected(a)).to.be.true;
+
+a.disconnect(b);
+
+expect(a.isConnected(b)).to.be.false;
+expect(b.isConnected(a)).to.be.false;
+
+b.connect(a);
+expect(a.isConnected(b)).to.be.true;
+expect(b.isConnected(a)).to.be.true;
+
+a.destroy();
+expect(b.isConnected(a)).to.be.false;