mirror of
https://github.com/stablyai/orca.git
synced 2026-11-13 09:27:29 +00:00
fix(readme-links): preserve commas in srcset URLs (#36957)
Tokenize srcset like the HTML parser: read each URL up to ASCII whitespace, strip trailing separator commas, and skip descriptors (including parenthesized commas) before the next candidate. Fixes #36955 Co-authored-by: Neil <neil@stably.ai>
This commit is contained in:
@@ -31,14 +31,47 @@ function trackedFiles(root, candidates) {
|
||||
return new Set(stdout.split('\0').filter(Boolean))
|
||||
}
|
||||
|
||||
function* srcsetTargets(value) {
|
||||
let position = 0
|
||||
while (position < value.length) {
|
||||
while (position < value.length && /[\t\n\f\r ,]/.test(value[position])) {
|
||||
position++
|
||||
}
|
||||
if (position === value.length) {
|
||||
return
|
||||
}
|
||||
const start = position
|
||||
while (position < value.length && !/[\t\n\f\r ]/.test(value[position])) {
|
||||
position++
|
||||
}
|
||||
let end = position
|
||||
while (value[end - 1] === ',') {
|
||||
end--
|
||||
}
|
||||
// HTML URL tokens can contain commas; trailing commas end a URL-only candidate.
|
||||
yield value.slice(start, end)
|
||||
if (end < position) {
|
||||
continue
|
||||
}
|
||||
let inParentheses = false
|
||||
while (position < value.length) {
|
||||
const character = value[position++]
|
||||
if (character === '(') {
|
||||
inParentheses = true
|
||||
} else if (character === ')') {
|
||||
inParentheses = false
|
||||
} else if (character === ',' && !inParentheses) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function* localTargets(markdown) {
|
||||
for (const [, attribute, doubleQuoted, singleQuoted] of markdown.matchAll(HTML_ATTRIBUTE)) {
|
||||
const value = doubleQuoted ?? singleQuoted
|
||||
// Only srcset lists candidates; each begins with its URL. src/href hold one whole URL.
|
||||
const targets =
|
||||
attribute.toLowerCase() === 'srcset'
|
||||
? value.split(',').map((candidate) => candidate.trim().split(/\s+/)[0])
|
||||
: [value.trim()]
|
||||
const targets = attribute.toLowerCase() === 'srcset' ? srcsetTargets(value) : [value.trim()]
|
||||
for (const target of targets) {
|
||||
if (target) {
|
||||
yield target
|
||||
|
||||
@@ -126,6 +126,48 @@ describe('README local link check', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('preserves commas inside srcset URLs', () => {
|
||||
const root = makeFixture({
|
||||
...validReadmes,
|
||||
'README.md': '<source SrcSet=" ,,\t docs/Hero,wide.png 1x,, \n docs/Hero,tall.png,, ">',
|
||||
'docs/Hero,wide.png': 'png',
|
||||
'docs/Hero,tall.png': 'png'
|
||||
})
|
||||
|
||||
expect(findBrokenReadmeLinks(root)).toEqual([])
|
||||
})
|
||||
|
||||
it('rejects a missing srcset URL even when its comma-separated fragments are tracked', () => {
|
||||
const root = makeFixture({
|
||||
...validReadmes,
|
||||
'README.md': '<source srcset="docs/Missing,wide.png 1x">',
|
||||
'docs/Missing': 'fragment',
|
||||
'wide.png': 'fragment'
|
||||
})
|
||||
|
||||
expect(findBrokenReadmeLinks(root).map((link) => link.target)).toEqual([
|
||||
'docs/Missing,wide.png'
|
||||
])
|
||||
})
|
||||
|
||||
it('ignores a srcset data URL while checking the following local candidate', () => {
|
||||
const root = makeFixture({
|
||||
...validReadmes,
|
||||
'README.md': '<source srcset="data:image/png;base64,AAAA 1x, docs/missing.png 2x">'
|
||||
})
|
||||
|
||||
expect(findBrokenReadmeLinks(root).map((link) => link.target)).toEqual(['docs/missing.png'])
|
||||
})
|
||||
|
||||
it('does not treat commas inside srcset descriptors as new candidates', () => {
|
||||
const root = makeFixture({
|
||||
...validReadmes,
|
||||
'README.md': '<source srcset="resources/build/icon.png future(1,2), docs/missing.png 2x">'
|
||||
})
|
||||
|
||||
expect(findBrokenReadmeLinks(root).map((link) => link.target)).toEqual(['docs/missing.png'])
|
||||
})
|
||||
|
||||
it('checks tracked media outside the detector sparse checkout', () => {
|
||||
const root = makeFixture(validReadmes)
|
||||
const workflow = parse(readFileSync(path.join(projectDir, '.github/workflows/pr.yml'), 'utf8'))
|
||||
|
||||
Reference in New Issue
Block a user