@humanspeak/svelte-markdown 0.6.0 → 0.6.8
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 +45 -38
- package/dist/Parser.svelte +12 -7
- package/dist/SvelteMarkdown.svelte +10 -8
- package/dist/SvelteMarkdown.svelte.d.ts +1 -1
- package/dist/renderers/Blockquote.svelte.d.ts +3 -2
- package/dist/renderers/Br.svelte.d.ts +3 -2
- package/dist/renderers/Code.svelte.d.ts +3 -2
- package/dist/renderers/Codespan.svelte.d.ts +3 -2
- package/dist/renderers/Del.svelte.d.ts +3 -2
- package/dist/renderers/Em.svelte.d.ts +3 -2
- package/dist/renderers/Heading.svelte.d.ts +3 -2
- package/dist/renderers/Image.svelte.d.ts +3 -2
- package/dist/renderers/Link.svelte.d.ts +3 -2
- package/dist/renderers/List.svelte.d.ts +3 -2
- package/dist/renderers/ListItem.svelte.d.ts +3 -2
- package/dist/renderers/Paragraph.svelte.d.ts +3 -2
- package/dist/renderers/Strong.svelte.d.ts +3 -2
- package/dist/renderers/Table.svelte.d.ts +3 -2
- package/dist/renderers/TableBody.svelte.d.ts +3 -2
- package/dist/renderers/TableCell.svelte.d.ts +4 -3
- package/dist/renderers/TableHead.svelte.d.ts +3 -2
- package/dist/renderers/TableRow.svelte.d.ts +3 -2
- package/dist/renderers/Text.svelte.d.ts +3 -2
- package/dist/renderers/html/A.svelte +1 -1
- package/dist/renderers/html/Abbr.svelte +1 -1
- package/dist/renderers/html/Address.svelte +1 -1
- package/dist/renderers/html/Article.svelte +1 -1
- package/dist/renderers/html/Aside.svelte +1 -1
- package/dist/renderers/html/Audio.svelte +1 -1
- package/dist/renderers/html/B.svelte +1 -1
- package/dist/renderers/html/Bdi.svelte +1 -1
- package/dist/renderers/html/Bdo.svelte +1 -1
- package/dist/renderers/html/Blockquote.svelte +1 -1
- package/dist/renderers/html/Button.svelte +1 -1
- package/dist/renderers/html/Canvas.svelte +1 -1
- package/dist/renderers/html/Cite.svelte +1 -1
- package/dist/renderers/html/Code.svelte +1 -1
- package/dist/renderers/html/Datalist.svelte +1 -1
- package/dist/renderers/html/Dd.svelte +1 -1
- package/dist/renderers/html/Del.svelte +1 -1
- package/dist/renderers/html/Details.svelte +1 -1
- package/dist/renderers/html/Dfn.svelte +1 -1
- package/dist/renderers/html/Dialog.svelte +1 -1
- package/dist/renderers/html/Div.svelte +1 -1
- package/dist/renderers/html/Dl.svelte +1 -1
- package/dist/renderers/html/Dt.svelte +1 -1
- package/dist/renderers/html/Em.svelte +1 -1
- package/dist/renderers/html/Embed.svelte +1 -1
- package/dist/renderers/html/Fieldset.svelte +1 -1
- package/dist/renderers/html/Footer.svelte +1 -1
- package/dist/renderers/html/Form.svelte +1 -1
- package/dist/renderers/html/H1.svelte +1 -1
- package/dist/renderers/html/H2.svelte +1 -1
- package/dist/renderers/html/H3.svelte +1 -1
- package/dist/renderers/html/H4.svelte +1 -1
- package/dist/renderers/html/H5.svelte +1 -1
- package/dist/renderers/html/H6.svelte +1 -1
- package/dist/renderers/html/Header.svelte +1 -1
- package/dist/renderers/html/Hgroup.svelte +1 -1
- package/dist/renderers/html/Hr.svelte +1 -3
- package/dist/renderers/html/I.svelte +1 -1
- package/dist/renderers/html/Iframe.svelte +1 -1
- package/dist/renderers/html/Img.svelte +1 -3
- package/dist/renderers/html/Input.svelte +1 -1
- package/dist/renderers/html/Kbd.svelte +1 -1
- package/dist/renderers/html/Label.svelte +1 -1
- package/dist/renderers/html/Legend.svelte +1 -1
- package/dist/renderers/html/Li.svelte +1 -1
- package/dist/renderers/html/Main.svelte +1 -1
- package/dist/renderers/html/Mark.svelte +1 -1
- package/dist/renderers/html/Menu.svelte +1 -1
- package/dist/renderers/html/Meter.svelte +1 -1
- package/dist/renderers/html/Nav.svelte +1 -1
- package/dist/renderers/html/Ol.svelte +1 -1
- package/dist/renderers/html/Optgroup.svelte +1 -1
- package/dist/renderers/html/Option.svelte +1 -1
- package/dist/renderers/html/Output.svelte +1 -1
- package/dist/renderers/html/P.svelte +1 -1
- package/dist/renderers/html/Param.svelte +1 -1
- package/dist/renderers/html/Picture.svelte +1 -1
- package/dist/renderers/html/Pre.svelte +1 -1
- package/dist/renderers/html/Progress.svelte +1 -1
- package/dist/renderers/html/S.svelte +1 -1
- package/dist/renderers/html/Samp.svelte +1 -1
- package/dist/renderers/html/Section.svelte +1 -1
- package/dist/renderers/html/Select.svelte +1 -1
- package/dist/renderers/html/Small.svelte +1 -1
- package/dist/renderers/html/Source.svelte +1 -1
- package/dist/renderers/html/Span.svelte +1 -1
- package/dist/renderers/html/Strong.svelte +1 -1
- package/dist/renderers/html/Sub.svelte +1 -1
- package/dist/renderers/html/Summary.svelte +1 -1
- package/dist/renderers/html/Table.svelte +1 -1
- package/dist/renderers/html/Tbody.svelte +1 -1
- package/dist/renderers/html/Td.svelte +1 -1
- package/dist/renderers/html/Textarea.svelte +1 -3
- package/dist/renderers/html/Tfoot.svelte +1 -1
- package/dist/renderers/html/Th.svelte +1 -1
- package/dist/renderers/html/Thead.svelte +1 -1
- package/dist/renderers/html/Tr.svelte +1 -1
- package/dist/renderers/html/Track.svelte +1 -1
- package/dist/renderers/html/U.svelte +1 -1
- package/dist/renderers/html/Ul.svelte +1 -1
- package/dist/renderers/html/Var.svelte +1 -1
- package/dist/renderers/html/index.js +108 -2
- package/dist/utils/markdown-parser.d.ts +28 -3
- package/dist/utils/token-cleanup.d.ts +13 -2
- package/dist/utils/token-cleanup.js +191 -52
- package/package.json +24 -23
- package/dist/renderers/html/Object.svelte +0 -12
- package/dist/renderers/html/Object.svelte.d.ts +0 -7
- package/dist/renderers/html/Video.svelte +0 -12
- package/dist/renderers/html/Video.svelte.d.ts +0 -7
|
@@ -1,61 +1,167 @@
|
|
|
1
1
|
import A from './A.svelte';
|
|
2
|
+
import Abbr from './Abbr.svelte';
|
|
3
|
+
import Address from './Address.svelte';
|
|
4
|
+
import Article from './Article.svelte';
|
|
5
|
+
import Aside from './Aside.svelte';
|
|
6
|
+
import Audio from './Audio.svelte';
|
|
7
|
+
import B from './B.svelte';
|
|
8
|
+
import Bdi from './Bdi.svelte';
|
|
9
|
+
import Bdo from './Bdo.svelte';
|
|
2
10
|
import Blockquote from './Blockquote.svelte';
|
|
11
|
+
import Button from './Button.svelte';
|
|
12
|
+
import Canvas from './Canvas.svelte';
|
|
13
|
+
import Cite from './Cite.svelte';
|
|
3
14
|
import Code from './Code.svelte';
|
|
15
|
+
import Datalist from './Datalist.svelte';
|
|
16
|
+
import Dd from './Dd.svelte';
|
|
4
17
|
import Del from './Del.svelte';
|
|
18
|
+
import Details from './Details.svelte';
|
|
19
|
+
import Dfn from './Dfn.svelte';
|
|
20
|
+
import Dialog from './Dialog.svelte';
|
|
21
|
+
import Div from './Div.svelte';
|
|
22
|
+
import Dl from './Dl.svelte';
|
|
23
|
+
import Dt from './Dt.svelte';
|
|
5
24
|
import Em from './Em.svelte';
|
|
25
|
+
import Embed from './Embed.svelte';
|
|
26
|
+
import Fieldset from './Fieldset.svelte';
|
|
27
|
+
import Footer from './Footer.svelte';
|
|
28
|
+
import Form from './Form.svelte';
|
|
6
29
|
import H1 from './H1.svelte';
|
|
7
30
|
import H2 from './H2.svelte';
|
|
8
31
|
import H3 from './H3.svelte';
|
|
9
32
|
import H4 from './H4.svelte';
|
|
10
33
|
import H5 from './H5.svelte';
|
|
11
34
|
import H6 from './H6.svelte';
|
|
35
|
+
import Header from './Header.svelte';
|
|
36
|
+
import Hgroup from './Hgroup.svelte';
|
|
12
37
|
import Hr from './Hr.svelte';
|
|
13
38
|
import I from './I.svelte';
|
|
39
|
+
import Iframe from './Iframe.svelte';
|
|
14
40
|
import Img from './Img.svelte';
|
|
41
|
+
import Input from './Input.svelte';
|
|
42
|
+
import Kbd from './Kbd.svelte';
|
|
43
|
+
import Label from './Label.svelte';
|
|
44
|
+
import Legend from './Legend.svelte';
|
|
15
45
|
import Li from './Li.svelte';
|
|
46
|
+
import Main from './Main.svelte';
|
|
47
|
+
import Mark from './Mark.svelte';
|
|
48
|
+
import Menu from './Menu.svelte';
|
|
49
|
+
import Meter from './Meter.svelte';
|
|
50
|
+
import Nav from './Nav.svelte';
|
|
16
51
|
import Ol from './Ol.svelte';
|
|
52
|
+
import Optgroup from './Optgroup.svelte';
|
|
53
|
+
import Option from './Option.svelte';
|
|
54
|
+
import Output from './Output.svelte';
|
|
17
55
|
import P from './P.svelte';
|
|
56
|
+
import Param from './Param.svelte';
|
|
57
|
+
import Picture from './Picture.svelte';
|
|
18
58
|
import Pre from './Pre.svelte';
|
|
59
|
+
import Progress from './Progress.svelte';
|
|
60
|
+
import S from './S.svelte';
|
|
61
|
+
import Samp from './Samp.svelte';
|
|
62
|
+
import Section from './Section.svelte';
|
|
63
|
+
import Select from './Select.svelte';
|
|
64
|
+
import Small from './Small.svelte';
|
|
65
|
+
import Source from './Source.svelte';
|
|
66
|
+
import Span from './Span.svelte';
|
|
19
67
|
import Strong from './Strong.svelte';
|
|
20
68
|
import Sub from './Sub.svelte';
|
|
69
|
+
import Summary from './Summary.svelte';
|
|
21
70
|
import Sup from './Sup.svelte';
|
|
22
71
|
import Table from './Table.svelte';
|
|
23
72
|
import Tbody from './Tbody.svelte';
|
|
24
73
|
import Td from './Td.svelte';
|
|
74
|
+
import Textarea from './Textarea.svelte';
|
|
25
75
|
import Tfoot from './Tfoot.svelte';
|
|
26
76
|
import Th from './Th.svelte';
|
|
27
77
|
import Thead from './Thead.svelte';
|
|
28
78
|
import Tr from './Tr.svelte';
|
|
79
|
+
import Track from './Track.svelte';
|
|
80
|
+
import U from './U.svelte';
|
|
29
81
|
import Ul from './Ul.svelte';
|
|
82
|
+
import Var from './Var.svelte';
|
|
30
83
|
export const Html = {
|
|
31
84
|
a: A,
|
|
85
|
+
abbr: Abbr,
|
|
86
|
+
address: Address,
|
|
87
|
+
article: Article,
|
|
88
|
+
aside: Aside,
|
|
89
|
+
audio: Audio,
|
|
90
|
+
b: B,
|
|
91
|
+
bdi: Bdi,
|
|
92
|
+
bdo: Bdo,
|
|
32
93
|
blockquote: Blockquote,
|
|
94
|
+
button: Button,
|
|
95
|
+
canvas: Canvas,
|
|
96
|
+
cite: Cite,
|
|
33
97
|
code: Code,
|
|
98
|
+
datalist: Datalist,
|
|
99
|
+
dd: Dd,
|
|
34
100
|
del: Del,
|
|
101
|
+
details: Details,
|
|
102
|
+
dfn: Dfn,
|
|
103
|
+
dialog: Dialog,
|
|
104
|
+
div: Div,
|
|
105
|
+
dl: Dl,
|
|
106
|
+
dt: Dt,
|
|
35
107
|
em: Em,
|
|
108
|
+
embed: Embed,
|
|
109
|
+
fieldset: Fieldset,
|
|
110
|
+
footer: Footer,
|
|
111
|
+
form: Form,
|
|
36
112
|
h1: H1,
|
|
37
113
|
h2: H2,
|
|
38
114
|
h3: H3,
|
|
39
115
|
h4: H4,
|
|
40
116
|
h5: H5,
|
|
41
117
|
h6: H6,
|
|
118
|
+
header: Header,
|
|
119
|
+
hgroup: Hgroup,
|
|
42
120
|
hr: Hr,
|
|
43
121
|
i: I,
|
|
122
|
+
iframe: Iframe,
|
|
44
123
|
img: Img,
|
|
124
|
+
input: Input,
|
|
125
|
+
kbd: Kbd,
|
|
126
|
+
label: Label,
|
|
127
|
+
legend: Legend,
|
|
45
128
|
li: Li,
|
|
129
|
+
main: Main,
|
|
130
|
+
mark: Mark,
|
|
131
|
+
menu: Menu,
|
|
132
|
+
meter: Meter,
|
|
133
|
+
nav: Nav,
|
|
46
134
|
ol: Ol,
|
|
135
|
+
optgroup: Optgroup,
|
|
136
|
+
option: Option,
|
|
137
|
+
output: Output,
|
|
47
138
|
p: P,
|
|
139
|
+
param: Param,
|
|
140
|
+
picture: Picture,
|
|
48
141
|
pre: Pre,
|
|
142
|
+
progress: Progress,
|
|
143
|
+
s: S,
|
|
144
|
+
samp: Samp,
|
|
145
|
+
section: Section,
|
|
146
|
+
select: Select,
|
|
147
|
+
small: Small,
|
|
148
|
+
source: Source,
|
|
149
|
+
span: Span,
|
|
49
150
|
strong: Strong,
|
|
50
151
|
sub: Sub,
|
|
152
|
+
summary: Summary,
|
|
51
153
|
sup: Sup,
|
|
52
154
|
table: Table,
|
|
53
155
|
tbody: Tbody,
|
|
54
156
|
td: Td,
|
|
157
|
+
textarea: Textarea,
|
|
158
|
+
tfoot: Tfoot,
|
|
55
159
|
th: Th,
|
|
56
160
|
thead: Thead,
|
|
57
161
|
tr: Tr,
|
|
58
|
-
|
|
59
|
-
|
|
162
|
+
track: Track,
|
|
163
|
+
u: U,
|
|
164
|
+
ul: Ul,
|
|
165
|
+
var: Var
|
|
60
166
|
};
|
|
61
167
|
export default Html;
|
|
@@ -1,11 +1,36 @@
|
|
|
1
1
|
export { default as Slugger } from 'github-slugger';
|
|
2
2
|
export { Lexer, type Token, type Tokens, type TokensList } from 'marked';
|
|
3
|
-
import { type HtmlRenderers } from '../renderers/html/index.js';
|
|
4
3
|
import type { Component } from 'svelte';
|
|
4
|
+
import { type HtmlRenderers } from '../renderers/html/index.js';
|
|
5
|
+
/**
|
|
6
|
+
* Type definition for markdown renderers
|
|
7
|
+
* Maps each markdown element to its corresponding Svelte component
|
|
8
|
+
*/
|
|
9
|
+
export type RendererComponent = Component<any, any, any> | undefined | null;
|
|
5
10
|
export type Renderers = {
|
|
6
11
|
html: HtmlRenderers;
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
heading: RendererComponent;
|
|
13
|
+
paragraph: RendererComponent;
|
|
14
|
+
blockquote: RendererComponent;
|
|
15
|
+
code: RendererComponent;
|
|
16
|
+
list: RendererComponent;
|
|
17
|
+
listitem: RendererComponent;
|
|
18
|
+
hr: RendererComponent;
|
|
19
|
+
table: RendererComponent;
|
|
20
|
+
tablehead: RendererComponent;
|
|
21
|
+
tablebody: RendererComponent;
|
|
22
|
+
tablerow: RendererComponent;
|
|
23
|
+
tablecell: RendererComponent;
|
|
24
|
+
text: RendererComponent;
|
|
25
|
+
link: RendererComponent;
|
|
26
|
+
image: RendererComponent;
|
|
27
|
+
em: RendererComponent;
|
|
28
|
+
strong: RendererComponent;
|
|
29
|
+
codespan: RendererComponent;
|
|
30
|
+
br: RendererComponent;
|
|
31
|
+
del: RendererComponent;
|
|
32
|
+
orderedlistitem: RendererComponent;
|
|
33
|
+
unorderedlistitem: RendererComponent;
|
|
9
34
|
};
|
|
10
35
|
export declare const defaultRenderers: Renderers;
|
|
11
36
|
export type SvelteMarkdownOptions = {
|
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
import type { Token
|
|
1
|
+
import type { Token } from 'marked';
|
|
2
|
+
/**
|
|
3
|
+
* Determines if a string contains an HTML opening or closing tag
|
|
4
|
+
* @param raw - The string to check for HTML tags
|
|
5
|
+
* @returns Object containing the tag name and whether it's an opening tag, or null if no tag found
|
|
6
|
+
*/
|
|
2
7
|
export declare const isHtmlOpenTag: (raw: string) => {
|
|
3
8
|
tag: string;
|
|
4
9
|
isOpening: boolean;
|
|
5
10
|
} | null;
|
|
6
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Main function to process and shrink HTML tokens
|
|
13
|
+
* Breaks down complex HTML structures into manageable tokens
|
|
14
|
+
* @param tokens - Array of tokens to process
|
|
15
|
+
* @returns Processed array of tokens with nested structure
|
|
16
|
+
*/
|
|
17
|
+
export declare const shrinkHtmlTokens: (tokens: Token[]) => Token[];
|
|
@@ -1,72 +1,211 @@
|
|
|
1
|
-
|
|
1
|
+
import { Parser } from 'htmlparser2';
|
|
2
|
+
/**
|
|
3
|
+
* Regular expression pattern to match HTML tags
|
|
4
|
+
* Matches both opening and closing tags with optional attributes
|
|
5
|
+
* Example matches: <div>, </div>, <img src="...">, <input type="text"/>
|
|
6
|
+
*/
|
|
2
7
|
const HTML_TAG_PATTERN = /<\/?([a-zA-Z][a-zA-Z0-9-]{0,})(?:\s+[^>]*)?>/;
|
|
3
8
|
const htmlTagRegex = new RegExp(HTML_TAG_PATTERN);
|
|
9
|
+
/**
|
|
10
|
+
* Determines if a string contains an HTML opening or closing tag
|
|
11
|
+
* @param raw - The string to check for HTML tags
|
|
12
|
+
* @returns Object containing the tag name and whether it's an opening tag, or null if no tag found
|
|
13
|
+
*/
|
|
4
14
|
export const isHtmlOpenTag = (raw) => {
|
|
5
|
-
//
|
|
15
|
+
// First check if the string contains any HTML tags at all (faster than full regex match)
|
|
6
16
|
if (!htmlTagRegex.test(raw))
|
|
7
17
|
return null;
|
|
18
|
+
// If we found a tag, extract its name and check if it's an opening tag
|
|
8
19
|
const match = raw.match(HTML_TAG_PATTERN);
|
|
9
20
|
if (!match)
|
|
10
21
|
return null;
|
|
11
22
|
return { tag: match[1], isOpening: !raw.startsWith('</') };
|
|
12
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* Extracts HTML attributes from a tag string
|
|
26
|
+
* @param raw - The raw HTML tag string (e.g., '<div class="example" id="test">')
|
|
27
|
+
* @returns An object containing key-value pairs of attributes
|
|
28
|
+
*/
|
|
29
|
+
const extractAttributes = (raw) => {
|
|
30
|
+
const attributes = {};
|
|
31
|
+
// Match pattern: attribute="value" or attribute='value'
|
|
32
|
+
const attributeRegex = /(\w+)=["']([^"']*?)["']/g;
|
|
33
|
+
let match;
|
|
34
|
+
// Continue finding matches until we've processed all attributes
|
|
35
|
+
while ((match = attributeRegex.exec(raw)) !== null) {
|
|
36
|
+
const [, key, value] = match;
|
|
37
|
+
attributes[key] = value.trim();
|
|
38
|
+
}
|
|
39
|
+
return attributes;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Parses an HTML string into an array of tokens
|
|
43
|
+
* Uses htmlparser2 to properly handle nested tags and text content
|
|
44
|
+
* @param html - The HTML string to parse
|
|
45
|
+
* @returns Array of tokens representing the HTML structure
|
|
46
|
+
*/
|
|
47
|
+
const parseHtmlBlock = (html) => {
|
|
48
|
+
const tokens = [];
|
|
49
|
+
// Buffer for accumulating text content between tags
|
|
50
|
+
let currentText = '';
|
|
51
|
+
const parser = new Parser({
|
|
52
|
+
// Called when an opening tag is encountered (<div>, <span>, etc.)
|
|
53
|
+
onopentag: (name, attributes) => {
|
|
54
|
+
// If we have accumulated any text, create a text token first
|
|
55
|
+
if (currentText.trim()) {
|
|
56
|
+
tokens.push({
|
|
57
|
+
type: 'text',
|
|
58
|
+
raw: currentText,
|
|
59
|
+
text: currentText
|
|
60
|
+
});
|
|
61
|
+
currentText = '';
|
|
62
|
+
}
|
|
63
|
+
// Create a token for the opening tag with its attributes
|
|
64
|
+
tokens.push({
|
|
65
|
+
type: 'html',
|
|
66
|
+
raw: `<${name}${Object.entries(attributes)
|
|
67
|
+
.map(([key, value]) => ` ${key}="${value}"`)
|
|
68
|
+
.join('')}>`,
|
|
69
|
+
tag: name,
|
|
70
|
+
attributes
|
|
71
|
+
});
|
|
72
|
+
},
|
|
73
|
+
// Called for text content between tags
|
|
74
|
+
ontext: (text) => {
|
|
75
|
+
currentText += text;
|
|
76
|
+
},
|
|
77
|
+
// Called when a closing tag is encountered (</div>, </span>, etc.)
|
|
78
|
+
onclosetag: (name) => {
|
|
79
|
+
// Push any accumulated text before the closing tag
|
|
80
|
+
if (currentText.trim()) {
|
|
81
|
+
tokens.push({
|
|
82
|
+
type: 'text',
|
|
83
|
+
raw: currentText,
|
|
84
|
+
text: currentText
|
|
85
|
+
});
|
|
86
|
+
currentText = '';
|
|
87
|
+
}
|
|
88
|
+
// Create a token for the closing tag
|
|
89
|
+
tokens.push({
|
|
90
|
+
type: 'html',
|
|
91
|
+
raw: `</${name}>`,
|
|
92
|
+
tag: name
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
// Process the HTML string
|
|
97
|
+
parser.write(html);
|
|
98
|
+
parser.end();
|
|
99
|
+
return tokens;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Checks if an HTML string contains multiple tags
|
|
103
|
+
* Used to determine if further parsing is needed
|
|
104
|
+
* @param html - The HTML string to check
|
|
105
|
+
* @returns boolean indicating if multiple tags are present
|
|
106
|
+
*/
|
|
107
|
+
const containsMultipleTags = (html) => {
|
|
108
|
+
// Count the number of opening tags (excluding self-closing)
|
|
109
|
+
const openingTags = html.match(/<[a-zA-Z][^>]*>/g) || [];
|
|
110
|
+
const closingTags = html.match(/<\/[a-zA-Z][^>]*>/g) || [];
|
|
111
|
+
return openingTags.length > 1 || closingTags.length > 1;
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Main function to process and shrink HTML tokens
|
|
115
|
+
* Breaks down complex HTML structures into manageable tokens
|
|
116
|
+
* @param tokens - Array of tokens to process
|
|
117
|
+
* @returns Processed array of tokens with nested structure
|
|
118
|
+
*/
|
|
13
119
|
export const shrinkHtmlTokens = (tokens) => {
|
|
14
120
|
const result = [];
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if ('tokens' in currentToken && currentToken.tokens) {
|
|
20
|
-
currentToken.tokens = shrinkHtmlTokens(currentToken.tokens);
|
|
21
|
-
result.push(currentToken);
|
|
22
|
-
continue;
|
|
121
|
+
for (const token of tokens) {
|
|
122
|
+
if (token.type === 'html' && containsMultipleTags(token.raw)) {
|
|
123
|
+
// Parse HTML with multiple tags into separate tokens
|
|
124
|
+
result.push(...parseHtmlBlock(token.raw));
|
|
23
125
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
126
|
+
else {
|
|
127
|
+
result.push(token);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Then process the tokens as before
|
|
131
|
+
return processHtmlTokens(result);
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Processes HTML tokens to create a nested structure
|
|
135
|
+
* Handles matching opening and closing tags, maintains proper nesting
|
|
136
|
+
* and preserves attributes
|
|
137
|
+
*
|
|
138
|
+
* @param tokens - Array of tokens to process
|
|
139
|
+
* @returns Processed array of tokens with proper nesting structure
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* Input tokens: [
|
|
143
|
+
* { type: 'html', raw: '<div>' },
|
|
144
|
+
* { type: 'text', raw: 'Hello' },
|
|
145
|
+
* { type: 'html', raw: '</div>' }
|
|
146
|
+
* ]
|
|
147
|
+
* Output: [
|
|
148
|
+
* { type: 'html', tag: 'div', tokens: [
|
|
149
|
+
* { type: 'text', raw: 'Hello' }
|
|
150
|
+
* ]}
|
|
151
|
+
* ]
|
|
152
|
+
*/
|
|
153
|
+
const processHtmlTokens = (tokens) => {
|
|
154
|
+
const result = [];
|
|
155
|
+
// Stack to keep track of opening tags and their positions
|
|
156
|
+
const stack = [];
|
|
157
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
158
|
+
const token = tokens[i];
|
|
159
|
+
// If token contains nested tokens, process them recursively
|
|
160
|
+
if ('tokens' in token && Array.isArray(token.tokens)) {
|
|
161
|
+
token.tokens = processHtmlTokens(token.tokens);
|
|
162
|
+
}
|
|
163
|
+
if (token.type === 'html') {
|
|
164
|
+
const tagInfo = isHtmlOpenTag(token.raw);
|
|
165
|
+
if (!tagInfo) {
|
|
166
|
+
// If we can't parse the tag, just add it as-is
|
|
167
|
+
result.push(token);
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (tagInfo.isOpening) {
|
|
171
|
+
// For opening tags, push to stack and add to result
|
|
172
|
+
stack.push({ tag: tagInfo.tag, startIndex: result.length });
|
|
173
|
+
result.push(token);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
// For closing tags, try to match with last opening tag
|
|
177
|
+
const lastOpening = stack.pop();
|
|
178
|
+
if (!lastOpening || lastOpening.tag !== tagInfo.tag) {
|
|
179
|
+
// If no matching opening tag, add closing tag as-is
|
|
180
|
+
result.push(token);
|
|
65
181
|
continue;
|
|
66
182
|
}
|
|
183
|
+
// Found matching tags - create nested structure
|
|
184
|
+
const startIndex = lastOpening.startIndex;
|
|
185
|
+
// Remove all tokens between opening and closing tags
|
|
186
|
+
const innerTokens = result.splice(startIndex + 1, result.length - startIndex - 1);
|
|
187
|
+
// Remove the opening tag
|
|
188
|
+
const openingToken = result.pop();
|
|
189
|
+
// Extract attributes from opening tag
|
|
190
|
+
const attributes = extractAttributes(openingToken.raw);
|
|
191
|
+
// Create new nested token structure
|
|
192
|
+
result.push({
|
|
193
|
+
type: 'html',
|
|
194
|
+
raw: openingToken.raw,
|
|
195
|
+
tag: tagInfo.tag,
|
|
196
|
+
tokens: processHtmlTokens(innerTokens),
|
|
197
|
+
attributes
|
|
198
|
+
});
|
|
67
199
|
}
|
|
68
200
|
}
|
|
69
|
-
|
|
201
|
+
else {
|
|
202
|
+
// Non-HTML tokens are added as-is
|
|
203
|
+
result.push(token);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// If we have unclosed tags, return original tokens
|
|
207
|
+
if (stack.length > 0) {
|
|
208
|
+
return tokens;
|
|
70
209
|
}
|
|
71
210
|
return result;
|
|
72
211
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@humanspeak/svelte-markdown",
|
|
3
3
|
"description": "A markdown renderer for Svelte",
|
|
4
|
-
"version": "0.6.
|
|
4
|
+
"version": "0.6.8",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "vite dev",
|
|
7
7
|
"build": "vite build && npm run package",
|
|
@@ -53,41 +53,42 @@
|
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"github-slugger": "^2.0.0",
|
|
56
|
-
"
|
|
56
|
+
"htmlparser2": "^10.0.0",
|
|
57
|
+
"marked": "^15.0.4"
|
|
57
58
|
},
|
|
58
59
|
"devDependencies": {
|
|
59
|
-
"@eslint/eslintrc": "^3.
|
|
60
|
-
"@eslint/js": "^9.
|
|
60
|
+
"@eslint/eslintrc": "^3.2.0",
|
|
61
|
+
"@eslint/js": "^9.17.0",
|
|
61
62
|
"@sveltejs/adapter-auto": "^3.3.1",
|
|
62
|
-
"@sveltejs/kit": "^2.
|
|
63
|
+
"@sveltejs/kit": "^2.15.1",
|
|
63
64
|
"@sveltejs/package": "^2.3.7",
|
|
64
|
-
"@sveltejs/vite-plugin-svelte": "^
|
|
65
|
+
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
|
65
66
|
"@testing-library/jest-dom": "^6.6.3",
|
|
66
|
-
"@testing-library/svelte": "^5.2.
|
|
67
|
+
"@testing-library/svelte": "^5.2.6",
|
|
67
68
|
"@testing-library/user-event": "^14.5.2",
|
|
68
|
-
"@types/node": "^22.
|
|
69
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
70
|
-
"@typescript-eslint/parser": "^8.
|
|
71
|
-
"@vitest/coverage-v8": "^2.1.
|
|
72
|
-
"eslint": "^9.
|
|
69
|
+
"@types/node": "^22.10.3",
|
|
70
|
+
"@typescript-eslint/eslint-plugin": "^8.19.0",
|
|
71
|
+
"@typescript-eslint/parser": "^8.19.0",
|
|
72
|
+
"@vitest/coverage-v8": "^2.1.8",
|
|
73
|
+
"eslint": "^9.17.0",
|
|
73
74
|
"eslint-config-prettier": "^9.1.0",
|
|
74
|
-
"eslint-plugin-svelte": "^2.46.
|
|
75
|
-
"globals": "^15.
|
|
75
|
+
"eslint-plugin-svelte": "^2.46.1",
|
|
76
|
+
"globals": "^15.14.0",
|
|
76
77
|
"jsdom": "^25.0.1",
|
|
77
|
-
"prettier": "^3.
|
|
78
|
+
"prettier": "^3.4.2",
|
|
78
79
|
"prettier-plugin-organize-imports": "^4.1.0",
|
|
79
|
-
"prettier-plugin-svelte": "^3.2
|
|
80
|
-
"prettier-plugin-tailwindcss": "^0.6.
|
|
80
|
+
"prettier-plugin-svelte": "^3.3.2",
|
|
81
|
+
"prettier-plugin-tailwindcss": "^0.6.9",
|
|
81
82
|
"publint": "^0.2.12",
|
|
82
|
-
"svelte": "^5.
|
|
83
|
-
"svelte-check": "^4.
|
|
84
|
-
"typescript": "^5.
|
|
85
|
-
"vite": "^
|
|
86
|
-
"vitest": "^2.1.
|
|
83
|
+
"svelte": "^5.16.0",
|
|
84
|
+
"svelte-check": "^4.1.1",
|
|
85
|
+
"typescript": "^5.7.2",
|
|
86
|
+
"vite": "^6.0.6",
|
|
87
|
+
"vitest": "^2.1.8"
|
|
87
88
|
},
|
|
88
89
|
"overrides": {
|
|
89
90
|
"@sveltejs/kit": {
|
|
90
91
|
"cookie": "^0.7.0"
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
|
-
}
|
|
94
|
+
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { Snippet } from 'svelte'
|
|
3
|
-
|
|
4
|
-
interface Props {
|
|
5
|
-
children?: Snippet
|
|
6
|
-
attributes?: Record<string, any>
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const { children, attributes }: Props = $props()
|
|
10
|
-
</script>
|
|
11
|
-
|
|
12
|
-
<object {...attributes}>{@render children?.()}</object>
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { Snippet } from 'svelte'
|
|
3
|
-
|
|
4
|
-
interface Props {
|
|
5
|
-
children?: Snippet
|
|
6
|
-
attributes?: Record<string, any>
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const { children, attributes }: Props = $props()
|
|
10
|
-
</script>
|
|
11
|
-
|
|
12
|
-
<video {...attributes}>{@render children?.()}</video>
|