@traq-markdown-engine/sdk 0.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.
Files changed (52) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +193 -0
  3. package/THIRD_PARTY_NOTICES.md +51 -0
  4. package/dist/contract.json +18 -0
  5. package/dist/embedding.d.ts +5 -0
  6. package/dist/embedding.js +34 -0
  7. package/dist/generated/artifact.d.ts +2 -0
  8. package/dist/generated/artifact.js +3 -0
  9. package/dist/generated/nodes.d.ts +54 -0
  10. package/dist/generated/nodes.js +17 -0
  11. package/dist/generated/presets.d.ts +7 -0
  12. package/dist/generated/presets.js +4 -0
  13. package/dist/generated/processing.d.ts +48 -0
  14. package/dist/generated/processing.js +1 -0
  15. package/dist/index.css +965 -0
  16. package/dist/index.d.ts +24 -0
  17. package/dist/index.js +95 -0
  18. package/dist/parser.wasm +0 -0
  19. package/dist/renderer/condensed.d.ts +4 -0
  20. package/dist/renderer/condensed.js +73 -0
  21. package/dist/renderer/embeddings.d.ts +23 -0
  22. package/dist/renderer/embeddings.js +145 -0
  23. package/dist/renderer/image-domains.d.ts +2 -0
  24. package/dist/renderer/image-domains.js +11 -0
  25. package/dist/renderer/index.d.ts +27 -0
  26. package/dist/renderer/index.js +93 -0
  27. package/dist/renderer/links.d.ts +8 -0
  28. package/dist/renderer/links.js +16 -0
  29. package/package.json +84 -0
  30. package/styles/animation/_ascension.sass +34 -0
  31. package/styles/animation/_atsumori.sass +19 -0
  32. package/styles/animation/_attract.sass +19 -0
  33. package/styles/animation/_conga.sass +11 -0
  34. package/styles/animation/_flashy.sass +7 -0
  35. package/styles/animation/_happa.sass +15 -0
  36. package/styles/animation/_index.sass +18 -0
  37. package/styles/animation/_invert.sass +5 -0
  38. package/styles/animation/_parrot.sass +5 -0
  39. package/styles/animation/_party.sass +11 -0
  40. package/styles/animation/_pull.sass +9 -0
  41. package/styles/animation/_pyon.sass +9 -0
  42. package/styles/animation/_rainbow.sass +5 -0
  43. package/styles/animation/_rotate.sass +11 -0
  44. package/styles/animation/_shake.sass +9 -0
  45. package/styles/animation/_stretch.sass +47 -0
  46. package/styles/animation/_turn.sass +11 -0
  47. package/styles/animation/_wiggle.sass +23 -0
  48. package/styles/animation/_zoom.sass +9 -0
  49. package/styles/index.scss +3 -0
  50. package/styles/markdown.scss +377 -0
  51. package/styles/stamp.scss +32 -0
  52. package/styles/stampEffect.scss +102 -0
@@ -0,0 +1,24 @@
1
+ import type { Document } from './generated/nodes.js';
2
+ import type { Extraction, ExtractorOptions } from './generated/processing.js';
3
+ export type { ExtractorOptions, Extraction, References, EmbeddedInfo, EmbeddingPlan, EmbeddingCandidate, LookupKind } from './generated/processing.js';
4
+ export type { Preset } from './generated/presets.js';
5
+ export { presets } from './generated/presets.js';
6
+ export { isKnownNode } from './generated/nodes.js';
7
+ export type { Document, Node, NodeKind, ParseError } from './generated/nodes.js';
8
+ export interface Parser {
9
+ parse(source: string): Document;
10
+ parseInline(source: string): Document;
11
+ dispose(): void;
12
+ }
13
+ export interface Extractor {
14
+ extract(document: Document): Extraction;
15
+ dispose(): void;
16
+ }
17
+ export interface Runtime {
18
+ createParser(preset: string): Parser;
19
+ createExtractor(options: ExtractorOptions): Extractor;
20
+ dispose(): void;
21
+ }
22
+ /** Compile Wasm once; each Parser owns an independent instance and Rust preset. */
23
+ export declare function createRuntime(bytes: Uint8Array): Promise<Runtime>;
24
+ export { embedReferences, mentionsUser } from './embedding.js';
package/dist/index.js ADDED
@@ -0,0 +1,95 @@
1
+ import { buildId, inputBytes } from './generated/artifact.js';
2
+ export { presets } from './generated/presets.js';
3
+ export { isKnownNode } from './generated/nodes.js';
4
+ /** Compile Wasm once; each Parser owns an independent instance and Rust preset. */
5
+ export async function createRuntime(bytes) {
6
+ let module = await WebAssembly.compile(new Uint8Array(bytes).buffer);
7
+ const instances = new Set();
8
+ return Object.freeze({
9
+ createParser(preset) {
10
+ const instance = instantiate('configure', preset);
11
+ return Object.freeze({
12
+ parse: (source) => instance.call('parse', source),
13
+ parseInline: (source) => instance.call('parse', source, 1),
14
+ dispose: instance.dispose
15
+ });
16
+ },
17
+ createExtractor(options) {
18
+ const instance = instantiate('configure_extractor', JSON.stringify(options));
19
+ return Object.freeze({
20
+ extract: (document) => instance.call('extract', JSON.stringify(document)),
21
+ dispose: instance.dispose
22
+ });
23
+ },
24
+ dispose() {
25
+ module = undefined;
26
+ for (const instance of instances) {
27
+ instance.dispose();
28
+ }
29
+ }
30
+ });
31
+ function instantiate(configuration, config) {
32
+ if (!module) {
33
+ throw new Error('Runtime is disposed');
34
+ }
35
+ let wasm = new WebAssembly.Instance(module, {})
36
+ .exports;
37
+ const encoder = new TextEncoder(), decoder = new TextDecoder('utf-8', {
38
+ fatal: true,
39
+ ignoreBOM: true
40
+ });
41
+ function call(operation, source, mode = 0) {
42
+ if (!wasm) {
43
+ throw new Error('Instance is disposed');
44
+ }
45
+ if (typeof source !== 'string') {
46
+ throw new TypeError('Expected source string');
47
+ }
48
+ if (source.length > inputBytes) {
49
+ throw new RangeError('Wasm input limit exceeded');
50
+ }
51
+ const input = encoder.encode(source);
52
+ if (input.length > inputBytes) {
53
+ throw new RangeError('Wasm input limit exceeded');
54
+ }
55
+ if (decoder.decode(input) !== source) {
56
+ throw new TypeError('Source contains an unpaired surrogate');
57
+ }
58
+ const pointer = wasm.input_ptr(input.length);
59
+ if (!pointer) {
60
+ throw new RangeError('Wasm input limit exceeded');
61
+ }
62
+ let result;
63
+ try {
64
+ new Uint8Array(wasm.memory.buffer, pointer, input.length).set(input);
65
+ const length = wasm[operation](mode);
66
+ result = JSON.parse(decoder.decode(new Uint8Array(wasm.memory.buffer, wasm.output_ptr(), length)));
67
+ }
68
+ catch (error) {
69
+ wasm = undefined;
70
+ throw error;
71
+ }
72
+ // Rust validates the AST before encoding; the build ID pairs its types.
73
+ if (result.error) {
74
+ throw new Error('Markdown: ' + JSON.stringify(result.error), {
75
+ cause: result.error
76
+ });
77
+ }
78
+ if (operation.startsWith('configure') && result.configured !== buildId) {
79
+ throw new Error('Wasm does not match this SDK build');
80
+ }
81
+ return (result.result ?? result.document);
82
+ }
83
+ call(configuration, config);
84
+ const instance = Object.freeze({
85
+ call,
86
+ dispose() {
87
+ wasm = undefined;
88
+ instances.delete(instance);
89
+ }
90
+ });
91
+ instances.add(instance);
92
+ return instance;
93
+ }
94
+ }
95
+ export { embedReferences, mentionsUser } from './embedding.js';
Binary file
@@ -0,0 +1,4 @@
1
+ import type { Plugin } from '@traq-markdown-engine/core/renderer';
2
+ import type { Options } from './index.js';
3
+ /** A condensed traQ message is a flattened document, not inline-only parsing. */
4
+ export declare function configureCondensed(common: Plugin, generic: Plugin, trap: Plugin, options: Options): void;
@@ -0,0 +1,73 @@
1
+ import { names as genericNames, isKnownNode as genericNode } from '@traq-markdown-engine/commonmark-plugin/generic/nodes';
2
+ import { isKnownNode, names } from '@traq-markdown-engine/commonmark-plugin/nodes';
3
+ import { validateLink as defaultPolicy } from '@traq-markdown-engine/commonmark-plugin/policy';
4
+ import { attributes, checked, escapeHtml } from '@traq-markdown-engine/core/html';
5
+ import { names as trapNames, isKnownNode as trapNode } from '@traq-markdown-engine/traq-plugin/nodes';
6
+ const blocks = (nodes, ctx) => (nodes ?? []).map(node => ctx.render([node])).join(' ');
7
+ function configureCommonCondensed(common, options) {
8
+ for (const kind of [names.Softbreak, names.Hardbreak])
9
+ common.replace(kind, checked(kind, isKnownNode, () => ' '));
10
+ common.replace(names.Paragraph, checked(names.Paragraph, isKnownNode, (n, ctx) => ctx.render(n.children)));
11
+ common.replace(names.Heading, checked(names.Heading, isKnownNode, (n, ctx) => '#'.repeat(n.data.level) + ' ' + ctx.render(n.children)));
12
+ common.replace(names.Blockquote, checked(names.Blockquote, isKnownNode, (n, ctx) => '> ' + blocks(n.children, ctx)));
13
+ common.replace(names.List, checked(names.List, isKnownNode, (n, ctx) => {
14
+ let index = 0;
15
+ const children = n.data.ordered
16
+ ? (n.children ?? []).map(child => {
17
+ if (!isKnownNode(child) || child.kind !== names.ListItem) {
18
+ return child;
19
+ }
20
+ return {
21
+ ...child,
22
+ data: {
23
+ marker: `${n.data.start + index++}${child.data.marker.slice(-1)}`
24
+ }
25
+ };
26
+ })
27
+ : n.children;
28
+ return blocks(children, ctx);
29
+ }));
30
+ common.replace(names.ListItem, checked(names.ListItem, isKnownNode, (n, ctx) => n.data.marker + ' ' + blocks(n.children, ctx)));
31
+ common.replace(names.ThematicBreak, checked(names.ThematicBreak, isKnownNode, n => ' ' + escapeHtml(n.data.marker) + ' '));
32
+ common.replace(names.CodeBlock, checked(names.CodeBlock, isKnownNode, n => '<code>' + escapeHtml(n.data.literal) + '</code>'));
33
+ common.replace(names.HtmlBlock, checked(names.HtmlBlock, isKnownNode, n => escapeHtml(n.data.literal)));
34
+ common.replace(names.Image, checked(names.Image, isKnownNode, (n, _ctx) => {
35
+ const label = escapeHtml(n.data.label_source);
36
+ if (!(options.validateLink ?? defaultPolicy)(n.data.destination))
37
+ return label;
38
+ return ('<a' +
39
+ attributes([
40
+ ['href', n.data.destination],
41
+ ...(n.data.title === null
42
+ ? []
43
+ : [['title', n.data.title]])
44
+ ]) +
45
+ ' data-is-image>' +
46
+ label +
47
+ '</a>');
48
+ }));
49
+ }
50
+ function configureGenericCondensed(generic) {
51
+ generic.replace(genericNames.Table, checked(genericNames.Table, genericNode, (n, ctx) => (n.children ?? [])
52
+ .map(row => {
53
+ if (!genericNode(row) || row.kind !== genericNames.Row)
54
+ throw new TypeError('Invalid table row');
55
+ return ((row.children ?? [])
56
+ .map(cell => {
57
+ if (!genericNode(cell) || cell.kind !== genericNames.Cell)
58
+ throw new TypeError('Invalid table cell');
59
+ return '| ' + ctx.render(cell.children);
60
+ })
61
+ .join(' ') + ' |');
62
+ })
63
+ .join(' ')));
64
+ }
65
+ function configureTrapCondensed(trap) {
66
+ trap.replace(trapNames.BlankLine, checked(trapNames.BlankLine, trapNode, () => ' '));
67
+ }
68
+ /** A condensed traQ message is a flattened document, not inline-only parsing. */
69
+ export function configureCondensed(common, generic, trap, options) {
70
+ configureCommonCondensed(common, options);
71
+ configureGenericCondensed(generic);
72
+ configureTrapCondensed(trap);
73
+ }
@@ -0,0 +1,23 @@
1
+ import type { Document, Node } from '@traq-markdown-engine/core/renderer';
2
+ export type Embedding = {
3
+ type: 'file';
4
+ id: string;
5
+ } | {
6
+ type: 'message';
7
+ id: string;
8
+ } | {
9
+ type: 'url';
10
+ url: string;
11
+ };
12
+ /** traQ links describe cards; external links describe OGP candidates. */
13
+ export declare function embeddingFromUrl(value: string, origin: string): Embedding | undefined;
14
+ /** Does not mutate the parser's document; both presentations can reuse it. */
15
+ export declare function prepareMessage(document: Document, origin: string, condensed: boolean): {
16
+ document: {
17
+ source: string;
18
+ children: Node[];
19
+ };
20
+ embeddings: Embedding[];
21
+ };
22
+ /** Whether the final paragraph ends with an embedding on a line of its own. */
23
+ export declare function endsWithEmbedding(document: Document, origin: string): boolean;
@@ -0,0 +1,145 @@
1
+ import { isKnownNode, names } from '@traq-markdown-engine/commonmark-plugin/nodes';
2
+ import { names as trap } from '@traq-markdown-engine/traq-plugin/nodes';
3
+ import { classifyTraqLink } from './links.js';
4
+ /** traQ links describe cards; external links describe OGP candidates. */
5
+ export function embeddingFromUrl(value, origin) {
6
+ let url;
7
+ try {
8
+ url = new URL(value);
9
+ }
10
+ catch {
11
+ return;
12
+ }
13
+ if (url.protocol !== 'http:' && url.protocol !== 'https:')
14
+ return;
15
+ const target = classifyTraqLink(value, origin);
16
+ if (target)
17
+ return target;
18
+ if (url.origin !== origin)
19
+ return { type: 'url', url: value };
20
+ }
21
+ function collectEmbeddings(nodes, origin, state, ids) {
22
+ for (const node of nodes) {
23
+ if (node.kind === trap.Spoiler)
24
+ continue;
25
+ if (isKnownNode(node) && node.kind === names.Link) {
26
+ const embedding = embeddingFromUrl(node.data.destination, origin);
27
+ if (embedding) {
28
+ state.links.set(node, embedding);
29
+ if (embedding.type === 'url' || !ids.has(embedding.id)) {
30
+ state.embeddings.push(embedding);
31
+ if (embedding.type !== 'url')
32
+ ids.add(embedding.id);
33
+ }
34
+ }
35
+ }
36
+ if (node.children)
37
+ collectEmbeddings(node.children, origin, state, ids);
38
+ }
39
+ }
40
+ function trimTrailingEmbeddings(children, links) {
41
+ const result = children.slice();
42
+ let last = result.length - 1;
43
+ while (result[last]?.kind === trap.BlankLine)
44
+ last--;
45
+ const paragraph = result[last];
46
+ if (paragraph?.kind !== names.Paragraph || !paragraph.children)
47
+ return result;
48
+ let end = paragraph.children.length - 1;
49
+ let removed = false;
50
+ while (end >= 0) {
51
+ const node = paragraph.children[end];
52
+ const embedding = links.get(node);
53
+ if (node.kind === names.Softbreak) {
54
+ end--;
55
+ continue;
56
+ }
57
+ if (embedding &&
58
+ embedding.type !== 'url' &&
59
+ isKnownNode(node) &&
60
+ node.kind === names.Link &&
61
+ node.data.form === 'linkify') {
62
+ removed = true;
63
+ end--;
64
+ continue;
65
+ }
66
+ break;
67
+ }
68
+ if (removed) {
69
+ result[last] = {
70
+ ...paragraph,
71
+ children: paragraph.children.slice(0, end + 1)
72
+ };
73
+ result.length = last + 1;
74
+ }
75
+ return result;
76
+ }
77
+ function replaceEmbeddingLabels(nodes, links) {
78
+ return nodes.map(node => {
79
+ const embedding = links.get(node);
80
+ if (embedding &&
81
+ (embedding.type === 'file' ||
82
+ (embedding.type === 'message' &&
83
+ isKnownNode(node) &&
84
+ node.kind === names.Link &&
85
+ node.data.form === 'linkify'))) {
86
+ return {
87
+ ...node,
88
+ children: [
89
+ {
90
+ kind: names.Text,
91
+ span: node.span,
92
+ data: {
93
+ value: embedding.type === 'file'
94
+ ? '[[添付ファイル]]'
95
+ : '[[引用メッセージ]]'
96
+ }
97
+ }
98
+ ]
99
+ };
100
+ }
101
+ return node.children
102
+ ? {
103
+ ...node,
104
+ children: replaceEmbeddingLabels(node.children, links)
105
+ }
106
+ : node;
107
+ });
108
+ }
109
+ /** Does not mutate the parser's document; both presentations can reuse it. */
110
+ export function prepareMessage(document, origin, condensed) {
111
+ const state = {
112
+ links: new Map(),
113
+ embeddings: []
114
+ };
115
+ collectEmbeddings(document.children, origin, state, new Set());
116
+ const children = trimTrailingEmbeddings(document.children, state.links);
117
+ const renderedChildren = condensed
118
+ ? replaceEmbeddingLabels(children, state.links)
119
+ : children;
120
+ return {
121
+ document: { ...document, children: renderedChildren },
122
+ embeddings: state.embeddings
123
+ };
124
+ }
125
+ /** Whether the final paragraph ends with an embedding on a line of its own. */
126
+ export function endsWithEmbedding(document, origin) {
127
+ const blocks = document.children.filter(node => node.kind !== trap.BlankLine);
128
+ const paragraph = blocks.at(-1);
129
+ if (paragraph?.kind !== names.Paragraph) {
130
+ return false;
131
+ }
132
+ const children = paragraph.children ?? [];
133
+ const last = children.at(-1);
134
+ const previous = children.at(-2);
135
+ if (!last ||
136
+ !isKnownNode(last) ||
137
+ last.kind !== names.Link ||
138
+ last.data.form !== 'linkify') {
139
+ return false;
140
+ }
141
+ if (previous && previous.kind !== names.Softbreak) {
142
+ return false;
143
+ }
144
+ return embeddingFromUrl(last.data.destination, origin) !== undefined;
145
+ }
@@ -0,0 +1,2 @@
1
+ declare const _default: string[];
2
+ export default _default;
@@ -0,0 +1,11 @@
1
+ export default [
2
+ 'libra.tokyotech.org',
3
+ 'user-images.githubusercontent.com',
4
+ 'git.trap.jp',
5
+ 'wiki.trapti.tech',
6
+ 'wiki.trap.jp',
7
+ 'md.trapti.tech',
8
+ 'md.trap.jp',
9
+ 'trap.jp',
10
+ 'traq-dev.tokyotech.org'
11
+ ];
@@ -0,0 +1,27 @@
1
+ import type { Options as GenericOptions } from '@traq-markdown-engine/commonmark-plugin/generic/renderer';
2
+ import type { Options as CommonOptions } from '@traq-markdown-engine/commonmark-plugin/renderer';
3
+ import type { Document } from '@traq-markdown-engine/core/renderer';
4
+ import type { Options as TrapOptions } from '@traq-markdown-engine/traq-plugin/renderer';
5
+ export { embeddingFromUrl, endsWithEmbedding } from './embeddings.js';
6
+ export type { Embedding } from './embeddings.js';
7
+ export type Options = CommonOptions & GenericOptions & TrapOptions;
8
+ export declare function html(options?: Options): import("@traq-markdown-engine/core/renderer").Preset;
9
+ /** Build standard and condensed message renderers from the same options. */
10
+ export declare function messageRenderers({ origin, ...options }: Options & {
11
+ origin: string;
12
+ }): Readonly<{
13
+ standard: Readonly<{
14
+ render(document: Document): {
15
+ rawText: string;
16
+ renderedText: string;
17
+ embeddings: import("./embeddings.js").Embedding[];
18
+ };
19
+ }>;
20
+ condensed: Readonly<{
21
+ render(document: Document): {
22
+ rawText: string;
23
+ renderedText: string;
24
+ embeddings: import("./embeddings.js").Embedding[];
25
+ };
26
+ }>;
27
+ }>;
@@ -0,0 +1,93 @@
1
+ import { math } from '@traq-markdown-engine/commonmark-plugin/generic/math';
2
+ import { plugin as generic } from '@traq-markdown-engine/commonmark-plugin/generic/renderer';
3
+ import { createHighlightFunc } from '@traq-markdown-engine/commonmark-plugin/highlight';
4
+ import { plugin as common } from '@traq-markdown-engine/commonmark-plugin/renderer';
5
+ import { PresetBuilder } from '@traq-markdown-engine/core/renderer';
6
+ import { renderer } from '@traq-markdown-engine/core/renderer';
7
+ import { plugin as trap } from '@traq-markdown-engine/traq-plugin/renderer';
8
+ import { configureCondensed } from './condensed.js';
9
+ import { prepareMessage } from './embeddings.js';
10
+ import imageDomains from './image-domains.js';
11
+ export { embeddingFromUrl, endsWithEmbedding } from './embeddings.js';
12
+ const highlight = createHighlightFunc('traq-code traq-lang');
13
+ const validateImage = (value) => {
14
+ try {
15
+ const url = new URL(value);
16
+ return url.protocol === 'https:' && imageDomains.includes(url.hostname);
17
+ }
18
+ catch {
19
+ return false;
20
+ }
21
+ };
22
+ function condensedOptions(options) {
23
+ const customMath = options.math;
24
+ return {
25
+ ...options,
26
+ math: customMath
27
+ ? (tex) => customMath(tex, false)
28
+ : (tex) => math(tex, false, {
29
+ maxSize: 1,
30
+ macros: {
31
+ '\\Huge': '',
32
+ '\\huge': '',
33
+ '\\LARGE': '',
34
+ '\\Large': '',
35
+ '\\large': ''
36
+ }
37
+ })
38
+ };
39
+ }
40
+ function build(options = {}, condensed = false) {
41
+ const commonPlugin = common({
42
+ breaks: true,
43
+ highlight,
44
+ validateImage,
45
+ linkAttributes: {
46
+ target: '_blank',
47
+ rel: 'nofollow noopener noreferrer'
48
+ },
49
+ ...options
50
+ });
51
+ const genericPlugin = generic(condensed ? condensedOptions(options) : options);
52
+ const trapPlugin = trap(options);
53
+ if (condensed) {
54
+ configureCondensed(commonPlugin, genericPlugin, trapPlugin, options);
55
+ }
56
+ return new PresetBuilder()
57
+ .add(commonPlugin)
58
+ .add(genericPlugin)
59
+ .add(trapPlugin)
60
+ .build();
61
+ }
62
+ export function html(options) {
63
+ return build(options);
64
+ }
65
+ /** Build standard and condensed message renderers from the same options. */
66
+ export function messageRenderers({ origin, ...options }) {
67
+ const embeddingOrigin = new URL(origin).origin;
68
+ function create(condensed) {
69
+ const view = renderer(build(options, condensed));
70
+ return Object.freeze({
71
+ render(document) {
72
+ const prepared = prepareMessage(document, embeddingOrigin, condensed);
73
+ const renderedText = condensed
74
+ ? prepared.document.children
75
+ .map(node => view.render({
76
+ ...prepared.document,
77
+ children: [node]
78
+ }))
79
+ .join(' ')
80
+ : view.render(prepared.document);
81
+ return {
82
+ rawText: document.source,
83
+ renderedText,
84
+ embeddings: prepared.embeddings
85
+ };
86
+ }
87
+ });
88
+ }
89
+ return Object.freeze({
90
+ standard: create(false),
91
+ condensed: create(true)
92
+ });
93
+ }
@@ -0,0 +1,8 @@
1
+ export type TraqLink = {
2
+ type: 'file' | 'message';
3
+ id: string;
4
+ };
5
+ /** Shared lexical policy with Rust processing/links.rs; no URL normalization.
6
+ * Only the configured origin and an exact UUID path identify a traQ resource.
7
+ */
8
+ export declare function classifyTraqLink(value: string, origin: string): TraqLink | undefined;
@@ -0,0 +1,16 @@
1
+ /** Shared lexical policy with Rust processing/links.rs; no URL normalization.
2
+ * Only the configured origin and an exact UUID path identify a traQ resource.
3
+ */
4
+ export function classifyTraqLink(value, origin) {
5
+ const base = origin.replace(/\/+$/, '');
6
+ if (!base || !value.startsWith(base))
7
+ return;
8
+ const path = value.slice(base.length).split(/[?#]/, 1)[0];
9
+ const match = /^\/(files|messages)\/([\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12})$/.exec(path);
10
+ if (!match || match[0] !== path)
11
+ return;
12
+ return {
13
+ type: match[1] === 'files' ? 'file' : 'message',
14
+ id: match[2].toLowerCase()
15
+ };
16
+ }
package/package.json ADDED
@@ -0,0 +1,84 @@
1
+ {
2
+ "name": "@traq-markdown-engine/sdk",
3
+ "version": "0.1.0",
4
+ "description": "traQ Markdown presets and processing, distributed as Rust, Wasm, Go and TypeScript.",
5
+ "homepage": "https://github.com/uni-kakurenbo/traq-markdown-engine#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/uni-kakurenbo/traq-markdown-engine/issues"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/uni-kakurenbo/traq-markdown-engine.git",
12
+ "directory": "packages/sdk"
13
+ },
14
+ "license": "MIT",
15
+ "publishConfig": {
16
+ "access": "public",
17
+ "registry": "https://registry.npmjs.org"
18
+ },
19
+ "author": "traP (https://github.com/traPtitech)",
20
+ "sideEffects": [
21
+ "./dist/index.css"
22
+ ],
23
+ "type": "module",
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "import": "./dist/index.js"
28
+ },
29
+ "./nodes": {
30
+ "types": "./dist/generated/nodes.d.ts",
31
+ "import": "./dist/generated/nodes.js"
32
+ },
33
+ "./parser.wasm": "./dist/parser.wasm",
34
+ "./contract.json": "./dist/contract.json",
35
+ "./renderer": {
36
+ "types": "./dist/renderer/index.d.ts",
37
+ "import": "./dist/renderer/index.js"
38
+ },
39
+ "./index.css": "./dist/index.css",
40
+ "./styles/*": "./styles/*.scss"
41
+ },
42
+ "files": [
43
+ "dist/index.js",
44
+ "dist/index.d.ts",
45
+ "dist/embedding.js",
46
+ "dist/embedding.d.ts",
47
+ "dist/generated",
48
+ "dist/parser.wasm",
49
+ "dist/contract.json",
50
+ "THIRD_PARTY_NOTICES.md",
51
+ "dist/renderer",
52
+ "dist/index.css",
53
+ "LICENSE",
54
+ "styles"
55
+ ],
56
+ "scripts": {
57
+ "build": "bun run scripts/build.ts",
58
+ "build:renderer": "sass --no-source-map styles/index.scss dist/index.css",
59
+ "build:ts": "bun run ../../scripts/tsc.ts -p typescript/tsconfig.build.json",
60
+ "example:go": "go -C examples/go run .",
61
+ "example:rust": "cargo run -p traq-markdown-example && cargo run -p traq-markdown-grammar --example parse && cargo run -p traq-markdown-processing --example notification && cargo run -p traq-markdown-processing --example compose-text",
62
+ "example:ts": "bun run examples/typescript/main.ts",
63
+ "examples": "bun run example:rust && bun run example:go && bun run example:ts",
64
+ "generate:bindings": "bun run scripts/generate-bindings.ts",
65
+ "test": "bun test ./typescript/tests",
66
+ "test:go": "go -C go test -count=1 ./...",
67
+ "typecheck": "bun run ../../scripts/tsc.ts -p typescript/tsconfig.json && bun run ../../scripts/tsc.ts -p examples/typescript/tsconfig.json"
68
+ },
69
+ "devDependencies": {
70
+ "@traq-markdown-engine/commonmark-plugin": "workspace:*",
71
+ "@traq-markdown-engine/core": "workspace:*",
72
+ "@traq-markdown-engine/traq-plugin": "workspace:*",
73
+ "markdown-it": "15.0.1",
74
+ "sass": "1.103.1"
75
+ },
76
+ "peerDependencies": {
77
+ "@traq-markdown-engine/commonmark-plugin": "0.1.0",
78
+ "@traq-markdown-engine/core": "0.1.0",
79
+ "@traq-markdown-engine/traq-plugin": "0.1.0"
80
+ },
81
+ "engines": {
82
+ "node": ">=24"
83
+ }
84
+ }
@@ -0,0 +1,34 @@
1
+ @keyframes ascension
2
+ 0%
3
+ filter: blur(0) drop-shadow(0 0.2em 0.2em #e3df62) saturate(1)
4
+ transform: translateY(0px)
5
+ 10%
6
+ filter: blur(0) drop-shadow(0 0.2em 0.3em #e3df62) saturate(1)
7
+ transform: translateY(-0.02em)
8
+ 20%
9
+ filter: blur(0) drop-shadow(0 0.2em 0.4em #e3df62) saturate(1)
10
+ transform: translateY(-0.04em)
11
+ 30%
12
+ filter: blur(0) drop-shadow(0 0.2em 0.5em #e3df62) saturate(0.9)
13
+ transform: translateY(-0.06em)
14
+ 40%
15
+ filter: blur(0) drop-shadow(0 0.2em 0.5em #e3df62) saturate(0.8)
16
+ transform: translateY(-0.08em)
17
+ 50%
18
+ filter: blur(0) drop-shadow(0 0.2em 0.5em #e3df62) saturate(0.7)
19
+ transform: translateY(-0.1em)
20
+ 60%
21
+ filter: blur(0.2em) drop-shadow(0 0.2em 0.5em #e3df62) saturate(0.6)
22
+ transform: translateY(-0.12em) scale(0.8)
23
+ 70%
24
+ filter: blur(0.4em) drop-shadow(0 0.2em 0.5em #e3df62) saturate(0.5)
25
+ transform: translateY(-0.14em) scale(0.6)
26
+ 80%
27
+ filter: blur(0.6em) drop-shadow(0 0.2em 0.5em #e3df62) saturate(0.4)
28
+ transform: translateY(-0.16em) scale(0.4)
29
+ 90%
30
+ filter: blur(0.8em) drop-shadow(0 0.2em 0.5em #e3df62) saturate(0.3)
31
+ transform: translateY(-0.18em) scale(0.2)
32
+ 100%
33
+ filter: blur(1em) drop-shadow(0 0.2em 0.5em #e3df62) saturate(0.3)
34
+ transform: translateY(-0.2em) scale(0)