@qiwi/tech-radar
Version:
Fully automated tech-radar generator
168 lines (149 loc) • 3.84 kB
JavaScript
import path from 'node:path'
import Eleventy from '@11ty/eleventy'
import fse from 'fs-extra'
import { uniq } from 'lodash-es'
import slash from 'slash'
import { rootDir, tplDir } from '../constants.js'
import { tempDir } from '../util.js'
import { genMdAssets } from './markdown.js'
export const genConfig = async ({ temp, output, prefix }) => {
const configPath = path.join(temp, 'config.js')
const configLoaderAbsPath = path.resolve(rootDir, 'generator/.eleventy.cjs')
const configLoaderRelPath = slash(path.relative(temp, configLoaderAbsPath))
const configMixin = { extra: { temp, prefix, output } }
const configContents = `
module.exports = (config) => require('${configLoaderRelPath}')(Object.assign(config, ${JSON.stringify(
configMixin,
)}))
`
await fse.outputFile(configPath, configContents, 'utf8')
return configPath
}
export const genRadarSettings = ({
title,
basePrefix,
navFooter,
date,
document,
scope,
renderSettings,
}) => {
const quadrants = Object.entries(document.quadrantTitles).map(
([id, name]) => ({ name, id }),
)
const extra = {
title,
date,
target: path.join(scope, date),
prefix: path.join(basePrefix, scope, date),
basePrefix,
footer: navFooter,
}
return { ...renderSettings, extra, quadrants }
}
export const genRadars = async ({ radars, ctx }) => {
await Promise.all(
radars.map(async (radar) => {
await genRadar({ ...ctx, radar })
await genTable({ ...ctx, radar })
}),
)
}
export const genRadar = async ({ ctx, radar }) => {
const temp = await tempDir(ctx.temp)
const output = path.join(ctx.output, radar.scope, radar.date)
const context = {
...ctx,
...radar,
output,
temp,
}
context.settings = genRadarSettings(context)
await genMdAssets(context)
await render('radar', context)
}
export const genTable = async ({ ctx, radar }) => {
const temp = await tempDir(ctx.temp)
const output = path.join(ctx.output, radar.scope, radar.date, 'table')
const settings = radar.document
const context = {
...ctx,
...radar,
settings,
output,
temp,
}
await render('table', context)
}
export const genRedirects = async ({ radars, output, ctx, temp }) => {
await Promise.all(
Object.entries(
radars.reduce((m, { scope, date }) => {
const prev = m[scope]
if (scope !== '.' && (!prev || prev < date)) {
m[scope] = date
}
return m
}, {}),
).map(async ([scope, date]) =>
render('redirect', {
...ctx,
temp: await tempDir(temp),
output: path.join(output, scope),
date,
settings: { extra: { date } },
}),
),
)
}
export const genNavPage = async ({
radars,
output,
ctx,
temp,
navTitle,
navFooter,
}) => {
const scopes = uniq(radars.map((r) => r.scope))
const settings = {
extra: {
radars,
scopes,
footer: navFooter,
title: navTitle,
},
}
await render('root', {
...ctx,
temp: await tempDir(temp),
output,
settings,
})
}
export const render = async (template, options) => {
const { temp, output, settings, templates } = options
const configPath = await genConfig(options)
const elev = new Eleventy(slash(temp), slash(output), { configPath })
// Copy templates
await fse.copy(tplDir, temp)
if (templates) {
await fse.copy(templates, temp)
}
// Store settings
const settingsPath = path.join(temp, '_data/settings.json')
const _settings = await fse.readJson(settingsPath)
await fse.outputFile(
settingsPath,
JSON.stringify({ ..._settings, ...settings }),
)
// Prepare entry point template
await fse.outputFile(
path.join(temp, 'index.njk'),
`---
layout: ${template}.njk
---
`,
)
await elev.init()
await elev.write()
}