117 lines
3.7 KiB
JavaScript
117 lines
3.7 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
const path = require("path");
|
|
const { resolveMarkdownTargets } = require("./lib/content");
|
|
const { extractRawDate, readFrontmatter, writeFrontmatter } = require("./lib/weather/frontmatter");
|
|
const { resolveArticleDate } = require("./lib/weather/time");
|
|
const { fetchWeather, hasConfiguredProvider, mergeWeather } = require("./lib/weather/providers");
|
|
const { loadWeatherConfig } = require("./lib/weather/config");
|
|
|
|
const CONTENT_ROOT = path.resolve("content");
|
|
|
|
async function processFile(filePath, config, { force = false } = {}) {
|
|
const frontmatter = await readFrontmatter(filePath);
|
|
|
|
if (!frontmatter) {
|
|
return { status: "no-frontmatter" };
|
|
}
|
|
|
|
const existingWeather = frontmatter.doc.has("weather") ? frontmatter.doc.get("weather") : null;
|
|
|
|
if (existingWeather && !force) {
|
|
return { status: "already-set" };
|
|
}
|
|
|
|
const dateValue = frontmatter.doc.get("date");
|
|
if (!dateValue) {
|
|
return { status: "no-date" };
|
|
}
|
|
|
|
const rawDate = extractRawDate(frontmatter.frontmatterText);
|
|
const targetDate = resolveArticleDate(dateValue, rawDate, config);
|
|
|
|
if (!targetDate) {
|
|
return { status: "invalid-date" };
|
|
}
|
|
|
|
const weather = await fetchWeather(targetDate, config);
|
|
|
|
let finalWeather = {};
|
|
|
|
if (force) {
|
|
finalWeather = weather || {};
|
|
} else if (existingWeather && typeof existingWeather === "object") {
|
|
finalWeather = JSON.parse(JSON.stringify(existingWeather));
|
|
if (weather) {
|
|
const added = mergeWeather(finalWeather, weather, weather.source?.[0]);
|
|
if (!added && Object.keys(finalWeather).length === 0) {
|
|
finalWeather = weather;
|
|
}
|
|
}
|
|
} else {
|
|
finalWeather = weather || {};
|
|
}
|
|
|
|
frontmatter.doc.set("weather", finalWeather);
|
|
|
|
await writeFrontmatter(filePath, frontmatter.doc, frontmatter.body);
|
|
|
|
return {
|
|
status: weather ? "updated" : "empty",
|
|
sources: weather?.source || [],
|
|
};
|
|
}
|
|
|
|
async function main() {
|
|
const cliArgs = process.argv.slice(2);
|
|
const force = cliArgs.includes("--force") || cliArgs.includes("-f");
|
|
const pathArgs = cliArgs.filter((arg) => arg !== "--force" && arg !== "-f");
|
|
|
|
const config = loadWeatherConfig();
|
|
if (!hasConfiguredProvider(config)) {
|
|
console.error("No weather provider configured. Update tools/config.json (weather.providers) before running this script.");
|
|
process.exit(1);
|
|
}
|
|
const files = await resolveMarkdownTargets(pathArgs, { rootDir: CONTENT_ROOT });
|
|
|
|
if (files.length === 0) {
|
|
console.log("No matching markdown files found.");
|
|
return;
|
|
}
|
|
|
|
let updated = 0;
|
|
let skipped = 0;
|
|
|
|
for (const file of files) {
|
|
const relativePath = path.relative(process.cwd(), file);
|
|
|
|
try {
|
|
const result = await processFile(file, config, { force });
|
|
|
|
switch (result.status) {
|
|
case "updated":
|
|
updated += 1;
|
|
console.log(`✔ Added weather to ${relativePath} (${result.sources.join(", ") || "unknown source"})`);
|
|
break;
|
|
case "empty":
|
|
updated += 1;
|
|
console.log(`• Added empty weather to ${relativePath}`);
|
|
break;
|
|
default:
|
|
skipped += 1;
|
|
console.log(`↷ Skipped ${relativePath} (${result.status})`);
|
|
}
|
|
} catch (error) {
|
|
skipped += 1;
|
|
console.error(`✖ Failed ${relativePath}: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
console.log(`\nSummary: ${updated} updated, ${skipped} skipped.`);
|
|
}
|
|
|
|
main().catch((error) => {
|
|
console.error(error);
|
|
process.exit(1);
|
|
});
|