Move update manifest generator into cinny for standalone Android builds.
All checks were successful
Trigger cinny-mobile / dispatch (push) Successful in 2s
All checks were successful
Trigger cinny-mobile / dispatch (push) Successful in 2s
This commit is contained in:
@@ -9,7 +9,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "vite",
|
"start": "vite",
|
||||||
"build": "node ../scripts/generate-update-manifest.mjs && vite build",
|
"build": "node scripts/generate-update-manifest.mjs && vite build",
|
||||||
"lint": "yarn check:eslint && yarn check:prettier",
|
"lint": "yarn check:eslint && yarn check:prettier",
|
||||||
"check:eslint": "eslint src/*",
|
"check:eslint": "eslint src/*",
|
||||||
"check:prettier": "prettier --check .",
|
"check:prettier": "prettier --check .",
|
||||||
|
|||||||
114
scripts/generate-update-manifest.mjs
Normal file
114
scripts/generate-update-manifest.mjs
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Regenerates public/update/manifest.json from markdown files.
|
||||||
|
*
|
||||||
|
* - currentupdate.md is always the "current" entry
|
||||||
|
* - Other *.md files matching X.Y.Z.md become "older" (sorted newest first)
|
||||||
|
* - title, date, version come from YAML frontmatter when present
|
||||||
|
*/
|
||||||
|
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
const ROOT = path.resolve(__dirname, '..');
|
||||||
|
const UPDATE_DIR = path.join(ROOT, 'public', 'update');
|
||||||
|
const MANIFEST_PATH = path.join(UPDATE_DIR, 'manifest.json');
|
||||||
|
const CURRENT_FILE = 'currentupdate.md';
|
||||||
|
const VERSION_FILE_RE = /^(\d+\.\d+\.\d+)\.md$/;
|
||||||
|
|
||||||
|
const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
|
||||||
|
|
||||||
|
function parseFrontmatter(source) {
|
||||||
|
const match = FRONTMATTER_RE.exec(source.trimStart());
|
||||||
|
if (!match) return {};
|
||||||
|
|
||||||
|
const frontmatter = {};
|
||||||
|
match[1].split('\n').forEach((line) => {
|
||||||
|
const colon = line.indexOf(':');
|
||||||
|
if (colon <= 0) return;
|
||||||
|
const key = line.slice(0, colon).trim();
|
||||||
|
const raw = line.slice(colon + 1).trim();
|
||||||
|
frontmatter[key] = raw.replace(/^['"]|['"]$/g, '');
|
||||||
|
});
|
||||||
|
return frontmatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareVersions(a, b) {
|
||||||
|
const pa = a.split('.').map((part) => Number.parseInt(part, 10));
|
||||||
|
const pb = b.split('.').map((part) => Number.parseInt(part, 10));
|
||||||
|
const len = Math.max(pa.length, pb.length);
|
||||||
|
|
||||||
|
for (let i = 0; i < len; i += 1) {
|
||||||
|
const na = pa[i] ?? 0;
|
||||||
|
const nb = pb[i] ?? 0;
|
||||||
|
if (na !== nb) return nb - na;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readMarkdownMeta(fileName) {
|
||||||
|
const filePath = path.join(UPDATE_DIR, fileName);
|
||||||
|
const source = fs.readFileSync(filePath, 'utf8');
|
||||||
|
const frontmatter = parseFrontmatter(source);
|
||||||
|
const versionFromName = VERSION_FILE_RE.exec(fileName)?.[1];
|
||||||
|
|
||||||
|
return {
|
||||||
|
file: fileName,
|
||||||
|
version: frontmatter.version ?? versionFromName,
|
||||||
|
title: frontmatter.title,
|
||||||
|
date: frontmatter.date,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildManifest() {
|
||||||
|
if (!fs.existsSync(UPDATE_DIR)) {
|
||||||
|
throw new Error(`Update directory not found: ${UPDATE_DIR}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentPath = path.join(UPDATE_DIR, CURRENT_FILE);
|
||||||
|
if (!fs.existsSync(currentPath)) {
|
||||||
|
throw new Error(`Missing ${CURRENT_FILE} in ${UPDATE_DIR}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const older = fs
|
||||||
|
.readdirSync(UPDATE_DIR, { withFileTypes: true })
|
||||||
|
.filter((entry) => entry.isFile() && VERSION_FILE_RE.test(entry.name))
|
||||||
|
.map((entry) => readMarkdownMeta(entry.name))
|
||||||
|
.filter((entry) => entry.version)
|
||||||
|
.sort((a, b) => compareVersions(a.version, b.version));
|
||||||
|
|
||||||
|
return {
|
||||||
|
current: CURRENT_FILE,
|
||||||
|
older: older.map(({ file, version, title, date }) => {
|
||||||
|
const item = { file };
|
||||||
|
if (version) item.version = version;
|
||||||
|
if (title) item.title = title;
|
||||||
|
if (date) item.date = date;
|
||||||
|
return item;
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
const manifest = buildManifest();
|
||||||
|
const json = `${JSON.stringify(manifest, null, 2)}\n`;
|
||||||
|
|
||||||
|
let previous = null;
|
||||||
|
if (fs.existsSync(MANIFEST_PATH)) {
|
||||||
|
previous = fs.readFileSync(MANIFEST_PATH, 'utf8');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previous === json) {
|
||||||
|
console.log('[update-manifest] manifest.json is already up to date');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(MANIFEST_PATH, json, 'utf8');
|
||||||
|
console.log(
|
||||||
|
`[update-manifest] wrote manifest.json (${manifest.older.length} older version(s))`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
Reference in New Issue
Block a user