Reformat src/*.mjs with Prettier; add format/format:check scripts

Every route handler was written as one dense semicolon-chained line
(server.mjs's main handler was over 2000 characters wide) — real
width, not a VSCode wrapping artifact. Ran Prettier to break statement
structure into properly indented multi-line code; left template
literal string contents untouched since Prettier doesn't reformat
inside those, so the large HTML-generating return strings are still
single long lines by nature, just no longer compounded by unformatted
surrounding JS. Verified: tests pass, node --check passes, and the
app renders identically before/after (screenshotted the diff).

No devDependency added — npx prettier@3.9.5 pinned in the new scripts
keeps the zero-runtime-dependency pledge intact; formatting is a dev-
time concern only.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Fredrik Johansson
2026-07-21 05:17:30 +02:00
co-authored by Claude Sonnet 5
parent cdcc3c7937
commit 4b7b5a42d3
7 changed files with 782 additions and 76 deletions
+70 -8
View File
@@ -1,9 +1,71 @@
const FIX_WORDS=/\b(fix(?:e[ds])?|bug|broken|race|crash|regression|rollback|restore[ds]?|duplicate[ds]?|auth|fail(?:ed|ure|ing)?)\b/i;
const validRepo=value=>/^[a-z0-9_.-]+\/[a-z0-9_.-]+$/i.test(value);
export async function scanGiteaCandidates({baseUrl,repositories,token='',limit=100,fetchImpl=fetch}){
const candidates=[],errors=[],headers={accept:'application/json'};if(token)headers.authorization=`token ${token}`;
for(const repo of repositories){if(!validRepo(repo)){errors.push({repo,error:'invalid owner/repository identifier'});continue}const [owner,name]=repo.split('/');let seen=0;
try{for(let page=1;seen<limit;page++){const count=Math.min(50,limit-seen),url=`${baseUrl.replace(/\/$/,'')}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/commits?limit=${count}&page=${page}`;const response=await fetchImpl(url,{headers,signal:AbortSignal.timeout(5000)});if(!response.ok)throw new Error(`Gitea returned ${response.status}`);const commits=await response.json();if(!Array.isArray(commits))throw new Error('unexpected Gitea response');for(const commit of commits){seen++;const subject=String(commit.commit?.message||'').split('\n')[0].trim(),match=subject.match(FIX_WORDS);if(!match)continue;let paths='';try{const detail=await fetchImpl(`${baseUrl.replace(/\/$/,'')}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/git/commits/${encodeURIComponent(commit.sha)}`,{headers,signal:AbortSignal.timeout(5000)});if(detail.ok){const data=await detail.json();paths=(data.files||[]).map(file=>file.filename).filter(Boolean).join('\n')}}catch{}candidates.push({repo,sha:commit.sha,committedAt:commit.commit?.committer?.date||commit.commit?.author?.date||commit.created||new Date().toISOString(),subject,paths,reason:`Gitea subject keyword: ${match[0].toLowerCase()}`})}if(commits.length<count)break}}
catch(error){errors.push({repo,error:error.message})}
}return{candidates,errors};
const FIX_WORDS =
/\b(fix(?:e[ds])?|bug|broken|race|crash|regression|rollback|restore[ds]?|duplicate[ds]?|auth|fail(?:ed|ure|ing)?)\b/i;
const validRepo = (value) => /^[a-z0-9_.-]+\/[a-z0-9_.-]+$/i.test(value);
export async function scanGiteaCandidates({
baseUrl,
repositories,
token = '',
limit = 100,
fetchImpl = fetch,
}) {
const candidates = [],
errors = [],
headers = { accept: 'application/json' };
if (token) headers.authorization = `token ${token}`;
for (const repo of repositories) {
if (!validRepo(repo)) {
errors.push({ repo, error: 'invalid owner/repository identifier' });
continue;
}
const [owner, name] = repo.split('/');
let seen = 0;
try {
for (let page = 1; seen < limit; page++) {
const count = Math.min(50, limit - seen),
url = `${baseUrl.replace(/\/$/, '')}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/commits?limit=${count}&page=${page}`;
const response = await fetchImpl(url, { headers, signal: AbortSignal.timeout(5000) });
if (!response.ok) throw new Error(`Gitea returned ${response.status}`);
const commits = await response.json();
if (!Array.isArray(commits)) throw new Error('unexpected Gitea response');
for (const commit of commits) {
seen++;
const subject = String(commit.commit?.message || '')
.split('\n')[0]
.trim(),
match = subject.match(FIX_WORDS);
if (!match) continue;
let paths = '';
try {
const detail = await fetchImpl(
`${baseUrl.replace(/\/$/, '')}/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/git/commits/${encodeURIComponent(commit.sha)}`,
{ headers, signal: AbortSignal.timeout(5000) },
);
if (detail.ok) {
const data = await detail.json();
paths = (data.files || [])
.map((file) => file.filename)
.filter(Boolean)
.join('\n');
}
} catch {}
candidates.push({
repo,
sha: commit.sha,
committedAt:
commit.commit?.committer?.date ||
commit.commit?.author?.date ||
commit.created ||
new Date().toISOString(),
subject,
paths,
reason: `Gitea subject keyword: ${match[0].toLowerCase()}`,
});
}
if (commits.length < count) break;
}
} catch (error) {
errors.push({ repo, error: error.message });
}
}
return { candidates, errors };
}