mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-09-27 02:43:48 +02:00
Re-enable lastUpdated, add lastUpdated logic to API doc generator
This commit is contained in:
@@ -10,6 +10,7 @@ import apiRoutes from '../api/index.json';
|
||||
import m3u8Grammar from './m3u8-grammar.json' with { type: 'json' };
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { execFileSync } from 'node:child_process';
|
||||
|
||||
const DESCRIPTION = 'A JavaScript library for reading, writing, and converting media files. Directly in the browser,'
|
||||
+ ' and faster than anybunny else.';
|
||||
@@ -27,8 +28,14 @@ export default withMermaid({
|
||||
for (const entry of entries) {
|
||||
const isDirectory = await fs.stat(path.join('./examples', entry)).then(stat => stat.isDirectory());
|
||||
if (isDirectory) {
|
||||
const gitDate = execFileSync(
|
||||
'git',
|
||||
['log', '-1', '--format=%cI', '--', path.join('./examples', entry)],
|
||||
).toString().trim();
|
||||
|
||||
items.push({
|
||||
url: `/examples/${entry}/`, // With trailing slash
|
||||
lastmod: new Date(gitDate).toISOString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -36,7 +43,7 @@ export default withMermaid({
|
||||
return items;
|
||||
},
|
||||
},
|
||||
// lastUpdated: true,
|
||||
lastUpdated: true,
|
||||
head: [
|
||||
['link', { rel: 'icon', type: 'image/png', href: '/mediabunny-logo.png' }],
|
||||
['link', { rel: 'icon', type: 'image/svg+xml', href: '/mediabunny-logo.svg' }],
|
||||
@@ -201,7 +208,7 @@ export default withMermaid({
|
||||
tailwindcss() as any,
|
||||
llmstxt({
|
||||
ignoreFiles: [
|
||||
'api/*',
|
||||
'api/!(index).md',
|
||||
'examples.md',
|
||||
'llms.md',
|
||||
],
|
||||
@@ -305,5 +312,10 @@ export default withMermaid({
|
||||
for (const file of files) {
|
||||
await fs.copyFile('./docs/api/' + file, './dist-docs/api/' + file);
|
||||
}
|
||||
|
||||
// The llms.txt generation leaves behind runs of empty lines, collapse them into one
|
||||
const llmsTxtPath = './dist-docs/llms.txt';
|
||||
const llmsTxt = await fs.readFile(llmsTxtPath, 'utf-8');
|
||||
await fs.writeFile(llmsTxtPath, llmsTxt.replace(/\n{3,}/g, '\n\n'));
|
||||
},
|
||||
});
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
import * as ts from 'typescript';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { execFileSync } from 'child_process';
|
||||
|
||||
const generateDocs = (entryFiles: string[], apiConfigFile: string, dry = false) => {
|
||||
const program = ts.createProgram(entryFiles, {
|
||||
@@ -629,6 +630,7 @@ const generateDocs = (entryFiles: string[], apiConfigFile: string, dry = false)
|
||||
// Data structures for "Used by" feature
|
||||
const usedByReferences = new Map<string, Set<{ user: string; context: string; type: 'constructor' | 'method' | 'property' | 'extends' | 'type_param' | 'type_alias' | 'variable' | 'function' }>>();
|
||||
const generatedDocs = new Map<string, string>();
|
||||
const symbolSourceFiles = new Map<string, string>();
|
||||
|
||||
const addUsage = (
|
||||
used: string,
|
||||
@@ -678,6 +680,9 @@ const generateDocs = (entryFiles: string[], apiConfigFile: string, dry = false)
|
||||
}
|
||||
}
|
||||
|
||||
// Remember where the symbol is actually defined (reexports don't count), for lastModified dates
|
||||
symbolSourceFiles.set(symbolName, targetDeclaration.getSourceFile().fileName);
|
||||
|
||||
const groupTag = ts.getJSDocTags(targetDeclaration).find(tag => tag.tagName.text === 'group');
|
||||
if (!groupTag || typeof groupTag.comment !== 'string') {
|
||||
throw new Error(`Symbol '${symbolName}' is missing @group JSDoc tag`);
|
||||
@@ -1750,6 +1755,8 @@ const generateDocs = (entryFiles: string[], apiConfigFile: string, dry = false)
|
||||
});
|
||||
|
||||
// Phase 3: Assemble final docs with "Used by" sections and write files
|
||||
let newestLastModified: string | null = null;
|
||||
|
||||
generatedDocs.forEach((markdown, symbolName) => {
|
||||
const usages = usedByReferences.get(symbolName);
|
||||
let usedByMarkdown = '';
|
||||
@@ -1821,8 +1828,16 @@ const generateDocs = (entryFiles: string[], apiConfigFile: string, dry = false)
|
||||
}
|
||||
}
|
||||
|
||||
const finalMarkdown = markdown.replace('<!-- USED_BY_SECTION -->', usedByMarkdown);
|
||||
if (!dry) {
|
||||
const lastModified = getLastModifiedDate(symbolSourceFiles.get(symbolName)!);
|
||||
if (!newestLastModified || new Date(lastModified) > new Date(newestLastModified)) {
|
||||
newestLastModified = lastModified;
|
||||
}
|
||||
|
||||
const finalMarkdown = addLastUpdatedToFrontmatter(
|
||||
markdown.replace('<!-- USED_BY_SECTION -->', usedByMarkdown),
|
||||
lastModified,
|
||||
);
|
||||
const outputPath = path.join(outputDir, `${symbolName}.md`);
|
||||
fs.writeFileSync(outputPath, finalMarkdown);
|
||||
console.log(`Generated: ${outputPath}`);
|
||||
@@ -1874,7 +1889,7 @@ const generateDocs = (entryFiles: string[], apiConfigFile: string, dry = false)
|
||||
|
||||
if (!dry) {
|
||||
const indexPath = path.join(outputDir, 'index.md');
|
||||
fs.writeFileSync(indexPath, indexMarkdown);
|
||||
fs.writeFileSync(indexPath, addLastUpdatedToFrontmatter(indexMarkdown, newestLastModified!));
|
||||
console.log(`Generated: ${indexPath}`);
|
||||
}
|
||||
|
||||
@@ -1901,6 +1916,30 @@ const generateDocs = (entryFiles: string[], apiConfigFile: string, dry = false)
|
||||
}
|
||||
};
|
||||
|
||||
// Last-commit date of a source file, so generated pages can carry an honest lastModified date.
|
||||
// Falls back to the filesystem mtime for files git doesn't know about yet.
|
||||
const lastModifiedCache = new Map<string, string>();
|
||||
const getLastModifiedDate = (filePath: string) => {
|
||||
let date = lastModifiedCache.get(filePath);
|
||||
if (date === undefined) {
|
||||
const gitDate = execFileSync('git', ['log', '-1', '--format=%cI', '--', filePath]).toString().trim();
|
||||
date = gitDate
|
||||
? new Date(gitDate).toISOString()
|
||||
: fs.statSync(filePath).mtime.toISOString();
|
||||
lastModifiedCache.set(filePath, date);
|
||||
}
|
||||
return date;
|
||||
};
|
||||
|
||||
// Unquoted ISO value so YAML parses it as a date -- VitePress only honors the lastUpdated
|
||||
// frontmatter key (for both the page footer and the sitemap) when it's an actual Date
|
||||
const addLastUpdatedToFrontmatter = (markdown: string, lastModified: string) => {
|
||||
if (markdown.startsWith('---\n')) {
|
||||
return markdown.replace('---\n', `---\nlastUpdated: ${lastModified}\n`);
|
||||
}
|
||||
return `---\nlastUpdated: ${lastModified}\n---\n\n${markdown}`;
|
||||
};
|
||||
|
||||
// Shared helper for extracting a JSDoc description, handling inline tags via raw-source fallback.
|
||||
// - `tagHandling: 'stopAtFirst'` matches the behavior used by property-level descriptions: if any
|
||||
// @-tag line is encountered, all subsequent lines are dropped (including any trailing description).
|
||||
|
||||
Reference in New Issue
Block a user