@mtkruto/node 0.70.1 → 0.71.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 +3 -4
- package/esm/0_deps.d.ts +2 -2
- package/esm/0_deps.d.ts.map +1 -1
- package/esm/0_deps.js +2 -2
- package/esm/client/0_html.d.ts +2 -1
- package/esm/client/0_html.d.ts.map +1 -1
- package/esm/client/0_html.js +420 -70
- package/esm/client/0_html_test.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.14/instance_of.d.ts +23 -0
- package/esm/deps/jsr.io/@std/assert/1.0.14/instance_of.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.14/instance_of.js +52 -0
- package/{script/deps/jsr.io/@std/streams/1.0.11 → esm/deps/jsr.io/@std/streams/1.0.12}/to_array_buffer.d.ts.map +1 -1
- package/package.json +1 -2
- package/script/0_deps.d.ts +2 -2
- package/script/0_deps.d.ts.map +1 -1
- package/script/0_deps.js +4 -4
- package/script/client/0_html.d.ts +2 -1
- package/script/client/0_html.d.ts.map +1 -1
- package/script/client/0_html.js +421 -70
- package/script/client/0_html_test.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.14/instance_of.d.ts +23 -0
- package/script/deps/jsr.io/@std/assert/1.0.14/instance_of.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.14/instance_of.js +55 -0
- package/{esm/deps/jsr.io/@std/streams/1.0.11 → script/deps/jsr.io/@std/streams/1.0.12}/to_array_buffer.d.ts.map +1 -1
- /package/esm/deps/jsr.io/@std/streams/{1.0.11 → 1.0.12}/to_array_buffer.d.ts +0 -0
- /package/esm/deps/jsr.io/@std/streams/{1.0.11 → 1.0.12}/to_array_buffer.js +0 -0
- /package/script/deps/jsr.io/@std/streams/{1.0.11 → 1.0.12}/to_array_buffer.d.ts +0 -0
- /package/script/deps/jsr.io/@std/streams/{1.0.11 → 1.0.12}/to_array_buffer.js +0 -0
package/README.md
CHANGED
|
@@ -10,12 +10,11 @@ Cross-runtime JavaScript library for building Telegram clients
|
|
|
10
10
|
|
|
11
11
|
### Key Features
|
|
12
12
|
|
|
13
|
-
- **Easy-to-use.** Provides high-level [methods](https://mtkruto.deno.dev/methods) and [types](https://mtkruto.deno.dev/types) for convenience.
|
|
14
13
|
- **Cross-runtime.** Supports Node.js, Deno, browsers, and Bun.
|
|
15
14
|
- **Type-safe.** Written in TypeScript with accurate typings.
|
|
16
|
-
- **
|
|
17
|
-
- **
|
|
18
|
-
- **Extensible.**
|
|
15
|
+
- **Prioritizes the Web.** Prefers Web APIs over runtime-specific APIs.
|
|
16
|
+
- **Easy-to-use.** Provides its own high-level API on top of the Telegram API.
|
|
17
|
+
- **Extensible.** Its middleware system lets you integrate external code.
|
|
19
18
|
|
|
20
19
|
> Note: MTKruto has not reached version 1.0.0 yet. While it can run in production, we currently do not recommend depending on it for critical projects.
|
|
21
20
|
|
package/esm/0_deps.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ export { assert } from "./deps/jsr.io/@std/assert/1.0.14/assert.js";
|
|
|
21
21
|
export { assertFalse } from "./deps/jsr.io/@std/assert/1.0.14/false.js";
|
|
22
22
|
export { assertEquals } from "./deps/jsr.io/@std/assert/1.0.14/equals.js";
|
|
23
23
|
export { unreachable } from "./deps/jsr.io/@std/assert/1.0.14/unreachable.js";
|
|
24
|
+
export { assertInstanceOf } from "./deps/jsr.io/@std/assert/1.0.14/instance_of.js";
|
|
24
25
|
export { AssertionError } from "./deps/jsr.io/@std/assert/1.0.14/assertion_error.js";
|
|
25
26
|
export { join } from "./deps/jsr.io/@std/path/1.1.2/join.js";
|
|
26
27
|
export { extname } from "./deps/jsr.io/@std/path/1.1.2/extname.js";
|
|
@@ -33,12 +34,11 @@ export { LruCache } from "./deps/jsr.io/@std/cache/0.2.0/lru_cache.js";
|
|
|
33
34
|
export { iterateReader } from "./deps/jsr.io/@std/io/0.225.2/iterate_reader.js";
|
|
34
35
|
export { format } from "./deps/jsr.io/@std/datetime/0.225.5/format.js";
|
|
35
36
|
export { MINUTE, SECOND } from "./deps/jsr.io/@std/datetime/0.225.5/constants.js";
|
|
36
|
-
export { toArrayBuffer } from "./deps/jsr.io/@std/streams/1.0.
|
|
37
|
+
export { toArrayBuffer } from "./deps/jsr.io/@std/streams/1.0.12/to_array_buffer.js";
|
|
37
38
|
export { decodeBase64, encodeBase64 } from "./deps/jsr.io/@std/encoding/1.0.7/base64.js";
|
|
38
39
|
export { encodeHex } from "./deps/jsr.io/@std/encoding/1.0.7/hex.js";
|
|
39
40
|
import { contentType as contentType_ } from "./deps/jsr.io/@std/media-types/1.1.0/content_type.js";
|
|
40
41
|
export declare const contentType: typeof contentType_;
|
|
41
42
|
export declare function extension(mimeType: string): string;
|
|
42
43
|
export { ige256Decrypt, ige256Encrypt, init as initTgCrypto } from "./deps/jsr.io/@roj/tgcrypto/1.0.1/dist/mod.js";
|
|
43
|
-
export { Parser } from "htmlparser2";
|
|
44
44
|
//# sourceMappingURL=0_deps.d.ts.map
|
package/esm/0_deps.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"0_deps.d.ts","sourceRoot":"","sources":["../src/0_deps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,4CAA4C,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,iDAAiD,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAE,MAAM,qDAAqD,CAAC;AAErF,OAAO,EAAE,IAAI,EAAE,MAAM,uCAAuC,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,0CAA0C,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,2CAA2C,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,8CAA8C,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,8CAA8C,CAAC;AAE1E,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,wCAAwC,CAAC;AAE1E,OAAO,EAAE,MAAM,EAAE,MAAM,0CAA0C,CAAC;AAElE,OAAO,EAAE,QAAQ,EAAE,MAAM,6CAA6C,CAAC;AAEvE,OAAO,EAAE,aAAa,EAAE,MAAM,iDAAiD,CAAC;AAEhF,OAAO,EAAE,MAAM,EAAE,MAAM,+CAA+C,CAAC;AAEvE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kDAAkD,CAAC;AAElF,OAAO,EAAE,aAAa,EAAE,MAAM,sDAAsD,CAAC;AAErF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,6CAA6C,CAAC;AAEzF,OAAO,EAAE,SAAS,EAAE,MAAM,0CAA0C,CAAC;AAErE,OAAO,EAAE,WAAW,IAAI,YAAY,EAAE,MAAM,sDAAsD,CAAC;AACnG,eAAO,MAAM,WAAW,EAAE,OAAO,YAMhC,CAAC;AAEF,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,UAMzC;AAED,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,IAAI,IAAI,YAAY,EAAE,MAAM,+CAA+C,CAAC
|
|
1
|
+
{"version":3,"file":"0_deps.d.ts","sourceRoot":"","sources":["../src/0_deps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,4CAA4C,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,iDAAiD,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,iDAAiD,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,MAAM,qDAAqD,CAAC;AAErF,OAAO,EAAE,IAAI,EAAE,MAAM,uCAAuC,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,0CAA0C,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,2CAA2C,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,8CAA8C,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,8CAA8C,CAAC;AAE1E,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,wCAAwC,CAAC;AAE1E,OAAO,EAAE,MAAM,EAAE,MAAM,0CAA0C,CAAC;AAElE,OAAO,EAAE,QAAQ,EAAE,MAAM,6CAA6C,CAAC;AAEvE,OAAO,EAAE,aAAa,EAAE,MAAM,iDAAiD,CAAC;AAEhF,OAAO,EAAE,MAAM,EAAE,MAAM,+CAA+C,CAAC;AAEvE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kDAAkD,CAAC;AAElF,OAAO,EAAE,aAAa,EAAE,MAAM,sDAAsD,CAAC;AAErF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,6CAA6C,CAAC;AAEzF,OAAO,EAAE,SAAS,EAAE,MAAM,0CAA0C,CAAC;AAErE,OAAO,EAAE,WAAW,IAAI,YAAY,EAAE,MAAM,sDAAsD,CAAC;AACnG,eAAO,MAAM,WAAW,EAAE,OAAO,YAMhC,CAAC;AAEF,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,UAMzC;AAED,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,IAAI,IAAI,YAAY,EAAE,MAAM,+CAA+C,CAAC"}
|
package/esm/0_deps.js
CHANGED
|
@@ -21,6 +21,7 @@ export { assert } from "./deps/jsr.io/@std/assert/1.0.14/assert.js";
|
|
|
21
21
|
export { assertFalse } from "./deps/jsr.io/@std/assert/1.0.14/false.js";
|
|
22
22
|
export { assertEquals } from "./deps/jsr.io/@std/assert/1.0.14/equals.js";
|
|
23
23
|
export { unreachable } from "./deps/jsr.io/@std/assert/1.0.14/unreachable.js";
|
|
24
|
+
export { assertInstanceOf } from "./deps/jsr.io/@std/assert/1.0.14/instance_of.js";
|
|
24
25
|
export { AssertionError } from "./deps/jsr.io/@std/assert/1.0.14/assertion_error.js";
|
|
25
26
|
export { join } from "./deps/jsr.io/@std/path/1.1.2/join.js";
|
|
26
27
|
export { extname } from "./deps/jsr.io/@std/path/1.1.2/extname.js";
|
|
@@ -33,7 +34,7 @@ export { LruCache } from "./deps/jsr.io/@std/cache/0.2.0/lru_cache.js";
|
|
|
33
34
|
export { iterateReader } from "./deps/jsr.io/@std/io/0.225.2/iterate_reader.js";
|
|
34
35
|
export { format } from "./deps/jsr.io/@std/datetime/0.225.5/format.js";
|
|
35
36
|
export { MINUTE, SECOND } from "./deps/jsr.io/@std/datetime/0.225.5/constants.js";
|
|
36
|
-
export { toArrayBuffer } from "./deps/jsr.io/@std/streams/1.0.
|
|
37
|
+
export { toArrayBuffer } from "./deps/jsr.io/@std/streams/1.0.12/to_array_buffer.js";
|
|
37
38
|
export { decodeBase64, encodeBase64 } from "./deps/jsr.io/@std/encoding/1.0.7/base64.js";
|
|
38
39
|
export { encodeHex } from "./deps/jsr.io/@std/encoding/1.0.7/hex.js";
|
|
39
40
|
import { contentType as contentType_ } from "./deps/jsr.io/@std/media-types/1.1.0/content_type.js";
|
|
@@ -55,4 +56,3 @@ export function extension(mimeType) {
|
|
|
55
56
|
}
|
|
56
57
|
}
|
|
57
58
|
export { ige256Decrypt, ige256Encrypt, init as initTgCrypto } from "./deps/jsr.io/@roj/tgcrypto/1.0.1/dist/mod.js";
|
|
58
|
-
export { Parser } from "htmlparser2";
|
package/esm/client/0_html.d.ts
CHANGED
|
@@ -18,5 +18,6 @@
|
|
|
18
18
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
19
19
|
*/
|
|
20
20
|
import type { MessageEntity } from "../3_types.js";
|
|
21
|
-
export declare function parseHtml(
|
|
21
|
+
export declare function parseHtml(html_: string): [string, MessageEntity[]];
|
|
22
|
+
export declare function parseAttributes(attributes: string[]): Record<string, string>;
|
|
22
23
|
//# sourceMappingURL=0_html.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"0_html.d.ts","sourceRoot":"","sources":["../../src/client/0_html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;
|
|
1
|
+
{"version":3,"file":"0_html.d.ts","sourceRoot":"","sources":["../../src/client/0_html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,aAAa,EAA2B,MAAM,eAAe,CAAC;AAuC5E,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CA6NlE;AACD,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAyD5E"}
|
package/esm/client/0_html.js
CHANGED
|
@@ -17,86 +17,436 @@
|
|
|
17
17
|
* You should have received a copy of the GNU Lesser General Public License
|
|
18
18
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
19
19
|
*/
|
|
20
|
-
import { Parser } from "../0_deps.js";
|
|
21
20
|
import { InputError } from "../0_errors.js";
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
const TAG_NAMES = [
|
|
22
|
+
"a",
|
|
23
|
+
"b",
|
|
24
|
+
"strong",
|
|
25
|
+
"i",
|
|
26
|
+
"em",
|
|
27
|
+
"s",
|
|
28
|
+
"strike",
|
|
29
|
+
"del",
|
|
30
|
+
"u",
|
|
31
|
+
"ins",
|
|
32
|
+
"tg-spoiler",
|
|
33
|
+
"tg-emoji",
|
|
34
|
+
"span",
|
|
35
|
+
"pre",
|
|
36
|
+
"code",
|
|
37
|
+
"blockquote",
|
|
38
|
+
];
|
|
39
|
+
const ENTITY_TYPES = [
|
|
40
|
+
"textLink",
|
|
41
|
+
"bold",
|
|
42
|
+
"bold",
|
|
43
|
+
"italic",
|
|
44
|
+
"italic",
|
|
45
|
+
"strikethrough",
|
|
46
|
+
"strikethrough",
|
|
47
|
+
"strikethrough",
|
|
48
|
+
"underline",
|
|
49
|
+
"underline",
|
|
50
|
+
"spoiler",
|
|
51
|
+
"customEmoji",
|
|
52
|
+
"spoiler",
|
|
53
|
+
"code",
|
|
54
|
+
"code",
|
|
55
|
+
"blockquote",
|
|
56
|
+
];
|
|
57
|
+
export function parseHtml(html_) {
|
|
58
|
+
html_ = html_.trim();
|
|
24
59
|
let text = "";
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
60
|
+
let entities = new Array();
|
|
61
|
+
const entityTags = new Array();
|
|
62
|
+
const tagStack = new Array();
|
|
63
|
+
const html = Array.from(html_);
|
|
64
|
+
for (let i = 0; i < html.length; ++i) {
|
|
65
|
+
const c = html[i];
|
|
66
|
+
if (c === "&") {
|
|
67
|
+
const result = decodeEntity(html, i);
|
|
68
|
+
[text, i] = [text + result[0], i + result[1]];
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
else if (c !== "<") {
|
|
72
|
+
text += c;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
++i;
|
|
76
|
+
let closing = false;
|
|
77
|
+
let end = i;
|
|
78
|
+
if (html[end] && html[end] === "/") {
|
|
79
|
+
closing = true;
|
|
80
|
+
++i;
|
|
81
|
+
++end;
|
|
82
|
+
}
|
|
83
|
+
while (html[end] && html[end] !== ">") {
|
|
84
|
+
++end;
|
|
85
|
+
}
|
|
86
|
+
const tagName_ = html.slice(i, end);
|
|
87
|
+
let tagName = tagName_.join("");
|
|
88
|
+
let attributes;
|
|
89
|
+
if (closing) {
|
|
90
|
+
tagName = tagName.trim().toLowerCase();
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const index = tagName_.indexOf(" ");
|
|
94
|
+
if (index !== -1) {
|
|
95
|
+
attributes = parseAttributes(tagName_.slice(index));
|
|
96
|
+
tagName = tagName.slice(0, index).toLowerCase();
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
tagName = tagName.toLowerCase();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (closing && !tagName.length && tagStack.length) {
|
|
103
|
+
tagName = tagStack[tagStack.length - 1].tagName;
|
|
104
|
+
}
|
|
105
|
+
if (!tagName.length) {
|
|
106
|
+
throw new InputError(`Invalid tag at offset ${i}.`);
|
|
107
|
+
}
|
|
108
|
+
else if (!TAG_NAMES.includes(tagName)) {
|
|
109
|
+
throw new InputError(`Unsupported HTML tag at offset ${i}: ${tagName}`);
|
|
110
|
+
}
|
|
111
|
+
else if (closing) {
|
|
112
|
+
const openTag = tagStack.pop();
|
|
113
|
+
if (openTag?.tagName !== tagName) {
|
|
114
|
+
throw new InputError(`Unexpected closing tag at offset ${i}.`);
|
|
115
|
+
}
|
|
116
|
+
const offset = openTag.openedAt;
|
|
117
|
+
const length = text.length - openTag.openedAt;
|
|
118
|
+
if (tagName === "a") {
|
|
119
|
+
let url = openTag.url;
|
|
120
|
+
if (!url) {
|
|
121
|
+
const text_ = text.slice(offset, offset + length);
|
|
122
|
+
try {
|
|
123
|
+
url = new URL(text_).href;
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
if (!Array.from(text).some(isSpace)) {
|
|
127
|
+
try {
|
|
128
|
+
url = new URL(`http://${text_}`).href;
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
//
|
|
132
|
+
}
|
|
133
|
+
}
|
|
50
134
|
}
|
|
51
|
-
stack.push({ type: "textLink", offset: text.length, length: 0, url });
|
|
52
|
-
break;
|
|
53
135
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
136
|
+
if (url) {
|
|
137
|
+
entities.push({
|
|
138
|
+
type: "textLink",
|
|
139
|
+
offset,
|
|
140
|
+
length,
|
|
141
|
+
url,
|
|
142
|
+
});
|
|
143
|
+
entityTags.push(openTag);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else if (tagName === "pre") {
|
|
147
|
+
const lastEntity = entities[entities.length - 1];
|
|
148
|
+
const entityTag = entityTags[entityTags.length - 1];
|
|
149
|
+
if (lastEntity && lastEntity.type === "code" && lastEntity.offset === offset && lastEntity.length === length && entityTag.language) {
|
|
150
|
+
entities[entities.length - 1] = {
|
|
151
|
+
type: "pre",
|
|
152
|
+
offset: lastEntity.offset,
|
|
153
|
+
length: lastEntity.length,
|
|
154
|
+
language: entityTag.language,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
entities.push({
|
|
159
|
+
type: "pre",
|
|
160
|
+
offset,
|
|
161
|
+
length,
|
|
162
|
+
language: "",
|
|
163
|
+
});
|
|
164
|
+
entityTags.push(openTag);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
else if (tagName === "code") {
|
|
168
|
+
const lastEntity = entities[entities.length - 1];
|
|
169
|
+
if (lastEntity && lastEntity.type === "pre" && lastEntity.offset === offset && lastEntity.length === length && openTag.language) {
|
|
170
|
+
lastEntity.language = openTag.language;
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
entities.push({
|
|
174
|
+
type: "code",
|
|
175
|
+
offset,
|
|
176
|
+
length,
|
|
177
|
+
});
|
|
178
|
+
entityTags.push(openTag);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else if (openTag.userId !== undefined) {
|
|
182
|
+
entities.push({
|
|
183
|
+
type: "textMention",
|
|
184
|
+
offset,
|
|
185
|
+
length,
|
|
186
|
+
userId: openTag.userId,
|
|
187
|
+
});
|
|
188
|
+
entityTags.push(openTag);
|
|
189
|
+
}
|
|
190
|
+
else if (tagName === "blockquote") {
|
|
191
|
+
const entity = {
|
|
192
|
+
type: "blockquote",
|
|
193
|
+
offset,
|
|
194
|
+
length,
|
|
195
|
+
};
|
|
196
|
+
if (openTag.collapsible) {
|
|
197
|
+
entity.collapsible = true;
|
|
198
|
+
}
|
|
199
|
+
entities.push(entity);
|
|
200
|
+
entityTags.push(openTag);
|
|
201
|
+
if (openTag.collapsible) {
|
|
202
|
+
entities[entities.length - 1].collapsible = true;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
else if (openTag.customEmojiId !== undefined) {
|
|
206
|
+
entities.push({
|
|
207
|
+
type: "customEmoji",
|
|
208
|
+
offset,
|
|
209
|
+
length,
|
|
210
|
+
customEmojiId: openTag.customEmojiId,
|
|
211
|
+
});
|
|
212
|
+
entityTags.push(openTag);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
entities.push({
|
|
216
|
+
type: ENTITY_TYPES[TAG_NAMES.indexOf(openTag.tagName)],
|
|
217
|
+
offset,
|
|
218
|
+
length,
|
|
219
|
+
});
|
|
220
|
+
entityTags.push(openTag);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
else if (tagName === "span" && attributes?.class !== "tg-spoiler") {
|
|
224
|
+
throw new InputError(`Invalid or missing attribute class for tag span at offset ${i}.`);
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
let url;
|
|
228
|
+
let language;
|
|
229
|
+
let userId;
|
|
230
|
+
let collapsible;
|
|
231
|
+
let customEmojiId;
|
|
232
|
+
if (tagName === "a") {
|
|
233
|
+
url = attributes?.href;
|
|
234
|
+
if (url) {
|
|
235
|
+
let url_;
|
|
236
|
+
try {
|
|
237
|
+
url_ = new URL(url);
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
try {
|
|
241
|
+
url_ = new URL(`http://${url}`);
|
|
242
|
+
url = url_.href;
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
throw new InputError(`Invalid URL specified for tag a at offset ${i}.`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (url_.protocol !== "tg:" && url_.protocol !== "ton:" && url_.protocol !== "http:" && url_.protocol !== "https:") {
|
|
249
|
+
throw new InputError(`Unsupported URL protocol at offset ${i}: ${url_.protocol}`);
|
|
250
|
+
}
|
|
251
|
+
if (url_.protocol === "tg:" && url_.hostname === "user") {
|
|
252
|
+
const id = Number(url_.searchParams.get("id"));
|
|
253
|
+
if (!isNaN(id) && id > 0) {
|
|
254
|
+
userId = id;
|
|
255
|
+
url = undefined;
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
throw new InputError(`Invalid ID specified for mention at offset ${i}.`);
|
|
259
|
+
}
|
|
65
260
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
else if (tagName === "code") {
|
|
264
|
+
language = attributes?.class?.replace("language-", "");
|
|
265
|
+
}
|
|
266
|
+
else if (tagName === "blockquote" && attributes?.expandable !== undefined) {
|
|
267
|
+
collapsible = true;
|
|
268
|
+
}
|
|
269
|
+
else if (tagName === "tg-emoji") {
|
|
270
|
+
customEmojiId = attributes?.["emoji-id"];
|
|
271
|
+
let valid;
|
|
272
|
+
try {
|
|
273
|
+
valid = BigInt(customEmojiId ?? "") !== 0n;
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
valid = false;
|
|
277
|
+
}
|
|
278
|
+
if (!valid) {
|
|
279
|
+
throw new InputError(`Invalid emoji-id specified for tag tg-emoji at offset ${i}.`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
tagStack.push({ tagName, openedAt: text.length, url, language, userId, collapsible, customEmojiId });
|
|
283
|
+
}
|
|
284
|
+
i += end - i;
|
|
285
|
+
}
|
|
286
|
+
entities = entities.filter((v) => v.length);
|
|
287
|
+
entities = sortEntities(entities);
|
|
288
|
+
return [text, entities];
|
|
289
|
+
}
|
|
290
|
+
export function parseAttributes(attributes) {
|
|
291
|
+
const parsed = {};
|
|
292
|
+
for (let i = 0; i < attributes.length; ++i) {
|
|
293
|
+
const c = attributes[i];
|
|
294
|
+
if (isSpace(c)) {
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
let end = i;
|
|
298
|
+
while (attributes[end] && !isSpace(attributes[end]) && attributes[end] !== "=") {
|
|
299
|
+
++end;
|
|
300
|
+
}
|
|
301
|
+
const name = attributes.slice(i, end);
|
|
302
|
+
while (attributes[end] && isSpace(attributes[end])) {
|
|
303
|
+
++end;
|
|
304
|
+
}
|
|
305
|
+
let value = new Array();
|
|
306
|
+
if (attributes[end] === "=") {
|
|
307
|
+
++end;
|
|
308
|
+
while (attributes[end] && isSpace(attributes[end])) {
|
|
309
|
+
++end;
|
|
310
|
+
}
|
|
311
|
+
if (attributes[end]) {
|
|
312
|
+
const isQuote = attributes[end] === '"' || attributes[end] === "'";
|
|
313
|
+
if (!isQuote) {
|
|
314
|
+
const valueStart = end;
|
|
315
|
+
++end;
|
|
316
|
+
while (attributes[end] && !isSpace(attributes[end])) {
|
|
317
|
+
++end;
|
|
73
318
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
319
|
+
value = attributes.slice(valueStart, end);
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
const quote = attributes[end];
|
|
323
|
+
++end;
|
|
324
|
+
const valueStart = end;
|
|
325
|
+
while (attributes[end] && attributes[end] !== quote) {
|
|
326
|
+
++end;
|
|
80
327
|
}
|
|
328
|
+
value = attributes.slice(valueStart, end);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
let value_ = "";
|
|
333
|
+
for (let i = 0; i < value.length; ++i) {
|
|
334
|
+
const c = value[i];
|
|
335
|
+
if (c === "&") {
|
|
336
|
+
const result = decodeEntity(value, i);
|
|
337
|
+
[value_, i] = [value_ + result[0], i + result[1]];
|
|
81
338
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (!text.length) {
|
|
85
|
-
data = data.trimStart();
|
|
339
|
+
else {
|
|
340
|
+
value_ += c;
|
|
86
341
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
342
|
+
}
|
|
343
|
+
parsed[name.join("")] = value_;
|
|
344
|
+
i += end - i;
|
|
345
|
+
}
|
|
346
|
+
return parsed;
|
|
347
|
+
}
|
|
348
|
+
function decodeEntity(html, i) {
|
|
349
|
+
let text = "";
|
|
350
|
+
let end = i + 1;
|
|
351
|
+
let fallback = false;
|
|
352
|
+
if (html[end] === "#") {
|
|
353
|
+
++end;
|
|
354
|
+
let code;
|
|
355
|
+
if (html[end] === "x") {
|
|
356
|
+
++end;
|
|
357
|
+
while (isHex(html[end])) {
|
|
358
|
+
++end;
|
|
90
359
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
360
|
+
const hex = html.slice(i + 3, end).join("");
|
|
361
|
+
code = parseInt(hex, 16);
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
while (isDigit(html[end])) {
|
|
365
|
+
++end;
|
|
96
366
|
}
|
|
97
|
-
|
|
367
|
+
const code_ = html.slice(i + 2, end).join("");
|
|
368
|
+
code = parseInt(code_);
|
|
369
|
+
}
|
|
370
|
+
if (!isNaN(code) && code !== 0 && code < 0x10ffff && end - i < 10) {
|
|
371
|
+
text = String.fromCharCode(code);
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
fallback = true;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
while (isAlpha(html[end])) {
|
|
379
|
+
++end;
|
|
380
|
+
}
|
|
381
|
+
const name = html.slice(i + 1, end).join("");
|
|
382
|
+
switch (name) {
|
|
383
|
+
case "amp":
|
|
384
|
+
text = "&";
|
|
385
|
+
break;
|
|
386
|
+
case "quot":
|
|
387
|
+
text = '"';
|
|
388
|
+
break;
|
|
389
|
+
case "lt":
|
|
390
|
+
text = "<";
|
|
391
|
+
break;
|
|
392
|
+
case "gt":
|
|
393
|
+
text = ">";
|
|
394
|
+
break;
|
|
395
|
+
default:
|
|
396
|
+
fallback = true;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (html[end] === ";") {
|
|
400
|
+
++end;
|
|
401
|
+
}
|
|
402
|
+
if (fallback) {
|
|
403
|
+
text = html.slice(i, end).join("");
|
|
404
|
+
}
|
|
405
|
+
return [text, end - i - 1];
|
|
406
|
+
}
|
|
407
|
+
function isAlpha(string) {
|
|
408
|
+
return "a" <= string && string <= "z";
|
|
409
|
+
}
|
|
410
|
+
function isDigit(string) {
|
|
411
|
+
return "0" <= string && string <= "9";
|
|
412
|
+
}
|
|
413
|
+
function isHex(string) {
|
|
414
|
+
return isDigit(string) || ("a" <= string && string <= "f");
|
|
415
|
+
}
|
|
416
|
+
function isSpace(string) {
|
|
417
|
+
return string === " " || string === "\t" || string === "\r" || string === "\n" || string === "\0" || string === "\v";
|
|
418
|
+
}
|
|
419
|
+
function sortEntities(entities) {
|
|
420
|
+
return entities.sort(({ offset, type, length }, other) => {
|
|
421
|
+
if (offset !== other.offset) {
|
|
422
|
+
return offset < other.offset ? -1 : 1;
|
|
423
|
+
}
|
|
424
|
+
if (length !== other.length) {
|
|
425
|
+
return length > other.length ? -1 : 1;
|
|
426
|
+
}
|
|
427
|
+
const priority = ENTITY_TYPE_PRIORITIES[type];
|
|
428
|
+
const otherPriority = ENTITY_TYPE_PRIORITIES[other.type];
|
|
429
|
+
return priority < otherPriority ? -1 : 1;
|
|
98
430
|
});
|
|
99
|
-
parser.write(html);
|
|
100
|
-
parser.end();
|
|
101
|
-
return [text, entities];
|
|
102
431
|
}
|
|
432
|
+
const ENTITY_TYPE_PRIORITIES = {
|
|
433
|
+
"mention": 50,
|
|
434
|
+
"hashtag": 50,
|
|
435
|
+
"botCommand": 50,
|
|
436
|
+
"url": 50,
|
|
437
|
+
"email": 50,
|
|
438
|
+
"bold": 90,
|
|
439
|
+
"italic": 91,
|
|
440
|
+
"code": 20,
|
|
441
|
+
"pre": 11,
|
|
442
|
+
"textLink": 49,
|
|
443
|
+
"textMention": 49,
|
|
444
|
+
"cashtag": 50,
|
|
445
|
+
"phoneNumber": 50,
|
|
446
|
+
"underline": 92,
|
|
447
|
+
"strikethrough": 93,
|
|
448
|
+
"blockquote": 0,
|
|
449
|
+
"bankCard": 50,
|
|
450
|
+
"spoiler": 94,
|
|
451
|
+
"customEmoji": 99,
|
|
452
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"0_html_test.d.ts","sourceRoot":"","sources":["../../src/client/0_html_test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Any constructor */
|
|
2
|
+
export type AnyConstructor = new (...args: any[]) => any;
|
|
3
|
+
/** Gets constructor type */
|
|
4
|
+
export type GetConstructorType<T extends AnyConstructor> = InstanceType<T>;
|
|
5
|
+
/**
|
|
6
|
+
* Make an assertion that `obj` is an instance of `type`.
|
|
7
|
+
* If not then throw.
|
|
8
|
+
*
|
|
9
|
+
* @example Usage
|
|
10
|
+
* ```ts ignore
|
|
11
|
+
* import { assertInstanceOf } from "@std/assert";
|
|
12
|
+
*
|
|
13
|
+
* assertInstanceOf(new Date(), Date); // Doesn't throw
|
|
14
|
+
* assertInstanceOf(new Date(), Number); // Throws
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @typeParam T The expected type of the object.
|
|
18
|
+
* @param actual The object to check.
|
|
19
|
+
* @param expectedType The expected class constructor.
|
|
20
|
+
* @param msg The optional message to display if the assertion fails.
|
|
21
|
+
*/
|
|
22
|
+
export declare function assertInstanceOf<T extends abstract new (...args: any[]) => any>(actual: unknown, expectedType: T, msg?: string): asserts actual is InstanceType<T>;
|
|
23
|
+
//# sourceMappingURL=instance_of.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance_of.d.ts","sourceRoot":"","sources":["../../../../../../src/deps/jsr.io/@std/assert/1.0.14/instance_of.ts"],"names":[],"mappings":"AAIA,sBAAsB;AAEtB,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC;AACzD,4BAA4B;AAC5B,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,cAAc,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC;AAE3E;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAE9B,CAAC,SAAS,QAAQ,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAE9C,MAAM,EAAE,OAAO,EACf,YAAY,EAAE,CAAC,EACf,GAAG,SAAK,GACP,OAAO,CAAC,MAAM,IAAI,YAAY,CAAC,CAAC,CAAC,CA6BnC"}
|