Source commit: 20b59dc46b72103c2f8a516c692b5cc3d54fab19 Public tree identity: sha256:aaa5ac7b58b2a0d23c6b11e5f76324bf3839ca1f62653a83deb736932adcfbd9
86 lines
2.7 KiB
JavaScript
86 lines
2.7 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
const assert = require("assert");
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
|
|
const repo = path.resolve(__dirname, "..");
|
|
const maxProductionLines = 1000;
|
|
|
|
const ignoredDirs = new Set([".git", ".cache", ".local", "target", "node_modules"]);
|
|
const rootIgnoredDirs = new Set(["experiments"]);
|
|
|
|
function isTestRustFile(relativePath) {
|
|
const normalized = relativePath.split(path.sep).join("/");
|
|
return (
|
|
normalized.endsWith("/tests.rs") ||
|
|
normalized.includes("/tests/") ||
|
|
normalized.endsWith("_test.rs")
|
|
);
|
|
}
|
|
|
|
function lineCount(source) {
|
|
return source.endsWith("\n")
|
|
? source.split("\n").length - 1
|
|
: source.split("\n").length;
|
|
}
|
|
|
|
function productionSource(source) {
|
|
// A trailing cfg(test) module is not compiled into the product and therefore
|
|
// is not production business logic. Keeping it next to the implementation is
|
|
// useful when it exercises private invariants; count only the source before
|
|
// that explicitly test-only suffix.
|
|
const testModule = /^#\[cfg\(test\)\]\r?\nmod\s+[A-Za-z_][A-Za-z0-9_]*\s*\{/m.exec(source);
|
|
return testModule ? source.slice(0, testModule.index) : source;
|
|
}
|
|
|
|
function walk(directory, results = []) {
|
|
const entries = fs.readdirSync(directory, { withFileTypes: true });
|
|
for (const entry of entries) {
|
|
const fullPath = path.join(directory, entry.name);
|
|
const relativePath = path.relative(repo, fullPath);
|
|
if (entry.isDirectory()) {
|
|
if (ignoredDirs.has(entry.name)) continue;
|
|
if (!relativePath.includes(path.sep) && rootIgnoredDirs.has(entry.name)) continue;
|
|
walk(fullPath, results);
|
|
continue;
|
|
}
|
|
if (entry.isFile() && entry.name.endsWith(".rs")) {
|
|
results.push(relativePath);
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
|
|
const oversizedProductionFiles = [];
|
|
const oversizedTestFiles = [];
|
|
|
|
for (const relativePath of walk(repo)) {
|
|
const source = fs.readFileSync(path.join(repo, relativePath), "utf8");
|
|
const testOnlyFile = isTestRustFile(relativePath);
|
|
const lines = lineCount(testOnlyFile ? source : productionSource(source));
|
|
if (lines <= maxProductionLines) continue;
|
|
|
|
const entry = { path: relativePath, lines };
|
|
if (testOnlyFile) {
|
|
oversizedTestFiles.push(entry);
|
|
} else {
|
|
oversizedProductionFiles.push(entry);
|
|
}
|
|
}
|
|
|
|
assert.deepStrictEqual(
|
|
oversizedProductionFiles,
|
|
[],
|
|
`production Rust files must stay at or below ${maxProductionLines} lines; split business logic before adding more code`
|
|
);
|
|
|
|
if (oversizedTestFiles.length > 0) {
|
|
console.log(
|
|
`Code-size guard ignored ${oversizedTestFiles.length} oversized test-only Rust file(s): ${oversizedTestFiles
|
|
.map((entry) => `${entry.path} (${entry.lines})`)
|
|
.join(", ")}`
|
|
);
|
|
}
|
|
|
|
console.log("Code-size guard passed");
|