blob: 8f88ab95850a04703b38010747717ac07a9abfab [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import fs from 'fs';
import path from 'path';
import yargs from 'yargs';
import {hideBin} from 'yargs/helpers';
const argv = yargs(hideBin(process.argv))
.option('html-output-file', {
type: 'string',
demandOption: true,
})
.option('js-output-file', {
type: 'string',
demandOption: true,
})
.option('sources-file', {
type: 'string',
demandOption: true,
})
.option('environment-setup-file', {
type: 'string',
demandOption: true,
})
.parseSync();
const HTML_OUTPUT_FILE = argv.htmlOutputFile;
const JS_OUTPUT_FILE = argv.jsOutputFile;
const SOURCES_FILE = argv.sourcesFile;
const ENVIRONMENT_FILE = argv.environmentSetupFile;
if (!HTML_OUTPUT_FILE || !JS_OUTPUT_FILE || !SOURCES_FILE || !ENVIRONMENT_FILE) {
console.error(
'Usage: node generate_docs.js --devtools-frontend-path <path> --html-output-file <path> --js-output-file <path> --sources-file <path> --environment-setup-file <path>');
process.exit(1);
}
async function main() {
const componentDocs = JSON.parse(fs.readFileSync(SOURCES_FILE, 'utf-8'));
const componentLinks = componentDocs
.map(p => path.basename(p, '.docs.js'))
.sort()
.map(componentName => `<li><a href="#${componentName}">${componentName}</a></li>`)
.join('\n');
const docImports = componentDocs
.map(p => {
const componentName = path.basename(p, '.docs.js');
return `'${componentName}': () => import('${p}'),`;
})
.join('\n');
let environmentSetupPath = path.relative(path.dirname(JS_OUTPUT_FILE), ENVIRONMENT_FILE);
if (!environmentSetupPath.startsWith('.')) {
environmentSetupPath = `./${environmentSetupPath}`;
}
const docLoader = `
import {setup, cleanup} from '${environmentSetupPath}';
const components = {
${docImports}
};
const mainContent = document.querySelector('.main-content');
async function loadComponent(name) {
if (!components[name] || !mainContent) {
return;
}
let container = document.getElementById('container');
// Replace the container to start off with a clean one.
if (container) {
container.remove();
await cleanup();
}
container = document.createElement('div');
container.id = 'container';
mainContent.appendChild(container);
await setup();
const {render} = await components[name]();
render(container);
}
window.addEventListener('hashchange', () => {
const componentName = window.location.hash.substr(1);
loadComponent(componentName);
});
if (window.location.hash) {
loadComponent(window.location.hash.substr(1));
}
`;
const styleSheets = [
'front_end/design_system_tokens.css',
'front_end/application_tokens.css',
'front_end/ui/legacy/inspectorCommon.css',
'front_end/ui/components/buttons/textButton.css',
'scripts/component_docs/component_docs.css',
];
const linksToStyleSheets = styleSheets
.map(
link => `<link rel="stylesheet" href="./${link}" type="text/css" />`,
)
.join('\n');
// The path to the loader script is now relative from the root of gen/.
const loaderScriptPath = path.relative(path.dirname(HTML_OUTPUT_FILE), JS_OUTPUT_FILE);
const indexHtml = `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<title>DevTools components</title>
${linksToStyleSheets}
</head>
<body>
<nav class="sidebar">
<h1>DevTools components</h1>
<ul class="components-list">
${componentLinks}
</ul>
</nav>
<div class="divider"></div>
<main class="main-content">
<div id="container"></div>
</main>
<script type="module" src="${loaderScriptPath}"></script>
</body>
</html>
`;
fs.writeFileSync(HTML_OUTPUT_FILE, indexHtml);
fs.writeFileSync(JS_OUTPUT_FILE, docLoader);
}
main();