@mzebley/mark-down 1.2.1 → 1.2.3

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,6 @@
1
1
  # mark↓ Core Runtime
2
- *(published as `@mzebley/mark-down`)*
2
+
3
+ _(published as `@mzebley/mark-down`)_
3
4
 
4
5
  This package provides the framework-agnostic `SnippetClient` and supporting types used to fetch, cache, and render Markdown snippets at runtime. For a monorepo overview visit the [root README](../../README.md).
5
6
 
@@ -54,9 +55,12 @@ The client lazily loads the manifest when first needed, then fetches Markdown fi
54
55
  - **`cache`** (`boolean`, default `true`) – enable or disable per-snippet and manifest memoisation.
55
56
  - **`verbose`** (`boolean`) – log helpful warnings (for example, slug mismatches) during development.
56
57
  - **`render`** (`(markdown: string) => string | Promise<string>`) – override the default `marked` renderer when you need custom HTML output.
58
+ - **`sanitize`** (`{ policy?: "default" | "strict" | "permissive"; config?: SanitizeHtmlOptions }`) – optionally sanitize rendered HTML before it is returned.
57
59
 
58
60
  All options are optional except `manifest`. Results are rendered with `marked` by default; override at the application level if you need a different Markdown pipeline.
59
61
 
62
+ `sanitize` is opt-in and uses [`sanitize-html`](https://github.com/apostrophecms/sanitize-html) under the hood. Use the `policy` presets for common Markdown output or override the `config` to tweak allowed tags/attributes. The React and Angular adapters already sanitize before rendering; enabling `sanitize` with those adapters is usually redundant.
63
+
60
64
  ## Working with snippets
61
65
 
62
66
  Commonly used APIs:
@@ -80,12 +84,13 @@ import { SnippetClient } from "@mzebley/mark-down";
80
84
 
81
85
  const client = new SnippetClient({
82
86
  manifest: () => import("./snippets-index.json"),
83
- fetch: (url) => fetch(url).then((response) => {
84
- if (!response.ok) {
85
- throw new Error(`Request failed with status ${response.status}`);
86
- }
87
- return response;
88
- }),
87
+ fetch: (url) =>
88
+ fetch(url).then((response) => {
89
+ if (!response.ok) {
90
+ throw new Error(`Request failed with status ${response.status}`);
91
+ }
92
+ return response;
93
+ }),
89
94
  });
90
95
  ```
91
96
 
@@ -145,11 +150,7 @@ Host the UMD file yourself or load it from a CDN—no build tooling required.
145
150
  Write plain Markdown directly in your HTML. The helper finds `[data-markdown]` blocks by default.
146
151
 
147
152
  ```html
148
- <div data-markdown>
149
- # Hello
150
-
151
- This is inline markdown with no build step.
152
- </div>
153
+ <div data-markdown># Hello This is inline markdown with no build step.</div>
153
154
 
154
155
  <script src="path/to/mark-down-inline.umd.js"></script>
155
156
  <script>
@@ -167,16 +168,8 @@ You can optionally prepend YAML front matter to provide metadata for each block.
167
168
 
168
169
  ```html
169
170
  <div data-markdown>
170
- ---
171
- slug: intro
172
- title: Introduction
173
- tags: [hero]
174
- variant: lead
175
- ---
176
-
177
- # Introduction
178
-
179
- This block has metadata.
171
+ --- slug: intro title: Introduction tags: [hero] variant: lead --- #
172
+ Introduction This block has metadata.
180
173
  </div>
181
174
  ```
182
175
 
@@ -196,6 +189,7 @@ enhanceInlineMarkdown({
196
189
  selector?: string; // defaults to "[data-markdown]"
197
190
  processFrontMatter?: boolean; // defaults to true
198
191
  applyMetaToDom?: boolean; // defaults to true
192
+ sanitize?: { policy?: "default" | "strict" | "permissive"; config?: SanitizeHtmlOptions };
199
193
  });
200
194
  ```
201
195
 
@@ -0,0 +1,20 @@
1
+ import { InjectionToken, Provider } from '@angular/core';
2
+ import { Observable } from 'rxjs';
3
+ import { f as SnippetClient, e as SnippetClientOptions, a as Snippet, S as SnippetMeta } from '../snippet-client-S6E_j24g.js';
4
+ import '../sanitize-DI2uKnlG.js';
5
+ import 'sanitize-html';
6
+
7
+ declare const SNIPPET_CLIENT: InjectionToken<SnippetClient>;
8
+ declare const SNIPPET_CLIENT_OPTIONS: InjectionToken<SnippetClientOptions>;
9
+ declare function provideSnippetClient(options: SnippetClientOptions): Provider[];
10
+ declare class MarkdownSnippetService {
11
+ private readonly client;
12
+ constructor(client: SnippetClient);
13
+ get(slug: string): Observable<Snippet>;
14
+ listAll(): Observable<SnippetMeta[]>;
15
+ listByGroup(group: string): Observable<SnippetMeta[]>;
16
+ listByType(type: string): Observable<SnippetMeta[]>;
17
+ html(slug: string): Observable<string>;
18
+ }
19
+
20
+ export { MarkdownSnippetService, SNIPPET_CLIENT, SNIPPET_CLIENT_OPTIONS, Snippet, SnippetClientOptions, SnippetMeta, provideSnippetClient };
@@ -0,0 +1,68 @@
1
+ import {
2
+ SnippetClient
3
+ } from "../chunk-X5L6GGFF.js";
4
+ import "../chunk-ZEQXN4ZD.js";
5
+ import "../chunk-WZCXKUXV.js";
6
+ import {
7
+ __decorateClass,
8
+ __decorateParam
9
+ } from "../chunk-BRKEJJFQ.js";
10
+
11
+ // src/angular/index.ts
12
+ import { Inject, Injectable, InjectionToken } from "@angular/core";
13
+ import { from, map, shareReplay } from "rxjs";
14
+ var SNIPPET_CLIENT = new InjectionToken(
15
+ "@mzebley/mark-down/SNIPPET_CLIENT"
16
+ );
17
+ var SNIPPET_CLIENT_OPTIONS = new InjectionToken(
18
+ "@mzebley/mark-down/SNIPPET_CLIENT_OPTIONS"
19
+ );
20
+ function provideSnippetClient(options) {
21
+ return [
22
+ { provide: SNIPPET_CLIENT_OPTIONS, useValue: options },
23
+ {
24
+ provide: SNIPPET_CLIENT,
25
+ useFactory: (opts) => new SnippetClient(opts),
26
+ deps: [SNIPPET_CLIENT_OPTIONS]
27
+ }
28
+ ];
29
+ }
30
+ var MarkdownSnippetService = class {
31
+ constructor(client) {
32
+ this.client = client;
33
+ }
34
+ get(slug) {
35
+ return from(this.client.get(slug)).pipe(
36
+ shareReplay({ bufferSize: 1, refCount: true })
37
+ );
38
+ }
39
+ listAll() {
40
+ return from(this.client.listAll()).pipe(
41
+ shareReplay({ bufferSize: 1, refCount: true })
42
+ );
43
+ }
44
+ listByGroup(group) {
45
+ return from(this.client.listByGroup(group)).pipe(
46
+ shareReplay({ bufferSize: 1, refCount: true })
47
+ );
48
+ }
49
+ listByType(type) {
50
+ return from(this.client.listByType(type)).pipe(
51
+ shareReplay({ bufferSize: 1, refCount: true })
52
+ );
53
+ }
54
+ html(slug) {
55
+ return this.get(slug).pipe(map((snippet) => snippet.html));
56
+ }
57
+ };
58
+ MarkdownSnippetService = __decorateClass([
59
+ Injectable({ providedIn: "root" }),
60
+ __decorateParam(0, Inject(SNIPPET_CLIENT))
61
+ ], MarkdownSnippetService);
62
+ export {
63
+ MarkdownSnippetService,
64
+ SNIPPET_CLIENT,
65
+ SNIPPET_CLIENT_OPTIONS,
66
+ provideSnippetClient
67
+ };
68
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/angular/index.ts"],"sourcesContent":["import { Inject, Injectable, InjectionToken, Provider } from \"@angular/core\";\nimport { from, map, Observable, shareReplay } from \"rxjs\";\nimport { SnippetClient } from \"../snippet-client\";\nimport type { Snippet, SnippetClientOptions, SnippetMeta } from \"../types\";\n\nexport const SNIPPET_CLIENT = new InjectionToken<SnippetClient>(\n \"@mzebley/mark-down/SNIPPET_CLIENT\",\n);\nexport const SNIPPET_CLIENT_OPTIONS = new InjectionToken<SnippetClientOptions>(\n \"@mzebley/mark-down/SNIPPET_CLIENT_OPTIONS\",\n);\n\nexport function provideSnippetClient(\n options: SnippetClientOptions,\n): Provider[] {\n return [\n { provide: SNIPPET_CLIENT_OPTIONS, useValue: options },\n {\n provide: SNIPPET_CLIENT,\n useFactory: (opts: SnippetClientOptions) => new SnippetClient(opts),\n deps: [SNIPPET_CLIENT_OPTIONS],\n },\n ];\n}\n\n@Injectable({ providedIn: \"root\" })\nexport class MarkdownSnippetService {\n constructor(@Inject(SNIPPET_CLIENT) private readonly client: SnippetClient) {}\n\n get(slug: string): Observable<Snippet> {\n return from(this.client.get(slug)).pipe(\n shareReplay({ bufferSize: 1, refCount: true }),\n );\n }\n\n listAll(): Observable<SnippetMeta[]> {\n return from(this.client.listAll()).pipe(\n shareReplay({ bufferSize: 1, refCount: true }),\n );\n }\n\n listByGroup(group: string): Observable<SnippetMeta[]> {\n return from(this.client.listByGroup(group)).pipe(\n shareReplay({ bufferSize: 1, refCount: true }),\n );\n }\n\n listByType(type: string): Observable<SnippetMeta[]> {\n return from(this.client.listByType(type)).pipe(\n shareReplay({ bufferSize: 1, refCount: true }),\n );\n }\n\n html(slug: string): Observable<string> {\n return this.get(slug).pipe(map((snippet) => snippet.html));\n }\n}\n\nexport type { Snippet, SnippetClientOptions, SnippetMeta } from \"../types\";\n"],"mappings":";;;;;;;;;;;AAAA,SAAS,QAAQ,YAAY,sBAAgC;AAC7D,SAAS,MAAM,KAAiB,mBAAmB;AAI5C,IAAM,iBAAiB,IAAI;AAAA,EAChC;AACF;AACO,IAAM,yBAAyB,IAAI;AAAA,EACxC;AACF;AAEO,SAAS,qBACd,SACY;AACZ,SAAO;AAAA,IACL,EAAE,SAAS,wBAAwB,UAAU,QAAQ;AAAA,IACrD;AAAA,MACE,SAAS;AAAA,MACT,YAAY,CAAC,SAA+B,IAAI,cAAc,IAAI;AAAA,MAClE,MAAM,CAAC,sBAAsB;AAAA,IAC/B;AAAA,EACF;AACF;AAGO,IAAM,yBAAN,MAA6B;AAAA,EAClC,YAAqD,QAAuB;AAAvB;AAAA,EAAwB;AAAA,EAE7E,IAAI,MAAmC;AACrC,WAAO,KAAK,KAAK,OAAO,IAAI,IAAI,CAAC,EAAE;AAAA,MACjC,YAAY,EAAE,YAAY,GAAG,UAAU,KAAK,CAAC;AAAA,IAC/C;AAAA,EACF;AAAA,EAEA,UAAqC;AACnC,WAAO,KAAK,KAAK,OAAO,QAAQ,CAAC,EAAE;AAAA,MACjC,YAAY,EAAE,YAAY,GAAG,UAAU,KAAK,CAAC;AAAA,IAC/C;AAAA,EACF;AAAA,EAEA,YAAY,OAA0C;AACpD,WAAO,KAAK,KAAK,OAAO,YAAY,KAAK,CAAC,EAAE;AAAA,MAC1C,YAAY,EAAE,YAAY,GAAG,UAAU,KAAK,CAAC;AAAA,IAC/C;AAAA,EACF;AAAA,EAEA,WAAW,MAAyC;AAClD,WAAO,KAAK,KAAK,OAAO,WAAW,IAAI,CAAC,EAAE;AAAA,MACxC,YAAY,EAAE,YAAY,GAAG,UAAU,KAAK,CAAC;AAAA,IAC/C;AAAA,EACF;AAAA,EAEA,KAAK,MAAkC;AACrC,WAAO,KAAK,IAAI,IAAI,EAAE,KAAK,IAAI,CAAC,YAAY,QAAQ,IAAI,CAAC;AAAA,EAC3D;AACF;AA9Ba,yBAAN;AAAA,EADN,WAAW,EAAE,YAAY,OAAO,CAAC;AAAA,EAEnB,0BAAO,cAAc;AAAA,GADvB;","names":[]}