Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ slides/webgl
/public/css
/public/zh/documents
/public/en/documents
/public/zh/coding-standard-content.html
/public/en/coding-standard-content.html
/public/*.html


Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,17 @@ It will:

### Local Config

To customize the links of `echarts-examples` and other configurations, you can create a local config file `echarts-doc/config/env.dev-local.js`, which is not tracked by git. The content can be copied from `echarts-doc/config/env.dev.js`, and then modify it as needed. `npm run dev` will use this local config file, if it exists, to replace `echarts-doc/config/env.dev.js`.
To customize the links of `echarts-examples` and other configurations, you can create a local config file `echarts-doc/config/env.dev-local.js`, which is not tracked by git, and its top-level properties will be used to override the corresponding properties of `echarts-doc/config/env.dev.js` when `npm run dev`.

For example, create a `echarts-doc/config/env.dev-local.js`:
```js
module.exports = {
// These props will override the same props in `echarts-doc/config/env.dev-local.js`
galleryViewPath: 'http://127.0.0.1:3002/en/view.html?local=1&c=',
galleryEditorPath: 'http://127.0.0.1:3002/en/editor.html?local=1&c=',
EMBEDDED_ECHARTS_SCRIPT_URL: 'http://localhost:8001/echarts/echarts/dist/echarts.js',
};
```


## Tips About Writing Doc
Expand Down
343 changes: 2 additions & 341 deletions build.js
Original file line number Diff line number Diff line change
@@ -1,344 +1,5 @@
/**
* ------------------------------------------------------------------------
* 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
* ```
* ------------------------------------------------------------------------
* @file For compatibiliy in case that some CI call this file. May not necessary.
*/

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);

const localOverridePath = './config/env.' + envType + '-local.js';
if (fs.existsSync(path.join(__dirname, localOverridePath))) {
config = require(localOverridePath);
}

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();
require('./build/build-doc.js');
Loading