@mzebley/mark-down 1.2.0 → 1.2.2
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/dist/angular/index.d.ts +18 -0
- package/dist/angular/index.js +58 -0
- package/dist/angular/index.js.map +1 -0
- package/dist/browser.js +580 -0
- package/dist/browser.js.map +1 -0
- package/{src/snippet-client.ts → dist/chunk-35YHML5Z.js} +97 -174
- package/dist/chunk-35YHML5Z.js.map +1 -0
- package/dist/chunk-BRKEJJFQ.js +17 -0
- package/dist/chunk-BRKEJJFQ.js.map +1 -0
- package/dist/chunk-GWLMADTU.js +19 -0
- package/dist/chunk-GWLMADTU.js.map +1 -0
- package/{src/front-matter.ts → dist/chunk-MWZFQXNW.js} +48 -39
- package/dist/chunk-MWZFQXNW.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/inline.d.ts +8 -0
- package/{src/inline.ts → dist/inline.js} +19 -34
- package/dist/inline.js.map +1 -0
- package/dist/mark-down-inline.umd.js +8486 -0
- package/dist/mark-down-inline.umd.js.map +1 -0
- package/dist/slug.d.ts +3 -0
- package/dist/slug.js +8 -0
- package/dist/slug.js.map +1 -0
- package/dist/snippet-client-CiQX2Zcn.d.ts +63 -0
- package/package.json +12 -6
- package/src/angular/index.ts +0 -47
- package/src/browser.ts +0 -141
- package/src/errors.ts +0 -19
- package/src/index.ts +0 -5
- package/src/markdown.ts +0 -11
- package/src/slug.ts +0 -21
- package/src/types.ts +0 -49
- package/tsconfig.json +0 -7
- package/tsup.config.ts +0 -59
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/slug.ts","../src/front-matter.ts","../src/errors.ts","../src/markdown.ts","../src/snippet-client.ts","../src/browser.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(`Slug '${input}' does not contain any alphanumeric characters`);\n }\n\n return normalized;\n}\n","import { parse as parseYaml } from \"yaml\";\nimport { ManifestLoadError } from \"./errors\";\nimport type { SnippetMeta } from \"./types\";\n\nexport interface FrontMatterResult {\n content: string;\n meta: Partial<SnippetMeta>;\n extra: Record<string, unknown>;\n slug?: string;\n hasFrontMatter: boolean;\n}\n\nconst FRONT_MATTER_PATTERN = /^(?:\\uFEFF)?[ \\t\\r\\n]*---\\s*\\r?\\n([\\s\\S]*?)\\r?\\n---\\s*\\r?\\n?/;\n\nexport function parseFrontMatter(raw: string): FrontMatterResult {\n const match = FRONT_MATTER_PATTERN.exec(raw);\n if (!match) {\n return { content: raw, meta: {}, extra: {}, hasFrontMatter: false };\n }\n\n const yamlSection = match[1];\n let data: unknown;\n try {\n data = parseYaml(yamlSection) ?? {};\n } catch (error) {\n throw new ManifestLoadError(\"Failed to parse snippet front-matter.\", error);\n }\n\n if (!isRecord(data)) {\n return { content: raw.slice(match[0].length), meta: {}, extra: {}, hasFrontMatter: true };\n }\n\n const { known, extra } = splitFrontMatter(data);\n\n return {\n content: raw.slice(match[0].length),\n meta: known.meta,\n extra,\n slug: known.slug,\n hasFrontMatter: true\n };\n}\n\nfunction splitFrontMatter(\n data: Record<string, unknown>\n): { known: { meta: Partial<SnippetMeta>; slug?: string }; extra: Record<string, unknown> } {\n const meta: Partial<SnippetMeta> = {};\n const extra: Record<string, unknown> = {};\n let slug: string | undefined;\n\n for (const [key, value] of Object.entries(data)) {\n switch (key) {\n case \"slug\":\n slug = typeof value === \"string\" ? value : undefined;\n break;\n case \"title\":\n if (typeof value === \"string\") {\n meta.title = value;\n }\n break;\n case \"type\":\n if (typeof value === \"string\") {\n meta.type = value;\n }\n break;\n case \"order\":\n if (typeof value === \"number\") {\n meta.order = value;\n }\n break;\n case \"tags\":\n meta.tags = normalizeTags(value);\n break;\n case \"group\":\n if (typeof value === \"string\" || value === null) {\n meta.group = value;\n }\n break;\n case \"draft\":\n if (typeof value === \"boolean\") {\n meta.draft = value;\n }\n break;\n default:\n extra[key] = value;\n break;\n }\n }\n\n return { known: { meta, slug }, extra };\n}\n\nfunction normalizeTags(value: unknown): string[] | undefined {\n if (!value) {\n return undefined;\n }\n if (Array.isArray(value)) {\n return value.map((item) => String(item));\n }\n if (typeof value === \"string\") {\n return value\n .split(\",\")\n .map((tag) => tag.trim())\n .filter(Boolean);\n }\n return undefined;\n}\n\nfunction isRecord(candidate: unknown): candidate is Record<string, unknown> {\n return Boolean(candidate) && typeof candidate === \"object\" && !Array.isArray(candidate);\n}\n","export class SnippetNotFoundError extends Error {\n readonly slug: string;\n\n constructor(slug: string) {\n super(`Snippet with slug '${slug}' was not found in the manifest.`);\n this.name = \"SnippetNotFoundError\";\n this.slug = slug;\n }\n}\n\nexport class ManifestLoadError extends Error {\n readonly cause?: unknown;\n\n constructor(message: string, cause?: unknown) {\n super(message);\n this.name = \"ManifestLoadError\";\n this.cause = cause instanceof Error ? cause : cause ? new Error(String(cause)) : undefined;\n }\n}\n","import { marked } from \"marked\";\n\nexport function renderMarkdown(markdown: string): string {\n const html = marked.parse(markdown);\n\n if (typeof html === \"string\") {\n return html;\n }\n\n throw new Error(\"renderMarkdown unexpectedly returned a Promise\");\n}\n","import { normalizeSlug } from \"./slug\";\nimport { parseFrontMatter } from \"./front-matter\";\nimport { renderMarkdown } from \"./markdown\";\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}\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(\"A manifest source must be provided to SnippetClient.\");\n }\n\n this.manifestUrl = typeof options.manifest === \"string\" ? options.manifest : undefined;\n this.inferredBase = this.manifestUrl ? deriveBaseFromManifest(this.manifestUrl) : 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 };\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\n .filter((item) => item.type === type)\n .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(\"Manifest loader must resolve to an array of snippet metadata.\");\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 ? this.snippetCache.get(meta.slug) : 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(`Failed to fetch snippet at '${url}'.`, error);\n }\n\n const frontMatter = this.options.frontMatter ? parseFrontMatter(raw) : undefined;\n const body = frontMatter?.content ?? raw;\n const html = await this.options.render(body);\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(`Failed to normalize front-matter slug '${frontMatter.slug}':`, error);\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(`Manifest at '${source}' is not valid JSON.`, error);\n }\n\n if (!Array.isArray(parsed)) {\n throw new ManifestLoadError(`Manifest at '${source}' must be a JSON array.`);\n }\n\n return parsed as SnippetMeta[];\n}\n\nfunction normalizeManifestEntry(entry: SnippetMeta): SnippetMeta {\n if (!entry.slug) {\n throw new ManifestLoadError(\"Manifest entry is missing required 'slug' property.\");\n }\n if (!entry.path) {\n throw new ManifestLoadError(`Manifest entry for '${entry.slug}' is missing required 'path'.`);\n }\n const normalized: SnippetMeta = {\n slug: entry.slug,\n title: entry.title,\n type: entry.type,\n order: entry.order,\n tags: entry.tags ? [...entry.tags] : undefined,\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 if (HTTP_PATTERN.test(value)) {\n try {\n const url = new URL(value);\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 (value.startsWith(\"//\")) {\n return `//${value.slice(2).replace(/\\/{2,}/g, \"/\")}`;\n }\n\n if (value.startsWith(\"/\")) {\n return `/${value\n .slice(1)\n .replace(/\\/{2,}/g, \"/\")}`;\n }\n\n return value.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>(value: T): 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: meta.tags ? [...meta.tags] : undefined,\n extra: cloneRecord(meta.extra)\n };\n}\n\nasync function defaultFetch(url: string): Promise<SnippetFetcherResult> {\n const runtimeFetch = (globalThis as typeof globalThis & { fetch?: typeof fetch }).fetch;\n if (!runtimeFetch) {\n throw new ManifestLoadError(\"No global fetch implementation is available. Provide a custom fetch function.\");\n }\n return runtimeFetch(url);\n}\n\nasync function resolveResponseText(response: ResponseLike, url: string): Promise<string> {\n if (!response.ok) {\n throw new ManifestLoadError(`Request to '${url}' failed with status ${response.status}.`);\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","installBufferShim();\n\nexport * from \"./index\";\n\nfunction installBufferShim() {\n const globalRef = globalThis as typeof globalThis & { Buffer?: BufferConstructor };\n\n if (typeof globalRef.Buffer !== \"undefined\") {\n return;\n }\n\n const textEncoder = new TextEncoder();\n const textDecoder = new TextDecoder();\n\n class BrowserBuffer extends Uint8Array {\n constructor(value: number | ArrayBufferLike | ArrayBufferView | ArrayLike<number>) {\n if (typeof value === \"number\") {\n super(value);\n return;\n }\n\n if (isArrayBufferLike(value)) {\n super(new Uint8Array(value));\n return;\n }\n\n if (ArrayBuffer.isView(value)) {\n super(\n new Uint8Array(value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength))\n );\n return;\n }\n\n super(Array.from(value));\n }\n\n override toString(encoding: BufferEncoding = \"utf-8\") {\n if (encoding !== \"utf-8\" && encoding !== \"utf8\") {\n throw new Error(`Unsupported encoding '${encoding}' in browser Buffer shim`);\n }\n return textDecoder.decode(this);\n }\n }\n\n const from = (value: string | ArrayLike<number> | BufferSource, encoding: BufferEncoding = \"utf-8\") => {\n if (typeof value === \"string\") {\n if (encoding !== \"utf-8\" && encoding !== \"utf8\") {\n throw new Error(`Unsupported encoding '${encoding}' in browser Buffer shim`);\n }\n return new BrowserBuffer(textEncoder.encode(value));\n }\n\n if (isArrayBufferLike(value)) {\n return new BrowserBuffer(new Uint8Array(value));\n }\n\n if (ArrayBuffer.isView(value)) {\n return new BrowserBuffer(value);\n }\n\n if (typeof (value as ArrayLike<number>).length === \"number\") {\n return new BrowserBuffer(Array.from(value as ArrayLike<number>));\n }\n\n throw new TypeError(\"Unsupported input passed to Buffer.from in browser shim\");\n };\n\n const alloc = (size: number, fill?: number | string) => {\n if (size < 0) {\n throw new RangeError(\"Invalid Buffer size\");\n }\n const buffer = new BrowserBuffer(size);\n if (typeof fill === \"number\") {\n buffer.fill(fill);\n } else if (typeof fill === \"string\") {\n if (!fill.length) {\n buffer.fill(0);\n } else {\n const pattern = textEncoder.encode(fill);\n for (let i = 0; i < buffer.length; i++) {\n buffer[i] = pattern[i % pattern.length];\n }\n }\n } else {\n buffer.fill(0);\n }\n return buffer;\n };\n\n const concat = (buffers: ArrayLike<Uint8Array>, totalLength?: number) => {\n const sanitized = Array.from(buffers, (buffer) =>\n buffer instanceof BrowserBuffer ? buffer : new BrowserBuffer(buffer)\n );\n const length = totalLength ?? sanitized.reduce((acc, current) => acc + current.length, 0);\n const result = new BrowserBuffer(length);\n let offset = 0;\n for (const buffer of sanitized) {\n result.set(buffer, offset);\n offset += buffer.length;\n }\n return result;\n };\n\n const byteLength = (value: string | ArrayBuffer | ArrayBufferView) => {\n if (typeof value === \"string\") {\n return textEncoder.encode(value).length;\n }\n if (value instanceof ArrayBuffer) {\n return value.byteLength;\n }\n if (ArrayBuffer.isView(value)) {\n return value.byteLength;\n }\n throw new TypeError(\"Unable to determine byte length for provided value\");\n };\n\n Object.defineProperties(BrowserBuffer, {\n from: { value: from },\n isBuffer: { value: (candidate: unknown) => candidate instanceof BrowserBuffer },\n alloc: { value: alloc },\n concat: { value: concat },\n byteLength: { value: byteLength }\n });\n\n BrowserBuffer.prototype.valueOf = function valueOf() {\n return this;\n };\n\n globalRef.Buffer = BrowserBuffer as unknown as BufferConstructor;\n\n if (typeof window !== \"undefined\" && typeof (window as typeof globalThis).Buffer === \"undefined\") {\n (window as typeof globalThis & { Buffer?: BufferConstructor }).Buffer = globalRef.Buffer;\n }\n}\n\nfunction isArrayBufferLike(value: unknown): value is ArrayBufferLike {\n if (value instanceof ArrayBuffer) {\n return true;\n }\n return typeof SharedArrayBuffer !== \"undefined\" && value instanceof SharedArrayBuffer;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,59 +1,30 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
interface SnippetClientInternalOptions {
|
|
18
|
-
manifest: ManifestSource;
|
|
19
|
-
base?: string;
|
|
20
|
-
fetch: (url: string) => Promise<string>;
|
|
21
|
-
frontMatter: boolean;
|
|
22
|
-
cache: boolean;
|
|
23
|
-
verbose: boolean;
|
|
24
|
-
render: (markdown: string) => Promise<string>;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const HTTP_PATTERN = /^https?:\/\//i;
|
|
28
|
-
|
|
29
|
-
export class SnippetClient {
|
|
30
|
-
private readonly options: SnippetClientInternalOptions;
|
|
31
|
-
private readonly manifestUrl?: string;
|
|
32
|
-
private readonly inferredBase?: string;
|
|
33
|
-
|
|
34
|
-
private manifestPromise?: Promise<SnippetMeta[]>;
|
|
35
|
-
private readonly snippetCache = new Map<string, Promise<Snippet>>();
|
|
36
|
-
|
|
37
|
-
constructor(options: SnippetClientOptions) {
|
|
1
|
+
import {
|
|
2
|
+
normalizeSlug
|
|
3
|
+
} from "./chunk-GWLMADTU.js";
|
|
4
|
+
import {
|
|
5
|
+
ManifestLoadError,
|
|
6
|
+
SnippetNotFoundError,
|
|
7
|
+
parseFrontMatter,
|
|
8
|
+
renderMarkdown
|
|
9
|
+
} from "./chunk-MWZFQXNW.js";
|
|
10
|
+
|
|
11
|
+
// src/snippet-client.ts
|
|
12
|
+
var HTTP_PATTERN = /^https?:\/\//i;
|
|
13
|
+
var SnippetClient = class {
|
|
14
|
+
constructor(options) {
|
|
15
|
+
this.snippetCache = /* @__PURE__ */ new Map();
|
|
38
16
|
if (!options || !options.manifest) {
|
|
39
17
|
throw new ManifestLoadError("A manifest source must be provided to SnippetClient.");
|
|
40
18
|
}
|
|
41
|
-
|
|
42
|
-
this.
|
|
43
|
-
this.inferredBase = this.manifestUrl ? deriveBaseFromManifest(this.manifestUrl) : undefined;
|
|
44
|
-
|
|
19
|
+
this.manifestUrl = typeof options.manifest === "string" ? options.manifest : void 0;
|
|
20
|
+
this.inferredBase = this.manifestUrl ? deriveBaseFromManifest(this.manifestUrl) : void 0;
|
|
45
21
|
const fetcher = options.fetch ?? defaultFetch;
|
|
46
|
-
|
|
47
22
|
const renderOption = options.render;
|
|
48
|
-
|
|
49
|
-
const renderer = renderOption
|
|
50
|
-
? async (markdown: string) => Promise.resolve(renderOption(markdown))
|
|
51
|
-
: async (markdown: string) => Promise.resolve(renderMarkdown(markdown));
|
|
52
|
-
|
|
23
|
+
const renderer = renderOption ? async (markdown) => Promise.resolve(renderOption(markdown)) : async (markdown) => Promise.resolve(renderMarkdown(markdown));
|
|
53
24
|
this.options = {
|
|
54
25
|
manifest: options.manifest,
|
|
55
26
|
base: options.base,
|
|
56
|
-
fetch: async (url
|
|
27
|
+
fetch: async (url) => {
|
|
57
28
|
const response = await fetcher(url);
|
|
58
29
|
if (typeof response === "string") {
|
|
59
30
|
return response;
|
|
@@ -66,8 +37,7 @@ export class SnippetClient {
|
|
|
66
37
|
render: renderer
|
|
67
38
|
};
|
|
68
39
|
}
|
|
69
|
-
|
|
70
|
-
async get(slug: string): Promise<Snippet> {
|
|
40
|
+
async get(slug) {
|
|
71
41
|
const manifest = await this.loadManifest();
|
|
72
42
|
const entry = manifest.find((item) => item.slug === slug);
|
|
73
43
|
if (!entry) {
|
|
@@ -75,84 +45,66 @@ export class SnippetClient {
|
|
|
75
45
|
}
|
|
76
46
|
return this.loadSnippet(entry);
|
|
77
47
|
}
|
|
78
|
-
|
|
79
|
-
async listAll(): Promise<SnippetMeta[]> {
|
|
48
|
+
async listAll() {
|
|
80
49
|
const manifest = await this.loadManifest();
|
|
81
50
|
return manifest.map(cloneMeta);
|
|
82
51
|
}
|
|
83
|
-
|
|
84
|
-
async listByGroup(group: string): Promise<SnippetMeta[]> {
|
|
52
|
+
async listByGroup(group) {
|
|
85
53
|
const manifest = await this.loadManifest();
|
|
86
|
-
return manifest
|
|
87
|
-
.filter((item) => (item.group ?? null) === group)
|
|
88
|
-
.map(cloneMeta);
|
|
54
|
+
return manifest.filter((item) => (item.group ?? null) === group).map(cloneMeta);
|
|
89
55
|
}
|
|
90
|
-
|
|
91
|
-
async listByType(type: string): Promise<SnippetMeta[]> {
|
|
56
|
+
async listByType(type) {
|
|
92
57
|
const manifest = await this.loadManifest();
|
|
93
|
-
return manifest
|
|
94
|
-
.filter((item) => item.type === type)
|
|
95
|
-
.map(cloneMeta);
|
|
58
|
+
return manifest.filter((item) => item.type === type).map(cloneMeta);
|
|
96
59
|
}
|
|
97
|
-
|
|
98
|
-
async search(filter: SnippetSearchFilter): Promise<SnippetMeta[]> {
|
|
60
|
+
async search(filter) {
|
|
99
61
|
const manifest = await this.loadManifest();
|
|
100
62
|
const tags = filter.tags ?? [];
|
|
101
63
|
const mode = filter.tagsMode ?? "any";
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return tags.some((tag) => metaTags.includes(tag));
|
|
122
|
-
})
|
|
123
|
-
.map(cloneMeta);
|
|
64
|
+
return manifest.filter((item) => {
|
|
65
|
+
if (filter.type && item.type !== filter.type) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
if (filter.group && (item.group ?? void 0) !== filter.group) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
if (!tags.length) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
const metaTags = item.tags ?? [];
|
|
75
|
+
if (!metaTags.length) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
if (mode === "all") {
|
|
79
|
+
return tags.every((tag) => metaTags.includes(tag));
|
|
80
|
+
}
|
|
81
|
+
return tags.some((tag) => metaTags.includes(tag));
|
|
82
|
+
}).map(cloneMeta);
|
|
124
83
|
}
|
|
125
|
-
|
|
126
|
-
async getHtml(slug: string): Promise<string> {
|
|
84
|
+
async getHtml(slug) {
|
|
127
85
|
const snippet = await this.get(slug);
|
|
128
86
|
return snippet.html;
|
|
129
87
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
this.manifestPromise = undefined;
|
|
88
|
+
invalidate() {
|
|
89
|
+
this.manifestPromise = void 0;
|
|
133
90
|
this.snippetCache.clear();
|
|
134
91
|
}
|
|
135
|
-
|
|
136
|
-
invalidateSlug(slug: string): void {
|
|
92
|
+
invalidateSlug(slug) {
|
|
137
93
|
this.snippetCache.delete(slug);
|
|
138
94
|
}
|
|
139
|
-
|
|
140
|
-
private async loadManifest(): Promise<SnippetMeta[]> {
|
|
95
|
+
async loadManifest() {
|
|
141
96
|
if (this.options.cache && this.manifestPromise) {
|
|
142
97
|
return this.manifestPromise;
|
|
143
98
|
}
|
|
144
|
-
|
|
145
99
|
const promise = this.resolveManifest();
|
|
146
100
|
if (this.options.cache) {
|
|
147
101
|
this.manifestPromise = promise;
|
|
148
102
|
}
|
|
149
103
|
return promise;
|
|
150
104
|
}
|
|
151
|
-
|
|
152
|
-
private async resolveManifest(): Promise<SnippetMeta[]> {
|
|
105
|
+
async resolveManifest() {
|
|
153
106
|
const source = this.options.manifest;
|
|
154
|
-
let entries
|
|
155
|
-
|
|
107
|
+
let entries;
|
|
156
108
|
try {
|
|
157
109
|
if (Array.isArray(source)) {
|
|
158
110
|
entries = source.map(normalizeManifestEntry);
|
|
@@ -172,12 +124,10 @@ export class SnippetClient {
|
|
|
172
124
|
}
|
|
173
125
|
throw new ManifestLoadError("Failed to load snippet manifest.", error);
|
|
174
126
|
}
|
|
175
|
-
|
|
176
127
|
return entries.map(cloneMeta);
|
|
177
128
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const cached = this.options.cache ? this.snippetCache.get(meta.slug) : undefined;
|
|
129
|
+
loadSnippet(meta) {
|
|
130
|
+
const cached = this.options.cache ? this.snippetCache.get(meta.slug) : void 0;
|
|
181
131
|
if (cached) {
|
|
182
132
|
return cached;
|
|
183
133
|
}
|
|
@@ -187,26 +137,22 @@ export class SnippetClient {
|
|
|
187
137
|
}
|
|
188
138
|
return promise;
|
|
189
139
|
}
|
|
190
|
-
|
|
191
|
-
private async fetchSnippet(meta: SnippetMeta): Promise<Snippet> {
|
|
140
|
+
async fetchSnippet(meta) {
|
|
192
141
|
const url = this.resolveSnippetPath(meta.path);
|
|
193
|
-
let raw
|
|
142
|
+
let raw;
|
|
194
143
|
try {
|
|
195
144
|
raw = await this.options.fetch(url);
|
|
196
145
|
} catch (error) {
|
|
197
146
|
throw new ManifestLoadError(`Failed to fetch snippet at '${url}'.`, error);
|
|
198
147
|
}
|
|
199
|
-
|
|
200
|
-
const frontMatter = this.options.frontMatter ? parseFrontMatter(raw) : undefined;
|
|
148
|
+
const frontMatter = this.options.frontMatter ? parseFrontMatter(raw) : void 0;
|
|
201
149
|
const body = frontMatter?.content ?? raw;
|
|
202
150
|
const html = await this.options.render(body);
|
|
203
|
-
|
|
204
|
-
const merged: SnippetMeta = {
|
|
151
|
+
const merged = {
|
|
205
152
|
...meta,
|
|
206
153
|
...pickMeta(frontMatter?.meta),
|
|
207
154
|
extra: mergeExtra(meta.extra, frontMatter?.extra)
|
|
208
155
|
};
|
|
209
|
-
|
|
210
156
|
if (frontMatter?.slug) {
|
|
211
157
|
try {
|
|
212
158
|
const normalizedFrontSlug = normalizeSlug(frontMatter.slug);
|
|
@@ -221,63 +167,54 @@ export class SnippetClient {
|
|
|
221
167
|
}
|
|
222
168
|
}
|
|
223
169
|
}
|
|
224
|
-
|
|
225
|
-
const snippet: Snippet = { ...merged, html, raw: body, markdown: body };
|
|
170
|
+
const snippet = { ...merged, html, raw: body, markdown: body };
|
|
226
171
|
if (merged.tags) {
|
|
227
172
|
snippet.tags = [...merged.tags];
|
|
228
173
|
}
|
|
229
174
|
return snippet;
|
|
230
175
|
}
|
|
231
|
-
|
|
232
|
-
private resolveSnippetPath(path: string): string {
|
|
176
|
+
resolveSnippetPath(path) {
|
|
233
177
|
if (HTTP_PATTERN.test(path)) {
|
|
234
178
|
return normalizeForwardSlashes(path);
|
|
235
179
|
}
|
|
236
|
-
|
|
237
180
|
const base = this.options.base ?? this.inferredBase ?? "";
|
|
238
|
-
|
|
239
181
|
if (path.startsWith("/")) {
|
|
240
182
|
if (base) {
|
|
241
183
|
return joinPaths(base, path);
|
|
242
184
|
}
|
|
243
185
|
return normalizeForwardSlashes(path);
|
|
244
186
|
}
|
|
245
|
-
|
|
246
187
|
if (base) {
|
|
247
188
|
return joinPaths(base, path);
|
|
248
189
|
}
|
|
249
190
|
return normalizeForwardSlashes(path);
|
|
250
191
|
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
let parsed: unknown;
|
|
192
|
+
};
|
|
193
|
+
function parseManifest(raw, source) {
|
|
194
|
+
let parsed;
|
|
255
195
|
try {
|
|
256
196
|
parsed = JSON.parse(raw);
|
|
257
197
|
} catch (error) {
|
|
258
198
|
throw new ManifestLoadError(`Manifest at '${source}' is not valid JSON.`, error);
|
|
259
199
|
}
|
|
260
|
-
|
|
261
200
|
if (!Array.isArray(parsed)) {
|
|
262
201
|
throw new ManifestLoadError(`Manifest at '${source}' must be a JSON array.`);
|
|
263
202
|
}
|
|
264
|
-
|
|
265
|
-
return parsed as SnippetMeta[];
|
|
203
|
+
return parsed;
|
|
266
204
|
}
|
|
267
|
-
|
|
268
|
-
function normalizeManifestEntry(entry: SnippetMeta): SnippetMeta {
|
|
205
|
+
function normalizeManifestEntry(entry) {
|
|
269
206
|
if (!entry.slug) {
|
|
270
207
|
throw new ManifestLoadError("Manifest entry is missing required 'slug' property.");
|
|
271
208
|
}
|
|
272
209
|
if (!entry.path) {
|
|
273
210
|
throw new ManifestLoadError(`Manifest entry for '${entry.slug}' is missing required 'path'.`);
|
|
274
211
|
}
|
|
275
|
-
const normalized
|
|
212
|
+
const normalized = {
|
|
276
213
|
slug: entry.slug,
|
|
277
214
|
title: entry.title,
|
|
278
215
|
type: entry.type,
|
|
279
216
|
order: entry.order,
|
|
280
|
-
tags: entry.tags ? [...entry.tags] :
|
|
217
|
+
tags: entry.tags ? [...entry.tags] : void 0,
|
|
281
218
|
path: normalizeForwardSlashes(entry.path),
|
|
282
219
|
group: entry.group ?? null,
|
|
283
220
|
draft: entry.draft,
|
|
@@ -285,8 +222,7 @@ function normalizeManifestEntry(entry: SnippetMeta): SnippetMeta {
|
|
|
285
222
|
};
|
|
286
223
|
return normalized;
|
|
287
224
|
}
|
|
288
|
-
|
|
289
|
-
function deriveBaseFromManifest(manifest: string): string | undefined {
|
|
225
|
+
function deriveBaseFromManifest(manifest) {
|
|
290
226
|
if (HTTP_PATTERN.test(manifest)) {
|
|
291
227
|
try {
|
|
292
228
|
const url = new URL(manifest);
|
|
@@ -297,19 +233,17 @@ function deriveBaseFromManifest(manifest: string): string | undefined {
|
|
|
297
233
|
return url.toString();
|
|
298
234
|
} catch (error) {
|
|
299
235
|
console.warn(`Unable to derive base from manifest '${manifest}':`, error);
|
|
300
|
-
return
|
|
236
|
+
return void 0;
|
|
301
237
|
}
|
|
302
238
|
}
|
|
303
|
-
|
|
304
239
|
const sanitized = manifest.replace(/[?#].*$/, "");
|
|
305
240
|
const index = sanitized.lastIndexOf("/");
|
|
306
241
|
if (index === -1) {
|
|
307
|
-
return
|
|
242
|
+
return void 0;
|
|
308
243
|
}
|
|
309
244
|
return sanitized.slice(0, index + 1);
|
|
310
245
|
}
|
|
311
|
-
|
|
312
|
-
function joinPaths(base: string, relative: string): string {
|
|
246
|
+
function joinPaths(base, relative) {
|
|
313
247
|
if (HTTP_PATTERN.test(base)) {
|
|
314
248
|
return new URL(relative, base).toString();
|
|
315
249
|
}
|
|
@@ -317,96 +251,85 @@ function joinPaths(base: string, relative: string): string {
|
|
|
317
251
|
const trimmed = relative.startsWith("/") ? relative.slice(1) : relative;
|
|
318
252
|
return normalizeForwardSlashes(`${leading}${trimmed}`);
|
|
319
253
|
}
|
|
320
|
-
|
|
321
|
-
function normalizeForwardSlashes(value: string): string {
|
|
254
|
+
function normalizeForwardSlashes(value) {
|
|
322
255
|
if (HTTP_PATTERN.test(value)) {
|
|
323
256
|
try {
|
|
324
257
|
const url = new URL(value);
|
|
325
258
|
url.pathname = url.pathname.replace(/\/{2,}/g, "/");
|
|
326
259
|
return url.toString();
|
|
327
260
|
} catch {
|
|
328
|
-
// fall back to manual normalization below
|
|
329
261
|
}
|
|
330
262
|
}
|
|
331
|
-
|
|
332
263
|
if (value.startsWith("//")) {
|
|
333
264
|
return `//${value.slice(2).replace(/\/{2,}/g, "/")}`;
|
|
334
265
|
}
|
|
335
|
-
|
|
336
266
|
if (value.startsWith("/")) {
|
|
337
|
-
return `/${value
|
|
338
|
-
.slice(1)
|
|
339
|
-
.replace(/\/{2,}/g, "/")}`;
|
|
267
|
+
return `/${value.slice(1).replace(/\/{2,}/g, "/")}`;
|
|
340
268
|
}
|
|
341
|
-
|
|
342
269
|
return value.replace(/\/{2,}/g, "/");
|
|
343
270
|
}
|
|
344
|
-
|
|
345
|
-
function mergeExtra(
|
|
346
|
-
base: Record<string, unknown> | undefined,
|
|
347
|
-
overrides: Record<string, unknown> | undefined
|
|
348
|
-
): Record<string, unknown> | undefined {
|
|
271
|
+
function mergeExtra(base, overrides) {
|
|
349
272
|
if (!base && !overrides) {
|
|
350
|
-
return
|
|
273
|
+
return void 0;
|
|
351
274
|
}
|
|
352
|
-
return { ...
|
|
275
|
+
return { ...base ?? {}, ...overrides ?? {} };
|
|
353
276
|
}
|
|
354
|
-
|
|
355
|
-
function cloneRecord<T extends Record<string, unknown> | undefined>(value: T): T {
|
|
277
|
+
function cloneRecord(value) {
|
|
356
278
|
if (!value) {
|
|
357
279
|
return value;
|
|
358
280
|
}
|
|
359
|
-
return { ...value }
|
|
281
|
+
return { ...value };
|
|
360
282
|
}
|
|
361
|
-
|
|
362
|
-
function cloneMeta(meta: SnippetMeta): SnippetMeta {
|
|
283
|
+
function cloneMeta(meta) {
|
|
363
284
|
return {
|
|
364
285
|
...meta,
|
|
365
|
-
tags: meta.tags ? [...meta.tags] :
|
|
286
|
+
tags: meta.tags ? [...meta.tags] : void 0,
|
|
366
287
|
extra: cloneRecord(meta.extra)
|
|
367
288
|
};
|
|
368
289
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
const runtimeFetch = (globalThis as typeof globalThis & { fetch?: typeof fetch }).fetch;
|
|
290
|
+
async function defaultFetch(url) {
|
|
291
|
+
const runtimeFetch = globalThis.fetch;
|
|
372
292
|
if (!runtimeFetch) {
|
|
373
293
|
throw new ManifestLoadError("No global fetch implementation is available. Provide a custom fetch function.");
|
|
374
294
|
}
|
|
375
295
|
return runtimeFetch(url);
|
|
376
296
|
}
|
|
377
|
-
|
|
378
|
-
async function resolveResponseText(response: ResponseLike, url: string): Promise<string> {
|
|
297
|
+
async function resolveResponseText(response, url) {
|
|
379
298
|
if (!response.ok) {
|
|
380
299
|
throw new ManifestLoadError(`Request to '${url}' failed with status ${response.status}.`);
|
|
381
300
|
}
|
|
382
301
|
return response.text();
|
|
383
302
|
}
|
|
384
|
-
|
|
385
|
-
function pickMeta(meta?: Partial<SnippetMeta>): Partial<SnippetMeta> {
|
|
303
|
+
function pickMeta(meta) {
|
|
386
304
|
if (!meta) {
|
|
387
305
|
return {};
|
|
388
306
|
}
|
|
389
|
-
const result
|
|
390
|
-
if (meta.title !==
|
|
307
|
+
const result = {};
|
|
308
|
+
if (meta.title !== void 0) {
|
|
391
309
|
result.title = meta.title;
|
|
392
310
|
}
|
|
393
|
-
if (meta.type !==
|
|
311
|
+
if (meta.type !== void 0) {
|
|
394
312
|
result.type = meta.type;
|
|
395
313
|
}
|
|
396
|
-
if (meta.order !==
|
|
314
|
+
if (meta.order !== void 0) {
|
|
397
315
|
result.order = meta.order;
|
|
398
316
|
}
|
|
399
|
-
if (meta.tags !==
|
|
317
|
+
if (meta.tags !== void 0) {
|
|
400
318
|
result.tags = [...meta.tags];
|
|
401
319
|
}
|
|
402
|
-
if (meta.group !==
|
|
320
|
+
if (meta.group !== void 0) {
|
|
403
321
|
result.group = meta.group;
|
|
404
322
|
}
|
|
405
|
-
if (meta.draft !==
|
|
323
|
+
if (meta.draft !== void 0) {
|
|
406
324
|
result.draft = meta.draft;
|
|
407
325
|
}
|
|
408
|
-
if (meta.path !==
|
|
326
|
+
if (meta.path !== void 0) {
|
|
409
327
|
result.path = meta.path;
|
|
410
328
|
}
|
|
411
329
|
return result;
|
|
412
330
|
}
|
|
331
|
+
|
|
332
|
+
export {
|
|
333
|
+
SnippetClient
|
|
334
|
+
};
|
|
335
|
+
//# sourceMappingURL=chunk-35YHML5Z.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 { 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}\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(\"A manifest source must be provided to SnippetClient.\");\n }\n\n this.manifestUrl = typeof options.manifest === \"string\" ? options.manifest : undefined;\n this.inferredBase = this.manifestUrl ? deriveBaseFromManifest(this.manifestUrl) : 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 };\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\n .filter((item) => item.type === type)\n .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(\"Manifest loader must resolve to an array of snippet metadata.\");\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 ? this.snippetCache.get(meta.slug) : 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(`Failed to fetch snippet at '${url}'.`, error);\n }\n\n const frontMatter = this.options.frontMatter ? parseFrontMatter(raw) : undefined;\n const body = frontMatter?.content ?? raw;\n const html = await this.options.render(body);\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(`Failed to normalize front-matter slug '${frontMatter.slug}':`, error);\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(`Manifest at '${source}' is not valid JSON.`, error);\n }\n\n if (!Array.isArray(parsed)) {\n throw new ManifestLoadError(`Manifest at '${source}' must be a JSON array.`);\n }\n\n return parsed as SnippetMeta[];\n}\n\nfunction normalizeManifestEntry(entry: SnippetMeta): SnippetMeta {\n if (!entry.slug) {\n throw new ManifestLoadError(\"Manifest entry is missing required 'slug' property.\");\n }\n if (!entry.path) {\n throw new ManifestLoadError(`Manifest entry for '${entry.slug}' is missing required 'path'.`);\n }\n const normalized: SnippetMeta = {\n slug: entry.slug,\n title: entry.title,\n type: entry.type,\n order: entry.order,\n tags: entry.tags ? [...entry.tags] : undefined,\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 if (HTTP_PATTERN.test(value)) {\n try {\n const url = new URL(value);\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 (value.startsWith(\"//\")) {\n return `//${value.slice(2).replace(/\\/{2,}/g, \"/\")}`;\n }\n\n if (value.startsWith(\"/\")) {\n return `/${value\n .slice(1)\n .replace(/\\/{2,}/g, \"/\")}`;\n }\n\n return value.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>(value: T): 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: meta.tags ? [...meta.tags] : undefined,\n extra: cloneRecord(meta.extra)\n };\n}\n\nasync function defaultFetch(url: string): Promise<SnippetFetcherResult> {\n const runtimeFetch = (globalThis as typeof globalThis & { fetch?: typeof fetch }).fetch;\n if (!runtimeFetch) {\n throw new ManifestLoadError(\"No global fetch implementation is available. Provide a custom fetch function.\");\n }\n return runtimeFetch(url);\n}\n\nasync function resolveResponseText(response: ResponseLike, url: string): Promise<string> {\n if (!response.ok) {\n throw new ManifestLoadError(`Request to '${url}' failed with status ${response.status}.`);\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,17 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
4
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
5
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
6
|
+
if (decorator = decorators[i])
|
|
7
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
8
|
+
if (kind && result) __defProp(target, key, result);
|
|
9
|
+
return result;
|
|
10
|
+
};
|
|
11
|
+
var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
__decorateClass,
|
|
15
|
+
__decorateParam
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=chunk-BRKEJJFQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,19 @@
|
|
|
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(`Slug '${input}' does not contain any alphanumeric characters`);
|
|
12
|
+
}
|
|
13
|
+
return normalized;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
normalizeSlug
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=chunk-GWLMADTU.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(`Slug '${input}' does not contain any alphanumeric characters`);\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,MAAM,SAAS,KAAK,gDAAgD;AAAA,EAChF;AAEA,SAAO;AACT;","names":[]}
|