mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-08-29 04:26:38 +00:00
chore: tighten TypeScript duplication lint
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
/** Shared repository file discovery and line-oriented reference scanning. */
|
||||
|
||||
import { globSync, readFileSync, realpathSync } from 'node:fs'
|
||||
import { relative, resolve } from 'node:path'
|
||||
|
||||
/** One authored path plus its canonical target for symlink deduplication. */
|
||||
export interface RepoFile {
|
||||
/** Absolute path matched by the caller's glob. */
|
||||
abs: string
|
||||
/** Absolute canonical path used only for deduplication. */
|
||||
real: string
|
||||
}
|
||||
|
||||
/** A rejected line-oriented repository reference. */
|
||||
export interface ReferenceViolation {
|
||||
/** Repo-relative file containing the reference. */
|
||||
file: string
|
||||
/** 1-based line containing the reference. */
|
||||
line: number
|
||||
/** Normalized reference text. */
|
||||
ref: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand repository-relative globs and deduplicate symlinked files.
|
||||
* @param root - absolute repository root.
|
||||
* @param patterns - repository-relative glob patterns, processed in order.
|
||||
* @param isExcluded - optional predicate over each matched relative path.
|
||||
* @returns matched files in stable first-seen order.
|
||||
*/
|
||||
export function uniqueRepoFiles(
|
||||
root: string,
|
||||
patterns: readonly string[],
|
||||
isExcluded: (relativePath: string) => boolean = () => false,
|
||||
): RepoFile[] {
|
||||
const seen = new Set<string>()
|
||||
const files: RepoFile[] = []
|
||||
for (const pattern of patterns) {
|
||||
for (const match of globSync(pattern, { cwd: root })) {
|
||||
if (isExcluded(match)) continue
|
||||
const abs = resolve(root, match)
|
||||
const real = realpathSync(abs)
|
||||
if (seen.has(real)) continue
|
||||
seen.add(real)
|
||||
files.push({ abs, real })
|
||||
}
|
||||
}
|
||||
return files
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan regex matches line by line and return the normalized matches rejected by
|
||||
* a caller predicate.
|
||||
* @param root - absolute repository root used for violation paths.
|
||||
* @param absPath - absolute text-file path to scan.
|
||||
* @param pattern - global regex matched independently against each line.
|
||||
* @param normalize - maps raw regex text to the reference the gate evaluates.
|
||||
* @param isViolation - returns true when the normalized reference is invalid.
|
||||
* @returns every rejected reference in source order.
|
||||
*/
|
||||
export function findReferenceViolations(
|
||||
root: string,
|
||||
absPath: string,
|
||||
pattern: RegExp,
|
||||
normalize: (raw: string) => string,
|
||||
isViolation: (ref: string) => boolean,
|
||||
): ReferenceViolation[] {
|
||||
const file = relative(root, absPath)
|
||||
const out: ReferenceViolation[] = []
|
||||
const lines = readFileSync(absPath, 'utf8').split('\n')
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i]
|
||||
if (line === undefined) continue
|
||||
for (const match of line.matchAll(pattern)) {
|
||||
const ref = normalize(match[0])
|
||||
if (isViolation(ref)) out.push({ file, line: i + 1, ref })
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user