build.js (266 lines of code) (raw):

/** * ------------------------------------------------------------------------ * Usage: * * ```shell * node build.js --env asf # build all for asf * node build.js --env echartsjs # build all for echartsjs. * node build.js --env localsite # build all for localsite. * node build.js --env dev # the same as "debug", dev the content of docs. * # Check `./config` to see the available env * ``` * ------------------------------------------------------------------------ */ const md2json = require('./tool/md2json'); const {extractDesc} = require('./tool/schemaHelper'); const fs = require('fs'); const fse = require('fs-extra'); const marked = require('marked'); const copydir = require('copy-dir'); const chalk = require('chalk'); // const MarkDownTOCRenderer = require('./tool/MarkDownTOCRenderer'); const argv = require('yargs').argv; const path = require('path'); const assert = require('assert'); const chokidar = require('chokidar'); const {debounce} = require('lodash'); const {getDocJSONPVarNname} = require('./src/shared'); const projectDir = __dirname; function initEnv() { let envType = argv.env; let isDev = argv.dev != null || argv.debug != null || argv.env === 'dev'; if (isDev) { console.warn('============================='); console.warn('!!! THIS IS IN DEV MODE !!!'); console.warn('============================='); envType = 'dev'; } if (!envType) { throw new Error('--env MUST be specified'); } let config = require('./config/env.' + envType); assert(path.isAbsolute(config.releaseDestDir) && path.isAbsolute(config.ecWWWGeneratedDir)); config.envType = envType; return config; } const config = initEnv(); const languages = ['zh', 'en']; config.gl = config.gl || {}; for (let key in config) { if (key !== 'gl' && !config.gl.hasOwnProperty(key)) { config.gl[key] = config[key]; } } async function md2jsonAsync(opt) { var newOpt = Object.assign({ path: path.join(opt.language, opt.entry, '**/*.md'), tplEnv: Object.assign({}, config, { galleryViewPath: config.galleryViewPath.replace('${lang}', opt.language), galleryEditorPath: config.galleryEditorPath.replace('${lang}', opt.language), handbookPath: config.handbookPath.replace('${lang}', opt.language) }), imageRoot: config.imagePath }, opt); function run(cb) { md2json(newOpt).then(schema => { writeSingleSchema(schema, opt.language, opt.entry, false); writeSingleSchemaPartioned(schema, opt.language, opt.entry, false); console.log(chalk.green('generated: ' + opt.language + '/' + opt.entry)); cb && cb(); }).catch(e => { console.log(e); }); } var runDebounced = debounce(run, 500, { leading: false, trailing: true }); return await new Promise((resolve, reject) => { run(resolve); if (argv.watch) { chokidar.watch(path.resolve(__dirname, opt.language, opt.entry), { ignoreInitial: true }).on('all', (event, path) => { console.log(path, event); runDebounced(); }); } }); } function copyAsset() { const assetSrcDir = path.resolve(projectDir, 'asset'); function doCopy() { for (let lang of languages) { const assetDestDir = path.resolve(config.releaseDestDir, `${lang}/documents/asset`); copydir.sync(assetSrcDir, assetDestDir); } } var doCopyDebounced = debounce(doCopy, 500, { leading: false, trailing: true }); doCopy(); if (argv.watch) { chokidar.watch(assetSrcDir, { ignoreInitial: true }).on('all', (event, path) => { console.log(path, event); doCopyDebounced(); }); } console.log('Copy asset done.'); } async function run() { for (let language of languages) { await md2jsonAsync({ sectionsAnyOf: ['visualMap', 'dataZoom', 'series', 'graphic.elements', 'dataset.transform'], entry: 'option', language }); await md2jsonAsync({ entry: 'tutorial', maxDepth: 1, language }); await md2jsonAsync({ entry: 'api', language }); await md2jsonAsync({ sectionsAnyOf: ['series'], entry: 'option-gl', // Overwrite tplEnv: config.gl, imageRoot: config.gl.imagePath, language }); } console.log('Build doc done.'); copyAsset(); if (!argv.watch) { // Not in watch dev mode try { // TODO Do we need to debug changelog in the doc folder? buildChangelog(); buildCodeStandard(); copySite(); } catch (e) { console.log('Error happens when copying to dest folders.'); console.log(e); } } console.log('All done.'); } function buildChangelog() { for (let lang of languages) { const srcPath = path.resolve(projectDir, `${lang}/changelog.md`); const destPath = path.resolve(config.ecWWWGeneratedDir, `${lang}/documents/changelog-content.html`); fse.outputFileSync( destPath, marked(fs.readFileSync(srcPath, 'utf-8')), 'utf-8' ); console.log(chalk.green('generated: ' + destPath)); } console.log('Build changelog done.'); } function buildCodeStandard() { // support for Chinese character const customRenderer = new marked.Renderer(); customRenderer.heading = function(text, level, raw) { const id = raw.toLowerCase().replace(/[^\w\u4e00-\u9fa5]+/g, '-'); return `<h${level} id="${id}">${text}</h${level}>\n`; }; for (let lang of languages) { const codeStandardDestPath = path.resolve(config.ecWWWGeneratedDir, `${lang}/coding-standard-content.html`); fse.ensureDirSync(path.dirname(codeStandardDestPath)); fse.outputFileSync( codeStandardDestPath, marked(fs.readFileSync(`${lang}/coding-standard.md`, 'utf-8'), { renderer: customRenderer }), 'utf-8' ); console.log(chalk.green('generated: ' + codeStandardDestPath)); } console.log('Build code standard done.'); } function copySite() { const jsSrcPath = path.resolve(projectDir, 'public/js/doc-bundle.js'); const cssSrcDir = path.resolve(projectDir, 'public/css'); // Copy js and css of doc site. for (let lang of languages) { const jsDestPath = path.resolve(config.releaseDestDir, `${lang}/js/doc-bundle.js`); fse.copySync(jsSrcPath, jsDestPath); console.log(chalk.green(`js copied to: ${jsDestPath}`)); const cssDestDir = path.resolve(config.releaseDestDir, `${lang}/css`); fse.copySync(cssSrcDir, cssDestDir); console.log(chalk.green(`css copied to: ${cssDestDir}`)); } console.log('Copy site done.'); } function writeSingleSchema(schema, language, docName, format) { const destPath = path.resolve(config.releaseDestDir, `${language}/documents/${docName}.json`); fse.ensureDirSync(path.dirname(destPath)); fse.outputFileSync( destPath, format ? JSON.stringify(schema, null, 2) : JSON.stringify(schema), 'utf-8' ); // console.log(chalk.green('generated: ' + destPath)); } function writeSingleSchemaPartioned(schema, language, docName, format) { const {outline, descriptions} = extractDesc(schema, docName); function convertToJS(basename, filePath) { const content = fs.readFileSync(filePath, 'utf-8'); const varName = getDocJSONPVarNname(basename); const code = `window.${varName} = ${content}`; fs.writeFileSync(filePath.replace(/\.json$/, '.js'), code, 'utf-8'); } const outlineBasename = `${docName}-outline.json`; const outlineDestPath = path.resolve(config.releaseDestDir, `${language}/documents/${docName}-parts/${outlineBasename}`); fse.ensureDirSync(path.dirname(outlineDestPath)); fse.outputFileSync( outlineDestPath, format ? JSON.stringify(outline, null, 2) : JSON.stringify(outline), 'utf-8' ); convertToJS(outlineBasename, outlineDestPath); function copyUIControlConfigs(source, target) { for (let key in source) { if (target[key]) { if (source[key].uiControl && !target[key].uiControl) { target[key].uiControl = source[key].uiControl; } if (source[key].exampleBaseOptions && !target[key].exampleBaseOptions) { target[key].exampleBaseOptions = source[key].exampleBaseOptions; } } else { // console.error(`Unmatched option path ${key}`); } } } function readOptionDesc(language, partKey) { const descDestPath = path.resolve(config.releaseDestDir, `${language}/documents/${docName}-parts/${partKey}.json`); try { const text = fs.readFileSync(descDestPath, 'utf-8'); return JSON.parse(text); } catch(e) { return; } } function writeOptionDesc(language, partKey, json) { const descBasename = `${partKey}.json`; const descDestPath = path.resolve(config.releaseDestDir, `${language}/documents/${docName}-parts/${descBasename}`); fse.ensureDirSync(path.dirname(descDestPath)); fse.outputFileSync( descDestPath, format ? JSON.stringify(json, null, 2) : JSON.stringify(json), 'utf-8' ); convertToJS(descBasename, descDestPath); } for (let partKey in descriptions) { let partDescriptions = descriptions[partKey]; // Copy ui control config from zh to english. if (language === 'zh') { languages.forEach(function (otherLang) { if (otherLang === 'zh') { return; } const json = readOptionDesc(otherLang, partKey); if (json) { copyUIControlConfigs(partDescriptions, json); writeOptionDesc(otherLang, partKey, json); } }); } else { const json = readOptionDesc('zh', partKey); if (json) { copyUIControlConfigs(json, partDescriptions); } } writeOptionDesc(language, partKey, partDescriptions); // console.log(chalk.green('generated: ' + descDestPath)); } }; run();