@grom.js/tgx 0.5.3 → 1.1.0
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 +26 -11
- package/dist/Line.d.ts +20 -0
- package/dist/Line.js +23 -0
- package/dist/Line.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -0
- package/dist/jsx-runtime.d.ts +4 -4
- package/dist/jsx-runtime.js +3 -2
- package/dist/jsx-runtime.js.map +1 -0
- package/dist/jsx.d.ts +5 -4
- package/dist/jsx.js +19 -17
- package/dist/jsx.js.map +1 -0
- package/dist/render.d.ts +6 -0
- package/dist/render.js +47 -0
- package/dist/render.js.map +1 -0
- package/dist/types.d.ts +10 -13
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/package.json +11 -13
- package/src/Line.ts +24 -0
- package/src/index.ts +4 -0
- package/src/jsx-runtime.ts +27 -0
- package/src/jsx.ts +148 -0
- package/src/render.ts +59 -0
- package/src/types.ts +520 -0
- package/dist/_utils/types.d.ts +0 -6
- package/dist/_utils/types.js +0 -1
- package/dist/html.d.ts +0 -6
- package/dist/html.js +0 -46
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|

|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/@grom.js/tgx)
|
|
4
|
+
[](https://jsr.io/@grom/tgx)
|
|
5
5
|
|
|
6
6
|
[JSX](https://facebook.github.io/jsx/) runtime for composing Telegram messages.
|
|
7
7
|
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
# Using npm
|
|
12
12
|
npm install @grom.js/tgx
|
|
13
13
|
|
|
14
|
-
# Using
|
|
14
|
+
# Using JSR
|
|
15
15
|
deno add jsr:@grom/tgx
|
|
16
16
|
```
|
|
17
17
|
|
|
@@ -21,29 +21,29 @@ Then in your `tsconfig.json`:
|
|
|
21
21
|
{
|
|
22
22
|
"compilerOptions": {
|
|
23
23
|
"jsx": "react-jsx",
|
|
24
|
-
"jsxImportSource": "@grom.js/tgx" // "@grom/tgx" for
|
|
24
|
+
"jsxImportSource": "@grom.js/tgx" // "@grom/tgx" for JSR
|
|
25
25
|
// ...
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
##
|
|
30
|
+
## Examples
|
|
31
31
|
|
|
32
32
|
Usage with [grammY](https://grammy.dev):
|
|
33
33
|
|
|
34
|
-
```
|
|
35
|
-
import { html } from '@grom.js/tgx'
|
|
34
|
+
```jsx
|
|
36
35
|
import { Bot } from 'grammy'
|
|
36
|
+
import { renderHtml } from '@grom.js/tgx'
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
const Greeting = (props) => (
|
|
39
|
+
<>Hello, <b>{props.name}</b>!</>
|
|
40
|
+
)
|
|
41
41
|
|
|
42
42
|
const bot = new Bot(/* TOKEN */)
|
|
43
43
|
|
|
44
44
|
bot.command('start', async (ctx) => {
|
|
45
45
|
await ctx.reply(
|
|
46
|
-
|
|
46
|
+
renderHtml(<Greeting name={ctx.from.first_name} />),
|
|
47
47
|
{ parse_mode: 'HTML' }
|
|
48
48
|
)
|
|
49
49
|
})
|
|
@@ -51,6 +51,21 @@ bot.command('start', async (ctx) => {
|
|
|
51
51
|
bot.start()
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
Usage with [effect-tg](https://github.com/grom-dev/effect-tg):
|
|
55
|
+
|
|
56
|
+
```jsx
|
|
57
|
+
import { Content, Dialog, Send, Text } from 'effect-tg'
|
|
58
|
+
|
|
59
|
+
const Greeting = (props) => (
|
|
60
|
+
<>Hello, <b>{props.name}</b>!</>
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
const greet = (id, name) => Send.sendMessage({
|
|
64
|
+
dialog: Dialog.user(id),
|
|
65
|
+
content: Content.text(Text.tgx(<Greeting name={name} />))
|
|
66
|
+
})
|
|
67
|
+
```
|
|
68
|
+
|
|
54
69
|
## License
|
|
55
70
|
|
|
56
71
|
[MIT](./LICENSE)
|
package/dist/Line.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { PropsWithChildren, TgxElement } from './types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Simple component that wraps its children in a fragment and adds a newline.
|
|
4
|
+
*
|
|
5
|
+
* Useful for creating multi-line messages.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```jsx
|
|
9
|
+
* import { Line } from '@grom.js/tgx'
|
|
10
|
+
*
|
|
11
|
+
* const Greeting = (props) => (
|
|
12
|
+
* <>
|
|
13
|
+
* <Line>Hello, <b>{props.name}</b>!</Line>
|
|
14
|
+
* <Line/>
|
|
15
|
+
* <Line><i>How are you doing?</i></Line>
|
|
16
|
+
* </>
|
|
17
|
+
* )
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function Line({ children }: PropsWithChildren): TgxElement;
|
package/dist/Line.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Fragment } from "./jsx.js";
|
|
2
|
+
/**
|
|
3
|
+
* Simple component that wraps its children in a fragment and adds a newline.
|
|
4
|
+
*
|
|
5
|
+
* Useful for creating multi-line messages.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```jsx
|
|
9
|
+
* import { Line } from '@grom.js/tgx'
|
|
10
|
+
*
|
|
11
|
+
* const Greeting = (props) => (
|
|
12
|
+
* <>
|
|
13
|
+
* <Line>Hello, <b>{props.name}</b>!</Line>
|
|
14
|
+
* <Line/>
|
|
15
|
+
* <Line><i>How are you doing?</i></Line>
|
|
16
|
+
* </>
|
|
17
|
+
* )
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export function Line({ children }) {
|
|
21
|
+
return Fragment({ children: [children, '\n'] });
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=Line.js.map
|
package/dist/Line.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Line.js","sourceRoot":"","sources":["../src/Line.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAEnC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,IAAI,CAAC,EAAE,QAAQ,EAAqB;IAClD,OAAO,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,CAAA;AACjD,CAAC"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAA;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA"}
|
package/dist/jsx-runtime.d.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type * as Tgx from './types.ts';
|
|
2
2
|
import { Fragment } from './jsx.ts';
|
|
3
3
|
declare function jsx(type: any, props: any, key: any): any;
|
|
4
4
|
export { Fragment, jsx, jsx as jsxDEV, jsx as jsxs, };
|
|
5
5
|
export declare namespace JSX {
|
|
6
|
-
type Element = TgxElement;
|
|
7
|
-
type ElementType = keyof
|
|
6
|
+
type Element = Tgx.TgxElement;
|
|
7
|
+
type ElementType = keyof IntrinsicElements | Tgx.Component;
|
|
8
8
|
interface ElementAttributesProperty {
|
|
9
9
|
props: {};
|
|
10
10
|
}
|
|
11
11
|
interface ElementChildrenAttribute {
|
|
12
12
|
children: {};
|
|
13
13
|
}
|
|
14
|
-
interface IntrinsicElements extends
|
|
14
|
+
interface IntrinsicElements extends Tgx.IntrinsicElements {
|
|
15
15
|
}
|
|
16
16
|
interface IntrinsicAttributes {
|
|
17
17
|
}
|
package/dist/jsx-runtime.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createElement, Fragment } from "./jsx.js";
|
|
2
2
|
function jsx(type, props, key) {
|
|
3
3
|
const { children } = props;
|
|
4
4
|
delete props.children;
|
|
5
5
|
if (arguments.length > 2) {
|
|
6
6
|
props.key = key;
|
|
7
7
|
}
|
|
8
|
-
return
|
|
8
|
+
return createElement(type, props, children);
|
|
9
9
|
}
|
|
10
10
|
export { Fragment, jsx, jsx as jsxDEV, jsx as jsxs, };
|
|
11
|
+
//# sourceMappingURL=jsx-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsx-runtime.js","sourceRoot":"","sources":["../src/jsx-runtime.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAElD,SAAS,GAAG,CAAC,IAAS,EAAE,KAAU,EAAE,GAAQ;IAC1C,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAA;IAC1B,OAAO,KAAK,CAAC,QAAQ,CAAA;IACrB,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,KAAK,CAAC,GAAG,GAAG,GAAG,CAAA;IACjB,CAAC;IACD,OAAO,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAA;AAC7C,CAAC;AAED,OAAO,EACL,QAAQ,EACR,GAAG,EACH,GAAG,IAAI,MAAM,EACb,GAAG,IAAI,IAAI,GACZ,CAAA"}
|
package/dist/jsx.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function
|
|
3
|
-
export declare function
|
|
1
|
+
import type { Component, IntrinsicElements, TgxElement, TgxElementFragment, TgxNode } from './types.ts';
|
|
2
|
+
export declare function createElement<T extends keyof IntrinsicElements>(type: T, props: IntrinsicElements[T], children: TgxNode): TgxElement;
|
|
3
|
+
export declare function createElement(type: Component, props: any, children: TgxNode): TgxElement;
|
|
4
4
|
export declare function Fragment(props?: {
|
|
5
5
|
children?: TgxNode;
|
|
6
|
-
}):
|
|
6
|
+
}): TgxElementFragment;
|
|
7
|
+
export declare function isIntrinsicElement(name: string): name is keyof IntrinsicElements;
|
package/dist/jsx.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export function
|
|
2
|
-
if (typeof type === 'string' &&
|
|
3
|
-
return
|
|
1
|
+
export function createElement(type, props, children) {
|
|
2
|
+
if (typeof type === 'string' && isIntrinsicElement(type)) {
|
|
3
|
+
return createElementIntrinsic({
|
|
4
4
|
tag: type,
|
|
5
5
|
props: { ...props, children },
|
|
6
6
|
});
|
|
@@ -28,21 +28,22 @@ function elementsFromNode(node) {
|
|
|
28
28
|
return node.flatMap(child => elementsFromNode(child));
|
|
29
29
|
return [node];
|
|
30
30
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
31
|
+
const INTRINSIC_ELEMENTS = new Set([
|
|
32
|
+
'b',
|
|
33
|
+
'i',
|
|
34
|
+
'u',
|
|
35
|
+
's',
|
|
36
|
+
'spoiler',
|
|
37
|
+
'a',
|
|
38
|
+
'emoji',
|
|
39
|
+
'code',
|
|
40
|
+
'codeblock',
|
|
41
|
+
'blockquote',
|
|
42
|
+
]);
|
|
43
|
+
export function isIntrinsicElement(name) {
|
|
44
|
+
return INTRINSIC_ELEMENTS.has(name);
|
|
44
45
|
}
|
|
45
|
-
function
|
|
46
|
+
function createElementIntrinsic(options) {
|
|
46
47
|
switch (options.tag) {
|
|
47
48
|
case 'b':
|
|
48
49
|
return {
|
|
@@ -106,3 +107,4 @@ function renderNativeElement(options) {
|
|
|
106
107
|
};
|
|
107
108
|
}
|
|
108
109
|
}
|
|
110
|
+
//# sourceMappingURL=jsx.js.map
|
package/dist/jsx.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsx.js","sourceRoot":"","sources":["../src/jsx.ts"],"names":[],"mappings":"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"}
|
package/dist/render.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { TgxElement } from './types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Converts {@link TgxElement} to a string formatted for Telegram's
|
|
4
|
+
* [HTML parse mode](https://core.telegram.org/bots/api#html-style).
|
|
5
|
+
*/
|
|
6
|
+
export declare function renderHtml(tgx: TgxElement | TgxElement[]): string;
|
package/dist/render.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts {@link TgxElement} to a string formatted for Telegram's
|
|
3
|
+
* [HTML parse mode](https://core.telegram.org/bots/api#html-style).
|
|
4
|
+
*/
|
|
5
|
+
export function renderHtml(tgx) {
|
|
6
|
+
return (Array.isArray(tgx) ? tgx : [tgx])
|
|
7
|
+
.map((el) => {
|
|
8
|
+
switch (el.type) {
|
|
9
|
+
case 'text': return renderTextElement(el);
|
|
10
|
+
case 'plain': return renderPlainElement(el);
|
|
11
|
+
case 'fragment': return renderHtml(el.subelements);
|
|
12
|
+
}
|
|
13
|
+
throw new Error(`Unknown element: ${el}.`);
|
|
14
|
+
})
|
|
15
|
+
.join('');
|
|
16
|
+
}
|
|
17
|
+
function renderTextElement(el) {
|
|
18
|
+
switch (el.entity.type) {
|
|
19
|
+
case 'bold': return `<b>${renderHtml(el.subelements)}</b>`;
|
|
20
|
+
case 'italic': return `<i>${renderHtml(el.subelements)}</i>`;
|
|
21
|
+
case 'underline': return `<u>${renderHtml(el.subelements)}</u>`;
|
|
22
|
+
case 'strikethrough': return `<s>${renderHtml(el.subelements)}</s>`;
|
|
23
|
+
case 'spoiler': return `<tg-spoiler>${renderHtml(el.subelements)}</tg-spoiler>`;
|
|
24
|
+
// TODO: Shouldn't we urlencode this?
|
|
25
|
+
case 'link': return `<a href="${el.entity.url}">${renderHtml(el.subelements)}</a>`;
|
|
26
|
+
case 'custom-emoji': return `<tg-emoji emoji-id="${el.entity.id}">${el.entity.alt}</tg-emoji>`;
|
|
27
|
+
case 'code': return `<code>${renderHtml(el.subelements)}</code>`;
|
|
28
|
+
case 'codeblock': return (el.entity.language
|
|
29
|
+
? `<pre><code class="language-${el.entity.language}">${renderHtml(el.subelements)}</code></pre>`
|
|
30
|
+
: `<pre>${renderHtml(el.subelements)}</pre>`);
|
|
31
|
+
case 'blockquote': return (el.entity.expandable
|
|
32
|
+
? `<blockquote expandable>${renderHtml(el.subelements)}</blockquote>`
|
|
33
|
+
: `<blockquote>${renderHtml(el.subelements)}</blockquote>`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function renderPlainElement({ value }) {
|
|
37
|
+
if (value == null || typeof value === 'boolean')
|
|
38
|
+
return '';
|
|
39
|
+
return sanitize(String(value));
|
|
40
|
+
}
|
|
41
|
+
function sanitize(unsafe) {
|
|
42
|
+
return unsafe
|
|
43
|
+
.replaceAll('&', '&') // must be first
|
|
44
|
+
.replaceAll('<', '<')
|
|
45
|
+
.replaceAll('>', '>');
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
export interface NativeElements {
|
|
1
|
+
export interface IntrinsicElements {
|
|
3
2
|
/**
|
|
4
3
|
* Bold text.
|
|
5
4
|
*/
|
|
@@ -60,11 +59,9 @@ export interface NativeElements {
|
|
|
60
59
|
/**
|
|
61
60
|
* Programming or markup language of the block.
|
|
62
61
|
*
|
|
63
|
-
*
|
|
64
|
-
* so the following languages are supported:
|
|
65
|
-
* https://github.com/TelegramMessenger/libprisma#supported-languages
|
|
62
|
+
* @see https://github.com/TelegramMessenger/libprisma#supported-languages
|
|
66
63
|
*/
|
|
67
|
-
lang?:
|
|
64
|
+
lang?: (string & {}) | 'markup' | 'html' | 'xml' | 'svg' | 'mathml' | 'ssml' | 'atom' | 'rss' | 'css' | 'clike' | 'regex' | 'javascript' | 'js' | 'abap' | 'abnf' | 'actionscript' | 'ada' | 'agda' | 'al' | 'antlr4' | 'g4' | 'apacheconf' | 'sql' | 'apex' | 'apl' | 'applescript' | 'aql' | 'c' | 'cpp' | 'arduino' | 'ino' | 'arff' | 'armasm' | 'arm-asm' | 'bash' | 'sh' | 'shell' | 'yaml' | 'yml' | 'markdown' | 'md' | 'arturo' | 'art' | 'asciidoc' | 'adoc' | 'csharp' | 'cs' | 'dotnet' | 'aspnet' | 'asm6502' | 'asmatmel' | 'autohotkey' | 'autoit' | 'avisynth' | 'avs' | 'avro-idl' | 'avdl' | 'awk' | 'gawk' | 'basic' | 'batch' | 'bbcode' | 'shortcode' | 'bbj' | 'bicep' | 'birb' | 'bison' | 'bnf' | 'rbnf' | 'bqn' | 'brainfuck' | 'brightscript' | 'bro' | 'cfscript' | 'cfc' | 'chaiscript' | 'cil' | 'cilkc' | 'cilk-c' | 'cilkcpp' | 'cilk-cpp' | 'cilk' | 'clojure' | 'cmake' | 'cobol' | 'coffeescript' | 'coffee' | 'concurnas' | 'conc' | 'csp' | 'cooklang' | 'ruby' | 'rb' | 'crystal' | 'csv' | 'cue' | 'cypher' | 'd' | 'dart' | 'dataweave' | 'dax' | 'dhall' | 'diff' | 'markup-templating' | 'django' | 'jinja2' | 'dns-zone-file' | 'dns-zone' | 'docker' | 'dockerfile' | 'dot' | 'gv' | 'ebnf' | 'editorconfig' | 'eiffel' | 'ejs' | 'eta' | 'elixir' | 'elm' | 'lua' | 'etlua' | 'erb' | 'erlang' | 'excel-formula' | 'xlsx' | 'xls' | 'fsharp' | 'factor' | 'false' | 'fift' | 'firestore-security-rules' | 'flow' | 'fortran' | 'ftl' | 'func' | 'gml' | 'gamemakerlanguage' | 'gap' | 'gcode' | 'gdscript' | 'gedcom' | 'gettext' | 'po' | 'git' | 'glsl' | 'gn' | 'gni' | 'linker-script' | 'ld' | 'go' | 'go-module' | 'go-mod' | 'gradle' | 'graphql' | 'groovy' | 'less' | 'scss' | 'textile' | 'haml' | 'handlebars' | 'hbs' | 'mustache' | 'haskell' | 'hs' | 'haxe' | 'hcl' | 'hlsl' | 'hoon' | 'hpkp' | 'hsts' | 'json' | 'webmanifest' | 'uri' | 'url' | 'http' | 'ichigojam' | 'icon' | 'icu-message-format' | 'idris' | 'idr' | 'ignore' | 'gitignore' | 'hgignore' | 'npmignore' | 'inform7' | 'ini' | 'io' | 'j' | 'java' | 'scala' | 'php' | 'javadoclike' | 'javadoc' | 'javastacktrace' | 'jolie' | 'jq' | 'typescript' | 'ts' | 'jsdoc' | 'n4js' | 'n4jsd' | 'json5' | 'jsonp' | 'jsstacktrace' | 'julia' | 'keepalived' | 'keyman' | 'kotlin' | 'kt' | 'kts' | 'kusto' | 'latex' | 'tex' | 'context' | 'latte' | 'scheme' | 'lilypond' | 'ly' | 'liquid' | 'lisp' | 'emacs' | 'elisp' | 'emacs-lisp' | 'livescript' | 'llvm' | 'log' | 'lolcode' | 'magma' | 'makefile' | 'mata' | 'matlab' | 'maxscript' | 'mel' | 'mermaid' | 'metafont' | 'mizar' | 'mongodb' | 'monkey' | 'moonscript' | 'moon' | 'n1ql' | 'nand2tetris-hdl' | 'naniscript' | 'nani' | 'nasm' | 'neon' | 'nevod' | 'nginx' | 'nim' | 'nix' | 'nsis' | 'objectivec' | 'objc' | 'ocaml' | 'odin' | 'opencl' | 'openqasm' | 'qasm' | 'oz' | 'parigp' | 'parser' | 'pascal' | 'objectpascal' | 'pascaligo' | 'psl' | 'pcaxis' | 'px' | 'peoplecode' | 'pcode' | 'perl' | 'phpdoc' | 'plant-uml' | 'plantuml' | 'plsql' | 'powerquery' | 'pq' | 'mscript' | 'powershell' | 'processing' | 'prolog' | 'promql' | 'properties' | 'protobuf' | 'stylus' | 'twig' | 'pug' | 'puppet' | 'purebasic' | 'pbfasm' | 'python' | 'py' | 'qsharp' | 'qs' | 'q' | 'qml' | 'qore' | 'r' | 'racket' | 'rkt' | 'cshtml' | 'razor' | 'jsx' | 'tsx' | 'reason' | 'rego' | 'renpy' | 'rpy' | 'rescript' | 'res' | 'rest' | 'rip' | 'roboconf' | 'robotframework' | 'robot' | 'rust' | 'sas' | 'sass' | 'shell-session' | 'sh-session' | 'shellsession' | 'smali' | 'smalltalk' | 'smarty' | 'sml' | 'smlnj' | 'solidity' | 'sol' | 'solution-file' | 'sln' | 'soy' | 'splunk-spl' | 'sqf' | 'squirrel' | 'stan' | 'stata' | 'iecst' | 'supercollider' | 'sclang' | 'swift' | 'systemd' | 'tact' | 't4-templating' | 't4-cs' | 't4' | 'vbnet' | 't4-vb' | 'tap' | 'tcl' | 'tt2' | 'toml' | 'ttcn' | 'ttcn3' | 'ttcn-3' | 'turtle' | 'trickle' | 'typescript-jsdoc' | 'typoscript' | 'tsconfig' | 'unrealscript' | 'uscript' | 'uc' | 'uri' | 'v' | 'vala' | 'vba' | 'vbscript' | 'velocity' | 'verilog' | 'vhdl' | 'vim' | 'visual-basic' | 'vb' | 'warpscript' | 'wasm' | 'web-idl' | 'webidl' | 'wgsl' | 'wiki' | 'wolfram' | 'mathematica' | 'nb' | 'wl' | 'xeora' | 'xeoracube' | 'xml-doc' | 'xojo' | 'xquery' | 'yaml' | 'yml' | 'yang' | 'zig';
|
|
68
65
|
}>;
|
|
69
66
|
/**
|
|
70
67
|
* Block quotation. Can be expandable or not.
|
|
@@ -74,20 +71,20 @@ export interface NativeElements {
|
|
|
74
71
|
}>;
|
|
75
72
|
}
|
|
76
73
|
export type TgxNode = TgxNode[] | TgxElement | string | number | boolean | null | undefined;
|
|
77
|
-
export type PropsWithChildren<P = {}> = {
|
|
74
|
+
export type PropsWithChildren<P = {}> = P & {
|
|
78
75
|
children?: TgxNode;
|
|
79
|
-
}
|
|
80
|
-
export type
|
|
81
|
-
export type TgxElement =
|
|
82
|
-
export interface
|
|
76
|
+
};
|
|
77
|
+
export type Component = (props: any) => TgxElement;
|
|
78
|
+
export type TgxElement = TgxElementPlain | TgxElementFragment | TgxElementText;
|
|
79
|
+
export interface TgxElementPlain {
|
|
83
80
|
type: 'plain';
|
|
84
81
|
value: string | number | boolean | null | undefined;
|
|
85
82
|
}
|
|
86
|
-
export interface
|
|
83
|
+
export interface TgxElementFragment {
|
|
87
84
|
type: 'fragment';
|
|
88
85
|
subelements: TgxElement[];
|
|
89
86
|
}
|
|
90
|
-
export interface
|
|
87
|
+
export interface TgxElementText {
|
|
91
88
|
type: 'text';
|
|
92
89
|
entity: TextEntity;
|
|
93
90
|
subelements: TgxElement[];
|
package/dist/types.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grom.js/tgx",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "1.1.0",
|
|
5
5
|
"description": "JSX runtime for composing Telegram messages",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Vladislav Deryabkin",
|
|
@@ -21,9 +21,6 @@
|
|
|
21
21
|
"types": "./dist/index.d.ts",
|
|
22
22
|
"import": "./dist/index.js"
|
|
23
23
|
},
|
|
24
|
-
"./types": {
|
|
25
|
-
"types": "./dist/types.d.ts"
|
|
26
|
-
},
|
|
27
24
|
"./jsx-runtime": {
|
|
28
25
|
"types": "./dist/jsx-runtime.d.ts",
|
|
29
26
|
"import": "./dist/jsx-runtime.js"
|
|
@@ -34,20 +31,21 @@
|
|
|
34
31
|
}
|
|
35
32
|
},
|
|
36
33
|
"files": [
|
|
37
|
-
"./dist/"
|
|
34
|
+
"./dist/",
|
|
35
|
+
"./src/"
|
|
38
36
|
],
|
|
39
37
|
"engines": {
|
|
40
38
|
"node": "22.x"
|
|
41
39
|
},
|
|
42
40
|
"devDependencies": {
|
|
43
|
-
"@antfu/eslint-config": "
|
|
44
|
-
"@types/node": "22.19.
|
|
45
|
-
"@vitest/coverage-v8": "4.0.
|
|
46
|
-
"bumpp": "10.
|
|
47
|
-
"eslint": "9.39.
|
|
48
|
-
"eslint-plugin-format": "1.0
|
|
49
|
-
"taze": "19.9.
|
|
50
|
-
"vitest": "4.0.
|
|
41
|
+
"@antfu/eslint-config": "7.4.3",
|
|
42
|
+
"@types/node": "22.19.11",
|
|
43
|
+
"@vitest/coverage-v8": "4.0.18",
|
|
44
|
+
"bumpp": "10.4.1",
|
|
45
|
+
"eslint": "9.39.2",
|
|
46
|
+
"eslint-plugin-format": "1.4.0",
|
|
47
|
+
"taze": "19.9.2",
|
|
48
|
+
"vitest": "4.0.18"
|
|
51
49
|
},
|
|
52
50
|
"scripts": {
|
|
53
51
|
"build": "rm -rf ./dist/ && tsc --project ./tsconfig.lib.json",
|
package/src/Line.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { PropsWithChildren, TgxElement } from './types.ts'
|
|
2
|
+
import { Fragment } from './jsx.ts'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Simple component that wraps its children in a fragment and adds a newline.
|
|
6
|
+
*
|
|
7
|
+
* Useful for creating multi-line messages.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```jsx
|
|
11
|
+
* import { Line } from '@grom.js/tgx'
|
|
12
|
+
*
|
|
13
|
+
* const Greeting = (props) => (
|
|
14
|
+
* <>
|
|
15
|
+
* <Line>Hello, <b>{props.name}</b>!</Line>
|
|
16
|
+
* <Line/>
|
|
17
|
+
* <Line><i>How are you doing?</i></Line>
|
|
18
|
+
* </>
|
|
19
|
+
* )
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function Line({ children }: PropsWithChildren): TgxElement {
|
|
23
|
+
return Fragment({ children: [children, '\n'] })
|
|
24
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type * as Tgx from './types.ts'
|
|
2
|
+
import { createElement, Fragment } from './jsx.ts'
|
|
3
|
+
|
|
4
|
+
function jsx(type: any, props: any, key: any): any {
|
|
5
|
+
const { children } = props
|
|
6
|
+
delete props.children
|
|
7
|
+
if (arguments.length > 2) {
|
|
8
|
+
props.key = key
|
|
9
|
+
}
|
|
10
|
+
return createElement(type, props, children)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
Fragment,
|
|
15
|
+
jsx,
|
|
16
|
+
jsx as jsxDEV,
|
|
17
|
+
jsx as jsxs,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export namespace JSX {
|
|
21
|
+
export type Element = Tgx.TgxElement
|
|
22
|
+
export type ElementType = keyof IntrinsicElements | Tgx.Component
|
|
23
|
+
export interface ElementAttributesProperty { props: {} }
|
|
24
|
+
export interface ElementChildrenAttribute { children: {} }
|
|
25
|
+
export interface IntrinsicElements extends Tgx.IntrinsicElements {}
|
|
26
|
+
export interface IntrinsicAttributes {}
|
|
27
|
+
}
|
package/src/jsx.ts
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Component,
|
|
3
|
+
IntrinsicElements,
|
|
4
|
+
TgxElement,
|
|
5
|
+
TgxElementFragment,
|
|
6
|
+
TgxNode,
|
|
7
|
+
} from './types.ts'
|
|
8
|
+
|
|
9
|
+
export function createElement<T extends keyof IntrinsicElements>(
|
|
10
|
+
type: T,
|
|
11
|
+
props: IntrinsicElements[T],
|
|
12
|
+
children: TgxNode,
|
|
13
|
+
): TgxElement
|
|
14
|
+
export function createElement(
|
|
15
|
+
type: Component,
|
|
16
|
+
props: any,
|
|
17
|
+
children: TgxNode,
|
|
18
|
+
): TgxElement
|
|
19
|
+
export function createElement(
|
|
20
|
+
type: unknown,
|
|
21
|
+
props: any,
|
|
22
|
+
children: TgxNode,
|
|
23
|
+
): TgxElement {
|
|
24
|
+
if (typeof type === 'string' && isIntrinsicElement(type)) {
|
|
25
|
+
return createElementIntrinsic({
|
|
26
|
+
tag: type,
|
|
27
|
+
props: { ...props, children },
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (typeof type === 'function')
|
|
32
|
+
return type({ ...props, children })
|
|
33
|
+
|
|
34
|
+
throw new Error(`Invalid JSX component: ${type}.`)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function Fragment(props?: { children?: TgxNode }): TgxElementFragment {
|
|
38
|
+
return {
|
|
39
|
+
type: 'fragment',
|
|
40
|
+
subelements: elementsFromNode(props?.children ?? []),
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function elementsFromNode(node: TgxNode): TgxElement[] {
|
|
45
|
+
switch (typeof node) {
|
|
46
|
+
case 'string':
|
|
47
|
+
case 'number':
|
|
48
|
+
case 'boolean':
|
|
49
|
+
return [{ type: 'plain', value: node }]
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (node == null)
|
|
53
|
+
return [{ type: 'plain', value: node }]
|
|
54
|
+
|
|
55
|
+
if (Array.isArray(node))
|
|
56
|
+
return node.flatMap(child => elementsFromNode(child))
|
|
57
|
+
|
|
58
|
+
return [node]
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const INTRINSIC_ELEMENTS = new Set([
|
|
62
|
+
'b',
|
|
63
|
+
'i',
|
|
64
|
+
'u',
|
|
65
|
+
's',
|
|
66
|
+
'spoiler',
|
|
67
|
+
'a',
|
|
68
|
+
'emoji',
|
|
69
|
+
'code',
|
|
70
|
+
'codeblock',
|
|
71
|
+
'blockquote',
|
|
72
|
+
])
|
|
73
|
+
|
|
74
|
+
export function isIntrinsicElement(name: string): name is keyof IntrinsicElements {
|
|
75
|
+
return INTRINSIC_ELEMENTS.has(name as keyof IntrinsicElements)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function createElementIntrinsic(
|
|
79
|
+
options: {
|
|
80
|
+
[K in keyof IntrinsicElements]: {
|
|
81
|
+
tag: K
|
|
82
|
+
props: IntrinsicElements[K]
|
|
83
|
+
}
|
|
84
|
+
}[keyof IntrinsicElements],
|
|
85
|
+
): TgxElement {
|
|
86
|
+
switch (options.tag) {
|
|
87
|
+
case 'b':
|
|
88
|
+
return {
|
|
89
|
+
type: 'text',
|
|
90
|
+
entity: { type: 'bold' },
|
|
91
|
+
subelements: elementsFromNode(options.props.children ?? []),
|
|
92
|
+
}
|
|
93
|
+
case 'i':
|
|
94
|
+
return {
|
|
95
|
+
type: 'text',
|
|
96
|
+
entity: { type: 'italic' },
|
|
97
|
+
subelements: elementsFromNode(options.props.children ?? []),
|
|
98
|
+
}
|
|
99
|
+
case 'u':
|
|
100
|
+
return {
|
|
101
|
+
type: 'text',
|
|
102
|
+
entity: { type: 'underline' },
|
|
103
|
+
subelements: elementsFromNode(options.props.children ?? []),
|
|
104
|
+
}
|
|
105
|
+
case 's':
|
|
106
|
+
return {
|
|
107
|
+
type: 'text',
|
|
108
|
+
entity: { type: 'strikethrough' },
|
|
109
|
+
subelements: elementsFromNode(options.props.children ?? []),
|
|
110
|
+
}
|
|
111
|
+
case 'spoiler':
|
|
112
|
+
return {
|
|
113
|
+
type: 'text',
|
|
114
|
+
entity: { type: 'spoiler' },
|
|
115
|
+
subelements: elementsFromNode(options.props.children ?? []),
|
|
116
|
+
}
|
|
117
|
+
case 'a':
|
|
118
|
+
return {
|
|
119
|
+
type: 'text',
|
|
120
|
+
entity: { type: 'link', url: options.props.href },
|
|
121
|
+
subelements: elementsFromNode(options.props.children ?? []),
|
|
122
|
+
}
|
|
123
|
+
case 'emoji':
|
|
124
|
+
return {
|
|
125
|
+
type: 'text',
|
|
126
|
+
entity: { type: 'custom-emoji', id: options.props.id, alt: options.props.alt },
|
|
127
|
+
subelements: [],
|
|
128
|
+
}
|
|
129
|
+
case 'code':
|
|
130
|
+
return {
|
|
131
|
+
type: 'text',
|
|
132
|
+
entity: { type: 'code' },
|
|
133
|
+
subelements: elementsFromNode(options.props.children ?? []),
|
|
134
|
+
}
|
|
135
|
+
case 'codeblock':
|
|
136
|
+
return {
|
|
137
|
+
type: 'text',
|
|
138
|
+
entity: { type: 'codeblock', language: options.props.lang },
|
|
139
|
+
subelements: elementsFromNode(options.props.children ?? []),
|
|
140
|
+
}
|
|
141
|
+
case 'blockquote':
|
|
142
|
+
return {
|
|
143
|
+
type: 'text',
|
|
144
|
+
entity: { type: 'blockquote', expandable: !!options.props.expandable },
|
|
145
|
+
subelements: elementsFromNode(options.props.children ?? []),
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
package/src/render.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { TgxElement, TgxElementPlain, TgxElementText } from './types.ts'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Converts {@link TgxElement} to a string formatted for Telegram's
|
|
5
|
+
* [HTML parse mode](https://core.telegram.org/bots/api#html-style).
|
|
6
|
+
*/
|
|
7
|
+
export function renderHtml(tgx: TgxElement | TgxElement[]): string {
|
|
8
|
+
return (Array.isArray(tgx) ? tgx : [tgx])
|
|
9
|
+
.map((el) => {
|
|
10
|
+
switch (el.type) {
|
|
11
|
+
case 'text': return renderTextElement(el)
|
|
12
|
+
case 'plain': return renderPlainElement(el)
|
|
13
|
+
case 'fragment': return renderHtml(el.subelements)
|
|
14
|
+
}
|
|
15
|
+
throw new Error(`Unknown element: ${el satisfies never}.`)
|
|
16
|
+
})
|
|
17
|
+
.join('')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function renderTextElement(el: TgxElementText): string {
|
|
21
|
+
switch (el.entity.type) {
|
|
22
|
+
case 'bold': return `<b>${renderHtml(el.subelements)}</b>`
|
|
23
|
+
case 'italic': return `<i>${renderHtml(el.subelements)}</i>`
|
|
24
|
+
case 'underline': return `<u>${renderHtml(el.subelements)}</u>`
|
|
25
|
+
case 'strikethrough': return `<s>${renderHtml(el.subelements)}</s>`
|
|
26
|
+
case 'spoiler': return `<tg-spoiler>${renderHtml(el.subelements)}</tg-spoiler>`
|
|
27
|
+
|
|
28
|
+
// TODO: Shouldn't we urlencode this?
|
|
29
|
+
case 'link': return `<a href="${el.entity.url}">${renderHtml(el.subelements)}</a>`
|
|
30
|
+
|
|
31
|
+
case 'custom-emoji': return `<tg-emoji emoji-id="${el.entity.id}">${el.entity.alt}</tg-emoji>`
|
|
32
|
+
case 'code': return `<code>${renderHtml(el.subelements)}</code>`
|
|
33
|
+
|
|
34
|
+
case 'codeblock': return (
|
|
35
|
+
el.entity.language
|
|
36
|
+
? `<pre><code class="language-${el.entity.language}">${renderHtml(el.subelements)}</code></pre>`
|
|
37
|
+
: `<pre>${renderHtml(el.subelements)}</pre>`
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
case 'blockquote': return (
|
|
41
|
+
el.entity.expandable
|
|
42
|
+
? `<blockquote expandable>${renderHtml(el.subelements)}</blockquote>`
|
|
43
|
+
: `<blockquote>${renderHtml(el.subelements)}</blockquote>`
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function renderPlainElement({ value }: TgxElementPlain): string {
|
|
49
|
+
if (value == null || typeof value === 'boolean')
|
|
50
|
+
return ''
|
|
51
|
+
return sanitize(String(value))
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function sanitize(unsafe: string): string {
|
|
55
|
+
return unsafe
|
|
56
|
+
.replaceAll('&', '&') // must be first
|
|
57
|
+
.replaceAll('<', '<')
|
|
58
|
+
.replaceAll('>', '>')
|
|
59
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
export interface IntrinsicElements {
|
|
2
|
+
/**
|
|
3
|
+
* Bold text.
|
|
4
|
+
*/
|
|
5
|
+
b: PropsWithChildren
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Italic text.
|
|
9
|
+
*/
|
|
10
|
+
i: PropsWithChildren
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Underlined text.
|
|
14
|
+
*/
|
|
15
|
+
u: PropsWithChildren
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Strikethrough text.
|
|
19
|
+
*/
|
|
20
|
+
s: PropsWithChildren
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Spoiler.
|
|
24
|
+
*/
|
|
25
|
+
spoiler: PropsWithChildren
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Inline URL or Telegram (deep) link.
|
|
29
|
+
*
|
|
30
|
+
* Read more about Telegram deep links:
|
|
31
|
+
* https://core.telegram.org/api/links
|
|
32
|
+
*/
|
|
33
|
+
a: PropsWithChildren<{
|
|
34
|
+
/**
|
|
35
|
+
* Link to open.
|
|
36
|
+
*
|
|
37
|
+
* @example "https://google.com"
|
|
38
|
+
* @example "tg://resolve?domain=BotFather"
|
|
39
|
+
*/
|
|
40
|
+
href: string
|
|
41
|
+
}>
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Custom Telegram emoji.
|
|
45
|
+
*/
|
|
46
|
+
emoji: {
|
|
47
|
+
/**
|
|
48
|
+
* Unique identifier of the custom emoji.
|
|
49
|
+
*/
|
|
50
|
+
id: string
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Alternative emoji that will be shown instead of the custom emoji in
|
|
54
|
+
* places where a custom emoji cannot be displayed.
|
|
55
|
+
*/
|
|
56
|
+
alt: string
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Inline fixed-width code.
|
|
61
|
+
*/
|
|
62
|
+
code: PropsWithChildren
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Fixed-width code block with the optional programming language.
|
|
66
|
+
*/
|
|
67
|
+
codeblock: PropsWithChildren<{
|
|
68
|
+
/**
|
|
69
|
+
* Programming or markup language of the block.
|
|
70
|
+
*
|
|
71
|
+
* @see https://github.com/TelegramMessenger/libprisma#supported-languages
|
|
72
|
+
*/
|
|
73
|
+
lang?:
|
|
74
|
+
| (string & {})
|
|
75
|
+
| 'markup'
|
|
76
|
+
| 'html'
|
|
77
|
+
| 'xml'
|
|
78
|
+
| 'svg'
|
|
79
|
+
| 'mathml'
|
|
80
|
+
| 'ssml'
|
|
81
|
+
| 'atom'
|
|
82
|
+
| 'rss'
|
|
83
|
+
| 'css'
|
|
84
|
+
| 'clike'
|
|
85
|
+
| 'regex'
|
|
86
|
+
| 'javascript'
|
|
87
|
+
| 'js'
|
|
88
|
+
| 'abap'
|
|
89
|
+
| 'abnf'
|
|
90
|
+
| 'actionscript'
|
|
91
|
+
| 'ada'
|
|
92
|
+
| 'agda'
|
|
93
|
+
| 'al'
|
|
94
|
+
| 'antlr4'
|
|
95
|
+
| 'g4'
|
|
96
|
+
| 'apacheconf'
|
|
97
|
+
| 'sql'
|
|
98
|
+
| 'apex'
|
|
99
|
+
| 'apl'
|
|
100
|
+
| 'applescript'
|
|
101
|
+
| 'aql'
|
|
102
|
+
| 'c'
|
|
103
|
+
| 'cpp'
|
|
104
|
+
| 'arduino'
|
|
105
|
+
| 'ino'
|
|
106
|
+
| 'arff'
|
|
107
|
+
| 'armasm'
|
|
108
|
+
| 'arm-asm'
|
|
109
|
+
| 'bash'
|
|
110
|
+
| 'sh'
|
|
111
|
+
| 'shell'
|
|
112
|
+
| 'yaml'
|
|
113
|
+
| 'yml'
|
|
114
|
+
| 'markdown'
|
|
115
|
+
| 'md'
|
|
116
|
+
| 'arturo'
|
|
117
|
+
| 'art'
|
|
118
|
+
| 'asciidoc'
|
|
119
|
+
| 'adoc'
|
|
120
|
+
| 'csharp'
|
|
121
|
+
| 'cs'
|
|
122
|
+
| 'dotnet'
|
|
123
|
+
| 'aspnet'
|
|
124
|
+
| 'asm6502'
|
|
125
|
+
| 'asmatmel'
|
|
126
|
+
| 'autohotkey'
|
|
127
|
+
| 'autoit'
|
|
128
|
+
| 'avisynth'
|
|
129
|
+
| 'avs'
|
|
130
|
+
| 'avro-idl'
|
|
131
|
+
| 'avdl'
|
|
132
|
+
| 'awk'
|
|
133
|
+
| 'gawk'
|
|
134
|
+
| 'basic'
|
|
135
|
+
| 'batch'
|
|
136
|
+
| 'bbcode'
|
|
137
|
+
| 'shortcode'
|
|
138
|
+
| 'bbj'
|
|
139
|
+
| 'bicep'
|
|
140
|
+
| 'birb'
|
|
141
|
+
| 'bison'
|
|
142
|
+
| 'bnf'
|
|
143
|
+
| 'rbnf'
|
|
144
|
+
| 'bqn'
|
|
145
|
+
| 'brainfuck'
|
|
146
|
+
| 'brightscript'
|
|
147
|
+
| 'bro'
|
|
148
|
+
| 'cfscript'
|
|
149
|
+
| 'cfc'
|
|
150
|
+
| 'chaiscript'
|
|
151
|
+
| 'cil'
|
|
152
|
+
| 'cilkc'
|
|
153
|
+
| 'cilk-c'
|
|
154
|
+
| 'cilkcpp'
|
|
155
|
+
| 'cilk-cpp'
|
|
156
|
+
| 'cilk'
|
|
157
|
+
| 'clojure'
|
|
158
|
+
| 'cmake'
|
|
159
|
+
| 'cobol'
|
|
160
|
+
| 'coffeescript'
|
|
161
|
+
| 'coffee'
|
|
162
|
+
| 'concurnas'
|
|
163
|
+
| 'conc'
|
|
164
|
+
| 'csp'
|
|
165
|
+
| 'cooklang'
|
|
166
|
+
| 'ruby'
|
|
167
|
+
| 'rb'
|
|
168
|
+
| 'crystal'
|
|
169
|
+
| 'csv'
|
|
170
|
+
| 'cue'
|
|
171
|
+
| 'cypher'
|
|
172
|
+
| 'd'
|
|
173
|
+
| 'dart'
|
|
174
|
+
| 'dataweave'
|
|
175
|
+
| 'dax'
|
|
176
|
+
| 'dhall'
|
|
177
|
+
| 'diff'
|
|
178
|
+
| 'markup-templating'
|
|
179
|
+
| 'django'
|
|
180
|
+
| 'jinja2'
|
|
181
|
+
| 'dns-zone-file'
|
|
182
|
+
| 'dns-zone'
|
|
183
|
+
| 'docker'
|
|
184
|
+
| 'dockerfile'
|
|
185
|
+
| 'dot'
|
|
186
|
+
| 'gv'
|
|
187
|
+
| 'ebnf'
|
|
188
|
+
| 'editorconfig'
|
|
189
|
+
| 'eiffel'
|
|
190
|
+
| 'ejs'
|
|
191
|
+
| 'eta'
|
|
192
|
+
| 'elixir'
|
|
193
|
+
| 'elm'
|
|
194
|
+
| 'lua'
|
|
195
|
+
| 'etlua'
|
|
196
|
+
| 'erb'
|
|
197
|
+
| 'erlang'
|
|
198
|
+
| 'excel-formula'
|
|
199
|
+
| 'xlsx'
|
|
200
|
+
| 'xls'
|
|
201
|
+
| 'fsharp'
|
|
202
|
+
| 'factor'
|
|
203
|
+
| 'false'
|
|
204
|
+
| 'fift'
|
|
205
|
+
| 'firestore-security-rules'
|
|
206
|
+
| 'flow'
|
|
207
|
+
| 'fortran'
|
|
208
|
+
| 'ftl'
|
|
209
|
+
| 'func'
|
|
210
|
+
| 'gml'
|
|
211
|
+
| 'gamemakerlanguage'
|
|
212
|
+
| 'gap'
|
|
213
|
+
| 'gcode'
|
|
214
|
+
| 'gdscript'
|
|
215
|
+
| 'gedcom'
|
|
216
|
+
| 'gettext'
|
|
217
|
+
| 'po'
|
|
218
|
+
| 'git'
|
|
219
|
+
| 'glsl'
|
|
220
|
+
| 'gn'
|
|
221
|
+
| 'gni'
|
|
222
|
+
| 'linker-script'
|
|
223
|
+
| 'ld'
|
|
224
|
+
| 'go'
|
|
225
|
+
| 'go-module'
|
|
226
|
+
| 'go-mod'
|
|
227
|
+
| 'gradle'
|
|
228
|
+
| 'graphql'
|
|
229
|
+
| 'groovy'
|
|
230
|
+
| 'less'
|
|
231
|
+
| 'scss'
|
|
232
|
+
| 'textile'
|
|
233
|
+
| 'haml'
|
|
234
|
+
| 'handlebars'
|
|
235
|
+
| 'hbs'
|
|
236
|
+
| 'mustache'
|
|
237
|
+
| 'haskell'
|
|
238
|
+
| 'hs'
|
|
239
|
+
| 'haxe'
|
|
240
|
+
| 'hcl'
|
|
241
|
+
| 'hlsl'
|
|
242
|
+
| 'hoon'
|
|
243
|
+
| 'hpkp'
|
|
244
|
+
| 'hsts'
|
|
245
|
+
| 'json'
|
|
246
|
+
| 'webmanifest'
|
|
247
|
+
| 'uri'
|
|
248
|
+
| 'url'
|
|
249
|
+
| 'http'
|
|
250
|
+
| 'ichigojam'
|
|
251
|
+
| 'icon'
|
|
252
|
+
| 'icu-message-format'
|
|
253
|
+
| 'idris'
|
|
254
|
+
| 'idr'
|
|
255
|
+
| 'ignore'
|
|
256
|
+
| 'gitignore'
|
|
257
|
+
| 'hgignore'
|
|
258
|
+
| 'npmignore'
|
|
259
|
+
| 'inform7'
|
|
260
|
+
| 'ini'
|
|
261
|
+
| 'io'
|
|
262
|
+
| 'j'
|
|
263
|
+
| 'java'
|
|
264
|
+
| 'scala'
|
|
265
|
+
| 'php'
|
|
266
|
+
| 'javadoclike'
|
|
267
|
+
| 'javadoc'
|
|
268
|
+
| 'javastacktrace'
|
|
269
|
+
| 'jolie'
|
|
270
|
+
| 'jq'
|
|
271
|
+
| 'typescript'
|
|
272
|
+
| 'ts'
|
|
273
|
+
| 'jsdoc'
|
|
274
|
+
| 'n4js'
|
|
275
|
+
| 'n4jsd'
|
|
276
|
+
| 'json5'
|
|
277
|
+
| 'jsonp'
|
|
278
|
+
| 'jsstacktrace'
|
|
279
|
+
| 'julia'
|
|
280
|
+
| 'keepalived'
|
|
281
|
+
| 'keyman'
|
|
282
|
+
| 'kotlin'
|
|
283
|
+
| 'kt'
|
|
284
|
+
| 'kts'
|
|
285
|
+
| 'kusto'
|
|
286
|
+
| 'latex'
|
|
287
|
+
| 'tex'
|
|
288
|
+
| 'context'
|
|
289
|
+
| 'latte'
|
|
290
|
+
| 'scheme'
|
|
291
|
+
| 'lilypond'
|
|
292
|
+
| 'ly'
|
|
293
|
+
| 'liquid'
|
|
294
|
+
| 'lisp'
|
|
295
|
+
| 'emacs'
|
|
296
|
+
| 'elisp'
|
|
297
|
+
| 'emacs-lisp'
|
|
298
|
+
| 'livescript'
|
|
299
|
+
| 'llvm'
|
|
300
|
+
| 'log'
|
|
301
|
+
| 'lolcode'
|
|
302
|
+
| 'magma'
|
|
303
|
+
| 'makefile'
|
|
304
|
+
| 'mata'
|
|
305
|
+
| 'matlab'
|
|
306
|
+
| 'maxscript'
|
|
307
|
+
| 'mel'
|
|
308
|
+
| 'mermaid'
|
|
309
|
+
| 'metafont'
|
|
310
|
+
| 'mizar'
|
|
311
|
+
| 'mongodb'
|
|
312
|
+
| 'monkey'
|
|
313
|
+
| 'moonscript'
|
|
314
|
+
| 'moon'
|
|
315
|
+
| 'n1ql'
|
|
316
|
+
| 'nand2tetris-hdl'
|
|
317
|
+
| 'naniscript'
|
|
318
|
+
| 'nani'
|
|
319
|
+
| 'nasm'
|
|
320
|
+
| 'neon'
|
|
321
|
+
| 'nevod'
|
|
322
|
+
| 'nginx'
|
|
323
|
+
| 'nim'
|
|
324
|
+
| 'nix'
|
|
325
|
+
| 'nsis'
|
|
326
|
+
| 'objectivec'
|
|
327
|
+
| 'objc'
|
|
328
|
+
| 'ocaml'
|
|
329
|
+
| 'odin'
|
|
330
|
+
| 'opencl'
|
|
331
|
+
| 'openqasm'
|
|
332
|
+
| 'qasm'
|
|
333
|
+
| 'oz'
|
|
334
|
+
| 'parigp'
|
|
335
|
+
| 'parser'
|
|
336
|
+
| 'pascal'
|
|
337
|
+
| 'objectpascal'
|
|
338
|
+
| 'pascaligo'
|
|
339
|
+
| 'psl'
|
|
340
|
+
| 'pcaxis'
|
|
341
|
+
| 'px'
|
|
342
|
+
| 'peoplecode'
|
|
343
|
+
| 'pcode'
|
|
344
|
+
| 'perl'
|
|
345
|
+
| 'phpdoc'
|
|
346
|
+
| 'plant-uml'
|
|
347
|
+
| 'plantuml'
|
|
348
|
+
| 'plsql'
|
|
349
|
+
| 'powerquery'
|
|
350
|
+
| 'pq'
|
|
351
|
+
| 'mscript'
|
|
352
|
+
| 'powershell'
|
|
353
|
+
| 'processing'
|
|
354
|
+
| 'prolog'
|
|
355
|
+
| 'promql'
|
|
356
|
+
| 'properties'
|
|
357
|
+
| 'protobuf'
|
|
358
|
+
| 'stylus'
|
|
359
|
+
| 'twig'
|
|
360
|
+
| 'pug'
|
|
361
|
+
| 'puppet'
|
|
362
|
+
| 'purebasic'
|
|
363
|
+
| 'pbfasm'
|
|
364
|
+
| 'python'
|
|
365
|
+
| 'py'
|
|
366
|
+
| 'qsharp'
|
|
367
|
+
| 'qs'
|
|
368
|
+
| 'q'
|
|
369
|
+
| 'qml'
|
|
370
|
+
| 'qore'
|
|
371
|
+
| 'r'
|
|
372
|
+
| 'racket'
|
|
373
|
+
| 'rkt'
|
|
374
|
+
| 'cshtml'
|
|
375
|
+
| 'razor'
|
|
376
|
+
| 'jsx'
|
|
377
|
+
| 'tsx'
|
|
378
|
+
| 'reason'
|
|
379
|
+
| 'rego'
|
|
380
|
+
| 'renpy'
|
|
381
|
+
| 'rpy'
|
|
382
|
+
| 'rescript'
|
|
383
|
+
| 'res'
|
|
384
|
+
| 'rest'
|
|
385
|
+
| 'rip'
|
|
386
|
+
| 'roboconf'
|
|
387
|
+
| 'robotframework'
|
|
388
|
+
| 'robot'
|
|
389
|
+
| 'rust'
|
|
390
|
+
| 'sas'
|
|
391
|
+
| 'sass'
|
|
392
|
+
| 'shell-session'
|
|
393
|
+
| 'sh-session'
|
|
394
|
+
| 'shellsession'
|
|
395
|
+
| 'smali'
|
|
396
|
+
| 'smalltalk'
|
|
397
|
+
| 'smarty'
|
|
398
|
+
| 'sml'
|
|
399
|
+
| 'smlnj'
|
|
400
|
+
| 'solidity'
|
|
401
|
+
| 'sol'
|
|
402
|
+
| 'solution-file'
|
|
403
|
+
| 'sln'
|
|
404
|
+
| 'soy'
|
|
405
|
+
| 'splunk-spl'
|
|
406
|
+
| 'sqf'
|
|
407
|
+
| 'squirrel'
|
|
408
|
+
| 'stan'
|
|
409
|
+
| 'stata'
|
|
410
|
+
| 'iecst'
|
|
411
|
+
| 'supercollider'
|
|
412
|
+
| 'sclang'
|
|
413
|
+
| 'swift'
|
|
414
|
+
| 'systemd'
|
|
415
|
+
| 'tact'
|
|
416
|
+
| 't4-templating'
|
|
417
|
+
| 't4-cs'
|
|
418
|
+
| 't4'
|
|
419
|
+
| 'vbnet'
|
|
420
|
+
| 't4-vb'
|
|
421
|
+
| 'tap'
|
|
422
|
+
| 'tcl'
|
|
423
|
+
| 'tt2'
|
|
424
|
+
| 'toml'
|
|
425
|
+
| 'ttcn'
|
|
426
|
+
| 'ttcn3'
|
|
427
|
+
| 'ttcn-3'
|
|
428
|
+
| 'turtle'
|
|
429
|
+
| 'trickle'
|
|
430
|
+
| 'typescript-jsdoc'
|
|
431
|
+
| 'typoscript'
|
|
432
|
+
| 'tsconfig'
|
|
433
|
+
| 'unrealscript'
|
|
434
|
+
| 'uscript'
|
|
435
|
+
| 'uc'
|
|
436
|
+
| 'uri'
|
|
437
|
+
| 'v'
|
|
438
|
+
| 'vala'
|
|
439
|
+
| 'vba'
|
|
440
|
+
| 'vbscript'
|
|
441
|
+
| 'velocity'
|
|
442
|
+
| 'verilog'
|
|
443
|
+
| 'vhdl'
|
|
444
|
+
| 'vim'
|
|
445
|
+
| 'visual-basic'
|
|
446
|
+
| 'vb'
|
|
447
|
+
| 'warpscript'
|
|
448
|
+
| 'wasm'
|
|
449
|
+
| 'web-idl'
|
|
450
|
+
| 'webidl'
|
|
451
|
+
| 'wgsl'
|
|
452
|
+
| 'wiki'
|
|
453
|
+
| 'wolfram'
|
|
454
|
+
| 'mathematica'
|
|
455
|
+
| 'nb'
|
|
456
|
+
| 'wl'
|
|
457
|
+
| 'xeora'
|
|
458
|
+
| 'xeoracube'
|
|
459
|
+
| 'xml-doc'
|
|
460
|
+
| 'xojo'
|
|
461
|
+
| 'xquery'
|
|
462
|
+
| 'yaml'
|
|
463
|
+
| 'yml'
|
|
464
|
+
| 'yang'
|
|
465
|
+
| 'zig'
|
|
466
|
+
}>
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Block quotation. Can be expandable or not.
|
|
470
|
+
*/
|
|
471
|
+
blockquote: PropsWithChildren<{
|
|
472
|
+
expandable?: boolean
|
|
473
|
+
}>
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
export type TgxNode
|
|
477
|
+
= | TgxNode[]
|
|
478
|
+
| TgxElement
|
|
479
|
+
| string
|
|
480
|
+
| number
|
|
481
|
+
| boolean
|
|
482
|
+
| null
|
|
483
|
+
| undefined
|
|
484
|
+
|
|
485
|
+
export type PropsWithChildren<P = {}> = P & { children?: TgxNode }
|
|
486
|
+
|
|
487
|
+
export type Component = (props: any) => TgxElement
|
|
488
|
+
|
|
489
|
+
export type TgxElement
|
|
490
|
+
= | TgxElementPlain
|
|
491
|
+
| TgxElementFragment
|
|
492
|
+
| TgxElementText
|
|
493
|
+
|
|
494
|
+
export interface TgxElementPlain {
|
|
495
|
+
type: 'plain'
|
|
496
|
+
value: string | number | boolean | null | undefined
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
export interface TgxElementFragment {
|
|
500
|
+
type: 'fragment'
|
|
501
|
+
subelements: TgxElement[]
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
export interface TgxElementText {
|
|
505
|
+
type: 'text'
|
|
506
|
+
entity: TextEntity
|
|
507
|
+
subelements: TgxElement[]
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
export type TextEntity
|
|
511
|
+
= | { type: 'bold' }
|
|
512
|
+
| { type: 'italic' }
|
|
513
|
+
| { type: 'underline' }
|
|
514
|
+
| { type: 'strikethrough' }
|
|
515
|
+
| { type: 'spoiler' }
|
|
516
|
+
| { type: 'link', url: string }
|
|
517
|
+
| { type: 'custom-emoji', id: string, alt: string }
|
|
518
|
+
| { type: 'code' }
|
|
519
|
+
| { type: 'codeblock', language?: string }
|
|
520
|
+
| { type: 'blockquote', expandable: boolean }
|
package/dist/_utils/types.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export type StringWithSuggestions<S extends string> = S | (string & {});
|
|
2
|
-
/**
|
|
3
|
-
* Aliases of all languages that are supported by [libprisma](https://github.com/TelegramMessenger/libprisma)
|
|
4
|
-
* (library that Telegram uses for highlighting syntax of code blocks).
|
|
5
|
-
*/
|
|
6
|
-
export type PrismLanguage = 'markup' | 'html' | 'xml' | 'svg' | 'mathml' | 'ssml' | 'atom' | 'rss' | 'css' | 'clike' | 'regex' | 'javascript' | 'js' | 'abap' | 'abnf' | 'actionscript' | 'ada' | 'agda' | 'al' | 'antlr4' | 'g4' | 'apacheconf' | 'sql' | 'apex' | 'apl' | 'applescript' | 'aql' | 'c' | 'cpp' | 'arduino' | 'ino' | 'arff' | 'armasm' | 'arm-asm' | 'bash' | 'sh' | 'shell' | 'yaml' | 'yml' | 'markdown' | 'md' | 'arturo' | 'art' | 'asciidoc' | 'adoc' | 'csharp' | 'cs' | 'dotnet' | 'aspnet' | 'asm6502' | 'asmatmel' | 'autohotkey' | 'autoit' | 'avisynth' | 'avs' | 'avro-idl' | 'avdl' | 'awk' | 'gawk' | 'basic' | 'batch' | 'bbcode' | 'shortcode' | 'bbj' | 'bicep' | 'birb' | 'bison' | 'bnf' | 'rbnf' | 'bqn' | 'brainfuck' | 'brightscript' | 'bro' | 'cfscript' | 'cfc' | 'chaiscript' | 'cil' | 'cilkc' | 'cilk-c' | 'cilkcpp' | 'cilk-cpp' | 'cilk' | 'clojure' | 'cmake' | 'cobol' | 'coffeescript' | 'coffee' | 'concurnas' | 'conc' | 'csp' | 'cooklang' | 'ruby' | 'rb' | 'crystal' | 'csv' | 'cue' | 'cypher' | 'd' | 'dart' | 'dataweave' | 'dax' | 'dhall' | 'diff' | 'markup-templating' | 'django' | 'jinja2' | 'dns-zone-file' | 'dns-zone' | 'docker' | 'dockerfile' | 'dot' | 'gv' | 'ebnf' | 'editorconfig' | 'eiffel' | 'ejs' | 'eta' | 'elixir' | 'elm' | 'lua' | 'etlua' | 'erb' | 'erlang' | 'excel-formula' | 'xlsx' | 'xls' | 'fsharp' | 'factor' | 'false' | 'fift' | 'firestore-security-rules' | 'flow' | 'fortran' | 'ftl' | 'func' | 'gml' | 'gamemakerlanguage' | 'gap' | 'gcode' | 'gdscript' | 'gedcom' | 'gettext' | 'po' | 'git' | 'glsl' | 'gn' | 'gni' | 'linker-script' | 'ld' | 'go' | 'go-module' | 'go-mod' | 'gradle' | 'graphql' | 'groovy' | 'less' | 'scss' | 'textile' | 'haml' | 'handlebars' | 'hbs' | 'mustache' | 'haskell' | 'hs' | 'haxe' | 'hcl' | 'hlsl' | 'hoon' | 'hpkp' | 'hsts' | 'json' | 'webmanifest' | 'uri' | 'url' | 'http' | 'ichigojam' | 'icon' | 'icu-message-format' | 'idris' | 'idr' | 'ignore' | 'gitignore' | 'hgignore' | 'npmignore' | 'inform7' | 'ini' | 'io' | 'j' | 'java' | 'scala' | 'php' | 'javadoclike' | 'javadoc' | 'javastacktrace' | 'jolie' | 'jq' | 'typescript' | 'ts' | 'jsdoc' | 'n4js' | 'n4jsd' | 'json5' | 'jsonp' | 'jsstacktrace' | 'julia' | 'keepalived' | 'keyman' | 'kotlin' | 'kt' | 'kts' | 'kusto' | 'latex' | 'tex' | 'context' | 'latte' | 'scheme' | 'lilypond' | 'ly' | 'liquid' | 'lisp' | 'emacs' | 'elisp' | 'emacs-lisp' | 'livescript' | 'llvm' | 'log' | 'lolcode' | 'magma' | 'makefile' | 'mata' | 'matlab' | 'maxscript' | 'mel' | 'mermaid' | 'metafont' | 'mizar' | 'mongodb' | 'monkey' | 'moonscript' | 'moon' | 'n1ql' | 'nand2tetris-hdl' | 'naniscript' | 'nani' | 'nasm' | 'neon' | 'nevod' | 'nginx' | 'nim' | 'nix' | 'nsis' | 'objectivec' | 'objc' | 'ocaml' | 'odin' | 'opencl' | 'openqasm' | 'qasm' | 'oz' | 'parigp' | 'parser' | 'pascal' | 'objectpascal' | 'pascaligo' | 'psl' | 'pcaxis' | 'px' | 'peoplecode' | 'pcode' | 'perl' | 'phpdoc' | 'plant-uml' | 'plantuml' | 'plsql' | 'powerquery' | 'pq' | 'mscript' | 'powershell' | 'processing' | 'prolog' | 'promql' | 'properties' | 'protobuf' | 'stylus' | 'twig' | 'pug' | 'puppet' | 'purebasic' | 'pbfasm' | 'python' | 'py' | 'qsharp' | 'qs' | 'q' | 'qml' | 'qore' | 'r' | 'racket' | 'rkt' | 'cshtml' | 'razor' | 'jsx' | 'tsx' | 'reason' | 'rego' | 'renpy' | 'rpy' | 'rescript' | 'res' | 'rest' | 'rip' | 'roboconf' | 'robotframework' | 'robot' | 'rust' | 'sas' | 'sass' | 'shell-session' | 'sh-session' | 'shellsession' | 'smali' | 'smalltalk' | 'smarty' | 'sml' | 'smlnj' | 'solidity' | 'sol' | 'solution-file' | 'sln' | 'soy' | 'splunk-spl' | 'sqf' | 'squirrel' | 'stan' | 'stata' | 'iecst' | 'supercollider' | 'sclang' | 'swift' | 'systemd' | 'tact' | 't4-templating' | 't4-cs' | 't4' | 'vbnet' | 't4-vb' | 'tap' | 'tcl' | 'tt2' | 'toml' | 'ttcn' | 'ttcn3' | 'ttcn-3' | 'turtle' | 'trickle' | 'typescript-jsdoc' | 'typoscript' | 'tsconfig' | 'unrealscript' | 'uscript' | 'uc' | 'uri' | 'v' | 'vala' | 'vba' | 'vbscript' | 'velocity' | 'verilog' | 'vhdl' | 'vim' | 'visual-basic' | 'vb' | 'warpscript' | 'wasm' | 'web-idl' | 'webidl' | 'wgsl' | 'wiki' | 'wolfram' | 'mathematica' | 'nb' | 'wl' | 'xeora' | 'xeoracube' | 'xml-doc' | 'xojo' | 'xquery' | 'yaml' | 'yml' | 'yang' | 'zig';
|
package/dist/_utils/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/html.d.ts
DELETED
package/dist/html.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Converts {@link TgxElement} to an HTML string formatted for Telegram's
|
|
3
|
-
* HTML parse mode.
|
|
4
|
-
*/
|
|
5
|
-
export function html(tgx) {
|
|
6
|
-
return (Array.isArray(tgx) ? tgx : [tgx])
|
|
7
|
-
.map((el) => {
|
|
8
|
-
switch (el.type) {
|
|
9
|
-
case 'plain': return htmlTgxPlainElement(el);
|
|
10
|
-
case 'fragment': return html(el.subelements);
|
|
11
|
-
case 'text': return htmlTgxTextElement(el);
|
|
12
|
-
}
|
|
13
|
-
throw new Error(`Unknown element: ${el}.`);
|
|
14
|
-
})
|
|
15
|
-
.join('');
|
|
16
|
-
}
|
|
17
|
-
function htmlTgxPlainElement({ value }) {
|
|
18
|
-
if (value == null || typeof value === 'boolean')
|
|
19
|
-
return '';
|
|
20
|
-
return sanitize(String(value));
|
|
21
|
-
}
|
|
22
|
-
function htmlTgxTextElement(el) {
|
|
23
|
-
switch (el.entity.type) {
|
|
24
|
-
case 'bold': return `<b>${html(el.subelements)}</b>`;
|
|
25
|
-
case 'italic': return `<i>${html(el.subelements)}</i>`;
|
|
26
|
-
case 'underline': return `<u>${html(el.subelements)}</u>`;
|
|
27
|
-
case 'strikethrough': return `<s>${html(el.subelements)}</s>`;
|
|
28
|
-
case 'spoiler': return `<tg-spoiler>${html(el.subelements)}</tg-spoiler>`;
|
|
29
|
-
// TODO: Shouldn't we urlencode this?
|
|
30
|
-
case 'link': return `<a href="${el.entity.url}">${html(el.subelements)}</a>`;
|
|
31
|
-
case 'custom-emoji': return `<tg-emoji emoji-id="${el.entity.id}">${el.entity.alt}</tg-emoji>`;
|
|
32
|
-
case 'code': return `<code>${html(el.subelements)}</code>`;
|
|
33
|
-
case 'codeblock': return (el.entity.language
|
|
34
|
-
? `<pre><code class="language-${el.entity.language}">${html(el.subelements)}</code></pre>`
|
|
35
|
-
: `<pre>${html(el.subelements)}</pre>`);
|
|
36
|
-
case 'blockquote': return (el.entity.expandable
|
|
37
|
-
? `<blockquote expandable>${html(el.subelements)}</blockquote>`
|
|
38
|
-
: `<blockquote>${html(el.subelements)}</blockquote>`);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
function sanitize(unsafe) {
|
|
42
|
-
return unsafe
|
|
43
|
-
.replaceAll('&', '&') // must be first
|
|
44
|
-
.replaceAll('<', '<')
|
|
45
|
-
.replaceAll('>', '>');
|
|
46
|
-
}
|