@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.
@@ -0,0 +1,379 @@
1
+ import {
2
+ normalizeSlug
3
+ } from "./chunk-ZEQXN4ZD.js";
4
+ import {
5
+ ManifestLoadError,
6
+ SnippetNotFoundError,
7
+ parseFrontMatter,
8
+ renderMarkdown,
9
+ sanitizeMarkup
10
+ } from "./chunk-WZCXKUXV.js";
11
+
12
+ // src/snippet-client.ts
13
+ var HTTP_PATTERN = /^https?:\/\//i;
14
+ var SnippetClient = class {
15
+ constructor(options) {
16
+ this.snippetCache = /* @__PURE__ */ new Map();
17
+ if (!options || !options.manifest) {
18
+ throw new ManifestLoadError(
19
+ "A manifest source must be provided to SnippetClient."
20
+ );
21
+ }
22
+ this.manifestUrl = typeof options.manifest === "string" ? options.manifest : void 0;
23
+ this.inferredBase = this.manifestUrl ? deriveBaseFromManifest(this.manifestUrl) : void 0;
24
+ const fetcher = options.fetch ?? defaultFetch;
25
+ const renderOption = options.render;
26
+ const renderer = renderOption ? async (markdown) => Promise.resolve(renderOption(markdown)) : async (markdown) => Promise.resolve(renderMarkdown(markdown));
27
+ this.options = {
28
+ manifest: options.manifest,
29
+ base: options.base,
30
+ fetch: async (url) => {
31
+ const response = await fetcher(url);
32
+ if (typeof response === "string") {
33
+ return response;
34
+ }
35
+ return resolveResponseText(response, url);
36
+ },
37
+ frontMatter: options.frontMatter !== false,
38
+ cache: options.cache !== false,
39
+ verbose: options.verbose === true,
40
+ render: renderer,
41
+ sanitize: options.sanitize
42
+ };
43
+ }
44
+ async get(slug) {
45
+ const manifest = await this.loadManifest();
46
+ const entry = manifest.find((item) => item.slug === slug);
47
+ if (!entry) {
48
+ throw new SnippetNotFoundError(slug);
49
+ }
50
+ return this.loadSnippet(entry);
51
+ }
52
+ async listAll() {
53
+ const manifest = await this.loadManifest();
54
+ return manifest.map(cloneMeta);
55
+ }
56
+ async listByGroup(group) {
57
+ const manifest = await this.loadManifest();
58
+ return manifest.filter((item) => (item.group ?? null) === group).map(cloneMeta);
59
+ }
60
+ async listByType(type) {
61
+ const manifest = await this.loadManifest();
62
+ return manifest.filter((item) => item.type === type).map(cloneMeta);
63
+ }
64
+ async search(filter) {
65
+ const manifest = await this.loadManifest();
66
+ const tags = filter.tags ?? [];
67
+ const mode = filter.tagsMode ?? "any";
68
+ return manifest.filter((item) => {
69
+ if (filter.type && item.type !== filter.type) {
70
+ return false;
71
+ }
72
+ if (filter.group && (item.group ?? void 0) !== filter.group) {
73
+ return false;
74
+ }
75
+ if (!tags.length) {
76
+ return true;
77
+ }
78
+ const metaTags = item.tags ?? [];
79
+ if (!metaTags.length) {
80
+ return false;
81
+ }
82
+ if (mode === "all") {
83
+ return tags.every((tag) => metaTags.includes(tag));
84
+ }
85
+ return tags.some((tag) => metaTags.includes(tag));
86
+ }).map(cloneMeta);
87
+ }
88
+ async getHtml(slug) {
89
+ const snippet = await this.get(slug);
90
+ return snippet.html;
91
+ }
92
+ invalidate() {
93
+ this.manifestPromise = void 0;
94
+ this.snippetCache.clear();
95
+ }
96
+ invalidateSlug(slug) {
97
+ this.snippetCache.delete(slug);
98
+ }
99
+ async loadManifest() {
100
+ if (this.options.cache && this.manifestPromise) {
101
+ return this.manifestPromise;
102
+ }
103
+ const promise = this.resolveManifest();
104
+ if (this.options.cache) {
105
+ this.manifestPromise = promise;
106
+ }
107
+ return promise;
108
+ }
109
+ async resolveManifest() {
110
+ const source = this.options.manifest;
111
+ let entries;
112
+ try {
113
+ if (Array.isArray(source)) {
114
+ entries = source.map(normalizeManifestEntry);
115
+ } else if (typeof source === "function") {
116
+ const result = await source();
117
+ if (!Array.isArray(result)) {
118
+ throw new ManifestLoadError(
119
+ "Manifest loader must resolve to an array of snippet metadata."
120
+ );
121
+ }
122
+ entries = result.map(normalizeManifestEntry);
123
+ } else {
124
+ const raw = await this.options.fetch(source);
125
+ entries = parseManifest(raw, source).map(normalizeManifestEntry);
126
+ }
127
+ } catch (error) {
128
+ if (error instanceof ManifestLoadError) {
129
+ throw error;
130
+ }
131
+ throw new ManifestLoadError("Failed to load snippet manifest.", error);
132
+ }
133
+ return entries.map(cloneMeta);
134
+ }
135
+ loadSnippet(meta) {
136
+ const cached = this.options.cache ? this.snippetCache.get(meta.slug) : void 0;
137
+ if (cached) {
138
+ return cached;
139
+ }
140
+ const promise = this.fetchSnippet(meta);
141
+ if (this.options.cache) {
142
+ this.snippetCache.set(meta.slug, promise);
143
+ }
144
+ return promise;
145
+ }
146
+ async fetchSnippet(meta) {
147
+ const url = this.resolveSnippetPath(meta.path);
148
+ let raw;
149
+ try {
150
+ raw = await this.options.fetch(url);
151
+ } catch (error) {
152
+ throw new ManifestLoadError(
153
+ `Failed to fetch snippet at '${url}'.`,
154
+ error
155
+ );
156
+ }
157
+ const frontMatter = this.options.frontMatter ? parseFrontMatter(raw) : void 0;
158
+ const body = frontMatter?.content ?? raw;
159
+ let html = await this.options.render(body);
160
+ if (this.options.sanitize) {
161
+ html = sanitizeMarkup(html, this.options.sanitize);
162
+ }
163
+ const merged = {
164
+ ...meta,
165
+ ...pickMeta(frontMatter?.meta),
166
+ extra: mergeExtra(meta.extra, frontMatter?.extra)
167
+ };
168
+ if (frontMatter?.slug) {
169
+ try {
170
+ const normalizedFrontSlug = normalizeSlug(frontMatter.slug);
171
+ if (normalizedFrontSlug !== meta.slug && this.options.verbose) {
172
+ console.warn(
173
+ `Front-matter slug '${frontMatter.slug}' (normalized: '${normalizedFrontSlug}') differs from manifest slug '${meta.slug}'.`
174
+ );
175
+ }
176
+ } catch (error) {
177
+ if (this.options.verbose) {
178
+ console.warn(
179
+ `Failed to normalize front-matter slug '${frontMatter.slug}':`,
180
+ error
181
+ );
182
+ }
183
+ }
184
+ }
185
+ const snippet = { ...merged, html, raw: body, markdown: body };
186
+ if (merged.tags) {
187
+ snippet.tags = [...merged.tags];
188
+ }
189
+ return snippet;
190
+ }
191
+ resolveSnippetPath(path) {
192
+ if (HTTP_PATTERN.test(path)) {
193
+ return normalizeForwardSlashes(path);
194
+ }
195
+ const base = this.options.base ?? this.inferredBase ?? "";
196
+ if (path.startsWith("/")) {
197
+ if (base) {
198
+ return joinPaths(base, path);
199
+ }
200
+ return normalizeForwardSlashes(path);
201
+ }
202
+ if (base) {
203
+ return joinPaths(base, path);
204
+ }
205
+ return normalizeForwardSlashes(path);
206
+ }
207
+ };
208
+ function parseManifest(raw, source) {
209
+ let parsed;
210
+ try {
211
+ parsed = JSON.parse(raw);
212
+ } catch (error) {
213
+ throw new ManifestLoadError(
214
+ `Manifest at '${source}' is not valid JSON.`,
215
+ error
216
+ );
217
+ }
218
+ if (!Array.isArray(parsed)) {
219
+ throw new ManifestLoadError(
220
+ `Manifest at '${source}' must be a JSON array.`
221
+ );
222
+ }
223
+ return parsed;
224
+ }
225
+ function normalizeManifestEntry(entry) {
226
+ if (!entry || typeof entry !== "object") {
227
+ throw new ManifestLoadError("Manifest entry must be an object.");
228
+ }
229
+ if (!entry.slug) {
230
+ throw new ManifestLoadError(
231
+ "Manifest entry is missing required 'slug' property."
232
+ );
233
+ }
234
+ if (!entry.path) {
235
+ throw new ManifestLoadError(
236
+ `Manifest entry for '${entry.slug}' is missing required 'path'.`
237
+ );
238
+ }
239
+ const normalized = {
240
+ slug: entry.slug,
241
+ title: entry.title,
242
+ type: entry.type,
243
+ order: entry.order,
244
+ tags: normalizeTags(entry.tags),
245
+ path: normalizeForwardSlashes(entry.path),
246
+ group: entry.group ?? null,
247
+ draft: entry.draft,
248
+ extra: cloneRecord(entry.extra)
249
+ };
250
+ return normalized;
251
+ }
252
+ function deriveBaseFromManifest(manifest) {
253
+ if (HTTP_PATTERN.test(manifest)) {
254
+ try {
255
+ const url = new URL(manifest);
256
+ url.hash = "";
257
+ url.search = "";
258
+ const path = url.pathname;
259
+ url.pathname = path.replace(/[^/]*$/, "");
260
+ return url.toString();
261
+ } catch (error) {
262
+ console.warn(`Unable to derive base from manifest '${manifest}':`, error);
263
+ return void 0;
264
+ }
265
+ }
266
+ const sanitized = manifest.replace(/[?#].*$/, "");
267
+ const index = sanitized.lastIndexOf("/");
268
+ if (index === -1) {
269
+ return void 0;
270
+ }
271
+ return sanitized.slice(0, index + 1);
272
+ }
273
+ function joinPaths(base, relative) {
274
+ if (HTTP_PATTERN.test(base)) {
275
+ return new URL(relative, base).toString();
276
+ }
277
+ const leading = base.endsWith("/") ? base : `${base}/`;
278
+ const trimmed = relative.startsWith("/") ? relative.slice(1) : relative;
279
+ return normalizeForwardSlashes(`${leading}${trimmed}`);
280
+ }
281
+ function normalizeForwardSlashes(value) {
282
+ const sanitized = value.replace(/\\/g, "/");
283
+ if (HTTP_PATTERN.test(sanitized)) {
284
+ try {
285
+ const url = new URL(sanitized);
286
+ url.pathname = url.pathname.replace(/\/{2,}/g, "/");
287
+ return url.toString();
288
+ } catch {
289
+ }
290
+ }
291
+ if (sanitized.startsWith("//")) {
292
+ return `//${sanitized.slice(2).replace(/\/{2,}/g, "/")}`;
293
+ }
294
+ if (sanitized.startsWith("/")) {
295
+ return `/${sanitized.slice(1).replace(/\/{2,}/g, "/")}`;
296
+ }
297
+ return sanitized.replace(/\/{2,}/g, "/");
298
+ }
299
+ function mergeExtra(base, overrides) {
300
+ if (!base && !overrides) {
301
+ return void 0;
302
+ }
303
+ return { ...base ?? {}, ...overrides ?? {} };
304
+ }
305
+ function cloneRecord(value) {
306
+ if (!value) {
307
+ return value;
308
+ }
309
+ return { ...value };
310
+ }
311
+ function cloneMeta(meta) {
312
+ return {
313
+ ...meta,
314
+ tags: normalizeTags(meta.tags),
315
+ extra: cloneRecord(meta.extra)
316
+ };
317
+ }
318
+ function normalizeTags(value) {
319
+ if (!value) {
320
+ return void 0;
321
+ }
322
+ if (Array.isArray(value)) {
323
+ return value.map((entry) => String(entry));
324
+ }
325
+ if (typeof value === "string") {
326
+ return value.split(",").map((entry) => entry.trim()).filter(Boolean);
327
+ }
328
+ return void 0;
329
+ }
330
+ async function defaultFetch(url) {
331
+ const runtimeFetch = globalThis.fetch;
332
+ if (!runtimeFetch) {
333
+ throw new ManifestLoadError(
334
+ "No global fetch implementation is available. Provide a custom fetch function."
335
+ );
336
+ }
337
+ return runtimeFetch(url);
338
+ }
339
+ async function resolveResponseText(response, url) {
340
+ if (!response.ok) {
341
+ throw new ManifestLoadError(
342
+ `Request to '${url}' failed with status ${response.status}.`
343
+ );
344
+ }
345
+ return response.text();
346
+ }
347
+ function pickMeta(meta) {
348
+ if (!meta) {
349
+ return {};
350
+ }
351
+ const result = {};
352
+ if (meta.title !== void 0) {
353
+ result.title = meta.title;
354
+ }
355
+ if (meta.type !== void 0) {
356
+ result.type = meta.type;
357
+ }
358
+ if (meta.order !== void 0) {
359
+ result.order = meta.order;
360
+ }
361
+ if (meta.tags !== void 0) {
362
+ result.tags = [...meta.tags];
363
+ }
364
+ if (meta.group !== void 0) {
365
+ result.group = meta.group;
366
+ }
367
+ if (meta.draft !== void 0) {
368
+ result.draft = meta.draft;
369
+ }
370
+ if (meta.path !== void 0) {
371
+ result.path = meta.path;
372
+ }
373
+ return result;
374
+ }
375
+
376
+ export {
377
+ SnippetClient
378
+ };
379
+ //# sourceMappingURL=chunk-X5L6GGFF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/snippet-client.ts"],"sourcesContent":["import { normalizeSlug } from \"./slug\";\nimport { parseFrontMatter } from \"./front-matter\";\nimport { renderMarkdown } from \"./markdown\";\nimport { sanitizeMarkup } from \"./sanitize\";\nimport { ManifestLoadError, SnippetNotFoundError } from \"./errors\";\nimport type {\n ManifestSource,\n ResponseLike,\n Snippet,\n SnippetClientOptions,\n SnippetFetcherResult,\n SnippetMeta,\n SnippetSearchFilter,\n} from \"./types\";\n\nexport { ManifestLoadError, SnippetNotFoundError } from \"./errors\";\n\ninterface SnippetClientInternalOptions {\n manifest: ManifestSource;\n base?: string;\n fetch: (url: string) => Promise<string>;\n frontMatter: boolean;\n cache: boolean;\n verbose: boolean;\n render: (markdown: string) => Promise<string>;\n sanitize?: SnippetClientOptions[\"sanitize\"];\n}\n\nconst HTTP_PATTERN = /^https?:\\/\\//i;\n\nexport class SnippetClient {\n private readonly options: SnippetClientInternalOptions;\n private readonly manifestUrl?: string;\n private readonly inferredBase?: string;\n\n private manifestPromise?: Promise<SnippetMeta[]>;\n private readonly snippetCache = new Map<string, Promise<Snippet>>();\n\n constructor(options: SnippetClientOptions) {\n if (!options || !options.manifest) {\n throw new ManifestLoadError(\n \"A manifest source must be provided to SnippetClient.\",\n );\n }\n\n this.manifestUrl =\n typeof options.manifest === \"string\" ? options.manifest : undefined;\n this.inferredBase = this.manifestUrl\n ? deriveBaseFromManifest(this.manifestUrl)\n : undefined;\n\n const fetcher = options.fetch ?? defaultFetch;\n\n const renderOption = options.render;\n\n const renderer = renderOption\n ? async (markdown: string) => Promise.resolve(renderOption(markdown))\n : async (markdown: string) => Promise.resolve(renderMarkdown(markdown));\n\n this.options = {\n manifest: options.manifest,\n base: options.base,\n fetch: async (url: string) => {\n const response = await fetcher(url);\n if (typeof response === \"string\") {\n return response;\n }\n return resolveResponseText(response, url);\n },\n frontMatter: options.frontMatter !== false,\n cache: options.cache !== false,\n verbose: options.verbose === true,\n render: renderer,\n sanitize: options.sanitize,\n };\n }\n\n async get(slug: string): Promise<Snippet> {\n const manifest = await this.loadManifest();\n const entry = manifest.find((item) => item.slug === slug);\n if (!entry) {\n throw new SnippetNotFoundError(slug);\n }\n return this.loadSnippet(entry);\n }\n\n async listAll(): Promise<SnippetMeta[]> {\n const manifest = await this.loadManifest();\n return manifest.map(cloneMeta);\n }\n\n async listByGroup(group: string): Promise<SnippetMeta[]> {\n const manifest = await this.loadManifest();\n return manifest\n .filter((item) => (item.group ?? null) === group)\n .map(cloneMeta);\n }\n\n async listByType(type: string): Promise<SnippetMeta[]> {\n const manifest = await this.loadManifest();\n return manifest.filter((item) => item.type === type).map(cloneMeta);\n }\n\n async search(filter: SnippetSearchFilter): Promise<SnippetMeta[]> {\n const manifest = await this.loadManifest();\n const tags = filter.tags ?? [];\n const mode = filter.tagsMode ?? \"any\";\n\n return manifest\n .filter((item) => {\n if (filter.type && item.type !== filter.type) {\n return false;\n }\n if (filter.group && (item.group ?? undefined) !== filter.group) {\n return false;\n }\n if (!tags.length) {\n return true;\n }\n const metaTags = item.tags ?? [];\n if (!metaTags.length) {\n return false;\n }\n if (mode === \"all\") {\n return tags.every((tag) => metaTags.includes(tag));\n }\n return tags.some((tag) => metaTags.includes(tag));\n })\n .map(cloneMeta);\n }\n\n async getHtml(slug: string): Promise<string> {\n const snippet = await this.get(slug);\n return snippet.html;\n }\n\n invalidate(): void {\n this.manifestPromise = undefined;\n this.snippetCache.clear();\n }\n\n invalidateSlug(slug: string): void {\n this.snippetCache.delete(slug);\n }\n\n private async loadManifest(): Promise<SnippetMeta[]> {\n if (this.options.cache && this.manifestPromise) {\n return this.manifestPromise;\n }\n\n const promise = this.resolveManifest();\n if (this.options.cache) {\n this.manifestPromise = promise;\n }\n return promise;\n }\n\n private async resolveManifest(): Promise<SnippetMeta[]> {\n const source = this.options.manifest;\n let entries: SnippetMeta[];\n\n try {\n if (Array.isArray(source)) {\n entries = source.map(normalizeManifestEntry);\n } else if (typeof source === \"function\") {\n const result = await source();\n if (!Array.isArray(result)) {\n throw new ManifestLoadError(\n \"Manifest loader must resolve to an array of snippet metadata.\",\n );\n }\n entries = result.map(normalizeManifestEntry);\n } else {\n const raw = await this.options.fetch(source);\n entries = parseManifest(raw, source).map(normalizeManifestEntry);\n }\n } catch (error) {\n if (error instanceof ManifestLoadError) {\n throw error;\n }\n throw new ManifestLoadError(\"Failed to load snippet manifest.\", error);\n }\n\n return entries.map(cloneMeta);\n }\n\n private loadSnippet(meta: SnippetMeta): Promise<Snippet> {\n const cached = this.options.cache\n ? this.snippetCache.get(meta.slug)\n : undefined;\n if (cached) {\n return cached;\n }\n const promise = this.fetchSnippet(meta);\n if (this.options.cache) {\n this.snippetCache.set(meta.slug, promise);\n }\n return promise;\n }\n\n private async fetchSnippet(meta: SnippetMeta): Promise<Snippet> {\n const url = this.resolveSnippetPath(meta.path);\n let raw: string;\n try {\n raw = await this.options.fetch(url);\n } catch (error) {\n throw new ManifestLoadError(\n `Failed to fetch snippet at '${url}'.`,\n error,\n );\n }\n\n const frontMatter = this.options.frontMatter\n ? parseFrontMatter(raw)\n : undefined;\n const body = frontMatter?.content ?? raw;\n let html = await this.options.render(body);\n if (this.options.sanitize) {\n html = sanitizeMarkup(html, this.options.sanitize);\n }\n\n const merged: SnippetMeta = {\n ...meta,\n ...pickMeta(frontMatter?.meta),\n extra: mergeExtra(meta.extra, frontMatter?.extra),\n };\n\n if (frontMatter?.slug) {\n try {\n const normalizedFrontSlug = normalizeSlug(frontMatter.slug);\n if (normalizedFrontSlug !== meta.slug && this.options.verbose) {\n console.warn(\n `Front-matter slug '${frontMatter.slug}' (normalized: '${normalizedFrontSlug}') differs from manifest slug '${meta.slug}'.`,\n );\n }\n } catch (error) {\n if (this.options.verbose) {\n console.warn(\n `Failed to normalize front-matter slug '${frontMatter.slug}':`,\n error,\n );\n }\n }\n }\n\n const snippet: Snippet = { ...merged, html, raw: body, markdown: body };\n if (merged.tags) {\n snippet.tags = [...merged.tags];\n }\n return snippet;\n }\n\n private resolveSnippetPath(path: string): string {\n if (HTTP_PATTERN.test(path)) {\n return normalizeForwardSlashes(path);\n }\n\n const base = this.options.base ?? this.inferredBase ?? \"\";\n\n if (path.startsWith(\"/\")) {\n if (base) {\n return joinPaths(base, path);\n }\n return normalizeForwardSlashes(path);\n }\n\n if (base) {\n return joinPaths(base, path);\n }\n return normalizeForwardSlashes(path);\n }\n}\n\nfunction parseManifest(raw: string, source: string): SnippetMeta[] {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (error) {\n throw new ManifestLoadError(\n `Manifest at '${source}' is not valid JSON.`,\n error,\n );\n }\n\n if (!Array.isArray(parsed)) {\n throw new ManifestLoadError(\n `Manifest at '${source}' must be a JSON array.`,\n );\n }\n\n return parsed as SnippetMeta[];\n}\n\nfunction normalizeManifestEntry(entry: SnippetMeta): SnippetMeta {\n if (!entry || typeof entry !== \"object\") {\n throw new ManifestLoadError(\"Manifest entry must be an object.\");\n }\n if (!entry.slug) {\n throw new ManifestLoadError(\n \"Manifest entry is missing required 'slug' property.\",\n );\n }\n if (!entry.path) {\n throw new ManifestLoadError(\n `Manifest entry for '${entry.slug}' is missing required 'path'.`,\n );\n }\n const normalized: SnippetMeta = {\n slug: entry.slug,\n title: entry.title,\n type: entry.type,\n order: entry.order,\n tags: normalizeTags(entry.tags),\n path: normalizeForwardSlashes(entry.path),\n group: entry.group ?? null,\n draft: entry.draft,\n extra: cloneRecord(entry.extra),\n };\n return normalized;\n}\n\nfunction deriveBaseFromManifest(manifest: string): string | undefined {\n if (HTTP_PATTERN.test(manifest)) {\n try {\n const url = new URL(manifest);\n url.hash = \"\";\n url.search = \"\";\n const path = url.pathname;\n url.pathname = path.replace(/[^/]*$/, \"\");\n return url.toString();\n } catch (error) {\n console.warn(`Unable to derive base from manifest '${manifest}':`, error);\n return undefined;\n }\n }\n\n const sanitized = manifest.replace(/[?#].*$/, \"\");\n const index = sanitized.lastIndexOf(\"/\");\n if (index === -1) {\n return undefined;\n }\n return sanitized.slice(0, index + 1);\n}\n\nfunction joinPaths(base: string, relative: string): string {\n if (HTTP_PATTERN.test(base)) {\n return new URL(relative, base).toString();\n }\n const leading = base.endsWith(\"/\") ? base : `${base}/`;\n const trimmed = relative.startsWith(\"/\") ? relative.slice(1) : relative;\n return normalizeForwardSlashes(`${leading}${trimmed}`);\n}\n\nfunction normalizeForwardSlashes(value: string): string {\n const sanitized = value.replace(/\\\\/g, \"/\");\n if (HTTP_PATTERN.test(sanitized)) {\n try {\n const url = new URL(sanitized);\n url.pathname = url.pathname.replace(/\\/{2,}/g, \"/\");\n return url.toString();\n } catch {\n // fall back to manual normalization below\n }\n }\n\n if (sanitized.startsWith(\"//\")) {\n return `//${sanitized.slice(2).replace(/\\/{2,}/g, \"/\")}`;\n }\n\n if (sanitized.startsWith(\"/\")) {\n return `/${sanitized.slice(1).replace(/\\/{2,}/g, \"/\")}`;\n }\n\n return sanitized.replace(/\\/{2,}/g, \"/\");\n}\n\nfunction mergeExtra(\n base: Record<string, unknown> | undefined,\n overrides: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined {\n if (!base && !overrides) {\n return undefined;\n }\n return { ...(base ?? {}), ...(overrides ?? {}) };\n}\n\nfunction cloneRecord<T extends Record<string, unknown> | undefined>(\n value: T,\n): T {\n if (!value) {\n return value;\n }\n return { ...value } as T;\n}\n\nfunction cloneMeta(meta: SnippetMeta): SnippetMeta {\n return {\n ...meta,\n tags: normalizeTags(meta.tags),\n extra: cloneRecord(meta.extra),\n };\n}\n\nfunction normalizeTags(value: unknown): string[] | undefined {\n if (!value) {\n return undefined;\n }\n if (Array.isArray(value)) {\n return value.map((entry) => String(entry));\n }\n if (typeof value === \"string\") {\n return value\n .split(\",\")\n .map((entry) => entry.trim())\n .filter(Boolean);\n }\n return undefined;\n}\n\nasync function defaultFetch(url: string): Promise<SnippetFetcherResult> {\n const runtimeFetch = (\n globalThis as typeof globalThis & { fetch?: typeof fetch }\n ).fetch;\n if (!runtimeFetch) {\n throw new ManifestLoadError(\n \"No global fetch implementation is available. Provide a custom fetch function.\",\n );\n }\n return runtimeFetch(url);\n}\n\nasync function resolveResponseText(\n response: ResponseLike,\n url: string,\n): Promise<string> {\n if (!response.ok) {\n throw new ManifestLoadError(\n `Request to '${url}' failed with status ${response.status}.`,\n );\n }\n return response.text();\n}\n\nfunction pickMeta(meta?: Partial<SnippetMeta>): Partial<SnippetMeta> {\n if (!meta) {\n return {};\n }\n const result: Partial<SnippetMeta> = {};\n if (meta.title !== undefined) {\n result.title = meta.title;\n }\n if (meta.type !== undefined) {\n result.type = meta.type;\n }\n if (meta.order !== undefined) {\n result.order = meta.order;\n }\n if (meta.tags !== undefined) {\n result.tags = [...meta.tags];\n }\n if (meta.group !== undefined) {\n result.group = meta.group;\n }\n if (meta.draft !== undefined) {\n result.draft = meta.draft;\n }\n if (meta.path !== undefined) {\n result.path = meta.path;\n }\n return result;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,21 @@
1
+ // src/slug.ts
2
+ var NON_ALPHANUMERIC = /[^a-z0-9]+/gi;
3
+ var LEADING_TRAILING_DASH = /^-+|-+$/g;
4
+ function normalizeSlug(input) {
5
+ const value = input?.trim();
6
+ if (!value) {
7
+ throw new Error("Cannot normalize an empty slug");
8
+ }
9
+ const normalized = value.toLowerCase().replace(NON_ALPHANUMERIC, "-").replace(/-{2,}/g, "-").replace(LEADING_TRAILING_DASH, "");
10
+ if (!normalized) {
11
+ throw new Error(
12
+ `Slug '${input}' does not contain any alphanumeric characters`
13
+ );
14
+ }
15
+ return normalized;
16
+ }
17
+
18
+ export {
19
+ normalizeSlug
20
+ };
21
+ //# sourceMappingURL=chunk-ZEQXN4ZD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/slug.ts"],"sourcesContent":["const NON_ALPHANUMERIC = /[^a-z0-9]+/gi;\nconst LEADING_TRAILING_DASH = /^-+|-+$/g;\n\nexport function normalizeSlug(input: string): string {\n const value = input?.trim();\n if (!value) {\n throw new Error(\"Cannot normalize an empty slug\");\n }\n\n const normalized = value\n .toLowerCase()\n .replace(NON_ALPHANUMERIC, \"-\")\n .replace(/-{2,}/g, \"-\")\n .replace(LEADING_TRAILING_DASH, \"\");\n\n if (!normalized) {\n throw new Error(\n `Slug '${input}' does not contain any alphanumeric characters`,\n );\n }\n\n return normalized;\n}\n"],"mappings":";AAAA,IAAM,mBAAmB;AACzB,IAAM,wBAAwB;AAEvB,SAAS,cAAc,OAAuB;AACnD,QAAM,QAAQ,OAAO,KAAK;AAC1B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AAEA,QAAM,aAAa,MAChB,YAAY,EACZ,QAAQ,kBAAkB,GAAG,EAC7B,QAAQ,UAAU,GAAG,EACrB,QAAQ,uBAAuB,EAAE;AAEpC,MAAI,CAAC,YAAY;AACf,UAAM,IAAI;AAAA,MACR,SAAS,KAAK;AAAA,IAChB;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
@@ -0,0 +1,27 @@
1
+ import { S as SnippetMeta } from './snippet-client-S6E_j24g.js';
2
+ export { M as ManifestSource, R as ResponseLike, a as Snippet, f as SnippetClient, e as SnippetClientOptions, d as SnippetFetcher, c as SnippetFetcherResult, b as SnippetSearchFilter } from './snippet-client-S6E_j24g.js';
3
+ export { normalizeSlug } from './slug.js';
4
+ export { S as SanitizeOptions, a as SanitizePolicy, s as sanitizeMarkup } from './sanitize-DI2uKnlG.js';
5
+ import 'sanitize-html';
6
+
7
+ declare class SnippetNotFoundError extends Error {
8
+ readonly slug: string;
9
+ constructor(slug: string);
10
+ }
11
+ declare class ManifestLoadError extends Error {
12
+ readonly cause?: unknown;
13
+ constructor(message: string, cause?: unknown);
14
+ }
15
+
16
+ interface FrontMatterResult {
17
+ content: string;
18
+ meta: Partial<SnippetMeta>;
19
+ extra: Record<string, unknown>;
20
+ slug?: string;
21
+ hasFrontMatter: boolean;
22
+ }
23
+ declare function parseFrontMatter(raw: string): FrontMatterResult;
24
+
25
+ declare function renderMarkdown(markdown: string): string;
26
+
27
+ export { ManifestLoadError, SnippetMeta, SnippetNotFoundError, parseFrontMatter, renderMarkdown };
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ import {
2
+ SnippetClient
3
+ } from "./chunk-X5L6GGFF.js";
4
+ import {
5
+ normalizeSlug
6
+ } from "./chunk-ZEQXN4ZD.js";
7
+ import {
8
+ ManifestLoadError,
9
+ SnippetNotFoundError,
10
+ parseFrontMatter,
11
+ renderMarkdown,
12
+ sanitizeMarkup
13
+ } from "./chunk-WZCXKUXV.js";
14
+ import "./chunk-BRKEJJFQ.js";
15
+ export {
16
+ ManifestLoadError,
17
+ SnippetClient,
18
+ SnippetNotFoundError,
19
+ normalizeSlug,
20
+ parseFrontMatter,
21
+ renderMarkdown,
22
+ sanitizeMarkup
23
+ };
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,12 @@
1
+ import { S as SanitizeOptions } from './sanitize-DI2uKnlG.js';
2
+ import 'sanitize-html';
3
+
4
+ interface InlineMarkdownOptions {
5
+ selector?: string;
6
+ processFrontMatter?: boolean;
7
+ applyMetaToDom?: boolean;
8
+ sanitize?: SanitizeOptions;
9
+ }
10
+ declare function enhanceInlineMarkdown(options?: InlineMarkdownOptions): void;
11
+
12
+ export { type InlineMarkdownOptions, enhanceInlineMarkdown };
@@ -1,80 +1,79 @@
1
- import { parseFrontMatter, type FrontMatterResult } from "./front-matter";
2
- import { renderMarkdown } from "./markdown";
3
-
4
- export interface InlineMarkdownOptions {
5
- selector?: string;
6
- processFrontMatter?: boolean;
7
- applyMetaToDom?: boolean;
8
- }
9
-
10
- const DEFAULT_SELECTOR = "[data-markdown]";
11
-
12
- export function enhanceInlineMarkdown(options: InlineMarkdownOptions = {}): void {
1
+ import {
2
+ parseFrontMatter,
3
+ renderMarkdown,
4
+ sanitizeMarkup
5
+ } from "./chunk-WZCXKUXV.js";
6
+ import "./chunk-BRKEJJFQ.js";
7
+
8
+ // src/inline.ts
9
+ var DEFAULT_SELECTOR = "[data-markdown]";
10
+ function enhanceInlineMarkdown(options = {}) {
13
11
  if (typeof document === "undefined") {
14
12
  return;
15
13
  }
16
-
17
14
  const selector = options.selector ?? DEFAULT_SELECTOR;
18
15
  const processFrontMatter = options.processFrontMatter !== false;
19
16
  const applyMetaToDom = options.applyMetaToDom !== false;
20
-
21
- const elements = Array.from(document.querySelectorAll<HTMLElement>(selector));
17
+ const sanitize = options.sanitize;
18
+ let elements = [];
19
+ try {
20
+ elements = Array.from(document.querySelectorAll(selector));
21
+ } catch (error) {
22
+ console.warn("[mark\u2193 inline] Invalid selector provided:", error);
23
+ return;
24
+ }
22
25
  for (const element of elements) {
23
26
  if (element.dataset.markdownProcessed === "true") {
24
27
  continue;
25
28
  }
26
- processElement(element, { processFrontMatter, applyMetaToDom });
29
+ processElement(element, { processFrontMatter, applyMetaToDom, sanitize });
27
30
  }
28
31
  }
29
-
30
- function processElement(
31
- element: HTMLElement,
32
- options: { processFrontMatter: boolean; applyMetaToDom: boolean }
33
- ): void {
32
+ function processElement(element, options) {
34
33
  const raw = element.textContent ?? "";
35
- let frontMatter: FrontMatterResult | undefined;
36
-
34
+ let frontMatter;
37
35
  if (options.processFrontMatter) {
38
36
  try {
39
37
  frontMatter = parseFrontMatter(raw);
40
38
  } catch (error) {
41
- console.warn("[mark↓ inline] Failed to parse front matter for element:", error);
42
- frontMatter = undefined;
39
+ console.warn(
40
+ "[mark\u2193 inline] Failed to parse front matter for element:",
41
+ error
42
+ );
43
+ frontMatter = void 0;
43
44
  }
44
45
  }
45
-
46
46
  const body = frontMatter?.content ?? raw;
47
- const html = renderMarkdown(body);
48
-
47
+ let html = renderMarkdown(body);
48
+ if (options.sanitize) {
49
+ html = sanitizeMarkup(html, options.sanitize);
50
+ }
49
51
  element.innerHTML = html;
50
52
  element.dataset.markdownProcessed = "true";
51
-
52
53
  if (options.applyMetaToDom && frontMatter?.hasFrontMatter) {
53
54
  applyMetaAttributes(element, frontMatter);
54
55
  }
55
56
  }
56
-
57
- function applyMetaAttributes(element: HTMLElement, frontMatter: FrontMatterResult): void {
57
+ function applyMetaAttributes(element, frontMatter) {
58
58
  const { slug, meta, extra } = frontMatter;
59
-
60
59
  if (slug) {
61
60
  if (!element.id) {
62
61
  element.id = slug;
63
62
  }
64
63
  element.dataset.slug = slug;
65
64
  }
66
-
67
65
  if (meta.title) {
68
66
  element.dataset.title = meta.title;
69
67
  }
70
-
71
68
  if (meta.tags?.length) {
72
69
  element.dataset.tags = meta.tags.join(",");
73
70
  }
74
-
75
71
  const variant = typeof extra.variant === "string" ? extra.variant.trim() : "";
76
72
  if (variant) {
77
73
  element.classList.add(`md-block--${variant}`);
78
74
  }
79
-
80
75
  }
76
+ export {
77
+ enhanceInlineMarkdown
78
+ };
79
+ //# sourceMappingURL=inline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/inline.ts"],"sourcesContent":["import { parseFrontMatter, type FrontMatterResult } from \"./front-matter\";\nimport { renderMarkdown } from \"./markdown\";\nimport { sanitizeMarkup, type SanitizeOptions } from \"./sanitize\";\n\nexport interface InlineMarkdownOptions {\n selector?: string;\n processFrontMatter?: boolean;\n applyMetaToDom?: boolean;\n sanitize?: SanitizeOptions;\n}\n\nconst DEFAULT_SELECTOR = \"[data-markdown]\";\n\nexport function enhanceInlineMarkdown(\n options: InlineMarkdownOptions = {},\n): void {\n if (typeof document === \"undefined\") {\n return;\n }\n\n const selector = options.selector ?? DEFAULT_SELECTOR;\n const processFrontMatter = options.processFrontMatter !== false;\n const applyMetaToDom = options.applyMetaToDom !== false;\n const sanitize = options.sanitize;\n\n let elements: HTMLElement[] = [];\n try {\n elements = Array.from(document.querySelectorAll<HTMLElement>(selector));\n } catch (error) {\n console.warn(\"[mark↓ inline] Invalid selector provided:\", error);\n return;\n }\n for (const element of elements) {\n if (element.dataset.markdownProcessed === \"true\") {\n continue;\n }\n processElement(element, { processFrontMatter, applyMetaToDom, sanitize });\n }\n}\n\nfunction processElement(\n element: HTMLElement,\n options: {\n processFrontMatter: boolean;\n applyMetaToDom: boolean;\n sanitize?: SanitizeOptions;\n },\n): void {\n const raw = element.textContent ?? \"\";\n let frontMatter: FrontMatterResult | undefined;\n\n if (options.processFrontMatter) {\n try {\n frontMatter = parseFrontMatter(raw);\n } catch (error) {\n console.warn(\n \"[mark↓ inline] Failed to parse front matter for element:\",\n error,\n );\n frontMatter = undefined;\n }\n }\n\n const body = frontMatter?.content ?? raw;\n let html = renderMarkdown(body);\n if (options.sanitize) {\n html = sanitizeMarkup(html, options.sanitize);\n }\n\n element.innerHTML = html;\n element.dataset.markdownProcessed = \"true\";\n\n if (options.applyMetaToDom && frontMatter?.hasFrontMatter) {\n applyMetaAttributes(element, frontMatter);\n }\n}\n\nfunction applyMetaAttributes(\n element: HTMLElement,\n frontMatter: FrontMatterResult,\n): void {\n const { slug, meta, extra } = frontMatter;\n\n if (slug) {\n if (!element.id) {\n element.id = slug;\n }\n element.dataset.slug = slug;\n }\n\n if (meta.title) {\n element.dataset.title = meta.title;\n }\n\n if (meta.tags?.length) {\n element.dataset.tags = meta.tags.join(\",\");\n }\n\n const variant = typeof extra.variant === \"string\" ? extra.variant.trim() : \"\";\n if (variant) {\n element.classList.add(`md-block--${variant}`);\n }\n}\n"],"mappings":";;;;;;;;AAWA,IAAM,mBAAmB;AAElB,SAAS,sBACd,UAAiC,CAAC,GAC5B;AACN,MAAI,OAAO,aAAa,aAAa;AACnC;AAAA,EACF;AAEA,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,qBAAqB,QAAQ,uBAAuB;AAC1D,QAAM,iBAAiB,QAAQ,mBAAmB;AAClD,QAAM,WAAW,QAAQ;AAEzB,MAAI,WAA0B,CAAC;AAC/B,MAAI;AACF,eAAW,MAAM,KAAK,SAAS,iBAA8B,QAAQ,CAAC;AAAA,EACxE,SAAS,OAAO;AACd,YAAQ,KAAK,kDAA6C,KAAK;AAC/D;AAAA,EACF;AACA,aAAW,WAAW,UAAU;AAC9B,QAAI,QAAQ,QAAQ,sBAAsB,QAAQ;AAChD;AAAA,IACF;AACA,mBAAe,SAAS,EAAE,oBAAoB,gBAAgB,SAAS,CAAC;AAAA,EAC1E;AACF;AAEA,SAAS,eACP,SACA,SAKM;AACN,QAAM,MAAM,QAAQ,eAAe;AACnC,MAAI;AAEJ,MAAI,QAAQ,oBAAoB;AAC9B,QAAI;AACF,oBAAc,iBAAiB,GAAG;AAAA,IACpC,SAAS,OAAO;AACd,cAAQ;AAAA,QACN;AAAA,QACA;AAAA,MACF;AACA,oBAAc;AAAA,IAChB;AAAA,EACF;AAEA,QAAM,OAAO,aAAa,WAAW;AACrC,MAAI,OAAO,eAAe,IAAI;AAC9B,MAAI,QAAQ,UAAU;AACpB,WAAO,eAAe,MAAM,QAAQ,QAAQ;AAAA,EAC9C;AAEA,UAAQ,YAAY;AACpB,UAAQ,QAAQ,oBAAoB;AAEpC,MAAI,QAAQ,kBAAkB,aAAa,gBAAgB;AACzD,wBAAoB,SAAS,WAAW;AAAA,EAC1C;AACF;AAEA,SAAS,oBACP,SACA,aACM;AACN,QAAM,EAAE,MAAM,MAAM,MAAM,IAAI;AAE9B,MAAI,MAAM;AACR,QAAI,CAAC,QAAQ,IAAI;AACf,cAAQ,KAAK;AAAA,IACf;AACA,YAAQ,QAAQ,OAAO;AAAA,EACzB;AAEA,MAAI,KAAK,OAAO;AACd,YAAQ,QAAQ,QAAQ,KAAK;AAAA,EAC/B;AAEA,MAAI,KAAK,MAAM,QAAQ;AACrB,YAAQ,QAAQ,OAAO,KAAK,KAAK,KAAK,GAAG;AAAA,EAC3C;AAEA,QAAM,UAAU,OAAO,MAAM,YAAY,WAAW,MAAM,QAAQ,KAAK,IAAI;AAC3E,MAAI,SAAS;AACX,YAAQ,UAAU,IAAI,aAAa,OAAO,EAAE;AAAA,EAC9C;AACF;","names":[]}