scripts/nativeUsageManifest.ts
Rama main · réplica de lectura del repositorio original.
/**
* Validation shared by the pod and Gradle dependency checks.
*
* An `exempt` entry is the one route that skips verification entirely, so the
* only thing standing behind it is the reason a human wrote and the date they
* wrote it. That makes the date worth validating as a date: `9999-99-99` and
* `2026-02-30` both pass a `\d{4}-\d{2}-\d{2}` shape test, and a future date is
* either a typo or a way to park a review forever.
*
* Age is reported as a warning rather than a failure on purpose. Failing on it
* would turn every exemption into a build that breaks on a date nobody chose,
* with no code change to explain it.
*/
const STALE_AFTER_DAYS = 365;
const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
type ReviewedDateResult = {error?: string; warning?: string};
/**
* Checks `reviewed` is a real calendar date, is not in the future, and says how
* old it is.
*/
function validateReviewedDate(reviewed: string | undefined, label: string): ReviewedDateResult {
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(reviewed ?? '');
if (!match) {
return {error: `${label}: "reviewed" must be a date in the YYYY-MM-DD format.`};
}
const [year, month, day] = match.slice(1).map(Number);
const parsed = new Date(Date.UTC(year, month - 1, day));
if (parsed.getUTCFullYear() !== year || parsed.getUTCMonth() !== month - 1 || parsed.getUTCDate() !== day) {
return {error: `${label}: "reviewed" is ${reviewed ?? ''}, which is not a real date.`};
}
// The date is compared against UTC midnight while a developer writes their
// own local date, so a day of slack keeps every timezone from UTC-12 to
// UTC+14 out of the future.
const ageInDays = Math.floor((Date.now() - parsed.getTime()) / MILLISECONDS_PER_DAY);
if (ageInDays < -1) {
return {error: `${label}: "reviewed" is ${reviewed ?? ''}, which is in the future.`};
}
if (ageInDays > STALE_AFTER_DAYS) {
return {warning: `${label}: last reviewed ${ageInDays} days ago (${reviewed ?? ''}). Confirm the reason still holds and update the date.`};
}
return {};
}
/**
* Rejects the empty strings a hand-edited manifest can pick up. An empty pattern
* matches at every position, so one empty entry would make a dependency
* unconditionally reachable.
*/
function findBlankEntry(values: string[], label: string, field: string): string | undefined {
if (values.some((value) => !value.trim())) {
return `${label}: "${field}" must not contain an empty string.`;
}
return undefined;
}
export type {ReviewedDateResult};
export {STALE_AFTER_DAYS, validateReviewedDate, findBlankEntry};