@grom.js/tgx 0.5.2 → 1.0.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 CHANGED
@@ -1,5 +1,8 @@
1
1
  ![tgx](tgx.png)
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/%40grom.js%2Ftgx?style=flat&logo=npm&logoColor=%23BB443E&logoSize=auto&label=Latest&labelColor=%23fff&color=%23BB443E)](https://www.npmjs.com/package/@grom.js/tgx)
4
+ [![jsr](https://img.shields.io/jsr/v/%40grom/tgx?style=flat&logo=jsr&logoColor=%231B3646&logoSize=auto&label=Latest&labelColor=%23F3E051&color=%231B3646)](https://jsr.io/@grom/tgx)
5
+
3
6
  [JSX](https://facebook.github.io/jsx/) runtime for composing Telegram messages.
4
7
 
5
8
  ## Installation
@@ -8,7 +11,7 @@
8
11
  # Using npm
9
12
  npm install @grom.js/tgx
10
13
 
11
- # Using jsr
14
+ # Using JSR
12
15
  deno add jsr:@grom/tgx
13
16
  ```
14
17
 
@@ -18,29 +21,29 @@ Then in your `tsconfig.json`:
18
21
  {
19
22
  "compilerOptions": {
20
23
  "jsx": "react-jsx",
21
- "jsxImportSource": "@grom.js/tgx" // "@grom/tgx" for jsr
24
+ "jsxImportSource": "@grom.js/tgx" // "@grom/tgx" for JSR
22
25
  // ...
23
26
  }
24
27
  }
25
28
  ```
26
29
 
27
- ## Example
30
+ ## Examples
28
31
 
29
32
  Usage with [grammY](https://grammy.dev):
30
33
 
31
- ```tsx
32
- import { html } from '@grom.js/tgx'
34
+ ```jsx
33
35
  import { Bot } from 'grammy'
36
+ import { renderHtml } from '@grom.js/tgx'
34
37
 
35
- function Greeting(props: { name: string }) {
36
- return <>Hello, <b>{props.name}</b>!</>
37
- }
38
+ const Greeting = (props) => (
39
+ <>Hello, <b>{props.name}</b>!</>
40
+ )
38
41
 
39
42
  const bot = new Bot(/* TOKEN */)
40
43
 
41
44
  bot.command('start', async (ctx) => {
42
45
  await ctx.reply(
43
- html(<Greeting name={ctx.from.first_name} />),
46
+ renderHtml(<Greeting name={ctx.from.first_name} />),
44
47
  { parse_mode: 'HTML' }
45
48
  )
46
49
  })
@@ -48,6 +51,21 @@ bot.command('start', async (ctx) => {
48
51
  bot.start()
49
52
  ```
50
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
+
51
69
  ## License
52
70
 
53
71
  [MIT](./LICENSE)
package/dist/index.d.ts CHANGED
@@ -1 +1,3 @@
1
- export { html } from './html.ts';
1
+ export * from './jsx.ts';
2
+ export * from './render.ts';
3
+ export * from './types.ts';
package/dist/index.js CHANGED
@@ -1 +1,4 @@
1
- export { html } from "./html.js";
1
+ export * from "./jsx.js";
2
+ export * from "./render.js";
3
+ export * from "./types.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA"}
@@ -1,17 +1,17 @@
1
- import type { FunctionComponent, NativeElements, TgxElement } from './types.ts';
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 NativeElements | FunctionComponent;
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 NativeElements {
14
+ interface IntrinsicElements extends Tgx.IntrinsicElements {
15
15
  }
16
16
  interface IntrinsicAttributes {
17
17
  }
@@ -1,10 +1,11 @@
1
- import { Fragment, render } from "./jsx.js";
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 render(type, props, children);
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 { FunctionComponent, NativeElements, TgxElement, TgxFragmentElement, TgxNode } from './types.ts';
2
- export declare function render<T extends keyof NativeElements>(type: T, props: NativeElements[T], children: TgxNode): TgxElement;
3
- export declare function render(type: FunctionComponent, props: any, children: TgxNode): TgxElement;
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
- }): TgxFragmentElement;
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 render(type, props, children) {
2
- if (typeof type === 'string' && isNativeTag(type)) {
3
- return renderNativeElement({
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
- function isNativeTag(tag) {
32
- return ([
33
- 'b',
34
- 'i',
35
- 'u',
36
- 's',
37
- 'spoiler',
38
- 'a',
39
- 'emoji',
40
- 'code',
41
- 'codeblock',
42
- 'blockquote',
43
- ]).includes(tag);
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 renderNativeElement(options) {
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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsx.js","sourceRoot":"","sources":["../src/jsx.ts"],"names":[],"mappings":"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"}
@@ -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('&', '&amp;') // must be first
44
+ .replaceAll('<', '&lt;')
45
+ .replaceAll('>', '&gt;');
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
- import type { PrismLanguage, StringWithSuggestions } from './_utils/types.ts';
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
- * Telegram uses libprisma for code highlighting,
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?: StringWithSuggestions<PrismLanguage>;
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
- } & P;
80
- export type FunctionComponent = (props: any) => TgxElement;
81
- export type TgxElement = TgxPlainValueElement | TgxFragmentElement | TgxTextElement;
82
- export interface TgxPlainValueElement {
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 TgxFragmentElement {
83
+ export interface TgxElementFragment {
87
84
  type: 'fragment';
88
85
  subelements: TgxElement[];
89
86
  }
90
- export interface TgxTextElement {
87
+ export interface TgxElementText {
91
88
  type: 'text';
92
89
  entity: TextEntity;
93
90
  subelements: TgxElement[];
package/dist/types.js CHANGED
@@ -1 +1,2 @@
1
1
  export {};
2
+ //# sourceMappingURL=types.js.map
@@ -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": "0.5.2",
4
+ "version": "1.0.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,7 +31,8 @@
34
31
  }
35
32
  },
36
33
  "files": [
37
- "./dist/"
34
+ "./dist/",
35
+ "./src/"
38
36
  ],
39
37
  "engines": {
40
38
  "node": "22.x"
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './jsx.ts'
2
+ export * from './render.ts'
3
+ export * from './types.ts'
@@ -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('&', '&amp;') // must be first
57
+ .replaceAll('<', '&lt;')
58
+ .replaceAll('>', '&gt;')
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 }
@@ -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';
@@ -1 +0,0 @@
1
- export {};
package/dist/html.d.ts DELETED
@@ -1,6 +0,0 @@
1
- import type { TgxElement } from './types.ts';
2
- /**
3
- * Converts {@link TgxElement} to an HTML string formatted for Telegram's
4
- * HTML parse mode.
5
- */
6
- export declare function html(tgx: TgxElement | TgxElement[]): string;
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('&', '&amp;') // must be first
44
- .replaceAll('<', '&lt;')
45
- .replaceAll('>', '&gt;');
46
- }