You've already forked The-API-Book
mirror of
https://github.com/twirl/The-API-Book.git
synced 2025-08-10 21:51:42 +02:00
The book completely rebuilt with book-builder v1
This commit is contained in:
@@ -1,27 +0,0 @@
|
||||
import { resolve } from 'path';
|
||||
import { readdirSync, writeFileSync, statSync } from 'fs';
|
||||
|
||||
const examplesDir = resolve('docs', 'examples');
|
||||
|
||||
export const buildLanding = (structure, lang, l10n, templates) => {
|
||||
const examples = readdirSync(examplesDir);
|
||||
|
||||
const landingHtml = templates.landing({
|
||||
structure: structure,
|
||||
examples: examples.reduce((examples, folder) => {
|
||||
const fullName = resolve(examplesDir, folder);
|
||||
if (statSync(fullName).isDirectory()) {
|
||||
const name = folder.match(/^\d+\. (.+)$/)[1];
|
||||
examples.push({
|
||||
name,
|
||||
path: `examples/${folder}`
|
||||
});
|
||||
}
|
||||
return examples;
|
||||
}, []),
|
||||
l10n: l10n[lang],
|
||||
lang,
|
||||
templates
|
||||
});
|
||||
writeFileSync(resolve('docs', l10n[lang].landingFile), landingHtml);
|
||||
};
|
182
scripts/build-landing.ts
Normal file
182
scripts/build-landing.ts
Normal file
@@ -0,0 +1,182 @@
|
||||
import { resolve } from 'node:path';
|
||||
import { readdir, writeFile } from 'node:fs/promises';
|
||||
import { statSync } from 'node:fs';
|
||||
import {
|
||||
Path,
|
||||
Structure
|
||||
} from '@twirl/book-builder';
|
||||
import {
|
||||
CustomTemplates,
|
||||
Example,
|
||||
ExtraStrings,
|
||||
linker,
|
||||
shareLink,
|
||||
toc
|
||||
} from '../src/templates';
|
||||
|
||||
export const buildLanding = async ({
|
||||
structure,
|
||||
examplesDir,
|
||||
lang,
|
||||
outFile,
|
||||
strings,
|
||||
templates
|
||||
}: LandingParameters) => {
|
||||
const examples = await readdir(examplesDir);
|
||||
|
||||
const landingHtml = await landingTemplate(
|
||||
{
|
||||
structure,
|
||||
strings,
|
||||
lang,
|
||||
templates
|
||||
},
|
||||
examples.reduce((examples: Example[], folder) => {
|
||||
const fullName = resolve(examplesDir, folder);
|
||||
if (statSync(fullName).isDirectory()) {
|
||||
const name = folder.match(/^\d+\. (.+)$/)![1];
|
||||
examples.push({
|
||||
name,
|
||||
path: `examples/${folder}` as Path
|
||||
});
|
||||
}
|
||||
return examples;
|
||||
}, [])
|
||||
);
|
||||
await writeFile(outFile, landingHtml);
|
||||
};
|
||||
|
||||
export const landingTemplate = async (
|
||||
{
|
||||
structure,
|
||||
strings,
|
||||
lang,
|
||||
templates
|
||||
}: Omit<LandingParameters, 'examplesDir' | 'outFile'>,
|
||||
examples: Example[]
|
||||
) => {
|
||||
const link = linker(strings, lang);
|
||||
return `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" type="image/png" href="assets/favicon.png" />
|
||||
<title>
|
||||
${strings.author}. ${strings.title}
|
||||
</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="${strings.description}"
|
||||
/>
|
||||
<meta property="og:type" content="article" />
|
||||
<meta
|
||||
property="og:title"
|
||||
content="${strings.author}. ${strings.title}"
|
||||
/>
|
||||
<meta
|
||||
property="og:description"
|
||||
content="${strings.description}"
|
||||
/>
|
||||
<meta property="og:image" content="assets/header.png" />
|
||||
<meta
|
||||
property="og:url"
|
||||
content="${strings.links.githubHref}"
|
||||
/>
|
||||
<link rel="stylesheet" href="assets/fonts.css"/>
|
||||
<link rel="stylesheet" href="assets/landing.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<img
|
||||
class="header"
|
||||
src="assets/header.jpg"
|
||||
alt="${strings.author}. ${strings.title}"
|
||||
/><br />
|
||||
<header>
|
||||
<h1>${strings.author}<br/><span class="title">${
|
||||
strings.title
|
||||
}</span></h1>
|
||||
${
|
||||
strings.landing.subTitle
|
||||
? `<h2>${strings.landing.subTitle}</h2>`
|
||||
: ''
|
||||
}
|
||||
</header>
|
||||
<br />${strings.landing.subscribeOn} ${strings.landing.updates
|
||||
.map(
|
||||
(source) =>
|
||||
`<a class="${source}" href="${
|
||||
strings.links[source + 'Href']
|
||||
}">${strings.links[source + 'Tag'] || ''}</a>`
|
||||
)
|
||||
.join(' · ')}
|
||||
${
|
||||
strings.landing.follow && strings.landing.follow.length
|
||||
? `<br/>${strings.landing.followOn} ${strings.landing.follow
|
||||
.map(
|
||||
(source) =>
|
||||
`<a class="${source}" href="${
|
||||
strings.links[source + 'Href']
|
||||
}">${strings.links[source + 'Tag'] || ''}</a>`
|
||||
)
|
||||
.join(' · ')}`
|
||||
: ''
|
||||
}
|
||||
<br />${strings.landing.supportThisWork} ${strings.landing.support
|
||||
.map(
|
||||
(source) =>
|
||||
`<a class="${source}" href="${
|
||||
strings.links[source + 'Href']
|
||||
}">${strings.links[source + 'Tag'] || ''}</a>`
|
||||
)
|
||||
.join(' · ')}
|
||||
<br />${strings.sidePanel.shareTo}: ${strings.sidePanel.services
|
||||
.map(
|
||||
({ key, link }) =>
|
||||
`<a class="share share-${key}" href="${shareLink(
|
||||
link,
|
||||
strings.sidePanel.shareParameters
|
||||
)}" target="_blank"></a>`
|
||||
)
|
||||
.join(' · ')}<br/>⚙️⚙️⚙️
|
||||
</nav>
|
||||
${strings.landing.content.join('\n')}
|
||||
${
|
||||
strings.landing.download
|
||||
? `<p>${strings.landing.download} <a href="${link(
|
||||
undefined,
|
||||
'pdf'
|
||||
)}">PDF</a> / <a href="${link(undefined, 'epub')}">EPUB</a> ${
|
||||
strings.landing.or
|
||||
} <a href="${link()}">${strings.landing.readOnline}</a>.
|
||||
</p>`
|
||||
: `<p>${strings.landing.readOnline}.</p>`
|
||||
}
|
||||
<h3>${strings.toc}</h3>
|
||||
${await toc({ structure, strings, templates, lang }, examples)}
|
||||
<p>${strings.landing.license}</p>
|
||||
<p>${strings.sourceCodeAt} <a href="${strings.links.githubHref}">${
|
||||
strings.links.githubString
|
||||
}</a></p>
|
||||
<h3><a name="about-author">${strings.aboutMe.title}</a></h3>
|
||||
<section class="about-me">
|
||||
<aside><img src="https://konstantinov.cc/static/me.png"/><br/>${
|
||||
strings.aboutMe.imageCredit
|
||||
}</aside>
|
||||
<div class="content">
|
||||
${strings.aboutMe.content.join('\n')}</div>
|
||||
</section>
|
||||
${strings.landing.footer.join('\n')}
|
||||
</body>
|
||||
</html>`;
|
||||
};
|
||||
|
||||
export interface LandingParameters {
|
||||
structure: Structure;
|
||||
examplesDir: Path;
|
||||
lang: string;
|
||||
outFile: Path;
|
||||
strings: ExtraStrings;
|
||||
templates: CustomTemplates;
|
||||
}
|
@@ -1,163 +0,0 @@
|
||||
import { readFileSync, readdirSync, unlinkSync } from 'fs';
|
||||
import { resolve as pathResolve } from 'path';
|
||||
import { init, plugins } from '@twirl/book-builder';
|
||||
import { templates } from '../src/templates.mjs';
|
||||
import { apiHighlight } from '../src/api-highlight.mjs';
|
||||
import { buildLanding } from './build-landing.mjs';
|
||||
|
||||
const { flags, args } = process.argv.slice(2).reduce(
|
||||
({ flags, args }, v) => {
|
||||
switch (v) {
|
||||
case '--no-cache':
|
||||
flags.noCache = true;
|
||||
break;
|
||||
case '--sample':
|
||||
flags.sample = true;
|
||||
}
|
||||
if (!v.startsWith('--')) {
|
||||
args.push(v);
|
||||
}
|
||||
return { flags, args };
|
||||
},
|
||||
{
|
||||
args: [],
|
||||
flags: {}
|
||||
}
|
||||
);
|
||||
|
||||
const l10n = {
|
||||
en: JSON.parse(readFileSync('./src/en/l10n.json', 'utf-8')),
|
||||
ru: JSON.parse(readFileSync('./src/ru/l10n.json', 'utf-8'))
|
||||
};
|
||||
|
||||
const css = ['fonts', 'common', 'screen', 'print', 'page', 'epub'].reduce(
|
||||
(css, file) => {
|
||||
css[file] = readFileSync(`src/css/${file}.css`).toString('utf-8');
|
||||
return css;
|
||||
},
|
||||
{}
|
||||
);
|
||||
|
||||
const targetCss = {
|
||||
html: [css.fonts, css.common, css.screen, css.print],
|
||||
pdf: [css.fonts, css.common, css.print],
|
||||
epub: [css.common, css.epub]
|
||||
};
|
||||
const extraCss = {
|
||||
html: css.page,
|
||||
pdf: css.page
|
||||
};
|
||||
|
||||
const langsToBuild = (args[0] && args[0].split(',').map((s) => s.trim())) || [
|
||||
'ru',
|
||||
'en'
|
||||
];
|
||||
|
||||
const targets = (
|
||||
(args[1] && args[1].split(',')) || ['html', 'pdf', 'epub', 'landing']
|
||||
).reduce((targets, arg) => {
|
||||
targets[arg.trim()] = true;
|
||||
return targets;
|
||||
}, {});
|
||||
|
||||
const chapters = args[2];
|
||||
const noCache = flags.noCache;
|
||||
|
||||
if (flags.noCache) {
|
||||
clean();
|
||||
}
|
||||
|
||||
console.log(`Building langs: ${langsToBuild.join(', ')}…`);
|
||||
(async () => {
|
||||
for (const lang of langsToBuild) {
|
||||
await init({
|
||||
lang,
|
||||
l10n: l10n[lang],
|
||||
basePath: pathResolve(`src`),
|
||||
path: pathResolve(`src/${lang}/clean-copy`),
|
||||
templates,
|
||||
pipeline: {
|
||||
css: {
|
||||
beforeAll: [
|
||||
plugins.css.backgroundImageDataUri,
|
||||
plugins.css.fontFaceDataUri
|
||||
]
|
||||
},
|
||||
ast: {
|
||||
preProcess: [
|
||||
plugins.ast.h3ToTitle,
|
||||
plugins.ast.h5Counter,
|
||||
plugins.ast.aImg,
|
||||
plugins.ast.imgSrcResolve,
|
||||
plugins.ast.highlighter({
|
||||
languages: ['javascript', 'typescript', 'json'],
|
||||
languageDefinitions: {
|
||||
json: apiHighlight
|
||||
}
|
||||
}),
|
||||
plugins.ast.ref,
|
||||
plugins.ast.ghTableFix,
|
||||
plugins.ast.stat
|
||||
]
|
||||
},
|
||||
htmlSourceValidator: {
|
||||
validator: 'WHATWG',
|
||||
ignore: [
|
||||
'heading-level',
|
||||
'no-raw-characters',
|
||||
'wcag/h37',
|
||||
'no-missing-references'
|
||||
]
|
||||
},
|
||||
html: {
|
||||
postProcess: [plugins.html.imgDataUri]
|
||||
}
|
||||
},
|
||||
chapters,
|
||||
noCache,
|
||||
sample: flags.sample,
|
||||
cover: 'src/cover_embed.png'
|
||||
}).then(async (builder) => {
|
||||
for (const target of Object.keys(targets)) {
|
||||
if (target !== 'landing') {
|
||||
await builder.build(
|
||||
target,
|
||||
pathResolve(
|
||||
'docs',
|
||||
`${l10n[lang].file}.${lang}${
|
||||
flags.sample ? '.sample' : ''
|
||||
}.${target}`
|
||||
),
|
||||
{
|
||||
css: targetCss[target],
|
||||
extraCss: extraCss[target]
|
||||
}
|
||||
);
|
||||
console.log(
|
||||
`Finished lang=${lang} target=${target}\n${Object.entries(
|
||||
{
|
||||
sources: 'Sources',
|
||||
references: 'references',
|
||||
words: 'words',
|
||||
characters: 'characters'
|
||||
}
|
||||
)
|
||||
.map(([k, v]) => `${v}: ${builder.structure[k]}`)
|
||||
.join(', ')}`
|
||||
);
|
||||
} else {
|
||||
buildLanding(builder.structure, lang, l10n, templates);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
function clean() {
|
||||
const tmpDir = pathResolve('.', '.tmp');
|
||||
const files = readdirSync(tmpDir);
|
||||
for (const fileName of files) {
|
||||
const file = pathResolve(tmpDir, fileName);
|
||||
unlinkSync(file);
|
||||
}
|
||||
}
|
327
scripts/build.ts
Normal file
327
scripts/build.ts
Normal file
@@ -0,0 +1,327 @@
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import {
|
||||
Bibliography,
|
||||
init,
|
||||
Path,
|
||||
plugins,
|
||||
LogLevel,
|
||||
applyAstPluginToStructure,
|
||||
L10n,
|
||||
} from '@twirl/book-builder';
|
||||
import { buildLanding } from './build-landing';
|
||||
import { CustomTemplates, ExtraStrings } from '../src/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));
|
Reference in New Issue
Block a user