mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
fix: preserve windows markdown link fragments (#4261)
This commit is contained in:
@@ -55,6 +55,20 @@ describe('resolveMarkdownLinkTarget', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('extracts hash line anchors from Windows drive-letter absolute .md links', () => {
|
||||
const r = resolveMarkdownLinkTarget(
|
||||
'C:\\repo\\docs\\guide.md#L10',
|
||||
'C:\\repo\\docs\\note.md',
|
||||
'C:\\repo'
|
||||
)
|
||||
expect(r).toMatchObject({
|
||||
kind: 'markdown',
|
||||
absolutePath: 'C:/repo/docs/guide.md',
|
||||
relativePath: 'docs/guide.md',
|
||||
line: 10
|
||||
})
|
||||
})
|
||||
|
||||
it('extracts line from #L10', () => {
|
||||
const r = resolveMarkdownLinkTarget('./guide.md#L10', SOURCE, ROOT)
|
||||
expect(r).toMatchObject({ kind: 'markdown', line: 10, column: undefined })
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { filesystemPathToFileUri, fileUriToFilesystemPath } from '../../../../shared/file-uri-path'
|
||||
import {
|
||||
filesystemPathHrefToFileUri,
|
||||
filesystemPathToFileUri,
|
||||
fileUriToFilesystemPath
|
||||
} from '../../../../shared/file-uri-path'
|
||||
import { isWindowsAbsolutePathLike } from '../../../../shared/cross-platform-path'
|
||||
|
||||
// Pure classifier for markdown link targets. Called by the link-activation
|
||||
@@ -112,7 +116,7 @@ function resolveRelativeToSource(rawHref: string, sourceFilePath: string): URL |
|
||||
if (isWindowsAbsolutePathLike(rawHref)) {
|
||||
// Why: URL treats `C:\...` as a custom `c:` scheme unless the Windows
|
||||
// absolute path is first converted to the file URL form used downstream.
|
||||
return new URL(filesystemPathToFileUri(rawHref))
|
||||
return new URL(filesystemPathHrefToFileUri(rawHref))
|
||||
}
|
||||
return new URL(rawHref, toFileUrl(sourceFilePath))
|
||||
} catch {
|
||||
|
||||
@@ -16,6 +16,12 @@ describe('getMarkdownPreviewLinkTarget', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('preserves hash fragments on Windows drive-letter absolute links', () => {
|
||||
expect(
|
||||
getMarkdownPreviewLinkTarget('C:\\repo\\docs\\guide.md#L10', '/repo/docs/README.md')
|
||||
).toBe('file:///C:/repo/docs/guide.md#L10')
|
||||
})
|
||||
|
||||
it('preserves external links', () => {
|
||||
expect(getMarkdownPreviewLinkTarget('https://example.com/docs', '/repo/docs/README.md')).toBe(
|
||||
'https://example.com/docs'
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { filesystemPathToFileUri, fileUriToFilesystemPath } from '../../../../shared/file-uri-path'
|
||||
import {
|
||||
filesystemPathHrefToFileUri,
|
||||
filesystemPathToFileUri,
|
||||
fileUriToFilesystemPath
|
||||
} from '../../../../shared/file-uri-path'
|
||||
import { isWindowsAbsolutePathLike } from '../../../../shared/cross-platform-path'
|
||||
|
||||
function toFileUrl(filePath: string): string {
|
||||
@@ -14,7 +18,7 @@ export function resolveMarkdownPreviewHref(rawUrl: string, filePath: string): UR
|
||||
if (isWindowsAbsolutePathLike(rawUrl)) {
|
||||
// Why: URL treats `C:\...` as a custom `c:` scheme unless we first
|
||||
// normalize the drive path into the file URL form markdown previews use.
|
||||
return new URL(filesystemPathToFileUri(rawUrl))
|
||||
return new URL(filesystemPathHrefToFileUri(rawUrl))
|
||||
}
|
||||
return new URL(rawUrl, toFileUrl(filePath))
|
||||
} catch {
|
||||
|
||||
@@ -28,6 +28,30 @@ export function filesystemPathToFileUri(filePath: string): string {
|
||||
return normalizedPath.startsWith('/') ? `file://${encodedPath}` : `file:///${encodedPath}`
|
||||
}
|
||||
|
||||
export function filesystemPathHrefToFileUri(filePathHref: string): string {
|
||||
const suffixIndex = filePathHref.search(/[?#]/)
|
||||
if (suffixIndex === -1) {
|
||||
return filesystemPathToFileUri(filePathHref)
|
||||
}
|
||||
|
||||
const pathPart = filePathHref.slice(0, suffixIndex)
|
||||
const suffix = filePathHref.slice(suffixIndex)
|
||||
const url = new URL(filesystemPathToFileUri(pathPart))
|
||||
if (suffix.startsWith('#')) {
|
||||
// Why: markdown href fragments like `#L10` should stay URL fragments,
|
||||
// not become `%23L10` inside the Windows filesystem path.
|
||||
url.hash = suffix
|
||||
return url.toString()
|
||||
}
|
||||
|
||||
const hashIndex = suffix.indexOf('#')
|
||||
url.search = hashIndex === -1 ? suffix : suffix.slice(0, hashIndex)
|
||||
if (hashIndex !== -1) {
|
||||
url.hash = suffix.slice(hashIndex)
|
||||
}
|
||||
return url.toString()
|
||||
}
|
||||
|
||||
export function fileUriToFilesystemPath(url: URL): string | null {
|
||||
if (url.protocol !== 'file:') {
|
||||
return null
|
||||
|
||||
Reference in New Issue
Block a user