pantsdown 1.8.2 → 1.9.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
@@ -89,12 +89,15 @@ export default App;
89
89
 
90
90
  ## ⚙️ Configuration
91
91
 
92
- The Pantsdown constructor accepts an optional configuration object:
92
+ The Pantsdown constructor accepts an optional configuration object.
93
+ If you
93
94
 
94
95
  ```typescript
95
- import { Pantsdown, PantsdownConfig } from "pantsdown";
96
+ import { Pantsdown, type PartialPantsdownConfig } from "pantsdown";
96
97
 
97
- const config: PantsdownConfig = {
98
+ // This is the default config object. If you provide
99
+ // a config object, it will be deeply merged into this.
100
+ const config: PartialPantsdownConfig = {
98
101
  renderer: {
99
102
  /**
100
103
  * Prefix to be added to relative image sources.
@@ -111,7 +114,7 @@ const config: PantsdownConfig = {
111
114
  * absolute src remains unchanged:
112
115
  * <img src="https://avatars.githubusercontent.com/wallpants" />
113
116
  */
114
- relativeImageUrlPrefix: "/__localimage__/",
117
+ relativeImageUrlPrefix: "",
115
118
 
116
119
  /**
117
120
  * Whether to render <details> html tags with attribute open=""
@@ -119,7 +122,7 @@ const config: PantsdownConfig = {
119
122
  * @default
120
123
  * false
121
124
  */
122
- detailsTagDefaultOpen: true,
125
+ detailsTagDefaultOpen: false,
123
126
  },
124
127
  };
125
128
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pantsdown",
3
- "version": "1.8.2",
3
+ "version": "1.9.0",
4
4
  "author": "wallpants",
5
5
  "description": "Markdown to 'GitHub HTML' parser",
6
6
  "license": "MIT",
package/src/code-copy.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  export const codeCopyScript = `
2
2
  <script id="code-copy-script" type="module">
3
3
  document.querySelectorAll("pre").forEach((pre) => {
4
+ const firstElement = pre.firstElementChild;
5
+ if (!firstElement || firstElement.tagName !== "CODE") return;
6
+
4
7
  const copyButton = document.createElement("button");
5
8
 
6
9
  const innerHTML =
package/src/pantsdown.ts CHANGED
@@ -2,17 +2,42 @@ import GithubSlugger from "github-slugger";
2
2
  import { codeCopyScript } from "./code-copy.ts";
3
3
  import { Lexer } from "./lexer.ts";
4
4
  import { Parser } from "./parser.ts";
5
- import { type PantsdownConfig } from "./types.ts";
5
+ import { type PantsdownConfig, type PartialPantsdownConfig } from "./types.ts";
6
+
7
+ const defaultConfig: PantsdownConfig = {
8
+ renderer: {
9
+ relativeImageUrlPrefix: "",
10
+ detailsTagDefaultOpen: false,
11
+ },
12
+ };
6
13
 
7
14
  export class Pantsdown {
8
15
  private lexer: Lexer;
9
16
  private parser: Parser;
17
+ config: PantsdownConfig = defaultConfig;
10
18
 
11
- constructor(config?: PantsdownConfig) {
19
+ constructor(config?: PartialPantsdownConfig) {
20
+ if (config) this.setConfig(config);
12
21
  this.lexer = new Lexer();
13
- this.parser = new Parser(config);
22
+ this.parser = new Parser(this);
23
+ }
24
+
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
+ };
14
36
  }
15
37
 
38
+ /**
39
+ * Parse markdown string
40
+ */
16
41
  parse(src: string): string {
17
42
  // re-init slugger to avoid slug count from incorrectly incrementing
18
43
  // from previosly slugged headings
package/src/parser.ts CHANGED
@@ -1,5 +1,6 @@
1
+ import { type Pantsdown } from "./pantsdown.ts";
1
2
  import { Renderer } from "./renderer.ts";
2
- import { type PantsdownConfig, type Token, type Tokens } from "./types.ts";
3
+ import { type Token, type Tokens } from "./types.ts";
3
4
  import { injectHtmlAttributes } from "./utils.ts";
4
5
 
5
6
  /**
@@ -8,8 +9,8 @@ import { injectHtmlAttributes } from "./utils.ts";
8
9
  export class Parser {
9
10
  renderer: Renderer;
10
11
 
11
- constructor(config: PantsdownConfig | undefined) {
12
- this.renderer = new Renderer(config);
12
+ constructor(pantsdown: Pantsdown) {
13
+ this.renderer = new Renderer(pantsdown);
13
14
  }
14
15
 
15
16
  /**
package/src/renderer.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import GithubSlugger from "github-slugger";
2
2
  import hljs from "highlight.js";
3
+ import { type Pantsdown } from "./pantsdown.ts";
3
4
  import { inline } from "./rules/inline.ts";
4
- import { type HTMLAttrs, type PantsdownConfig, type SourceMap, type Tokens } from "./types.ts";
5
+ import { type HTMLAttrs, type SourceMap, type Tokens } from "./types.ts";
5
6
  import {
6
7
  cleanUrl,
7
8
  escape,
@@ -11,45 +12,33 @@ import {
11
12
  injectHtmlAttributes,
12
13
  } from "./utils.ts";
13
14
 
14
- const defaultConfig: NonNullable<PantsdownConfig["renderer"]> = {
15
- relativeImageUrlPrefix: "",
16
- detailsTagDefaultOpen: false,
17
- };
18
-
19
15
  /**
20
16
  * An object containing functions to render tokens to HTML.
21
17
  */
22
18
  export class Renderer {
23
- private rendererConfig: NonNullable<PantsdownConfig["renderer"]>;
19
+ private pantsdown: Pantsdown;
24
20
  slugger = new GithubSlugger();
25
21
 
26
- constructor(config: PantsdownConfig | undefined) {
27
- const rendererConfig = Object.assign(defaultConfig, config?.renderer ?? {});
28
- this.rendererConfig = rendererConfig;
22
+ constructor(pantsdown: Pantsdown) {
23
+ this.pantsdown = pantsdown;
29
24
  }
30
25
 
31
26
  code(code: string, infostring: string | undefined, sourceMap: SourceMap): string {
32
27
  const lang = (infostring ?? "").match(/^\S*/)?.[0];
33
28
  code = code.replace(/\n$/, "") + "\n";
34
29
 
35
- // TODO: render pre and code instead of this section
30
+ const attrs: HTMLAttrs = [];
31
+
36
32
  if (lang === "mermaid") {
37
- return injectHtmlAttributes(
38
- `<section><div class="mermaid">${code}</div></section>`,
39
- [["class", "mermaid-container"]],
40
- sourceMap,
41
- );
33
+ attrs.push(["class", "mermaid-container mermaid"]);
34
+ } else {
35
+ const language = lang && hljs.getLanguage(lang) ? lang : "plaintext";
36
+ code = hljs.highlight(code, { language }).value;
37
+ code = `<code class="hljs language-${escape(language)}">${code}</code>`;
42
38
  }
43
39
 
44
- const language = lang && hljs.getLanguage(lang) ? lang : "plaintext";
45
- const highlightedCode = hljs.highlight(code, { language }).value;
46
-
47
- const result =
48
- `<pre style="position: relative;">` +
49
- `<code class="hljs language-${escape(language)}">${highlightedCode}</code>` +
50
- `</pre>`;
51
-
52
- return injectHtmlAttributes(result, [], sourceMap);
40
+ const result = `<pre style="position: relative;">` + code + `</pre>`;
41
+ return injectHtmlAttributes(result, attrs, sourceMap);
53
42
  }
54
43
 
55
44
  alert(body: string, token: Tokens["Alert"]): string {
@@ -64,11 +53,14 @@ export class Renderer {
64
53
  }
65
54
 
66
55
  html(html: string, _block: boolean, sourceMap?: SourceMap | undefined): string {
67
- const result = fixHtmlLocalImageHref(html, this.rendererConfig.relativeImageUrlPrefix);
56
+ const result = fixHtmlLocalImageHref(
57
+ html,
58
+ this.pantsdown.config.renderer.relativeImageUrlPrefix,
59
+ );
68
60
 
69
61
  const attrs: HTMLAttrs = [];
70
62
 
71
- if (this.rendererConfig.detailsTagDefaultOpen) {
63
+ if (this.pantsdown.config.renderer.detailsTagDefaultOpen) {
72
64
  const tag = inline.tag.exec(html);
73
65
  if (tag?.[0] === "<details>") {
74
66
  attrs.push(["open", ""]);
@@ -189,7 +181,10 @@ export class Renderer {
189
181
  return text;
190
182
  }
191
183
  const attrs: HTMLAttrs = [
192
- ["src", fixLocalImageHref(cleanHref, this.rendererConfig.relativeImageUrlPrefix)],
184
+ [
185
+ "src",
186
+ fixLocalImageHref(cleanHref, this.pantsdown.config.renderer.relativeImageUrlPrefix),
187
+ ],
193
188
  ["alt", text],
194
189
  ];
195
190
  if (title) attrs.push(["title", title]);
package/src/types.ts CHANGED
@@ -219,7 +219,7 @@ export type Token =
219
219
  export type Links = Record<string, { href: string; title: string }>;
220
220
 
221
221
  export type PantsdownConfig = {
222
- renderer?: {
222
+ renderer: {
223
223
  /**
224
224
  * Prefix to be added to relative image sources.
225
225
  * Must start and end with "/"
@@ -235,7 +235,7 @@ export type PantsdownConfig = {
235
235
  * absolute src remains unchanged:
236
236
  * <img src="https://avatars.githubusercontent.com/wallpants" />
237
237
  */
238
- relativeImageUrlPrefix?: string;
238
+ relativeImageUrlPrefix: string;
239
239
 
240
240
  /**
241
241
  * Whether to render <details> html tags with attribute `open=""`
@@ -243,6 +243,12 @@ export type PantsdownConfig = {
243
243
  * @default
244
244
  * false
245
245
  */
246
- detailsTagDefaultOpen?: boolean;
246
+ detailsTagDefaultOpen: boolean;
247
247
  };
248
248
  };
249
+
250
+ type DeepPartial<T> = {
251
+ [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
252
+ };
253
+
254
+ export type PartialPantsdownConfig = DeepPartial<PantsdownConfig>;