scripts/dokka/generate-templates.js (57 lines of code) (raw):

const {join} = require('path'); const {execFileSync, execSync, spawnSync} = require('child_process'); const {readdirSync, readFileSync, writeFileSync} = require('fs'); const KeyValueParser = require('key-value-parser'); console.info(`Start generating Dokka's templates`); walkTroughTemplates('dokka-templates'); function isFreemakerTemplate(item) { return item.isFile() && item.name.endsWith('.ftl'); } function replaceEnv(value) { let matched; while (matched = value.match(/\$\{process\.env\.([^}]+)}/)) { const { 0: token, 1: variable, index } = matched; const envValue = process.env[variable] || ''; value = value.substring(0, index) + envValue + value.substring(index + token.length); } return value; } function parsePropsString([definition, _, componentName, propsString]) { return new Promise((resolve, reject) => { new KeyValueParser(propsString || '', { async: true, quoted: '\"' }) .on('end', props => resolve([definition, componentName, props])) .on('error', err => reject(err)); }); } function parseFreemakerContent(originalContent) { /* parse to [ fullEntry, componentName, propsString ] */ const parseRegex = /(\{%\s*ktl_component\s+"(\w+)"\s*(\s[^%]+)?%})/g; const content = replaceEnv(originalContent); return Promise.all([...content.matchAll(parseRegex)].map(parsePropsString)) .then(entries => entries .reduce((text, [definition, componentName, props]) => { const rendered = compileComponent(componentName, props); return text.replace(definition, rendered); }, content) ) } /** * Use the next example to define ktl component in ftl templates: {% ktl_component "COMPONENT_NAME" [PROPS] %} */ function walkTroughTemplates(filePath) { readdirSync(filePath, {withFileTypes: true}).forEach(item => { const currentPath = join(filePath, item.name); if (item.isDirectory()) walkTroughTemplates(currentPath); else if (isFreemakerTemplate(item)) { const originalContent = readFileSync(currentPath).toString('UTF-8'); parseFreemakerContent(originalContent).then(newContent => { if (newContent !== originalContent) { console.info(`Updating ${currentPath} file`); writeFileSync(currentPath, newContent); console.info(`${currentPath} file is updated`); } }); } }); } function compileComponent(name, props) { const propsString = JSON.stringify(props); const stdout = execFileSync('node', ['scripts/react-renderer/compile.js', name, propsString, 'dokka'], {encoding: 'utf-8'}); return `<!-- ktl_component: {"name": "${name}", "props": ${propsString} } --> ${stdout}`; }