firstsun-dev_git-files-sync/src/utils/git-blob-sha.ts
ClaudiaFang 09bdf0c0c7 fix: satisfy Obsidian plugin scan (undescribed directive, popout-window timers)
- src/utils/git-blob-sha.ts: add a required description to the
  sonarjs/hashing eslint-disable comment.
- src/services/github-service.ts, src/settings.ts: use
  window.setTimeout()/window.clearTimeout() instead of the bare
  globals, so timers still fire correctly in Obsidian popout windows.
  connectionTestTimer is now typed as plain `number` (window.setTimeout's
  DOM return type) instead of ReturnType<typeof window.setTimeout>,
  which resolves to Node's Timeout under this repo's tsconfig due to
  @types/node's global augmentation colliding with the DOM lib.
- tests/setup.ts: the node-env `window` polyfill only stubbed
  setInterval/clearInterval; add setTimeout/clearTimeout delegating to
  the real globals so vi.useFakeTimers() still controls them.
2026-07-14 13:29:52 +00:00

21 lines
1.2 KiB
TypeScript

/**
* Computes a file's git blob SHA-1 locally: sha1("blob " + byteLength + "\0" + contentBytes).
* This is exactly what `git hash-object` produces, so it can be compared directly
* against a tree entry's SHA to classify sync status without fetching remote
* content. Uses the Web Crypto API (crypto.subtle), available on both desktop
* and mobile.
*/
export async function gitBlobSha(content: string | ArrayBuffer): Promise<string> {
const contentBytes = typeof content === 'string' ? new TextEncoder().encode(content) : new Uint8Array(content);
const header = new TextEncoder().encode(`blob ${contentBytes.byteLength}\0`);
const combined = new Uint8Array(header.byteLength + contentBytes.byteLength);
combined.set(header, 0);
combined.set(contentBytes, header.byteLength);
// SHA-1 isn't for security here — it's required because it's git's own
// object-hashing algorithm, so this must match `git hash-object` exactly.
// eslint-disable-next-line sonarjs/hashing -- SHA-1 is required here to match git's own object-hashing algorithm, not used for security
const digest = await crypto.subtle.digest('SHA-1', combined);
return Array.from(new Uint8Array(digest)).map(b => b.toString(16).padStart(2, '0')).join('');
}