pantsdown 2.2.3 → 2.2.5

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/src/pantsdown.ts CHANGED
@@ -5,49 +5,50 @@ import { Parser } from "./parser.ts";
5
5
  import { type PantsdownConfig, type PartialPantsdownConfig } from "./types.ts";
6
6
 
7
7
  const defaultConfig: PantsdownConfig = {
8
- renderer: {
9
- relativeImageUrlPrefix: "",
10
- detailsTagDefaultOpen: false,
11
- },
8
+ renderer: {
9
+ relativeImageUrlPrefix: "",
10
+ absoluteImageUrlPrefix: undefined,
11
+ detailsTagDefaultOpen: false,
12
+ },
12
13
  };
13
14
 
14
15
  export class Pantsdown {
15
- private lexer: Lexer;
16
- private parser: Parser;
17
- config: PantsdownConfig = defaultConfig;
16
+ private lexer: Lexer;
17
+ private parser: Parser;
18
+ config: PantsdownConfig = defaultConfig;
18
19
 
19
- constructor(config?: PartialPantsdownConfig) {
20
- if (config) this.setConfig(config);
21
- this.lexer = new Lexer();
22
- this.parser = new Parser(this);
23
- }
20
+ constructor(config?: PartialPantsdownConfig) {
21
+ if (config) this.setConfig(config);
22
+ this.lexer = new Lexer();
23
+ this.parser = new Parser(this);
24
+ }
24
25
 
25
- /**
26
- * Update config
27
- * The object you provide will be deeply merged into current config.
28
- */
29
- setConfig(config: PartialPantsdownConfig) {
30
- this.config = {
31
- renderer: {
32
- ...this.config.renderer,
33
- ...config.renderer,
34
- },
35
- };
36
- }
26
+ /**
27
+ * Update config
28
+ * The object you provide will be deeply merged into current config.
29
+ */
30
+ setConfig(config: PartialPantsdownConfig) {
31
+ this.config = {
32
+ renderer: {
33
+ ...this.config.renderer,
34
+ ...config.renderer,
35
+ },
36
+ };
37
+ }
37
38
 
38
- /**
39
- * Parse markdown string
40
- */
41
- parse(src: string): { html: string; javascript: string } {
42
- // re-init slugger to avoid slug count from incorrectly incrementing
43
- // from previosly slugged headings
44
- this.parser.renderer.slugger = new GithubSlugger();
39
+ /**
40
+ * Parse markdown string
41
+ */
42
+ parse(src: string): { html: string; javascript: string } {
43
+ // re-init slugger to avoid slug count from incorrectly incrementing
44
+ // from previosly slugged headings
45
+ this.parser.renderer.slugger = new GithubSlugger();
45
46
 
46
- const tokens = this.lexer.lex(src);
47
- const html = this.parser.parse(tokens);
48
- return {
49
- html,
50
- javascript,
51
- };
52
- }
47
+ const tokens = this.lexer.lex(src);
48
+ const html = this.parser.parse(tokens);
49
+ return {
50
+ html,
51
+ javascript,
52
+ };
53
+ }
53
54
  }
package/src/parser.ts CHANGED
@@ -7,266 +7,250 @@ import { injectHtmlAttributes } from "./utils.ts";
7
7
  * Parsing & Compiling
8
8
  */
9
9
  export class Parser {
10
- renderer: Renderer;
10
+ renderer: Renderer;
11
11
 
12
- constructor(pantsdown: Pantsdown) {
13
- this.renderer = new Renderer(pantsdown);
14
- }
12
+ constructor(pantsdown: Pantsdown) {
13
+ this.renderer = new Renderer(pantsdown);
14
+ }
15
15
 
16
- /**
17
- * Parse Loop
18
- */
19
- parse(tokens: Token[], top = true): string {
20
- let out = "";
16
+ /**
17
+ * Parse Loop
18
+ */
19
+ parse(tokens: Token[], top = true): string {
20
+ let out = "";
21
21
 
22
- for (let i = 0, len = tokens.length; i < len; i++) {
23
- const token = tokens[i]!;
22
+ for (let i = 0, len = tokens.length; i < len; i++) {
23
+ const token = tokens[i]!;
24
24
 
25
- switch (token.type) {
26
- case "space": {
27
- continue;
28
- }
29
- case "hr": {
30
- out += this.renderer.hr(token.sourceMap);
31
- continue;
32
- }
33
- case "heading": {
34
- out += this.renderer.heading(
35
- this.parseInline(token.tokens),
36
- token.depth,
37
- token.sourceMap,
38
- );
39
- continue;
40
- }
41
- case "code": {
42
- out += this.renderer.code(token.text, token.lang, token.sourceMap);
43
- continue;
44
- }
45
- case "table": {
46
- let header = "";
25
+ switch (token.type) {
26
+ case "space": {
27
+ continue;
28
+ }
29
+ case "hr": {
30
+ out += this.renderer.hr(token.sourceMap);
31
+ continue;
32
+ }
33
+ case "heading": {
34
+ out += this.renderer.heading(
35
+ this.parseInline(token.tokens),
36
+ token.depth,
37
+ token.sourceMap,
38
+ );
39
+ continue;
40
+ }
41
+ case "code": {
42
+ out += this.renderer.code(token.text, token.lang, token.sourceMap);
43
+ continue;
44
+ }
45
+ case "table": {
46
+ let header = "";
47
47
 
48
- // header
49
- let cell = "";
50
- for (let j = 0, len = token.header.length; j < len; j++) {
51
- cell += this.renderer.tablecell(this.parseInline(token.header[j]!.tokens), {
52
- header: true,
53
- align: token.align[j]!,
54
- });
55
- }
56
- const sourceMapLineStart = token.sourceMap?.[0];
57
- header += this.renderer.tablerow(cell, sourceMapLineStart);
48
+ // header
49
+ let cell = "";
50
+ for (let j = 0, len = token.header.length; j < len; j++) {
51
+ cell += this.renderer.tablecell(this.parseInline(token.header[j]!.tokens), {
52
+ header: true,
53
+ align: token.align[j]!,
54
+ });
55
+ }
56
+ const sourceMapLineStart = token.sourceMap?.[0];
57
+ header += this.renderer.tablerow(cell, sourceMapLineStart);
58
58
 
59
- let body = "";
60
- for (let j = 0, rowsLen = token.rows.length; j < rowsLen; j++) {
61
- const row = token.rows[j]!;
59
+ let body = "";
60
+ for (let j = 0, rowsLen = token.rows.length; j < rowsLen; j++) {
61
+ const row = token.rows[j]!;
62
62
 
63
- cell = "";
64
- for (let k = 0, rowLen = row.length; k < rowLen; k++) {
65
- cell += this.renderer.tablecell(this.parseInline(row[k]!.tokens), {
66
- header: false,
67
- align: token.align[k]!,
68
- });
69
- }
63
+ cell = "";
64
+ for (let k = 0, rowLen = row.length; k < rowLen; k++) {
65
+ cell += this.renderer.tablecell(this.parseInline(row[k]!.tokens), {
66
+ header: false,
67
+ align: token.align[k]!,
68
+ });
69
+ }
70
70
 
71
- body += this.renderer.tablerow(
72
- cell,
73
- sourceMapLineStart ? sourceMapLineStart + 2 + j : undefined,
74
- );
75
- }
76
- out += this.renderer.table(header, body);
77
- continue;
78
- }
79
- case "alert": {
80
- const body = this.parse(token.tokens);
81
- out += this.renderer.alert(body, token);
82
- continue;
83
- }
84
- case "blockquote": {
85
- const body = this.parse(token.tokens);
86
- out += this.renderer.blockquote(body);
87
- continue;
88
- }
89
- case "list": {
90
- const ordered = token.ordered;
91
- const start = token.start;
92
- const loose = token.loose;
93
- let containsTaskList = false;
71
+ body += this.renderer.tablerow(
72
+ cell,
73
+ sourceMapLineStart ? sourceMapLineStart + 2 + j : undefined,
74
+ );
75
+ }
76
+ out += this.renderer.table(header, body);
77
+ continue;
78
+ }
79
+ case "alert": {
80
+ const body = this.parse(token.tokens);
81
+ out += this.renderer.alert(body, token);
82
+ continue;
83
+ }
84
+ case "blockquote": {
85
+ const body = this.parse(token.tokens);
86
+ out += this.renderer.blockquote(body);
87
+ continue;
88
+ }
89
+ case "list": {
90
+ const ordered = token.ordered;
91
+ const start = token.start;
92
+ const loose = token.loose;
93
+ let containsTaskList = false;
94
94
 
95
- let body = "";
96
- for (let j = 0, itemsLen = token.items.length; j < itemsLen; j++) {
97
- const item = token.items[j]!;
98
- const checked = item.checked;
99
- const task = item.task;
95
+ let body = "";
96
+ for (let j = 0, itemsLen = token.items.length; j < itemsLen; j++) {
97
+ const item = token.items[j]!;
98
+ const checked = item.checked;
99
+ const task = item.task;
100
100
 
101
- let itemBody = "";
102
- if (item.task) {
103
- containsTaskList = true;
104
- const checkbox = this.renderer.checkbox(Boolean(checked), [
105
- "task-list-item-checkbox",
106
- ]);
107
- if (loose) {
108
- if (
109
- item.tokens.length > 0 &&
110
- item.tokens[0]!.type === "paragraph"
111
- ) {
112
- item.tokens[0].text = checkbox + " " + item.tokens[0].text;
113
- if (
114
- item.tokens[0].tokens.length > 0 &&
115
- item.tokens[0].tokens[0]!.type === "text"
116
- ) {
117
- item.tokens[0].tokens[0]!.text =
118
- checkbox + " " + item.tokens[0].tokens[0]!.text;
119
- }
120
- } else {
121
- item.tokens.unshift({
122
- type: "text",
123
- text: checkbox + " ",
124
- } as Tokens["Text"]);
125
- }
126
- } else {
127
- itemBody += checkbox + " ";
128
- }
101
+ let itemBody = "";
102
+ if (item.task) {
103
+ containsTaskList = true;
104
+ const checkbox = this.renderer.checkbox(Boolean(checked), [
105
+ "task-list-item-checkbox",
106
+ ]);
107
+ if (loose) {
108
+ if (item.tokens.length > 0 && item.tokens[0]!.type === "paragraph") {
109
+ item.tokens[0].text = checkbox + " " + item.tokens[0].text;
110
+ if (
111
+ item.tokens[0].tokens.length > 0 &&
112
+ item.tokens[0].tokens[0]!.type === "text"
113
+ ) {
114
+ item.tokens[0].tokens[0]!.text =
115
+ checkbox + " " + item.tokens[0].tokens[0]!.text;
116
+ }
117
+ } else {
118
+ item.tokens.unshift({
119
+ type: "text",
120
+ text: checkbox + " ",
121
+ } as Tokens["Text"]);
129
122
  }
123
+ } else {
124
+ itemBody += checkbox + " ";
125
+ }
126
+ }
130
127
 
131
- itemBody += this.parse(item.tokens, loose);
132
- body += this.renderer.listitem(
133
- itemBody,
134
- task,
135
- Boolean(checked),
136
- item.sourceMap,
137
- );
138
- }
128
+ itemBody += this.parse(item.tokens, loose);
129
+ body += this.renderer.listitem(itemBody, task, Boolean(checked), item.sourceMap);
130
+ }
139
131
 
140
- const listClasses: string[] = [];
141
- if (containsTaskList) listClasses.push("contains-task-list");
142
- out += this.renderer.list(body, ordered, start, listClasses);
143
- continue;
144
- }
145
- case "html": {
146
- out += this.renderer.html(
147
- token.text,
148
- token.block,
149
- "sourceMap" in token ? token.sourceMap : undefined,
150
- );
151
- continue;
152
- }
153
- case "footnotes": {
154
- const body = token.items.reduce((acc, { label, content, sourceMap }) => {
155
- let footnoteItem = `<li id="footnote-${encodeURIComponent(label)}">\n`;
156
- footnoteItem += this.parse(content);
157
- footnoteItem += "</li>\n";
132
+ const listClasses: string[] = [];
133
+ if (containsTaskList) listClasses.push("contains-task-list");
134
+ out += this.renderer.list(body, ordered, start, listClasses);
135
+ continue;
136
+ }
137
+ case "html": {
138
+ out += this.renderer.html(
139
+ token.text,
140
+ token.block,
141
+ "sourceMap" in token ? token.sourceMap : undefined,
142
+ );
143
+ continue;
144
+ }
145
+ case "footnotes": {
146
+ const body = token.items.reduce((acc, { label, content, sourceMap }) => {
147
+ let footnoteItem = `<li id="footnote-${encodeURIComponent(label)}">\n`;
148
+ footnoteItem += this.parse(content);
149
+ footnoteItem += "</li>\n";
158
150
 
159
- footnoteItem = injectHtmlAttributes(footnoteItem, [], sourceMap);
151
+ footnoteItem = injectHtmlAttributes(footnoteItem, [], sourceMap);
160
152
 
161
- return acc + footnoteItem;
162
- }, "");
153
+ return acc + footnoteItem;
154
+ }, "");
163
155
 
164
- out += this.renderer.footnotes(token, body);
165
- continue;
166
- }
167
- case "paragraph": {
168
- out += this.renderer.paragraph(this.parseInline(token.tokens), token.sourceMap);
169
- continue;
170
- }
171
- case "text": {
172
- let textToken = token as Tokens["Text"];
173
- let body = textToken.tokens
174
- ? this.parseInline(textToken.tokens)
175
- : textToken.text;
176
- while (i + 1 < tokens.length && tokens[i + 1]?.type === "text") {
177
- textToken = tokens[++i] as Tokens["Text"];
178
- body +=
179
- "\n" +
180
- (textToken.tokens
181
- ? this.parseInline(textToken.tokens)
182
- : textToken.text);
183
- }
184
- out += top ? this.renderer.paragraph(body, textToken.sourceMap) : body;
185
- continue;
186
- }
187
- case "latexBlock": {
188
- out += this.renderer.latexBlock(token.text, token.sourceMap);
189
- continue;
190
- }
156
+ out += this.renderer.footnotes(token, body);
157
+ continue;
158
+ }
159
+ case "paragraph": {
160
+ out += this.renderer.paragraph(this.parseInline(token.tokens), token.sourceMap);
161
+ continue;
162
+ }
163
+ case "text": {
164
+ let textToken = token as Tokens["Text"];
165
+ let body = textToken.tokens ? this.parseInline(textToken.tokens) : textToken.text;
166
+ while (i + 1 < tokens.length && tokens[i + 1]?.type === "text") {
167
+ textToken = tokens[++i] as Tokens["Text"];
168
+ body +=
169
+ "\n" +
170
+ (textToken.tokens ? this.parseInline(textToken.tokens) : textToken.text);
171
+ }
172
+ out += top ? this.renderer.paragraph(body, textToken.sourceMap) : body;
173
+ continue;
174
+ }
175
+ case "latexBlock": {
176
+ out += this.renderer.latexBlock(token.text, token.sourceMap);
177
+ continue;
178
+ }
191
179
 
192
- default: {
193
- const errMsg = 'Token with "' + token.type + '" type was not found.';
194
- throw new Error(errMsg);
195
- }
180
+ default: {
181
+ const errMsg = 'Token with "' + token.type + '" type was not found.';
182
+ throw new Error(errMsg);
196
183
  }
197
- }
184
+ }
185
+ }
198
186
 
199
- return out;
200
- }
187
+ return out;
188
+ }
201
189
 
202
- /**
203
- * Parse Inline Tokens
204
- */
205
- parseInline(tokens: Token[]): string {
206
- let out = "";
190
+ /**
191
+ * Parse Inline Tokens
192
+ */
193
+ parseInline(tokens: Token[]): string {
194
+ let out = "";
207
195
 
208
- for (let i = 0, len = tokens.length; i < len; i++) {
209
- const token = tokens[i]!;
196
+ for (let i = 0, len = tokens.length; i < len; i++) {
197
+ const token = tokens[i]!;
210
198
 
211
- switch (token.type) {
212
- case "escape": {
213
- out += this.renderer.text(token.text);
214
- break;
215
- }
216
- case "html": {
217
- out += this.renderer.html(token.text, false);
218
- break;
219
- }
220
- case "link": {
221
- out += this.renderer.link(
222
- token.href,
223
- token.title,
224
- this.parseInline(token.tokens),
225
- );
226
- break;
227
- }
228
- case "image": {
229
- out += this.renderer.image(token.href, token.title, token.text);
230
- break;
231
- }
232
- case "strong": {
233
- out += this.renderer.strong(this.parseInline(token.tokens));
234
- break;
235
- }
236
- case "em": {
237
- out += this.renderer.em(this.parseInline(token.tokens));
238
- break;
239
- }
240
- case "footnoteRef": {
241
- out += this.renderer.footnoteRef(token);
242
- break;
243
- }
244
- case "codespan": {
245
- out += this.renderer.codespan(token.text);
246
- break;
247
- }
248
- case "br": {
249
- out += this.renderer.br();
250
- break;
251
- }
252
- case "del": {
253
- out += this.renderer.del(this.parseInline(token.tokens));
254
- break;
255
- }
256
- case "text": {
257
- out += this.renderer.text(token.text);
258
- break;
259
- }
260
- case "latexInline": {
261
- out += this.renderer.latexInline(token.text);
262
- break;
263
- }
264
- default: {
265
- const errMsg = 'Token with "' + token.type + '" type was not found.';
266
- throw new Error(errMsg);
267
- }
199
+ switch (token.type) {
200
+ case "escape": {
201
+ out += this.renderer.text(token.text);
202
+ break;
203
+ }
204
+ case "html": {
205
+ out += this.renderer.html(token.text, false);
206
+ break;
207
+ }
208
+ case "link": {
209
+ out += this.renderer.link(token.href, token.title, this.parseInline(token.tokens));
210
+ break;
211
+ }
212
+ case "image": {
213
+ out += this.renderer.image(token.href, token.title, token.text);
214
+ break;
215
+ }
216
+ case "strong": {
217
+ out += this.renderer.strong(this.parseInline(token.tokens));
218
+ break;
219
+ }
220
+ case "em": {
221
+ out += this.renderer.em(this.parseInline(token.tokens));
222
+ break;
223
+ }
224
+ case "footnoteRef": {
225
+ out += this.renderer.footnoteRef(token);
226
+ break;
227
+ }
228
+ case "codespan": {
229
+ out += this.renderer.codespan(token.text);
230
+ break;
231
+ }
232
+ case "br": {
233
+ out += this.renderer.br();
234
+ break;
235
+ }
236
+ case "del": {
237
+ out += this.renderer.del(this.parseInline(token.tokens));
238
+ break;
239
+ }
240
+ case "text": {
241
+ out += this.renderer.text(token.text);
242
+ break;
243
+ }
244
+ case "latexInline": {
245
+ out += this.renderer.latexInline(token.text);
246
+ break;
247
+ }
248
+ default: {
249
+ const errMsg = 'Token with "' + token.type + '" type was not found.';
250
+ throw new Error(errMsg);
268
251
  }
269
- }
270
- return out;
271
- }
252
+ }
253
+ }
254
+ return out;
255
+ }
272
256
  }