1
0
mirror of https://github.com/twirl/The-API-Book.git synced 2025-05-19 21:33:04 +02:00
2025-02-01 21:23:37 +02:00

328 lines
9.7 KiB
TypeScript

import { readFile } from 'node:fs/promises';
import { resolve } from 'node:path';
import {
Bibliography,
init,
Path,
plugins,
LogLevel,
applyAstPluginToStructure,
L10n
} from './builder-model';
import { buildLanding } from './build-landing';
import { CustomTemplates, ExtraStrings } from './templates';
const SRC = resolve('./src') as Path;
const LOCALES: { [language: string]: string } = {
en: 'en-US',
ru: 'ru-RU'
};
const { args, flags } = process.argv.slice(2).reduce(
({ args, flags }, v) => {
if (v.startsWith('--')) {
flags.add(
v.slice(2).replace(/-\w/g, (m) => m.charAt(1).toUpperCase())
);
} else {
args.push(v);
}
return { args, flags };
},
{ args: [] as string[], flags: new Set<string>() }
);
async function initBuilder(
language: string,
locale: string,
strings: ExtraStrings,
target: 'epub' | 'html' | 'pdf'
): Promise<{
bookBuilder: Awaited<ReturnType<typeof init>>;
templates: CustomTemplates;
l10n: L10n<CustomTemplates, ExtraStrings>;
}> {
const bookBuilder = await init({
source: {
dir: resolve(SRC, language, 'clean-copy') as Path,
base: SRC
},
options: {
tmpDir: resolve('./.tmp') as Path,
noCache: flags.has('noCache'),
purgeCache: flags.has('purgeCache'),
logLevel: LogLevel.DEBUG
}
});
const templates = new CustomTemplates(
target,
bookBuilder.context,
language,
locale,
{
...strings,
favicon: await bookBuilder.toDataUri(strings.favicon)
},
{ anchorLink: 'anchor', externalLink: 'external' }
);
return {
bookBuilder,
templates,
l10n: { language, locale, strings, templates }
};
}
const builders = {
html: async ({
outFile,
language,
locale,
strings,
bibliography,
cssFiles
}) => {
const { bookBuilder, templates, l10n } = await initBuilder(
language,
locale,
strings,
'html'
);
await bookBuilder.build<CustomTemplates, ExtraStrings, 'html'>(
'html',
l10n,
{
structure: {
plugins: [
plugins.structure.h3Title(),
plugins.structure.h5Counter(),
plugins.structure.highlighter({
languages: ['javascript', 'typescript', 'json']
}),
plugins.structure.hoistSingleChapters(),
plugins.structure.tableOfContents(),
plugins.structure.imprintPages(
templates.htmlImprintPages(),
'front-page'
),
plugins.structure.reference({
bibliography
}),
plugins.structure.imgDataUri(),
plugins.structure.aImg()
]
},
html: {
plugins: [plugins.html.validator()]
},
css: {
plugins: [plugins.css.dataUri()]
}
},
{
css: [cssFiles.FONTS, cssFiles.COMMON, cssFiles.SCREEN].join(
'\n'
),
outFile
}
);
},
epub: async ({
outFile,
language,
locale,
strings,
bibliography,
cssFiles,
baseDir
}) => {
const { bookBuilder, templates, l10n } = await initBuilder(
language,
locale,
strings,
'epub'
);
await bookBuilder.build<CustomTemplates, ExtraStrings, 'epub'>(
'epub',
l10n,
{
structure: {
plugins: [
plugins.structure.h3Title(),
plugins.structure.h5Counter(),
plugins.structure.highlighter({
languages: ['javascript', 'typescript', 'json']
}),
plugins.structure.hoistSingleChapters(),
plugins.structure.imprintPages(
templates.htmlImprintPages(),
'front-page'
),
plugins.structure.reference({
bibliography,
prependPath: 'bibliography.xhtml'
}),
plugins.structure.epubLink(),
plugins.structure.aImg(),
plugins.structure.imgSrcToFileUrl(baseDir)
]
},
epub: {
plugins: []
},
css: {
plugins: []
}
},
{
css: [cssFiles.COMMON, cssFiles.EPUB].join('\n'),
outFile
}
);
},
pdf: async ({
outFile,
language,
locale,
strings,
bibliography,
cssFiles
}) => {
const { bookBuilder, templates, l10n } = await initBuilder(
language,
locale,
strings,
'pdf'
);
await bookBuilder.build<CustomTemplates, ExtraStrings, 'pdf'>(
'pdf',
l10n,
{
structure: {
plugins: [
plugins.structure.h3Title(),
plugins.structure.h5Counter(),
plugins.structure.highlighter({
languages: ['javascript', 'typescript', 'json']
}),
plugins.structure.hoistSingleChapters(),
plugins.structure.tableOfContents(),
plugins.structure.imprintPages(
templates.htmlImprintPages(),
'front-page'
),
plugins.structure.reference({
bibliography
}),
plugins.structure.imgDataUri(),
plugins.structure.aImg()
]
},
pdf: {
plugins: []
},
css: {
plugins: [plugins.css.dataUri()]
}
},
{
css: [
cssFiles.FONTS,
cssFiles.COMMON,
cssFiles.PAGE,
cssFiles.PRINT
].join('\n'),
outFile,
useCachedContent: false
}
);
},
landing: async ({ language, locale, strings }) => {
const { bookBuilder, templates } = await initBuilder(
language,
locale,
strings,
'html'
);
await applyAstPluginToStructure(
bookBuilder.context,
{ language, locale, strings, templates },
bookBuilder.structure,
plugins.structureAst.h3Title()
);
await buildLanding({
structure: bookBuilder.structure,
lang: language,
examplesDir: resolve('docs', 'examples') as Path,
outFile: resolve('docs', strings.landingFile) as Path,
strings,
templates
});
}
} as {
[target: string]: (params: {
outFile: Path;
language: string;
locale: string;
strings: ExtraStrings;
bibliography: Bibliography;
cssFiles: Record<string, string>;
baseDir: Path;
}) => Promise<void>;
};
async function main() {
const cssFiles = {
COMMON: await readFile(resolve(SRC, 'css', 'common.css'), 'utf-8'),
FONTS: await readFile(resolve(SRC, 'css', 'fonts.css'), 'utf-8'),
SCREEN: await readFile(resolve(SRC, 'css', 'screen.css'), 'utf-8'),
EPUB: await readFile(resolve(SRC, 'css', 'epub.css'), 'utf-8'),
PRINT: await readFile(resolve(SRC, 'css', 'print.css'), 'utf-8'),
PAGE: await readFile(resolve(SRC, 'css', 'page.css'), 'utf-8')
};
const languages = (args[0] ?? 'en,ru').split(',').map((s) => s.trim());
const targets = (args[1] ?? 'html,epub,pdf')
.split(',')
.map((s) => s.trim());
for (const language of languages) {
const locale = LOCALES[language];
if (!locale) {
throw new Error(`Unknown locale ${locale}`);
}
const strings = JSON.parse(
await readFile(resolve(SRC, language, 'l10n.json'), 'utf-8')
) as ExtraStrings;
const bibliography = JSON.parse(
await readFile(resolve(SRC, language, 'bibliography.json'), 'utf-8')
) as Bibliography;
for (const target of targets) {
const builder = builders[target];
if (typeof builder !== 'function') {
throw new Error(`Unknown target ${target}`);
}
const outFile = resolve(
'docs',
`API.${language}.${target}`
) as Path;
await builder({
outFile,
language,
locale,
strings,
bibliography,
cssFiles,
baseDir: SRC
});
}
}
}
main()
.catch((e) => console.error(e, e.stack))
.then(() => process.exit(0));