diff --git a/docs/c2patool/container.md b/docs/c2patool/container.md index 6db8ad1c..a96f4c68 100644 --- a/docs/c2patool/container.md +++ b/docs/c2patool/container.md @@ -1,6 +1,7 @@ --- id: c2patool-index title: C2PA Tool +custom_edit_path: c2pa-rs/edit/main/cli/README.md --- :::tip diff --git a/docs/js-sdk/js-landing.mdx b/docs/js-sdk/js-landing.mdx index df1d1756..4e8d9c5c 100644 --- a/docs/js-sdk/js-landing.mdx +++ b/docs/js-sdk/js-landing.mdx @@ -1,6 +1,7 @@ --- id: js-landing title: JavaScript library +custom_edit_path: c2pa-js/edit/main/README.md --- :::tip diff --git a/docs/nodejs.md b/docs/nodejs.md index 83392164..d15a2ffa 100644 --- a/docs/nodejs.md +++ b/docs/nodejs.md @@ -1,6 +1,7 @@ --- id: node-landing title: Node.js library +custom_edit_path: c2pa-node-v2/edit/main/README.md --- import Readme from './c2pa-node-v2/readme.md'; diff --git a/docusaurus.config.js b/docusaurus.config.js index 87a61eb8..d6d08e14 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -6,6 +6,9 @@ const lightCodeTheme = require('prism-react-renderer').themes.github; const darkCodeTheme = require('prism-react-renderer').themes.dracula; +const remoteDocs = require('./remote-docs.json'); +const { readFileSync } = require('fs'); +const { resolve } = require('path'); const copyright = `
@@ -17,32 +20,98 @@ const copyright = ` `; // Map of external repositories to their GitHub repository names, paths, and organizations +// Used to create 'Edit this page' links const externalRepos = { - 'c2pa-c': { repo: 'c2pa-c', path: '', org: 'contentauth' }, - 'c2pa-min': { repo: 'c2pa-min', path: '', org: 'contentauth' }, - 'c2pa-node': { repo: 'c2pa-node', path: '', org: 'contentauth' }, - 'c2pa-node-example': { - repo: 'c2pa-node-example', - path: '', - org: 'contentauth', - }, + 'c2pa-cpp': { repo: 'c2pa-cpp', path: '', org: 'contentauth' }, + 'c2pa-ios': { repo: 'c2pa-ios', path: '', org: 'contentauth' }, + 'c2pa-android': { repo: 'c2pa-android', path: '', org: 'contentauth' }, + 'c2pa-js': { repo: 'c2pa-js', path: '', org: 'contentauth' }, + + 'c2pa-node-v2': { repo: 'c2pa-node', path: '', org: 'contentauth' }, 'c2pa-python': { repo: 'c2pa-python', path: '', org: 'contentauth' }, 'c2pa-python-example': { repo: 'c2pa-python-example', path: '', org: 'contentauth', }, - 'c2pa-service-example': { - repo: 'c2pa-service-example', - path: '', - org: 'contentauth', - }, + c2patool: { repo: 'c2pa-rs', path: 'cli/', org: 'contentauth' }, 'rust-sdk': { repo: 'c2pa-rs', path: '', org: 'contentauth' }, trustmark: { repo: 'trustmark', path: '', org: 'adobe' }, }; -/** @type {import('@docusaurus/types').Config} */ +// Exact edit URLs for docs that are mirrored from remote-docs.json sources. +// This handles cases where local doc names differ from source repo paths. +/** @type {Record} */ +const remoteDocEditUrls = {}; + +for (const source of remoteDocs.sources) { + if (typeof source.dest !== 'string' || !source.dest.startsWith('docs/')) { + continue; + } + if (typeof source.repo !== 'string' || typeof source.path !== 'string') { + continue; + } + + const docPath = source.dest.replace(/^docs\//, '').toLowerCase(); + let branch = 'main'; + if ('branch' in source && typeof source.branch === 'string') { + branch = source.branch; + } + + remoteDocEditUrls[ + docPath + ] = `https://github.com/${source.repo}/edit/${branch}/${source.path}`; +} + +const contentauthGithubBaseUrl = 'https://github.com/contentauth/'; +const frontMatterRegex = /^---\r?\n([\s\S]*?)\r?\n---/; +const customEditPathRegex = /^\s*custom_edit_path:\s*(.+?)\s*$/m; +/** @type {Map} */ +const customEditUrlCache = new Map(); + +/** + * Reads a doc's frontmatter and returns its custom contentauth edit URL, if any. + * @param {string | undefined} versionDocsDirPath + * @param {string} docPath + * @returns {string | null} + */ +function getFrontMatterCustomEditUrl(versionDocsDirPath, docPath) { + if (!versionDocsDirPath) { + return null; + } + + const cacheKey = `${versionDocsDirPath}:${docPath}`; + if (customEditUrlCache.has(cacheKey)) { + return customEditUrlCache.get(cacheKey) ?? null; + } + + let customEditUrl = null; + try { + const markdown = readFileSync(resolve(versionDocsDirPath, docPath), 'utf8'); + const frontMatterMatch = markdown.match(frontMatterRegex); + if (frontMatterMatch) { + const customEditPathMatch = + frontMatterMatch[1].match(customEditPathRegex); + if (customEditPathMatch) { + const customEditPath = customEditPathMatch[1] + .trim() + .replace(/^['"]|['"]$/g, '') + .replace(/^\/+/, ''); + if (customEditPath) { + customEditUrl = `${contentauthGithubBaseUrl}${customEditPath}`; + } + } + } + } catch { + // Ignore missing/non-readable files and continue with default edit URL logic. + } + + customEditUrlCache.set(cacheKey, customEditUrl); + return customEditUrl; +} + +/** @returns {Promise} */ async function createConfig() { const { default: remarkGithubAdmonitionsToDirectives } = await import( 'remark-github-admonitions-to-directives' @@ -90,7 +159,9 @@ async function createConfig() { docs: { beforeDefaultRemarkPlugins: [remarkGithubAdmonitionsToDirectives], sidebarPath: require.resolve('./sidebars.js'), - editUrl: ({ docPath }) => { + editUrl: ({ docPath, versionDocsDirPath }) => { + const normalizedDocPath = docPath.toLowerCase(); + // Don't show edit link for dynamically generated API docs if (docPath.startsWith('js-sdk/api/')) { return null; @@ -101,16 +172,34 @@ async function createConfig() { return 'https://github.com/contentauth/c2pa-rs/edit/main/docs/supported-formats.md'; } + // Allow docs to point at a contentauth README/source via frontmatter. + const customEditUrl = getFrontMatterCustomEditUrl( + versionDocsDirPath, + docPath, + ); + if (customEditUrl) { + return customEditUrl; + } + + // Use explicit source mappings from remote-docs.json when available. + const remoteDocEditUrl = remoteDocEditUrls[normalizedDocPath]; + if (remoteDocEditUrl) { + return remoteDocEditUrl; + } + // Check if the doc is from an external repository const externalRepo = Object.keys(externalRepos).find((repo) => - docPath.startsWith(`${repo}/`), + normalizedDocPath.startsWith(`${repo}/`), ); if (externalRepo) { // Get the GitHub repository info for this external repo const repoInfo = externalRepos[externalRepo]; // Remove the repo prefix from the path to get the relative path in the repo - let repoPath = docPath.replace(`${externalRepo}/`, ''); + let repoPath = normalizedDocPath.replace( + `${externalRepo}/`, + '', + ); // Convert readme.md to README.md in the path repoPath = repoPath.replace(/readme\.md$/i, 'README.md'); return `https://github.com/${repoInfo.org}/${repoInfo.repo}/edit/main/${repoInfo.path}${repoPath}`;