feat(desktop): add element metadata builder

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
程序员阿江(Relakkes) 2026-05-29 13:23:33 +08:00
parent 7e417219df
commit 19116cb4d9
2 changed files with 45 additions and 0 deletions

View File

@ -0,0 +1,20 @@
import { describe, expect, it, beforeEach, vi } from 'vitest'
import { buildElementMetadata } from './metadata'
beforeEach(() => { document.body.innerHTML = `<h1 id="t" class="a b">Hello World</h1>` })
describe('buildElementMetadata', () => {
it('captures tag/id/classes/text/selector and styles', () => {
const el = document.getElementById('t')!
el.getBoundingClientRect = () => ({ x: 1, y: 2, width: 3, height: 4, top: 2, left: 1, right: 4, bottom: 6, toJSON: () => ({}) }) as DOMRect
vi.spyOn(window, 'getComputedStyle').mockReturnValue({ color: 'rgb(0,0,0)', backgroundColor: 'rgba(0,0,0,0)', opacity: '1', fontFamily: 'serif', fontSize: '40px' } as unknown as CSSStyleDeclaration)
const m = buildElementMetadata(el)
expect(m.tag).toBe('h1')
expect(m.id).toBe('t')
expect(m.classes).toEqual(['a', 'b'])
expect(m.text).toBe('Hello World')
expect(m.boundingBox).toEqual({ x: 1, y: 2, w: 3, h: 4 })
expect(m.computedStyles.color).toBe('rgb(0,0,0)')
expect(m.selector).toBe('#t')
})
})

View File

@ -0,0 +1,25 @@
import { buildSelector, buildNthPath } from './selector'
export type ElementMetadata = {
selector: string; nthPath: string; tag: string; id?: string; classes: string[]
text?: string; boundingBox: { x: number; y: number; w: number; h: number }
computedStyles: Record<string, string>; outerHtmlSnippet?: string
}
const STYLE_KEYS = ['color', 'backgroundColor', 'opacity', 'fontFamily', 'fontSize', 'fontWeight', 'textAlign', 'padding', 'margin'] as const
export function buildElementMetadata(el: Element): ElementMetadata {
const cs = window.getComputedStyle(el)
const styles: Record<string, string> = {}
for (const k of STYLE_KEYS) styles[k] = (cs as unknown as Record<string, string>)[k] ?? ''
const r = el.getBoundingClientRect()
const sel = buildSelector(el)
return {
selector: sel, nthPath: buildNthPath(el), tag: el.tagName.toLowerCase(),
id: el.id || undefined, classes: Array.from(el.classList),
text: (el.textContent ?? '').trim().slice(0, 200) || undefined,
boundingBox: { x: r.x, y: r.y, w: r.width, h: r.height },
computedStyles: styles,
outerHtmlSnippet: sel.includes(':nth') ? el.outerHTML.slice(0, 300) : undefined,
}
}