|  | /* | 
|  | * Licensed to the Apache Software Foundation (ASF) under one | 
|  | * or more contributor license agreements.  See the NOTICE file | 
|  | * distributed with this work for additional information | 
|  | * regarding copyright ownership.  The ASF licenses this file | 
|  | * to you under the Apache License, Version 2.0 (the | 
|  | * "License"); you may not use this file except in compliance | 
|  | * with the License.  You may obtain a copy of the License at | 
|  | * | 
|  | *   http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, | 
|  | * software distributed under the License is distributed on an | 
|  | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
|  | * KIND, either express or implied.  See the License for the | 
|  | * specific language governing permissions and limitations | 
|  | * under the License. | 
|  | */ | 
|  |  | 
|  | /** | 
|  | * [Create CommonJS files]: | 
|  | * Compatible with prevoius folder structure: `echarts/lib` exists in `node_modules` | 
|  | * (1) Build all files to CommonJS to `echarts/lib`. | 
|  | * (2) Remove __DEV__. | 
|  | * (3) Mount `echarts/src/export.js` to `echarts/lib/echarts.js`. | 
|  | * | 
|  | * [Create ESModule files]: | 
|  | * Build all files to CommonJS to `echarts/esm`. | 
|  | */ | 
|  |  | 
|  | const nodePath = require('path'); | 
|  | const assert = require('assert'); | 
|  | const fs = require('fs'); | 
|  | const fsExtra = require('fs-extra'); | 
|  | const chalk = require('chalk'); | 
|  | const ts = require('typescript'); | 
|  | const globby = require('globby'); | 
|  | const transformDEVUtil = require('./transform-dev'); | 
|  | const preamble = require('./preamble'); | 
|  | const dts = require('@lang/rollup-plugin-dts').default; | 
|  | const rollup = require('rollup'); | 
|  | const { transformImport } = require('zrender/build/transformImport'); | 
|  |  | 
|  | const ecDir = nodePath.resolve(__dirname, '..'); | 
|  | const tmpDir = nodePath.resolve(ecDir, 'pre-publish-tmp'); | 
|  |  | 
|  | const tsConfig = readTSConfig(); | 
|  |  | 
|  | const autoGeneratedFileAlert = ` | 
|  | /** | 
|  | * AUTO-GENERATED FILE. DO NOT MODIFY. | 
|  | */ | 
|  |  | 
|  | `; | 
|  |  | 
|  | const mainSrcGlobby = { | 
|  | patterns: [ | 
|  | 'src/**/*.ts' | 
|  | ], | 
|  | cwd: ecDir | 
|  | }; | 
|  | const extensionSrcGlobby = { | 
|  | patterns: [ | 
|  | 'extension-src/**/*.ts' | 
|  | ], | 
|  | cwd: ecDir | 
|  | }; | 
|  | const extensionSrcDir = nodePath.resolve(ecDir, 'extension-src'); | 
|  | const extensionESMDir = nodePath.resolve(ecDir, 'extension'); | 
|  |  | 
|  | const typesDir = nodePath.resolve(ecDir, 'types'); | 
|  | const esmDir = 'lib'; | 
|  |  | 
|  |  | 
|  | const compileWorkList = [ | 
|  | { | 
|  | logLabel: 'main ts -> js-esm', | 
|  | compilerOptionsOverride: { | 
|  | module: 'ES2015', | 
|  | rootDir: ecDir, | 
|  | outDir: tmpDir, | 
|  | // Generate types when buidling esm | 
|  | declaration: true, | 
|  | declarationDir: typesDir | 
|  | }, | 
|  | srcGlobby: mainSrcGlobby, | 
|  | transformOptions: { | 
|  | filesGlobby: {patterns: ['**/*.js'], cwd: tmpDir}, | 
|  | preamble: preamble.js, | 
|  | transformDEV: true | 
|  | }, | 
|  | before: async function () { | 
|  | fsExtra.removeSync(tmpDir); | 
|  | fsExtra.removeSync(nodePath.resolve(ecDir, 'types')); | 
|  | fsExtra.removeSync(nodePath.resolve(ecDir, esmDir)); | 
|  | fsExtra.removeSync(nodePath.resolve(ecDir, 'index.js')); | 
|  | fsExtra.removeSync(nodePath.resolve(ecDir, 'index.blank.js')); | 
|  | fsExtra.removeSync(nodePath.resolve(ecDir, 'index.common.js')); | 
|  | fsExtra.removeSync(nodePath.resolve(ecDir, 'index.simple.js')); | 
|  | }, | 
|  | after: async function () { | 
|  | fs.renameSync(nodePath.resolve(tmpDir, 'src/echarts.all.js'), nodePath.resolve(ecDir, 'index.js')); | 
|  | fs.renameSync(nodePath.resolve(tmpDir, 'src/echarts.blank.js'), nodePath.resolve(ecDir, 'index.blank.js')); | 
|  | fs.renameSync(nodePath.resolve(tmpDir, 'src/echarts.common.js'), nodePath.resolve(ecDir, 'index.common.js')); | 
|  | fs.renameSync(nodePath.resolve(tmpDir, 'src/echarts.simple.js'), nodePath.resolve(ecDir, 'index.simple.js')); | 
|  | fs.renameSync(nodePath.resolve(tmpDir, 'src'), nodePath.resolve(ecDir, esmDir)); | 
|  |  | 
|  | transformRootFolderInEntry(nodePath.resolve(ecDir, 'index.js'), esmDir); | 
|  | transformRootFolderInEntry(nodePath.resolve(ecDir, 'index.blank.js'), esmDir); | 
|  | transformRootFolderInEntry(nodePath.resolve(ecDir, 'index.common.js'), esmDir); | 
|  | transformRootFolderInEntry(nodePath.resolve(ecDir, 'index.simple.js'), esmDir); | 
|  |  | 
|  | await transformLibFiles(nodePath.resolve(ecDir, esmDir), esmDir); | 
|  | await transformLibFiles(nodePath.resolve(ecDir, 'types'), esmDir); | 
|  | fsExtra.removeSync(tmpDir); | 
|  | } | 
|  | }, | 
|  | { | 
|  | logLabel: 'extension ts -> js-esm', | 
|  | compilerOptionsOverride: { | 
|  | module: 'ES2015', | 
|  | declaration: false, | 
|  | rootDir: extensionSrcDir, | 
|  | outDir: extensionESMDir | 
|  | }, | 
|  | srcGlobby: extensionSrcGlobby, | 
|  | transformOptions: { | 
|  | filesGlobby: {patterns: ['**/*.js'], cwd: extensionESMDir}, | 
|  | preamble: preamble.js, | 
|  | transformDEV: true | 
|  | }, | 
|  | before: async function () { | 
|  | fsExtra.removeSync(extensionESMDir); | 
|  | }, | 
|  | after: async function () { | 
|  | await transformLibFiles(extensionESMDir, 'lib'); | 
|  | } | 
|  | } | 
|  | ]; | 
|  |  | 
|  |  | 
|  |  | 
|  | /** | 
|  | * @public | 
|  | */ | 
|  | module.exports = async function () { | 
|  |  | 
|  | for (let { | 
|  | logLabel, compilerOptionsOverride, srcGlobby, | 
|  | transformOptions, before, after | 
|  | } of compileWorkList) { | 
|  |  | 
|  | process.stdout.write(chalk.green.dim(`[${logLabel}]: compiling ...`)); | 
|  |  | 
|  | before && await before(); | 
|  |  | 
|  | let srcPathList = await readFilePaths(srcGlobby); | 
|  |  | 
|  | await tsCompile(compilerOptionsOverride, srcPathList); | 
|  |  | 
|  | process.stdout.write(chalk.green.dim(` done \n`)); | 
|  |  | 
|  | process.stdout.write(chalk.green.dim(`[${logLabel}]: transforming ...`)); | 
|  |  | 
|  | await transformCode(transformOptions); | 
|  |  | 
|  | after && await after(); | 
|  |  | 
|  | process.stdout.write(chalk.green.dim(` done \n`)); | 
|  | } | 
|  |  | 
|  | process.stdout.write(chalk.green.dim(`Generating entries ...`)); | 
|  | generateEntries(); | 
|  | process.stdout.write(chalk.green.dim(`Bundling DTS ...`)); | 
|  | await bundleDTS(); | 
|  |  | 
|  | console.log(chalk.green.dim('All done.')); | 
|  | }; | 
|  |  | 
|  | async function runTsCompile(localTs, compilerOptions, srcPathList) { | 
|  | // Must do it. becuase the value in tsconfig.json might be different from the inner representation. | 
|  | // For example: moduleResolution: "NODE" => moduleResolution: 2 | 
|  | const {options, errors} = localTs.convertCompilerOptionsFromJson(compilerOptions, ecDir); | 
|  |  | 
|  | if (errors.length) { | 
|  | let errMsg = 'tsconfig parse failed: ' | 
|  | + errors.map(error => error.messageText).join('. ') | 
|  | + '\n compilerOptions: \n' + JSON.stringify(compilerOptions, null, 4); | 
|  | assert(false, errMsg); | 
|  | } | 
|  |  | 
|  | // See: https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API | 
|  |  | 
|  | let program = localTs.createProgram(srcPathList, options); | 
|  | let emitResult = program.emit(); | 
|  |  | 
|  | let allDiagnostics = localTs | 
|  | .getPreEmitDiagnostics(program) | 
|  | .concat(emitResult.diagnostics); | 
|  |  | 
|  | allDiagnostics.forEach(diagnostic => { | 
|  | if (diagnostic.file) { | 
|  | let {line, character} = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); | 
|  | let message = localTs.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); | 
|  | console.log(chalk.red(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`)); | 
|  | } | 
|  | else { | 
|  | console.log(chalk.red(localTs.flattenDiagnosticMessageText(diagnostic.messageText, '\n'))); | 
|  | } | 
|  | }); | 
|  | if (allDiagnostics.length > 0) { | 
|  | throw new Error('TypeScript Compile Failed') | 
|  | } | 
|  | } | 
|  | module.exports.runTsCompile = runTsCompile; | 
|  |  | 
|  | async function tsCompile(compilerOptionsOverride, srcPathList) { | 
|  | assert( | 
|  | compilerOptionsOverride | 
|  | && compilerOptionsOverride.module | 
|  | && compilerOptionsOverride.rootDir | 
|  | && compilerOptionsOverride.outDir | 
|  | ); | 
|  |  | 
|  | let compilerOptions = { | 
|  | ...tsConfig.compilerOptions, | 
|  | ...compilerOptionsOverride, | 
|  | sourceMap: false | 
|  | }; | 
|  |  | 
|  | runTsCompile(ts, compilerOptions, srcPathList); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Transform import/require path in the entry file to `esm` or `lib`. | 
|  | */ | 
|  | function transformRootFolderInEntry(entryFile, replacement) { | 
|  | let code = fs.readFileSync(entryFile, 'utf-8'); | 
|  | // Simple regex replacement | 
|  | // TODO More robust way? | 
|  | assert( | 
|  | !/(import\s+|from\s+|require\(\s*)["']\.\/echarts\./.test(code) | 
|  | && !/(import\s+|from\s+|require\(\s*)["']echarts\./.test(code), | 
|  | 'Import echarts.xxx.ts is not supported.' | 
|  | ); | 
|  | code = code.replace(/((import\s+|from\s+|require\(\s*)["'])\.\//g, `$1./${replacement}/`); | 
|  | fs.writeFileSync( | 
|  | entryFile, | 
|  | // Also transform zrender. | 
|  | singleTransformImport(code, replacement), | 
|  | 'utf-8' | 
|  | ); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Transform `zrender/src` to `zrender/lib` in all files | 
|  | */ | 
|  | async function transformLibFiles(rooltFolder, replacement) { | 
|  | const files = await readFilePaths({ | 
|  | patterns: ['**/*.js', '**/*.d.ts'], | 
|  | cwd: rooltFolder | 
|  | }); | 
|  | // Simple regex replacement | 
|  | // TODO More robust way? | 
|  | for (let fileName of files) { | 
|  | let code = fs.readFileSync(fileName, 'utf-8'); | 
|  | code = singleTransformImport(code, replacement); | 
|  | // For lower ts version, not use import type | 
|  | // TODO Use https://github.com/sandersn/downlevel-dts ? | 
|  | // if (fileName.endsWith('.d.ts')) { | 
|  | //     code = singleTransformImportType(code); | 
|  | // } | 
|  | fs.writeFileSync(fileName, code, 'utf-8'); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * 1. Transform zrender/src to zrender/lib | 
|  | * 2. Add .js extensions | 
|  | */ | 
|  | function singleTransformImport(code, replacement) { | 
|  | return transformImport( | 
|  | code.replace(/([\"\'])zrender\/src\//g, `$1zrender/${replacement}/`), | 
|  | (moduleName) => { | 
|  | // Ignore 'tslib' and 'echarts' in the extensions. | 
|  | if (moduleName === 'tslib' || moduleName === 'echarts') { | 
|  | return moduleName; | 
|  | } | 
|  | else if (moduleName === 'zrender/lib/export') { | 
|  | throw new Error('Should not import the whole zrender library.'); | 
|  | } | 
|  | else if (moduleName.endsWith('.ts')) { | 
|  | // Replace ts with js | 
|  | return moduleName.replace(/\.ts$/, '.js'); | 
|  | } | 
|  | else if (moduleName.endsWith('.js')) { | 
|  | return moduleName; | 
|  | } | 
|  | else { | 
|  | return moduleName + '.js' | 
|  | } | 
|  | } | 
|  | ); | 
|  | } | 
|  |  | 
|  | // function singleTransformImportType(code) { | 
|  | //     return code.replace(/import\s+type\s+/g, 'import '); | 
|  | // } | 
|  |  | 
|  | /** | 
|  | * @param {Object} transformOptions | 
|  | * @param {Object} transformOptions.filesGlobby {patterns: string[], cwd: string} | 
|  | * @param {string} [transformOptions.preamble] See './preamble.js' | 
|  | * @param {boolean} [transformOptions.transformDEV] | 
|  | */ | 
|  | async function transformCode({filesGlobby, preamble, transformDEV}) { | 
|  |  | 
|  | let filePaths = await readFilePaths(filesGlobby); | 
|  |  | 
|  | filePaths.map(filePath => { | 
|  | let code = fs.readFileSync(filePath, 'utf8'); | 
|  |  | 
|  | if (transformDEV) { | 
|  | let result = transformDEVUtil.transform(code, false); | 
|  | code = result.code; | 
|  | } | 
|  |  | 
|  | code = autoGeneratedFileAlert + code; | 
|  |  | 
|  | if (preamble) { | 
|  | code = preamble + code; | 
|  | } | 
|  |  | 
|  | fs.writeFileSync(filePath, code, 'utf8'); | 
|  | }); | 
|  | } | 
|  |  | 
|  | async function readFilePaths({patterns, cwd}) { | 
|  | assert(patterns && cwd); | 
|  | return ( | 
|  | await globby(patterns, {cwd}) | 
|  | ).map( | 
|  | srcPath => nodePath.resolve(cwd, srcPath) | 
|  | ); | 
|  | } | 
|  |  | 
|  | async function bundleDTS() { | 
|  |  | 
|  | const outDir = nodePath.resolve(__dirname, '../types/dist'); | 
|  | const commonConfig = { | 
|  | onwarn(warning, rollupWarn) { | 
|  | // Not warn circular dependency | 
|  | if (warning.code !== 'CIRCULAR_DEPENDENCY') { | 
|  | rollupWarn(warning); | 
|  | } | 
|  | }, | 
|  | plugins: [ | 
|  | dts({ | 
|  | respectExternal: true | 
|  | }) | 
|  | //             { | 
|  | //                 generateBundle(options, bundle) { | 
|  | //                     for (let chunk of Object.values(bundle)) { | 
|  | //                         chunk.code = ` | 
|  | // type Omit<T, K> = Pick<T, Exclude<keyof T, K>>; | 
|  | // ${chunk.code}` | 
|  | //                     } | 
|  | //                 } | 
|  | //             } | 
|  | ] | 
|  | }; | 
|  |  | 
|  | // Bundle chunks. | 
|  | const parts = [ | 
|  | 'core', 'charts', 'components', 'renderers', 'option', 'features' | 
|  | ]; | 
|  | const inputs = {}; | 
|  | parts.forEach(partName => { | 
|  | inputs[partName] = nodePath.resolve(__dirname, `../types/src/export/${partName}.d.ts`) | 
|  | }); | 
|  |  | 
|  | const bundle = await rollup.rollup({ | 
|  | input: inputs, | 
|  | ...commonConfig | 
|  | }); | 
|  | let idx = 1; | 
|  | await bundle.write({ | 
|  | dir: outDir, | 
|  | minifyInternalExports: false, | 
|  | manualChunks: (id) => { | 
|  | // Only create one chunk. | 
|  | return 'shared'; | 
|  | }, | 
|  | chunkFileNames: 'shared.d.ts' | 
|  | }); | 
|  |  | 
|  | // Bundle all in one | 
|  | const bundleAllInOne = await rollup.rollup({ | 
|  | input: nodePath.resolve(__dirname, `../types/src/export/all.d.ts`), | 
|  | ...commonConfig | 
|  | }); | 
|  | await bundleAllInOne.write({ | 
|  | file: nodePath.resolve(outDir, 'echarts.d.ts') | 
|  | }); | 
|  | } | 
|  |  | 
|  | function readTSConfig() { | 
|  | // tsconfig.json may have comment string, which is invalid if | 
|  | // using `require('tsconfig.json'). So we use a loose parser. | 
|  | let filePath = nodePath.resolve(ecDir, 'tsconfig.json'); | 
|  | const tsConfigText = fs.readFileSync(filePath, {encoding: 'utf8'}); | 
|  | return (new Function(`return ( ${tsConfigText} )`))(); | 
|  | } | 
|  |  | 
|  |  | 
|  | function generateEntries() { | 
|  | ['charts', 'components', 'renderers', 'core', 'features'].forEach(entryName => { | 
|  | if (entryName !== 'option') { | 
|  | const jsCode = fs.readFileSync(nodePath.join(__dirname, `template/${entryName}.js`), 'utf-8'); | 
|  | fs.writeFileSync(nodePath.join(__dirname, `../${entryName}.js`), jsCode, 'utf-8'); | 
|  | } | 
|  |  | 
|  | const dtsCode = fs.readFileSync(nodePath.join(__dirname, `/template/${entryName}.d.ts`), 'utf-8'); | 
|  | fs.writeFileSync(nodePath.join(__dirname, `../${entryName}.d.ts`), dtsCode, 'utf-8'); | 
|  | }); | 
|  | } | 
|  |  | 
|  | module.exports.readTSConfig = readTSConfig; |