@primeui-devkit/markdown-core 0.1.0-beta.1

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/LICENSE.md ADDED
@@ -0,0 +1,45 @@
1
+ # PrimeUI License
2
+
3
+ This package is part of **PrimeUI**, a family of commercial UI libraries by PrimeTek Informatics.
4
+
5
+ ## How PrimeUI May Be Used
6
+
7
+ PrimeUI may be used under one of two licenses. You choose the one that applies to you based on eligibility.
8
+
9
+ ### Community License (Free)
10
+
11
+ Free for organizations that meet all of the following criteria:
12
+
13
+ - Less than $1,000,000 USD in annual gross revenue
14
+ - Fewer than 5 developers
15
+ - Fewer than 10 employees
16
+ - Less than $3,000,000 USD in venture capital or outside funding
17
+
18
+ Individuals, students, non-profits, and non-commercial open source projects also qualify.
19
+
20
+ The Community License provides full access to the core libraries and supports up to 4 developers. It requires annual renewal by confirming continued eligibility.
21
+
22
+ ### Commercial License (Paid)
23
+
24
+ For organizations that do not qualify for the Community License.
25
+
26
+ Licensed per developer, perpetual, with one year of updates included. Renewal is optional and extends access to new versions. The Commercial Suite also includes PrimeBlocks, Theme Designer, all PrimeUI Pro components, and Premium Support.
27
+
28
+ ## License Key
29
+
30
+ A valid license key is required to use this software. License verification is performed offline, with no telemetry and no remote connection. A missing, invalid, or expired key may cause the software to display a license notice.
31
+
32
+ ## Full Terms
33
+
34
+ The complete license terms, eligibility details, and renewal information are available at:
35
+
36
+ - Community License: <https://primeui.dev/licenses/community>
37
+ - Commercial License: <https://primeui.dev/licenses/commercial>
38
+
39
+ ## Restrictions
40
+
41
+ This software is distributed as a compiled package. You may not reverse-engineer, decompile, or extract its source code, redistribute it as a component library or development tool, or remove its license mechanisms. Redistributing the software so that third parties can develop with it requires a separate OEM License. See the full terms for details.
42
+
43
+ ---
44
+
45
+ © 2026 PrimeTek Informatics. All rights reserved.
package/README.md ADDED
@@ -0,0 +1,78 @@
1
+ # @primeui-devkit/markdown-core
2
+
3
+ Framework-agnostic markdown engine. Parses markdown with component directives
4
+ (`::name{props}`) into a serializable AST that every `*-markdown` renderer consumes.
5
+
6
+ ```ts
7
+ import { createDocsParser } from '@primeui-devkit/markdown-core/preset';
8
+
9
+ const parse = createDocsParser(); // headings + toc + alert + binding
10
+ const tree = await parse('# Hello\n\n::demo-viewer{name="basic"}\n::');
11
+ // the tree is plain JSON — cacheable, serializable, consumable by any renderer
12
+ ```
13
+
14
+ Parsing is asynchronous — plugins may load resources — so the result has to be awaited
15
+ before any of the tree helpers below will accept it.
16
+
17
+ Lower-level API: `createMarkdownParser`, `parseMarkdown`, `defineMarkdownPlugin`.
18
+ Optional plugins as subpaths: `./plugins/{headings,toc,highlight,alert,binding}`
19
+ (highlight needs the optional `shiki` peer).
20
+
21
+ Types: `MarkdownTree`, `MarkdownNode`, `MarkdownElement`, `MarkdownPlugin`, `MarkdownParser`.
22
+
23
+ ## Syntax highlighting
24
+
25
+ The preset deliberately leaves highlighting out. A highlighter is heavy and not every page
26
+ needs one, so it ships as an optional peer:
27
+
28
+ ```bash
29
+ pnpm add shiki
30
+ ```
31
+
32
+ Install it before importing `./plugins/highlight`. Without it that import fails while the
33
+ module is still loading, with `Cannot find package 'shiki'` raised from inside the parsing
34
+ backend — the message names neither this package nor the missing peer, and no `try` around
35
+ the import can catch it.
36
+
37
+ Highlighting is asynchronous, so it runs as its own step after parsing rather than inside
38
+ it:
39
+
40
+ ```ts
41
+ import { createDocsParser } from '@primeui-devkit/markdown-core/preset';
42
+ import { highlightTree } from '@primeui-devkit/markdown-core/plugins/highlight';
43
+
44
+ const parse = createDocsParser();
45
+ const tree = await highlightTree(await parse(source));
46
+ ```
47
+
48
+ Both themes are emitted at once, so a page switches between light and dark without
49
+ highlighting anything again.
50
+
51
+ Only registered themes work. Passing a name the backend does not know produces
52
+ unhighlighted output without reporting anything, so `highlightTree` checks first and
53
+ throws with the list of what is available — `availableThemes()` returns the same list.
54
+
55
+ ```ts
56
+ await highlightTree(tree, { themes: { light: 'material-theme-lighter', dark: 'material-theme-palenight' } });
57
+ ```
58
+
59
+ `@primeui-devkit/highlighter` is a separate package for highlighting a standalone snippet
60
+ to HTML. Neither depends on the other: this one works on a parsed tree, that one on a
61
+ string, and a repository takes whichever it needs.
62
+
63
+ ## Content utilities
64
+
65
+ Parser-free subpaths for tooling and pipelines — usable in Node scripts, build
66
+ steps, and browsers without pulling the engine in:
67
+
68
+ - `./tree` — `tocFromTree`, `titleFromTree`, `descriptionFromTree`, `walkTree`, `textOf`, `headingSections`, node helpers (`isElement`, `tagOf`, `propsOf`, `childrenOf`)
69
+ - `./search` — `buildSearchIndex(pages)` → heading-level `SearchDocument[]` (feed a local search, Algolia, or an agent) and `searchDocuments(index, query)` — a dependency-free scorer for docs-sized corpora
70
+ - `./llms` — `renderLlmsIndex`, `renderLlmsFull`, `rawMarkdownFiles` for llms.txt pipelines
71
+
72
+ ```ts
73
+ import { buildSearchIndex } from '@primeui-devkit/markdown-core/search';
74
+ import { renderLlmsIndex } from '@primeui-devkit/markdown-core/llms';
75
+
76
+ const index = buildSearchIndex(pages.map((p) => ({ route: p.route, tree: p.tree })));
77
+ const llms = renderLlmsIndex(pages, { title: 'Docs', siteUrl: 'https://docs.example.dev' });
78
+ ```
@@ -0,0 +1,36 @@
1
+ # Third-Party Notices
2
+
3
+ This package uses the following third-party open source software.
4
+ Each is provided under its own license, reproduced below.
5
+
6
+ ---
7
+
8
+ ## comark
9
+
10
+ Copyright (c) 2026 Comark team and contributors
11
+
12
+ The markdown parsing engine used by this package (https://github.com/comarkdown/comark).
13
+
14
+ Licensed under the MIT License.
15
+
16
+ MIT License
17
+
18
+ Copyright (c) 2026 Comark team and contributors
19
+
20
+ Permission is hereby granted, free of charge, to any person obtaining a copy
21
+ of this software and associated documentation files (the "Software"), to deal
22
+ in the Software without restriction, including without limitation the rights
23
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24
+ copies of the Software, and to permit persons to whom the Software is
25
+ furnished to do so, subject to the following conditions:
26
+
27
+ The above copyright notice and this permission notice shall be included in all
28
+ copies or substantial portions of the Software.
29
+
30
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ export { ComarkElement as MarkdownElement, ComarkNode as MarkdownNode, ParseOptions as MarkdownParseOptions, ComarkParseFn as MarkdownParser, ComarkPlugin as MarkdownPlugin, NodeRenderData as MarkdownRenderData, ComarkTree as MarkdownTree, autoCloseMarkdown, createParse as createMarkdownParser, defineComarkPlugin as defineMarkdownPlugin, parseFrontmatter, parse as parseMarkdown } from 'comark';
2
+ export { pascalCase, resolveAttributes } from 'comark/utils';
3
+ export { HeadingSection, TocItem, childrenOf, descriptionFromTree, headingSections, isElement, propsOf, tagOf, textOf, titleFromTree, tocFromTree, walkTree } from './tree.js';
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export{autoCloseMarkdown,createParse as createMarkdownParser,defineComarkPlugin as defineMarkdownPlugin,parseFrontmatter,parse as parseMarkdown}from'comark';export{pascalCase,resolveAttributes}from'comark/utils';function u(e){return e?.meta?.toc?.links??[]}function f(e){return String(e?.frontmatter?.title??e?.meta?.title??"")}function l(e){return String(e?.frontmatter?.description??"")}function a(e){return Array.isArray(e)}function d(e){return e[0]}function m(e){return e[1]??{}}function s(e){return e.slice(2)}function w(e,t){let n=(r,o)=>{if(!(t(r,o)===false||!a(r)))for(let k of s(r))n(k,r);};for(let r of e.nodes??[])n(r,null);}function i(e){return typeof e=="string"?e:Array.isArray(e)&&typeof e[0]!="string"?e.map(t=>i(t)).join(""):a(e)?s(e).map(t=>i(t)).join(""):""}var c=new Set(["h1","h2","h3","h4","h5","h6"]);function p(e){let t=[],n={id:"",heading:"",depth:0,text:""};for(let r of e.nodes??[]){if(a(r)&&c.has(d(r))){(n.text.trim()||n.heading)&&t.push(n),n={id:String(m(r).id??""),heading:i(r),depth:Number(d(r).slice(1)),text:""};continue}if(a(r)&&d(r)==="pre")continue;let o=i(r).trim();o&&(n.text+=(n.text?" ":"")+o);}return (n.text.trim()||n.heading)&&t.push(n),t}export{s as childrenOf,l as descriptionFromTree,p as headingSections,a as isElement,m as propsOf,d as tagOf,i as textOf,f as titleFromTree,u as tocFromTree,w as walkTree};
package/dist/llms.d.ts ADDED
@@ -0,0 +1,45 @@
1
+ interface LlmsPage {
2
+ /** Route/slug of the page, e.g. 'charts/animation' (no leading slash needed). */
3
+ route: string;
4
+ /** Raw markdown source of the page. */
5
+ markdown: string;
6
+ /** Optional explicit title; defaults to the first `# ` heading. */
7
+ title?: string;
8
+ /** Optional one-line description, appended to index links and full sections. */
9
+ description?: string;
10
+ }
11
+ interface LlmsIndexOptions {
12
+ /** Site title placed at the top of llms.txt. */
13
+ title: string;
14
+ /** One-line site description for the `>` summary. */
15
+ description?: string;
16
+ /** Absolute origin used in links, e.g. 'https://vue.example.dev'. */
17
+ siteUrl: string;
18
+ /**
19
+ * How each link points at a page, given its route:
20
+ * - 'page' (default): `${siteUrl}/${route}`
21
+ * - 'raw': `${siteUrl}/raw/${route}.md`
22
+ */
23
+ linkTarget?: 'page' | 'raw';
24
+ /** Heading above the link list. @default 'Documentation' */
25
+ heading?: string;
26
+ }
27
+ interface LlmsFullOptions {
28
+ /** Title placed at the top of llms-full.txt. */
29
+ title: string;
30
+ /** One-line description under the title. */
31
+ description?: string;
32
+ /** Rewrite a page's markdown before concatenation (e.g. expand demo tags). */
33
+ transform?: (page: LlmsPage) => string;
34
+ }
35
+ declare function pageTitle(page: LlmsPage): string;
36
+ /** llms.txt — the index document: site summary plus one link per page. */
37
+ declare function renderLlmsIndex(pages: LlmsPage[], options: LlmsIndexOptions): string;
38
+ /** llms-full.txt — every page's markdown concatenated into one document. */
39
+ declare function renderLlmsFull(pages: LlmsPage[], options: LlmsFullOptions): string;
40
+ /** File plan for the raw markdown mirror: [route, content]. */
41
+ declare function rawMarkdownFiles(pages: LlmsPage[], options?: {
42
+ transform?: (page: LlmsPage) => string;
43
+ }): Array<[string, string]>;
44
+
45
+ export { type LlmsFullOptions, type LlmsIndexOptions, type LlmsPage, pageTitle, rawMarkdownFiles, renderLlmsFull, renderLlmsIndex };
package/dist/llms.js ADDED
@@ -0,0 +1,9 @@
1
+ function i(t){return t.title??t.markdown.match(/^#\s+(.+)$/m)?.[1]??t.route}function l(t,r){let e=t.route.replace(/^\//,"");return r.linkTarget==="raw"?`${r.siteUrl}/raw/${e}.md`:`${r.siteUrl}/${e}`}function a(t,r){return [`# ${r.title}`,"",`> ${r.description??""}`,"",`## ${r.heading??"Documentation"}`,...t.map(n=>`- [${i(n)}](${l(n,r)})${n.description?`: ${n.description}`:""}`)].join(`
2
+ `)}function m(t,r){return [`# ${r.title}`,"",`> ${r.description??""}`,"",...t.map(n=>{let s=r.transform?r.transform(n):n.markdown.trim();return `## ${i(n)}
3
+
4
+ ${n.description?`${n.description}
5
+
6
+ `:""}${s}`})].join(`
7
+
8
+ `)}function o(t,r){return t.map(e=>[e.route.replace(/^\//,""),r?.transform?r.transform(e):e.markdown])}
9
+ export{i as pageTitle,o as rawMarkdownFiles,m as renderLlmsFull,a as renderLlmsIndex};
@@ -0,0 +1,5 @@
1
+ export * from 'comark/plugins/alert';
2
+ export { default } from 'comark/plugins/alert';
3
+ import 'comark/plugins/binding';
4
+ import 'comark/plugins/headings';
5
+ import 'comark/plugins/toc';
@@ -0,0 +1 @@
1
+ export*from'comark/plugins/alert';export{default}from'comark/plugins/alert';
@@ -0,0 +1,2 @@
1
+ export * from 'comark/plugins/binding';
2
+ export { default } from 'comark/plugins/binding';
@@ -0,0 +1 @@
1
+ export*from'comark/plugins/binding';export{default}from'comark/plugins/binding';
@@ -0,0 +1,2 @@
1
+ export * from 'comark/plugins/headings';
2
+ export { default } from 'comark/plugins/headings';
@@ -0,0 +1 @@
1
+ export*from'comark/plugins/headings';export{default}from'comark/plugins/headings';
@@ -0,0 +1,67 @@
1
+ import { ComarkPlugin, ComarkTree } from 'comark';
2
+
3
+ /**
4
+ * NOTE ON THE OPTIONAL PEER — importing this subpath without `shiki` installed fails at
5
+ * module load with `Cannot find package 'shiki'`, thrown from inside the backend rather
6
+ * than from here. That cannot be caught: the failing import is the static one above, which
7
+ * runs before any code in this file. Making it dynamic would push the cost onto every
8
+ * caller and would still not help {@link default}, which is synchronous by contract.
9
+ *
10
+ * So the message stays as it is, and the requirement is documented instead: the README and
11
+ * the package's `peerDependenciesMeta` both state that highlighting needs `shiki`.
12
+ */
13
+ /**
14
+ * Syntax highlighting for code blocks.
15
+ *
16
+ * The options below are this package's own. The backend exposes the highlighting engine's
17
+ * types directly — themes, language registrations, transformers — and re-exporting those
18
+ * would tie every caller to that engine through a package whose whole purpose is to keep
19
+ * it out of sight.
20
+ */
21
+ interface HighlightOptions {
22
+ /**
23
+ * Themes to render with. Both are emitted, so a page can switch between light and dark
24
+ * without highlighting anything again.
25
+ *
26
+ * Only registered themes work. A name the backend does not know leaves every block
27
+ * unhighlighted without reporting anything, so {@link highlightTree} checks first.
28
+ */
29
+ themes?: {
30
+ light: string;
31
+ dark: string;
32
+ };
33
+ /** Whether to inline the theme's background and colour on the block. Defaults to `false`. */
34
+ inlineStyles?: boolean;
35
+ }
36
+ /** Themes the backend registers by default. */
37
+ declare const defaultThemes: {
38
+ readonly light: "material-theme-lighter";
39
+ readonly dark: "material-theme-palenight";
40
+ };
41
+ /** Themes available without registering any of your own. */
42
+ declare function availableThemes(): Promise<string[]>;
43
+ /**
44
+ * Highlight every code block in a parsed tree.
45
+ *
46
+ * Highlighting is asynchronous and happens after parsing, so it runs as its own step:
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * import { createDocsParser } from '@primeui-devkit/markdown-core/preset';
51
+ * import { highlightTree } from '@primeui-devkit/markdown-core/plugins/highlight';
52
+ *
53
+ * const parse = createDocsParser();
54
+ * const tree = await highlightTree(await parse(source));
55
+ * ```
56
+ */
57
+ declare function highlightTree(tree: ComarkTree, options?: HighlightOptions): Promise<ComarkTree>;
58
+ /**
59
+ * The same highlighting as a parser plugin.
60
+ *
61
+ * Kept for parsers that drive the plugin pipeline themselves. Prefer {@link highlightTree}:
62
+ * the plugin form marks blocks as highlighted without tokenising them, because tokenising
63
+ * is asynchronous and the plugin hook is not.
64
+ */
65
+ declare function highlight(options?: HighlightOptions): ComarkPlugin<any, any>;
66
+
67
+ export { type HighlightOptions, availableThemes, highlight as default, defaultThemes, highlightTree };
@@ -0,0 +1 @@
1
+ import s,{getHighlighter,highlightCodeBlocks}from'comark/plugins/highlight';var c={light:"material-theme-lighter",dark:"material-theme-palenight"};async function g(){return (await getHighlighter()).getLoadedThemes?.()??[]}async function p(t,i={}){let{themes:e,inlineStyles:a=false}=i;if(e){let r=await g(),n=[e.light,e.dark].filter(l=>!r.includes(l));if(n.length>0)throw new Error(`Unknown theme${n.length>1?"s":""}: ${n.join(", ")}. Available: ${r.join(", ")}.`)}return await highlightCodeBlocks(t,{...e?{themes:e}:{},preStyles:a})}function m(t={}){let{themes:i,inlineStyles:e=false}=t;return s({...i?{themes:i}:{},preStyles:e})}export{g as availableThemes,m as default,c as defaultThemes,p as highlightTree};
@@ -0,0 +1,2 @@
1
+ export * from 'comark/plugins/toc';
2
+ export { default } from 'comark/plugins/toc';
@@ -0,0 +1 @@
1
+ export*from'comark/plugins/toc';export{default}from'comark/plugins/toc';
@@ -0,0 +1,32 @@
1
+ import { ComarkPlugin, ComarkParseFn } from 'comark';
2
+
3
+ /**
4
+ * Options handed to the parser underneath.
5
+ *
6
+ * Deliberately loose: the parsing backend accepts more than this preset models, and
7
+ * naming its option type here would put its full schema — and its name — into a public
8
+ * signature. Anything valid for the backend passes through.
9
+ */
10
+ type ParserPassthrough = Record<string, unknown>;
11
+ interface DocsParserOptions {
12
+ /** Heading ids for anchors. @default true */
13
+ headings?: boolean;
14
+ /** Table of contents in tree.meta.toc. @default true */
15
+ toc?: boolean;
16
+ /** ::alert containers. @default true */
17
+ alert?: boolean;
18
+ /** {{ binding }} interpolation. @default true */
19
+ binding?: boolean;
20
+ /** Extra plugins — e.g. a configured highlight plugin from ./plugins/highlight. */
21
+ plugins?: ComarkPlugin<any, any>[];
22
+ /** Options forwarded to the underlying parser. Plugins are set by this preset. */
23
+ parse?: ParserPassthrough;
24
+ }
25
+ /**
26
+ * Docs-flavored parser preset: the plugin set every showcase/docs app needs,
27
+ * assembled once. Syntax highlighting is intentionally NOT bundled — shiki is
28
+ * heavy and optional; pass a configured highlight plugin via `plugins`.
29
+ */
30
+ declare function createDocsParser(options?: DocsParserOptions): ComarkParseFn<any, any>;
31
+
32
+ export { type DocsParserOptions, type ParserPassthrough, createDocsParser };
package/dist/preset.js ADDED
@@ -0,0 +1 @@
1
+ import {createParse}from'comark';import e from'comark/plugins/alert';import o from'comark/plugins/binding';import s from'comark/plugins/headings';import i from'comark/plugins/toc';function g(r={}){let a=[];return r.headings!==false&&a.push(s()),r.toc!==false&&a.push(i()),r.alert!==false&&a.push(e()),r.binding!==false&&a.push(o()),r.plugins&&a.push(...r.plugins),createParse({...r.parse,plugins:a})}export{g as createDocsParser};
@@ -0,0 +1,4 @@
1
+ declare const PROSE_COMPONENTS: readonly ["ProseA", "ProseBlockquote", "ProseCode", "ProseEm", "ProseH1", "ProseH2", "ProseH3", "ProseH4", "ProseH5", "ProseH6", "ProseHr", "ProseImg", "ProseLi", "ProseOl", "ProseP", "ProsePre", "ProseStrong", "ProseTable", "ProseTbody", "ProseTd", "ProseTh", "ProseThead", "ProseTr", "ProseUl"];
2
+ type ProseComponentName = (typeof PROSE_COMPONENTS)[number];
3
+
4
+ export { PROSE_COMPONENTS, type ProseComponentName };
package/dist/prose.js ADDED
@@ -0,0 +1 @@
1
+ var e=["ProseA","ProseBlockquote","ProseCode","ProseEm","ProseH1","ProseH2","ProseH3","ProseH4","ProseH5","ProseH6","ProseHr","ProseImg","ProseLi","ProseOl","ProseP","ProsePre","ProseStrong","ProseTable","ProseTbody","ProseTd","ProseTh","ProseThead","ProseTr","ProseUl"];export{e as PROSE_COMPONENTS};
@@ -0,0 +1,30 @@
1
+ import { ComarkTree } from 'comark';
2
+
3
+ interface SearchPage {
4
+ /** Route of the page, e.g. '/charts/animation'. */
5
+ route: string;
6
+ tree: ComarkTree;
7
+ }
8
+ interface SearchDocument {
9
+ /** Route plus anchor, e.g. '/charts/animation#easing'. */
10
+ url: string;
11
+ route: string;
12
+ page: string;
13
+ heading: string;
14
+ text: string;
15
+ }
16
+ /**
17
+ * Flattens parsed pages into heading-level search documents. The output is
18
+ * plain JSON: ship it to the client for local search, hand it to Algolia, or
19
+ * serve it to agents — same records everywhere.
20
+ */
21
+ declare function buildSearchIndex(pages: SearchPage[]): SearchDocument[];
22
+ /**
23
+ * Dependency-free local search over an index: case-insensitive, every term
24
+ * must match, heading/title hits outrank body hits. Good enough for docs-size
25
+ * indexes; swap in Algolia or MiniSearch behind the same SearchDocument shape
26
+ * when the corpus outgrows it.
27
+ */
28
+ declare function searchDocuments(index: SearchDocument[], query: string, limit?: number): SearchDocument[];
29
+
30
+ export { type SearchDocument, type SearchPage, buildSearchIndex, searchDocuments };
package/dist/search.js ADDED
@@ -0,0 +1 @@
1
+ function g(e){return String(e?.frontmatter?.title??e?.meta?.title??"")}function u(e){return Array.isArray(e)}function d(e){return e[0]}function k(e){return e[1]??{}}function w(e){return e.slice(2)}function s(e){return typeof e=="string"?e:Array.isArray(e)&&typeof e[0]!="string"?e.map(o=>s(o)).join(""):u(e)?w(e).map(o=>s(o)).join(""):""}var x=new Set(["h1","h2","h3","h4","h5","h6"]);function l(e){let o=[],n={id:"",heading:"",depth:0,text:""};for(let t of e.nodes??[]){if(u(t)&&x.has(d(t))){(n.text.trim()||n.heading)&&o.push(n),n={id:String(k(t).id??""),heading:s(t),depth:Number(d(t).slice(1)),text:""};continue}if(u(t)&&d(t)==="pre")continue;let i=s(t).trim();i&&(n.text+=(n.text?" ":"")+i);}return (n.text.trim()||n.heading)&&o.push(n),o}function T(e){let o=[];for(let{route:n,tree:t}of e){let i=g(t);for(let r of l(t))o.push({url:r.id?`${n}#${r.id}`:n,route:n,page:i,heading:r.heading||i,text:r.text});}return o}function N(e,o,n=10){let t=o.toLowerCase().split(/\s+/).filter(Boolean);if(!t.length)return [];let i=[];for(let r of e){let c=(r.page+" "+r.heading).toLowerCase(),p=r.text.toLowerCase(),a=0;for(let f of t){let m=c.includes(f),h=p.includes(f);if(!m&&!h){a=0;break}a+=m?5:1;}a>0&&i.push({doc:r,score:a});}return i.sort((r,c)=>c.score-r.score).slice(0,n).map(r=>r.doc)}export{T as buildSearchIndex,N as searchDocuments};
package/dist/tree.d.ts ADDED
@@ -0,0 +1,44 @@
1
+ import { ComarkElement, ComarkNode, ComarkTree } from 'comark';
2
+ import 'comark/utils';
3
+
4
+ interface TocItem {
5
+ id: string;
6
+ text: string;
7
+ depth: number;
8
+ children?: TocItem[];
9
+ }
10
+ /** Table of contents produced by the toc plugin, normalized to a plain array. */
11
+ declare function tocFromTree(tree: ComarkTree | null | undefined): TocItem[];
12
+ /** Page title: frontmatter wins, then the title the parser derived from the first heading. */
13
+ declare function titleFromTree(tree: ComarkTree | null | undefined): string;
14
+ /** Page description from frontmatter, when present. */
15
+ declare function descriptionFromTree(tree: ComarkTree | null | undefined): string;
16
+ declare function isElement(node: ComarkNode): node is ComarkElement;
17
+ declare function tagOf(node: ComarkElement): string;
18
+ declare function propsOf(node: ComarkElement): Record<string, unknown>;
19
+ declare function childrenOf(node: ComarkElement): ComarkNode[];
20
+ /**
21
+ * Depth-first walk over every node in the tree. Return `false` from the
22
+ * visitor to skip a node's children.
23
+ */
24
+ declare function walkTree(tree: ComarkTree, visit: (node: ComarkNode, parent: ComarkElement | null) => void | boolean): void;
25
+ /** Plain-text content of a node (or node list) — markup and components stripped. */
26
+ declare function textOf(node: ComarkNode | ComarkNode[]): string;
27
+ interface HeadingSection {
28
+ /** Heading id (anchor target); empty for content before the first heading. */
29
+ id: string;
30
+ /** Heading text; empty for content before the first heading. */
31
+ heading: string;
32
+ /** Heading depth (1-6); 0 for content before the first heading. */
33
+ depth: number;
34
+ /** Plain text of everything under this heading, code blocks excluded. */
35
+ text: string;
36
+ }
37
+ /**
38
+ * Splits a page into heading-anchored sections of plain text — the natural
39
+ * unit for search indexing and llms excerpts. Code blocks are excluded so
40
+ * indexes stay prose-focused.
41
+ */
42
+ declare function headingSections(tree: ComarkTree): HeadingSection[];
43
+
44
+ export { type HeadingSection, type TocItem, childrenOf, descriptionFromTree, headingSections, isElement, propsOf, tagOf, textOf, titleFromTree, tocFromTree, walkTree };
package/dist/tree.js ADDED
@@ -0,0 +1 @@
1
+ function l(e){return e?.meta?.toc?.links??[]}function k(e){return String(e?.frontmatter?.title??e?.meta?.title??"")}function m(e){return String(e?.frontmatter?.description??"")}function i(e){return Array.isArray(e)}function d(e){return e[0]}function u(e){return e[1]??{}}function s(e){return e.slice(2)}function w(e,r){let t=(n,o)=>{if(!(r(n,o)===false||!i(n)))for(let c of s(n))t(c,n);};for(let n of e.nodes??[])t(n,null);}function a(e){return typeof e=="string"?e:Array.isArray(e)&&typeof e[0]!="string"?e.map(r=>a(r)).join(""):i(e)?s(e).map(r=>a(r)).join(""):""}var f=new Set(["h1","h2","h3","h4","h5","h6"]);function p(e){let r=[],t={id:"",heading:"",depth:0,text:""};for(let n of e.nodes??[]){if(i(n)&&f.has(d(n))){(t.text.trim()||t.heading)&&r.push(t),t={id:String(u(n).id??""),heading:a(n),depth:Number(d(n).slice(1)),text:""};continue}if(i(n)&&d(n)==="pre")continue;let o=a(n).trim();o&&(t.text+=(t.text?" ":"")+o);}return (t.text.trim()||t.heading)&&r.push(t),r}export{s as childrenOf,m as descriptionFromTree,p as headingSections,i as isElement,u as propsOf,d as tagOf,a as textOf,k as titleFromTree,l as tocFromTree,w as walkTree};
package/package.json ADDED
@@ -0,0 +1,132 @@
1
+ {
2
+ "name": "@primeui-devkit/markdown-core",
3
+ "version": "0.1.0-beta.1",
4
+ "description": "Framework-agnostic markdown engine. Parses markdown with component directives into a serializable tree consumed by the framework renderers. The parsing backend is an internal implementation detail.",
5
+ "author": "PrimeTek Informatics",
6
+ "license": "SEE LICENSE IN LICENSE.md",
7
+ "bugs": {
8
+ "url": "https://support.primeui.dev"
9
+ },
10
+ "type": "module",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ },
16
+ "./preset": {
17
+ "types": "./dist/preset.d.ts",
18
+ "import": "./dist/preset.js"
19
+ },
20
+ "./tree": {
21
+ "types": "./dist/tree.d.ts",
22
+ "import": "./dist/tree.js"
23
+ },
24
+ "./search": {
25
+ "types": "./dist/search.d.ts",
26
+ "import": "./dist/search.js"
27
+ },
28
+ "./llms": {
29
+ "types": "./dist/llms.d.ts",
30
+ "import": "./dist/llms.js"
31
+ },
32
+ "./prose": {
33
+ "types": "./dist/prose.d.ts",
34
+ "import": "./dist/prose.js"
35
+ },
36
+ "./plugins/headings": {
37
+ "types": "./dist/plugins/headings.d.ts",
38
+ "import": "./dist/plugins/headings.js"
39
+ },
40
+ "./plugins/toc": {
41
+ "types": "./dist/plugins/toc.d.ts",
42
+ "import": "./dist/plugins/toc.js"
43
+ },
44
+ "./plugins/highlight": {
45
+ "types": "./dist/plugins/highlight.d.ts",
46
+ "import": "./dist/plugins/highlight.js"
47
+ },
48
+ "./plugins/alert": {
49
+ "types": "./dist/plugins/alert.d.ts",
50
+ "import": "./dist/plugins/alert.js"
51
+ },
52
+ "./plugins/binding": {
53
+ "types": "./dist/plugins/binding.d.ts",
54
+ "import": "./dist/plugins/binding.js"
55
+ },
56
+ "./package.json": "./package.json"
57
+ },
58
+ "typesVersions": {
59
+ "*": {
60
+ "preset": [
61
+ "./dist/preset.d.ts"
62
+ ],
63
+ "tree": [
64
+ "./dist/tree.d.ts"
65
+ ],
66
+ "search": [
67
+ "./dist/search.d.ts"
68
+ ],
69
+ "llms": [
70
+ "./dist/llms.d.ts"
71
+ ],
72
+ "prose": [
73
+ "./dist/prose.d.ts"
74
+ ],
75
+ "plugins/headings": [
76
+ "./dist/plugins/headings.d.ts"
77
+ ],
78
+ "plugins/toc": [
79
+ "./dist/plugins/toc.d.ts"
80
+ ],
81
+ "plugins/highlight": [
82
+ "./dist/plugins/highlight.d.ts"
83
+ ],
84
+ "plugins/alert": [
85
+ "./dist/plugins/alert.d.ts"
86
+ ],
87
+ "plugins/binding": [
88
+ "./dist/plugins/binding.d.ts"
89
+ ]
90
+ }
91
+ },
92
+ "types": "./dist/index.d.ts",
93
+ "module": "./dist/index.js",
94
+ "files": [
95
+ "dist",
96
+ "LICENSE.md",
97
+ "THIRD-PARTY-NOTICES.txt",
98
+ "README.md"
99
+ ],
100
+ "sideEffects": false,
101
+ "dependencies": {
102
+ "comark": "^0.5.1"
103
+ },
104
+ "peerDependencies": {
105
+ "shiki": "^4.4.2"
106
+ },
107
+ "peerDependenciesMeta": {
108
+ "shiki": {
109
+ "optional": true
110
+ }
111
+ },
112
+ "devDependencies": {
113
+ "cross-env": "^10.1.0",
114
+ "tsup": "^8.5.1",
115
+ "typescript": "~6.0.0",
116
+ "vitest": "4.1.10",
117
+ "@primeui-devkit/test-config": "0.0.0",
118
+ "@primeui-devkit/bundler": "0.0.0",
119
+ "@primeui-devkit/ts-config": "0.0.0"
120
+ },
121
+ "publishConfig": {
122
+ "access": "public"
123
+ },
124
+ "scripts": {
125
+ "build": "pnpm run build:package",
126
+ "build:package": "pnpm run test && tsup",
127
+ "type:check": "tsc --noEmit",
128
+ "test": "cross-env NODE_ENV=test vitest run",
129
+ "test:watch": "vitest --watch",
130
+ "test:coverage": "vitest run --coverage"
131
+ }
132
+ }