a44c7c21e466

count a repo's lines as source lines only: files in a known language, tests, docs and data left out, recounting existing mirrors once (v3.0.104)

time
2026-09-29 18:11 UTC · 2 weeks ago
machine
Junes-MacBook-Pro.local
agent
claude-opus-5-5
session
match kepr 2 repo page
parent
b420f182b4cc
3 files package.json+1 −1src/mirror/store.ts+12 −6tests/sync.test.ts+3 −4
package.json+1 −1
@@ -1,6 +1,6 @@11 {22 	"name": "kepr",3-	"version": "3.0.103",3+	"version": "3.0.104",44 	"private": true,55 	"type": "module",66 	"scripts": {

view file

src/mirror/store.ts+12 −6
@@ -102,6 +102,10 @@102102 103103 // Vendored code is someone else's: counting Koh 3's bundled SQLite made it read as 290k lines of C.104104 const VENDORED = /(^|\/)(vendor|third_party|node_modules)\//;105+// Tests are not the program: counted, Koh 3's read as 18k lines of V where it has 11k.106+const TEST = /(^|\/)(tests?|__tests__)\/|_test\.|\.(test|spec)\.|(^|\/)test_[^/]*\.py$/;107+// Bumped when what counts as a line changes, so every mirror recounts once when it opens.108+const STATS_RULE = "source-only";105109 106110 const open = new Map<string, Database>();107111 @@ -131,9 +135,8 @@131135 			db.run(`PRAGMA user_version = ${SCHEMA_VERSION}`);132136 		})();133137 	}134-	// Mirrors whose stats predate `stats_save` (per-language lines, counted past checkpoints) are135-	// recounted now, not at the next save.136-	if (mirrorState(db, "head") && mirrorState(db, "stats_save") === null) refreshStats(db);138+	// Mirrors counted under an older rule are recounted now, not at the next save.139+	if (mirrorState(db, "head") && mirrorState(db, "stats_rule") !== STATS_RULE) refreshStats(db);137140 	open.set(path, db);138141 	return db;139142 }@@ -242,6 +245,7 @@242245 243246 // Lines and languages never change between syncs, so they are counted once here, not per view. They244247 // come from the newest real save, not `head`: a checkpoint's files are not public history (§21.4).248+// Lines are source lines: files in a known language, tests left out; docs and data never count.245249 function refreshStats(db: Database): void {246250 	const save =247251 		db@@ -257,15 +261,16 @@257261 	let lines = 0;258262 	const byLanguage = new Map<string, number>();259263 	for (const file of files) {260-		if (VENDORED.test(file.path) || file.size > MAX_COUNTED) continue;264+		const language = LANGUAGES[file.path.split(".").pop() ?? ""];265+		if (!language || VENDORED.test(file.path) || TEST.test(file.path)) continue;266+		if (file.size > MAX_COUNTED) continue;261267 		const bytes = inflateSync(file.data);262268 		if (bytes.includes(0)) continue;263269 		let count = 0;264270 		for (const byte of bytes) if (byte === 10) count++;265271 		if (bytes.length > 0 && bytes[bytes.length - 1] !== 10) count++;266272 		lines += count;267-		const language = LANGUAGES[file.path.split(".").pop() ?? ""];268-		if (language) byLanguage.set(language, (byLanguage.get(language) ?? 0) + count);273+		byLanguage.set(language, (byLanguage.get(language) ?? 0) + count);269274 	}270275 	const languages = [...byLanguage].sort((a, b) => b[1] - a[1]);271276 	const setState = db.query("INSERT OR REPLACE INTO state (key, value) VALUES (?, ?)");@@ -273,4 +278,5 @@273278 	setState.run("language", languages[0]?.[0] ?? "");274279 	setState.run("languages", JSON.stringify(languages));275280 	setState.run("stats_save", save);281+	setState.run("stats_rule", STATS_RULE);276282 }

view file

tests/sync.test.ts+3 −4
@@ -86,10 +86,9 @@8686 		const stats = repoStats(t.mirror());8787 		expect(stats.saves).toBe(3);8888 		expect(stats.language).toBe("TypeScript");89-		// README 9 + guide 3 + secret 1 + util 1 + main 2 + .kohignore90-		expect(stats.lines).toBeGreaterThan(16);91-		// vendor/big.c's 100 lines of C count toward neither.92-		expect(stats.lines).toBeLessThan(100);89+		// Source lines only: util.ts 2 + main.ts 2. The README, guide, secret and .kohignore are not90+		// code, and vendor/big.c's 100 lines of C are someone else's.91+		expect(stats.lines).toBe(4);9392 		expect(stats.updated).toBe(saveByPrefix(t.mirror(), head())?.created_at ?? -1);9493 	});9594 

view file