forked from boos/BoosAPI
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,176 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
vi.mock('../src/monaco-shim', () => {
|
||||
class Range {
|
||||
constructor(
|
||||
public startLineNumber: number,
|
||||
public startColumn: number,
|
||||
public endLineNumber: number,
|
||||
public endColumn: number,
|
||||
) {}
|
||||
}
|
||||
|
||||
return {
|
||||
default: {
|
||||
Range,
|
||||
editor: {
|
||||
EditorOption: {
|
||||
lineHeight: 'lineHeight',
|
||||
},
|
||||
},
|
||||
},
|
||||
Range,
|
||||
editor: {
|
||||
EditorOption: {
|
||||
lineHeight: 'lineHeight',
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
import {
|
||||
applyDefaultDiffHunkAction,
|
||||
findLineChangeByHoverLine,
|
||||
hasModifiedLines,
|
||||
hasOriginalLines,
|
||||
inferInlineDiffHunkHoverSide,
|
||||
positionDiffHunkNode,
|
||||
} from '../src/core/diffHunk'
|
||||
|
||||
function createModel(lines: string[]) {
|
||||
const value = () => lines.join('\n')
|
||||
return {
|
||||
getLineCount() {
|
||||
return lines.length
|
||||
},
|
||||
getLineMaxColumn(line: number) {
|
||||
return (lines[line - 1] ?? '').length + 1
|
||||
},
|
||||
getValueInRange(range: any) {
|
||||
const start = range.startLineNumber - 1
|
||||
const end = range.endLineNumber - 1
|
||||
const selected = lines.slice(start, Math.max(start, end))
|
||||
if (range.endColumn !== 1 && end < lines.length)
|
||||
selected.push(lines[end] ?? '')
|
||||
return `${selected.join('\n')}${selected.length > 0 ? '\n' : ''}`
|
||||
},
|
||||
applyEdits: vi.fn(),
|
||||
}
|
||||
}
|
||||
|
||||
describe('diffHunk helpers', () => {
|
||||
it('detects whether a hunk has original or modified lines', () => {
|
||||
const insertion = {
|
||||
originalStartLineNumber: 0,
|
||||
originalEndLineNumber: 0,
|
||||
modifiedStartLineNumber: 3,
|
||||
modifiedEndLineNumber: 4,
|
||||
} as any
|
||||
|
||||
expect(hasOriginalLines(insertion)).toBe(false)
|
||||
expect(hasModifiedLines(insertion)).toBe(true)
|
||||
})
|
||||
|
||||
it('finds the nearest hovered line change within tolerance', () => {
|
||||
const changes = [
|
||||
{
|
||||
originalStartLineNumber: 2,
|
||||
originalEndLineNumber: 3,
|
||||
modifiedStartLineNumber: 2,
|
||||
modifiedEndLineNumber: 3,
|
||||
},
|
||||
{
|
||||
originalStartLineNumber: 10,
|
||||
originalEndLineNumber: 10,
|
||||
modifiedStartLineNumber: 12,
|
||||
modifiedEndLineNumber: 12,
|
||||
},
|
||||
] as any
|
||||
|
||||
expect(findLineChangeByHoverLine(changes, 'modified', 3)).toBe(changes[0])
|
||||
expect(findLineChangeByHoverLine(changes, 'modified', 14)).toBe(changes[1])
|
||||
expect(findLineChangeByHoverLine(changes, 'modified', 20)).toBeNull()
|
||||
})
|
||||
|
||||
it('infers inline hover side from DOM hint or hover line fallback', () => {
|
||||
const change = {
|
||||
originalStartLineNumber: 4,
|
||||
originalEndLineNumber: 5,
|
||||
modifiedStartLineNumber: 6,
|
||||
modifiedEndLineNumber: 7,
|
||||
} as any
|
||||
|
||||
const deletedTarget = {
|
||||
closest(selector: string) {
|
||||
return selector.includes('line-delete') ? {} : null
|
||||
},
|
||||
} as HTMLElement
|
||||
const insertedTarget = {
|
||||
closest(selector: string) {
|
||||
return selector.includes('line-insert') ? {} : null
|
||||
},
|
||||
} as HTMLElement
|
||||
|
||||
expect(inferInlineDiffHunkHoverSide(change, 5, deletedTarget)).toBe('upper')
|
||||
expect(inferInlineDiffHunkHoverSide(change, 7, insertedTarget)).toBe('lower')
|
||||
expect(inferInlineDiffHunkHoverSide(change, 5, null)).toBe('upper')
|
||||
expect(inferInlineDiffHunkHoverSide(change, 6, null)).toBe('lower')
|
||||
})
|
||||
|
||||
it('applies the default lower-stage action by copying modified lines into original', () => {
|
||||
const originalModel = createModel(['a', 'b'])
|
||||
const modifiedModel = createModel(['a', 'b', 'c'])
|
||||
const lineChange = {
|
||||
originalStartLineNumber: 0,
|
||||
originalEndLineNumber: 0,
|
||||
modifiedStartLineNumber: 3,
|
||||
modifiedEndLineNumber: 3,
|
||||
} as any
|
||||
|
||||
applyDefaultDiffHunkAction({
|
||||
action: 'stage',
|
||||
side: 'lower',
|
||||
lineChange,
|
||||
originalModel: originalModel as any,
|
||||
modifiedModel: modifiedModel as any,
|
||||
})
|
||||
|
||||
expect(originalModel.applyEdits).toHaveBeenCalledTimes(1)
|
||||
expect(originalModel.applyEdits.mock.calls[0][0][0].text).toBe('c\n')
|
||||
})
|
||||
|
||||
it('positions a hunk node within the editor host', () => {
|
||||
const node = {
|
||||
offsetWidth: 120,
|
||||
offsetHeight: 24,
|
||||
style: {
|
||||
transform: '',
|
||||
display: '',
|
||||
},
|
||||
} as unknown as HTMLDivElement
|
||||
const editor = {
|
||||
getContainerDomNode() {
|
||||
return {
|
||||
offsetLeft: 10,
|
||||
clientWidth: 400,
|
||||
offsetTop: 20,
|
||||
clientHeight: 200,
|
||||
}
|
||||
},
|
||||
getTopForLineNumber(line: number) {
|
||||
return line * 20
|
||||
},
|
||||
getScrollTop() {
|
||||
return 20
|
||||
},
|
||||
getOption() {
|
||||
return 20
|
||||
},
|
||||
} as any
|
||||
|
||||
positionDiffHunkNode(node, editor, 5)
|
||||
|
||||
expect(node.style.display).toBe('flex')
|
||||
expect(node.style.transform).toContain('translate(')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user