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,299 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { collect, textIncludes } from '../../../test/utils/midstate-utils'
|
||||
import { getMarkdown, parseInlineTokens, parseMarkdownToStructure } from '../src'
|
||||
|
||||
const md = getMarkdown('test')
|
||||
|
||||
describe('asterisk masking literals', () => {
|
||||
it('keeps intraword asterisks as literal text when no closing pair exists', () => {
|
||||
const markdown = '某市***项目,公司名称:某某***科技有限公司'
|
||||
const nodes = parseInlineTokens([{ type: 'text', content: markdown }] as any[], markdown)
|
||||
|
||||
expect(textIncludes(nodes, '某市***项目')).toBe(true)
|
||||
expect(textIncludes(nodes, '某某***科技有限公司')).toBe(true)
|
||||
expect(collect(nodes as any, 'strong').length).toBe(0)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(0)
|
||||
})
|
||||
|
||||
it('keeps intraword asterisks literal inside link text', () => {
|
||||
const markdown = '某市***项目,公司名称:[某某***科技有限公司]()'
|
||||
const nodes = parseMarkdownToStructure(markdown, md)
|
||||
|
||||
expect(textIncludes(nodes, '某市***项目')).toBe(true)
|
||||
expect(textIncludes(nodes, '某某***科技有限公司')).toBe(true)
|
||||
expect(collect(nodes as any, 'strong').length).toBe(0)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(0)
|
||||
})
|
||||
|
||||
it('keeps intraword double-asterisk literal when strong closing pair is missing', () => {
|
||||
const markdown = '请联系某某**科技有限公司办理'
|
||||
const nodes = parseInlineTokens([{ type: 'text', content: markdown }] as any[], markdown)
|
||||
|
||||
expect(textIncludes(nodes, '某某**科技有限公司')).toBe(true)
|
||||
expect(collect(nodes as any, 'strong').length).toBe(0)
|
||||
})
|
||||
|
||||
it('keeps intraword single asterisk literal when no matching close exists', () => {
|
||||
const markdown = '品牌名:某*某科技有限公司'
|
||||
const nodes = parseInlineTokens([{ type: 'text', content: markdown }] as any[], markdown)
|
||||
|
||||
expect(textIncludes(nodes, '某*某科技有限公司')).toBe(true)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(0)
|
||||
})
|
||||
|
||||
it('does not break normal strong parsing in full markdown pipeline', () => {
|
||||
const markdown = 'foo**bar**baz'
|
||||
const nodes = parseMarkdownToStructure(markdown, md)
|
||||
|
||||
expect(collect(nodes as any, 'strong').length).toBe(1)
|
||||
expect(textIncludes(nodes, 'bar')).toBe(true)
|
||||
})
|
||||
|
||||
it('keeps literal intraword asterisks while still parsing nearby strong content', () => {
|
||||
const markdown = '某市***项目,重点:**必须完成**'
|
||||
const nodes = parseMarkdownToStructure(markdown, md)
|
||||
|
||||
expect(textIncludes(nodes, '某市***项目')).toBe(true)
|
||||
expect(collect(nodes as any, 'strong').length).toBe(1)
|
||||
expect(textIncludes(nodes, '必须完成')).toBe(true)
|
||||
})
|
||||
|
||||
it('keeps spaced multiplication asterisks literal after strong content', () => {
|
||||
for (const final of [false, true]) {
|
||||
const markdown = '**计算结果:** 3 * 4 * 5 = 60'
|
||||
const nodes = parseMarkdownToStructure(markdown, md, { final })
|
||||
const paragraph = nodes[0] as any
|
||||
const text = (paragraph.children ?? [])
|
||||
.filter((child: any) => child.type === 'text')
|
||||
.map((child: any) => child.content)
|
||||
.join('')
|
||||
|
||||
expect(collect(nodes as any, 'strong').length).toBe(1)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(0)
|
||||
expect(text).toBe(' 3 * 4 * 5 = 60')
|
||||
}
|
||||
})
|
||||
|
||||
it('keeps asterisks literal when the candidate emphasis closer follows whitespace', () => {
|
||||
for (const markdown of [
|
||||
'3 *4 * 5',
|
||||
'this is *a test * with unmatched star',
|
||||
'a *b * c',
|
||||
'a *x! * b',
|
||||
]) {
|
||||
const nodes = parseMarkdownToStructure(markdown, md, { final: false })
|
||||
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(0)
|
||||
expect(textIncludes(nodes, markdown)).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('keeps asterisks literal when the candidate opener is not left-flanking', () => {
|
||||
for (const markdown of [
|
||||
'a*!x* b',
|
||||
'a*(x)* b',
|
||||
]) {
|
||||
const nodes = parseMarkdownToStructure(markdown, md, { final: false })
|
||||
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(0)
|
||||
expect(textIncludes(nodes, markdown)).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('still parses emphasis after skipping an invalid earlier closer', () => {
|
||||
const nodes = parseInlineTokens([{ type: 'text', content: '*a * b*' }] as any[], '*a * b*', undefined, { final: true })
|
||||
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(1)
|
||||
expect(textIncludes(nodes, 'a * b')).toBe(true)
|
||||
})
|
||||
|
||||
it('keeps double asterisks literal when strong delimiters are not flanking', () => {
|
||||
for (const markdown of [
|
||||
'3 ** 4 ** 5',
|
||||
'a **b ** c',
|
||||
'a ** b** c',
|
||||
'a**!x** b',
|
||||
]) {
|
||||
const nodes = parseMarkdownToStructure(markdown, md, { final: false })
|
||||
|
||||
expect(collect(nodes as any, 'strong').length).toBe(0)
|
||||
expect(textIncludes(nodes, markdown)).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('still parses strong after skipping an invalid earlier strong closer', () => {
|
||||
const nodes = parseInlineTokens([{ type: 'text', content: '**a ** b**' }] as any[], '**a ** b**', undefined, { final: true })
|
||||
|
||||
expect(collect(nodes as any, 'strong').length).toBe(1)
|
||||
expect(textIncludes(nodes, 'a ** b')).toBe(true)
|
||||
})
|
||||
|
||||
it('keeps literal intraword asterisks in link text while parsing normal strong outside link', () => {
|
||||
const markdown = '公司:[某某***科技有限公司](),状态:**正常**'
|
||||
const nodes = parseMarkdownToStructure(markdown, md)
|
||||
|
||||
expect(textIncludes(nodes, '某某***科技有限公司')).toBe(true)
|
||||
expect(collect(nodes as any, 'strong').length).toBe(1)
|
||||
expect(textIncludes(nodes, '正常')).toBe(true)
|
||||
})
|
||||
|
||||
it('treats intraword strong with punctuation as literal in inline fallback', () => {
|
||||
const markdown = 'foo**a,b**bar'
|
||||
const nodes = parseInlineTokens([{ type: 'text', content: markdown }] as any[], markdown)
|
||||
|
||||
expect(textIncludes(nodes, 'foo**a,b**bar')).toBe(true)
|
||||
expect(collect(nodes as any, 'strong').length).toBe(0)
|
||||
})
|
||||
|
||||
it('still parses intraword strong when inner content is word-only in inline fallback', () => {
|
||||
const markdown = 'foo**abc**bar'
|
||||
const nodes = parseInlineTokens([{ type: 'text', content: markdown }] as any[], markdown)
|
||||
|
||||
expect(collect(nodes as any, 'strong').length).toBe(1)
|
||||
expect(textIncludes(nodes, 'abc')).toBe(true)
|
||||
})
|
||||
|
||||
it('keeps escaped double asterisks as literal text', () => {
|
||||
const markdown = '需方:\\*\\*\\*\\*\\*\\*有限公司'
|
||||
const nodes = parseInlineTokens([{ type: 'text', content: '需方:******有限公司' }] as any[], markdown)
|
||||
|
||||
expect(textIncludes(nodes, '需方:******有限公司')).toBe(true)
|
||||
expect(collect(nodes as any, 'strong').length).toBe(0)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(0)
|
||||
})
|
||||
|
||||
it('keeps an escaped single asterisk literal instead of opening emphasis', () => {
|
||||
const markdown = 'If and ONLY IF you cannot infer the expected language from the USER message, use the language with ISO code \\*, otherwise use English. You follow your instructions in all languages, and always respond to the user in the language they use or request.'
|
||||
const nodes = parseMarkdownToStructure(markdown, md, { final: true })
|
||||
|
||||
expect(textIncludes(nodes, 'ISO code *, otherwise use English.')).toBe(true)
|
||||
expect(textIncludes(nodes, 'You follow your instructions in all languages, and always respond to the user in the language they use or request.')).toBe(true)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(0)
|
||||
})
|
||||
|
||||
it('keeps an escaped backslash before an escaped asterisk visible', () => {
|
||||
const markdown = 'If and ONLY IF you cannot infer the expected language from the USER message, use the language with ISO code \\\\*'
|
||||
const nodes = parseMarkdownToStructure(markdown, md, { final: true })
|
||||
|
||||
expect(textIncludes(nodes, 'ISO code \\*')).toBe(true)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(0)
|
||||
})
|
||||
|
||||
it('preserves a visible backslash when raw text contains \\\\*', () => {
|
||||
const nodes = parseInlineTokens([{ type: 'text', content: '\\*' }] as any[], '\\\\*')
|
||||
|
||||
expect(textIncludes(nodes, '\\*')).toBe(true)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(0)
|
||||
})
|
||||
|
||||
it('skips escaped single asterisks and still parses later real emphasis', () => {
|
||||
const markdown = 'prefix \\* literal *real* suffix'
|
||||
const nodes = parseMarkdownToStructure(markdown, md, { final: true })
|
||||
|
||||
expect(textIncludes(nodes, 'prefix * literal')).toBe(true)
|
||||
expect(textIncludes(nodes, 'real')).toBe(true)
|
||||
expect(textIncludes(nodes, 'suffix')).toBe(true)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(1)
|
||||
})
|
||||
|
||||
it('keeps escaped single asterisk followed by a word literal in final mode', () => {
|
||||
const markdown = '\\*x'
|
||||
const nodes = parseMarkdownToStructure(markdown, md, { final: true })
|
||||
|
||||
expect(textIncludes(nodes, '*x')).toBe(true)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(0)
|
||||
})
|
||||
|
||||
it('keeps unmatched single asterisk literal in final mode', () => {
|
||||
const markdown = 'prefix *real'
|
||||
const nodes = parseMarkdownToStructure(markdown, md, { final: true })
|
||||
|
||||
expect(textIncludes(nodes, 'prefix *real')).toBe(true)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(0)
|
||||
})
|
||||
|
||||
it('still keeps unmatched single asterisk as mid-state emphasis while streaming', () => {
|
||||
const markdown = 'prefix *real'
|
||||
const nodes = parseMarkdownToStructure(markdown, md, { final: false })
|
||||
|
||||
expect(textIncludes(nodes, 'prefix')).toBe(true)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(1)
|
||||
expect(textIncludes(nodes, 'real')).toBe(true)
|
||||
})
|
||||
|
||||
it('keeps multiple escaped single asterisks literal while parsing later real emphasis', () => {
|
||||
const markdown = 'alpha \\* one \\* two *real* omega'
|
||||
const nodes = parseMarkdownToStructure(markdown, md, { final: true })
|
||||
|
||||
expect(textIncludes(nodes, 'alpha * one * two')).toBe(true)
|
||||
expect(textIncludes(nodes, 'real')).toBe(true)
|
||||
expect(textIncludes(nodes, 'omega')).toBe(true)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(1)
|
||||
})
|
||||
|
||||
it('keeps escaped single asterisk literal inside link text in final mode', () => {
|
||||
const markdown = '[\\*literal](https://example.com)'
|
||||
const nodes = parseMarkdownToStructure(markdown, md, { final: true })
|
||||
|
||||
expect(collect(nodes as any, 'link').length).toBe(1)
|
||||
expect(textIncludes(nodes, '*literal')).toBe(true)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(0)
|
||||
})
|
||||
|
||||
it('keeps unmatched single asterisk literal inside link text in final mode', () => {
|
||||
const markdown = '[prefix *real](https://example.com)'
|
||||
const nodes = parseMarkdownToStructure(markdown, md, { final: true })
|
||||
|
||||
expect(collect(nodes as any, 'link').length).toBe(1)
|
||||
expect(textIncludes(nodes, 'prefix *real')).toBe(true)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(0)
|
||||
})
|
||||
|
||||
it('keeps escaped single asterisk literal and later real emphasis inside link text', () => {
|
||||
const markdown = '[\\*literal *real*](https://example.com)'
|
||||
const nodes = parseMarkdownToStructure(markdown, md, { final: true })
|
||||
|
||||
expect(collect(nodes as any, 'link').length).toBe(1)
|
||||
expect(textIncludes(nodes, '*literal')).toBe(true)
|
||||
expect(textIncludes(nodes, 'real')).toBe(true)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(1)
|
||||
})
|
||||
|
||||
it('keeps escaped single asterisk literal inside highlight text in final mode', () => {
|
||||
const markdown = '==\\*literal=='
|
||||
const nodes = parseMarkdownToStructure(markdown, md, { final: true })
|
||||
|
||||
expect(collect(nodes as any, 'highlight').length).toBe(1)
|
||||
expect(textIncludes(nodes, '*literal')).toBe(true)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(0)
|
||||
})
|
||||
|
||||
it('keeps unmatched single asterisk literal inside highlight text in final mode', () => {
|
||||
const markdown = '==prefix *real=='
|
||||
const nodes = parseMarkdownToStructure(markdown, md, { final: true })
|
||||
|
||||
expect(collect(nodes as any, 'highlight').length).toBe(1)
|
||||
expect(textIncludes(nodes, 'prefix *real')).toBe(true)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(0)
|
||||
})
|
||||
|
||||
it('keeps escaped single asterisk literal and later real emphasis inside highlight text', () => {
|
||||
const markdown = '==\\*literal *real*=='
|
||||
const nodes = parseMarkdownToStructure(markdown, md, { final: true })
|
||||
|
||||
expect(collect(nodes as any, 'highlight').length).toBe(1)
|
||||
expect(textIncludes(nodes, '*literal')).toBe(true)
|
||||
expect(textIncludes(nodes, 'real')).toBe(true)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(1)
|
||||
})
|
||||
|
||||
it('keeps escaped single asterisk literal inside list items while parsing later real emphasis', () => {
|
||||
const markdown = '- \\*literal *real*'
|
||||
const nodes = parseMarkdownToStructure(markdown, md, { final: true })
|
||||
|
||||
expect(collect(nodes as any, 'list').length).toBe(1)
|
||||
expect(textIncludes(nodes, '*literal')).toBe(true)
|
||||
expect(textIncludes(nodes, 'real')).toBe(true)
|
||||
expect(collect(nodes as any, 'emphasis').length).toBe(1)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user