6af92621b7dba437be69c05f3ff49079ba637383
braney
Fri Sep 4 11:43:39 2026 -0700
docent: let convert: take a bare string, like every other verb
convert: hs1 left the argument as a String, so o.to was undefined and o.search
picked up String.prototype.search. The run then reported
convert: "function search() { [native code] }" matched nothing
which says nothing about what is wrong with the script. A bare string is now
the target assembly, matching hub:, addCustomTrack:, loadSession: and the rest.
quicklift: is still never implied, so convert: hs1 is a plain coordinate
convert; the README row says so now.
Found while writing the first of the regression tests for #38252, fourteen of
which open with convert:.
refs #37892
diff --git src/hg/utils/docent/docent.js src/hg/utils/docent/docent.js
index c8604e635d1..faa72a30d3b 100755
--- src/hg/utils/docent/docent.js
+++ src/hg/utils/docent/docent.js
@@ -1395,31 +1395,36 @@
async function resolveTarget(to) {
if (/^GC[AF]_/i.test(to)) return to;
const matches = await page.$$eval('#hglft_toDbSelect option', (os, q) => {
const norm = t => t.toLowerCase().replace(/[^a-z0-9]+/g, ' ');
const toks = norm(q).trim().split(' ').filter(Boolean);
return os.filter(o => toks.every(tk => norm(o.text).includes(tk))).map(o => ({ v: o.value, t: o.text }));
}, String(to));
if (!matches.length) throw new Error('convert target not found in Assembly dropdown: ' + to);
if (matches.length > 1) {
console.warn(`WARNING: "${to}" matches ${matches.length} assemblies; using the first. Use an exact accession to disambiguate:`);
matches.forEach(m => console.warn(` ${m.v} ${m.t}`));
}
return matches[0].v;
}
async function convert(o) {
- o = o || {};
+ // A bare string is the target assembly, the way every other verb takes its one
+ // obvious argument. Without this `convert: hs1` left o as the String, so o.to was
+ // undefined and o.search picked up String.prototype.search -- the run then reported
+ // `convert: "function search() { [native code] }" matched nothing`, which tells the
+ // reader nothing about what is wrong with their script.
+ o = (typeof o === 'string') ? { to: o } : (o || {});
// `shot:` here can name up to three moments of the Convert page, none of which any
// other verb can reach (after Submit the tour is already on the results page):
// shot: convert_filled -- just before Submit (the common one)
// shot: {opened: a, filled: b, result: c}
// opened the page as it comes up, nothing chosen yet
// filled target searched for, QuickLift/Hide-defaults set -- ready to Submit
// result the conversion result page (the coordinate link `open: lift` clicks)
const shots = (o.shot == null) ? {}
: (typeof o.shot === 'string' ? { filled: o.shot } : o.shot);
for (const k of Object.keys(shots))
if (!['opened', 'filled', 'result'].includes(k))
console.warn(`convert shot: unknown moment "${k}" (use opened, filled or result)`);
try {
await glideTo('#view'); await page.hover('#view'); await dwell(900);
await clickGlide('a#convertMenuLink'); await page.waitForSelector('#hglft_toDbSelect', { timeout: 8000 });