2020-11-09 00:31:31 +03:00
const fs = require ( 'fs' ) ;
2020-12-08 15:43:01 +03:00
const path = require ( 'path' ) ;
2020-12-20 14:31:45 +03:00
const builders = require ( './src/lib/builders' ) ;
const mdHtml = require ( './src/lib/md-html' ) ;
const htmlProcess = require ( './src/lib/html-process' ) ;
2020-12-08 15:43:01 +03:00
2020-12-20 14:31:45 +03:00
const css = fs . readFileSync ( './src/style.css' , 'utf-8' ) ;
2020-12-08 15:43:01 +03:00
2020-12-06 22:16:52 +03:00
const l10n = {
en : {
2020-12-08 15:43:01 +03:00
title : 'The API' ,
2020-12-06 22:16:52 +03:00
author : 'Sergey Konstantinov' ,
2020-12-08 15:43:01 +03:00
chapter : 'Chapter' ,
toc : 'Table of Contents' ,
2020-12-14 13:31:06 +03:00
frontPage : 'Front Page' ,
description : "Designing APIs is a very special skill: API is a multiplier to both your opportunities and mistakes. This book is written to share the expertise and describe the best practices in the API design. The book comprises three large sections. In Section I we'll discuss designing APIs as a concept: how to build the architecture properly, from a high-level planning down to final interfaces. Section II is dedicated to an API's lifecycle: how interfaces evolve over time, and how to elaborate the product to match users' needs. Finally, Section III is more about un-engineering sides of the API, like API marketing, organizing support, and working with a community." ,
locale : 'en_US'
2020-11-09 00:31:31 +03:00
} ,
2020-12-06 22:16:52 +03:00
ru : {
2020-12-08 15:43:01 +03:00
title : 'API' ,
2020-12-06 22:16:52 +03:00
author : 'Сергей Константинов' ,
2020-12-08 15:43:01 +03:00
chapter : 'Глава' ,
toc : 'Содержание' ,
2020-12-14 13:31:06 +03:00
frontPage : 'Титульный лист' ,
description : 'Разработка API — особый навык: API является как мультипликатором ваших возможностей, так и мультипликатором ваших ошибок. Эта книга написана для того, чтобы поделиться опытом и изложить лучшие практики проектирования API. Книга состоит из трёх больших разделов. В первом разделе мы поговорим о проектировании API на стадии разработки концепции — как грамотно выстроить архитектуру, от крупноблочного планирования до конечных интерфейсов. Второй раздел будет посвящён жизненному циклу API — как интерфейсы эволюционируют со временем и как развивать продукт так, чтобы отвечать потребностям пользователей. Наконец, третий раздел будет касаться больше не-разработческих сторон жизни API — поддержки, маркетинга, работы с комьюнити.' ,
locale : 'ru_RU'
2020-12-06 22:16:52 +03:00
}
} ;
2020-12-09 00:20:54 +03:00
2020-12-20 14:31:45 +03:00
const langsToBuild = process . argv [ 2 ] &&
process . argv [ 2 ] . split ( ',' ) . map ( ( s ) => s . trim ( ) ) ||
[ 'ru' , 'en' ] ;
const targets = ( process . argv [ 3 ] &&
process . argv [ 3 ] . split ( ',' ) ||
[ 'html' , 'pdf' , 'epub' ]
) . reduce ( ( targets , arg ) => {
targets [ arg . trim ( ) ] = true ;
return targets ;
} , { } ) ;
2020-12-06 22:16:52 +03:00
2020-12-08 15:43:01 +03:00
buildDocs ( langsToBuild , targets , l10n ) . then ( ( ) => {
2020-12-07 12:23:55 +03:00
console . log ( 'Done!' ) ;
2020-12-06 22:16:52 +03:00
process . exit ( 0 ) ;
} , ( e ) => {
console . error ( e ) ;
process . exit ( 255 ) ;
} ) ;
2020-12-08 15:43:01 +03:00
function buildDocs ( langsToBuild , targets , l10n ) {
console . log ( ` Building in following languages: ${
langsToBuild . join ( ', ' )
} , targets : $ {
Object . keys ( targets ) . join ( ', ' )
} ` );
2020-12-06 22:16:52 +03:00
return Promise . all (
2020-12-08 15:43:01 +03:00
langsToBuild . map ( ( lang ) => buildDoc ( lang , targets , l10n [ lang ] ) )
2020-12-06 22:16:52 +03:00
) ;
}
2020-11-09 00:31:31 +03:00
2020-12-20 14:31:45 +03:00
async function buildDoc ( lang , targets , l10n ) {
2020-12-14 13:31:06 +03:00
const pageBreak = '<div class="page-break"></div>' ;
2020-12-20 14:31:45 +03:00
const structure = await getStructure ( {
2020-12-06 22:16:52 +03:00
path : ` ./src/ ${ lang } /clean-copy/ ` ,
l10n ,
2020-12-14 13:31:06 +03:00
pageBreak
2020-12-08 15:43:01 +03:00
} ) ;
2020-12-14 13:31:06 +03:00
const tableOfContents = ` <nav><h2> ${ l10n . toc } </h2><ul class="table-of-contents"> ${
structure . sections . map ( ( section ) => {
return ` <li><a href="# ${ section . anchor } "> ${ section . title } </a><ul> ${
section . chapters . map ( ( chapter ) => {
return ` <li><a href="# ${ chapter . anchor } "> ${ chapter . title } </a></li> `
} ) . join ( '' )
} < / u l > < / l i > ` ;
} ) . join ( '' )
} < / u l > < / n a v > $ { p a g e B r e a k } ` ;
const getRef = ( anchor ) => {
return ` <a href="# ${ anchor } " class="anchor" name=" ${ anchor } "></a> ` ;
}
2020-12-08 15:43:01 +03:00
const htmlContent = [
structure . frontPage ,
2020-12-14 13:31:06 +03:00
tableOfContents ,
2020-12-08 15:43:01 +03:00
... structure . sections
. map ( ( section ) => section . chapters . reduce ( ( content , chapter ) => {
if ( chapter . title ) {
2020-12-14 13:31:06 +03:00
content . push ( ` <h3> ${ getRef ( chapter . anchor ) } ${ chapter . title } </h3> ` ) ;
2020-12-08 15:43:01 +03:00
}
content . push ( chapter . content ) ;
return content ;
2020-12-14 13:31:06 +03:00
} , [ section . title ? ` <h2> ${ getRef ( section . anchor ) } ${ section . title } </h2> ` : '' ] ) . join ( '' ) )
2020-12-20 14:31:45 +03:00
] ;
2020-11-09 00:31:31 +03:00
2020-12-20 14:31:45 +03:00
const html = targets . html || targets . pdf ? ( await htmlProcess ( ` <html><head>
2020-12-06 22:16:52 +03:00
< meta charset = "utf-8" / >
2020-12-08 15:43:01 +03:00
< title > $ { l10n . author } . $ { l10n . title } < / t i t l e >
2020-12-06 22:16:52 +03:00
< meta name = "author" content = "${l10n.author}" / >
2020-12-14 13:31:06 +03:00
< meta name = "description" content = "${l10n.description}" / >
< meta property = "og:title" content = "${l10n.author}. ${l10n.title}" / >
< meta property = "og:url" content = "https://twirl.github.io/The-API-Book/docs/API.${lang}.html" / >
< meta property = "og:type" content = "article" / >
< meta property = "og:description" content = "${l10n.description}" / >
< meta property = "og:locale" content = "${l10n.locale}" / >
2020-12-07 12:23:55 +03:00
< link rel = "stylesheet" href = "https://fonts.googleapis.com/css2?family=PT+Serif&family=PT+Sans&family=Inconsolata" / >
2020-12-09 00:20:54 +03:00
< style > $ { css } < / s t y l e >
2020-12-06 22:16:52 +03:00
< / h e a d > < b o d y >
2020-12-20 14:31:45 +03:00
< article > $ { htmlContent . join ( '\n' ) } < / a r t i c l e >
< / b o d y > < / h t m l > ` , {
base : _ _dirname
} ) ) . contents : '' ;
2020-12-06 22:16:52 +03:00
2020-12-08 15:43:01 +03:00
return Promise . all ( [ 'html' , 'pdf' , 'epub' ] . map ( ( target ) => {
return targets [ target ] ? builders [ target ] ( {
lang ,
structure ,
html ,
l10n ,
path : path . join ( _ _dirname , 'docs' , ` API. ${ lang } . ${ target } ` )
} ) : Promise . resolve ( ) ;
} ) ) ;
2020-12-06 22:16:52 +03:00
}
2020-11-09 00:31:31 +03:00
2020-12-20 14:31:45 +03:00
async function getStructure ( { path , l10n , pageBreak } ) {
2020-12-08 15:43:01 +03:00
const structure = {
frontPage : fs . readFileSync ( ` ${ path } intro.html ` , 'utf-8' ) + pageBreak ,
sections : [ ]
} ;
2020-11-09 00:31:31 +03:00
let counter = 1 ;
2020-12-20 14:31:45 +03:00
await fs . readdirSync ( path )
2020-11-09 00:31:31 +03:00
. filter ( ( p ) => fs . statSync ( ` ${ path } ${ p } ` ) . isDirectory ( ) )
. sort ( )
2020-12-20 14:31:45 +03:00
. reduce ( async ( p , dir , index ) => {
const structure = await p ;
2020-11-09 00:31:31 +03:00
const name = dir . split ( '-' ) [ 1 ] ;
2020-12-08 15:43:01 +03:00
const section = {
title : name ,
2020-12-14 13:31:06 +03:00
anchor : ` section- ${ index + 1 } ` ,
2020-12-08 15:43:01 +03:00
chapters : [ ]
}
2020-11-09 00:31:31 +03:00
const subdir = ` ${ path } ${ dir } / ` ;
2020-12-20 14:31:45 +03:00
await fs . readdirSync ( subdir )
2020-11-09 00:31:31 +03:00
. filter ( ( p ) => fs . statSync ( ` ${ subdir } ${ p } ` ) . isFile ( ) && p . indexOf ( '.md' ) == p . length - 3 )
. sort ( )
2020-12-20 14:31:45 +03:00
. reduce ( async ( p , file ) => {
const section = await p ;
2020-12-08 15:43:01 +03:00
const md = fs . readFileSync ( ` ${ subdir } ${ file } ` , 'utf-8' ) . trim ( ) ;
2020-12-20 14:31:45 +03:00
const content = await mdHtml ( md , {
counter ,
l10n ,
base : _ _dirname
} ) ;
2020-12-08 15:43:01 +03:00
section . chapters . push ( {
2020-12-20 14:31:45 +03:00
anchor : content . data . anchor ,
title : content . data . title ,
content : content . contents + pageBreak
2020-12-08 15:43:01 +03:00
} ) ;
2020-12-14 13:31:06 +03:00
counter ++ ;
2020-12-20 14:31:45 +03:00
return section ;
} , Promise . resolve ( section ) ) ;
2020-12-08 15:43:01 +03:00
structure . sections . push ( section ) ;
2020-12-20 14:31:45 +03:00
return structure ;
} , Promise . resolve ( structure ) ) ;
2020-12-08 15:43:01 +03:00
return structure ;
2020-12-06 22:16:52 +03:00
}