feat(desktop): embed BoosAPI Desktop client as a subproject
Vendor the rebranded BoosAPI Desktop client (Tauri + Vue) into metapi as a monorepo subdirectory under desktop/. Source only — node_modules, dist, Cargo target and the upstream .git history are excluded. desktop/ keeps its own independent Cargo workspace (desktop/src-tauri with crates/*); it is not part of the backend boosapi crate, so a `cargo check` at the metapi root still compiles only the backend. Build the desktop app from desktop/src-tauri per desktop/README.md. Note: app icons are still placeholder assets pending the final BoosAPI logo. The updater signing keys live outside the repo and are not included.
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
import type { BaseNode, MarkdownIt, ParseOptions } from 'stream-markdown-parser'
|
||||
import { getMarkdown, mergeCustomHtmlTags, parseMarkdownToStructure } from 'stream-markdown-parser'
|
||||
|
||||
export interface NestedMarkdownNodesInput {
|
||||
node?: (BaseNode & Record<string, any>) | null
|
||||
nodes?: readonly BaseNode[] | null
|
||||
content?: string | null
|
||||
}
|
||||
|
||||
export interface NestedMarkdownNodesOptions {
|
||||
cacheKey?: string
|
||||
final?: boolean
|
||||
parseOptions?: ParseOptions
|
||||
customHtmlTags?: readonly string[]
|
||||
customMarkdownIt?: (markdown: MarkdownIt) => MarkdownIt
|
||||
}
|
||||
|
||||
const DEFAULT_CACHE_KEY = 'markstream-vue2-nested-nodes'
|
||||
const markdownCache = new Map<string, MarkdownIt>()
|
||||
|
||||
export function parseNestedMarkdownToNodes(
|
||||
input: NestedMarkdownNodesInput,
|
||||
options: NestedMarkdownNodesOptions = {},
|
||||
): BaseNode[] {
|
||||
if (Array.isArray(input.nodes))
|
||||
return input.nodes.slice()
|
||||
|
||||
const nestedNode = input.node
|
||||
if (nestedNode) {
|
||||
const children = getNodeList(nestedNode.children)
|
||||
if (children.length > 0)
|
||||
return children.slice()
|
||||
}
|
||||
|
||||
const content = resolveContent(input)
|
||||
if (!content)
|
||||
return []
|
||||
|
||||
const parseOptions = resolveParseOptions(input, options)
|
||||
const markdown = resolveMarkdownInstance(options)
|
||||
return parseMarkdownToStructure(content, markdown, parseOptions)
|
||||
}
|
||||
|
||||
function resolveContent(input: NestedMarkdownNodesInput) {
|
||||
if (typeof input.content === 'string')
|
||||
return input.content
|
||||
if (typeof input.node?.content === 'string')
|
||||
return input.node.content
|
||||
return ''
|
||||
}
|
||||
|
||||
function resolveParseOptions(
|
||||
input: NestedMarkdownNodesInput,
|
||||
options: NestedMarkdownNodesOptions,
|
||||
): ParseOptions | undefined {
|
||||
const base = options.parseOptions ?? {}
|
||||
const resolvedFinal = options.final ?? resolveFinalFromNode(input.node)
|
||||
const customHtmlTags = mergeCustomHtmlTags(options.customHtmlTags, (base as any).customHtmlTags)
|
||||
|
||||
if (resolvedFinal == null && customHtmlTags.length === 0)
|
||||
return base
|
||||
|
||||
return {
|
||||
...(base as any),
|
||||
...(resolvedFinal == null ? {} : { final: resolvedFinal }),
|
||||
...(customHtmlTags.length === 0 ? {} : { customHtmlTags }),
|
||||
} as ParseOptions
|
||||
}
|
||||
|
||||
function resolveFinalFromNode(node?: (BaseNode & Record<string, any>) | null) {
|
||||
if (!node || typeof node !== 'object')
|
||||
return undefined
|
||||
if (typeof node.loading === 'boolean')
|
||||
return !node.loading
|
||||
return undefined
|
||||
}
|
||||
|
||||
function resolveMarkdownInstance(options: NestedMarkdownNodesOptions) {
|
||||
const normalizedTags = mergeCustomHtmlTags(options.customHtmlTags, (options.parseOptions as any)?.customHtmlTags)
|
||||
const cacheKey = `${options.cacheKey || DEFAULT_CACHE_KEY}::${normalizedTags.join(',')}`
|
||||
let markdown = markdownCache.get(cacheKey)
|
||||
|
||||
if (!markdown) {
|
||||
markdown = getMarkdown(cacheKey, {
|
||||
customHtmlTags: normalizedTags,
|
||||
})
|
||||
markdownCache.set(cacheKey, markdown)
|
||||
}
|
||||
|
||||
return options.customMarkdownIt
|
||||
? options.customMarkdownIt(markdown)
|
||||
: markdown
|
||||
}
|
||||
|
||||
function getNodeList(value: unknown) {
|
||||
return Array.isArray(value) ? value as BaseNode[] : []
|
||||
}
|
||||
Reference in New Issue
Block a user