docs: function addImportFrom(ast, moduleSource, defaultImport, namedImport, namespaceImport) {
    // Summary:
    //  Add import from source module. Such as import { xxx } from './x';
    let names = [];
  
    if (namedImport) {
      if (typeof namedImport === 'string') {
        names.push(namedImport);
      } else {
        names = names.concat(namedImport);
      }
    }
  
    const changes = [];
    const t = babelTypes;
  
    let targetImportPos = 0;
    let sourceExisted = false;
    traverse(ast, {
      ImportDeclaration(path) {
        const node = path.node;
        targetImportPos = path.node.end + 1;
  
        if (!node.specifiers || !node.source || node.source.value !== moduleSource) return;
        sourceExisted = true;
        let newNames = [];
        const alreadyHaveDefaultImport = !!_.find(node.specifiers, {
          type: 'ImportDefaultSpecifier',
        });
        const alreadyHaveNamespaceImport = !!_.find(node.specifiers, {
          type: 'ImportNamespaceSpecifier',
        });
        if (defaultImport && !alreadyHaveDefaultImport) newNames.push(defaultImport);
        if (namespaceImport && !alreadyHaveNamespaceImport) newNames.push(namespaceImport);
  
        newNames = newNames.concat(names);
  
        // only add names which don't exist
        newNames = newNames.filter(n => !_.find(node.specifiers, s => s.local.name === n));
  
        if (newNames.length > 0) {
          const newSpecifiers = [].concat(node.specifiers);
          newNames.forEach(n => {
            const local = t.identifier(n);
            const imported = local; // TODO: doesn't support local alias.
            if (n === defaultImport) {
              newSpecifiers.unshift(t.importDefaultSpecifier(local));
            } else if (n === namespaceImport) {
              newSpecifiers.push(t.importNamespaceSpecifier(local));
            } else {
              newSpecifiers.push(t.importSpecifier(local, imported));
            }
          });
  
          const newNode = Object.assign({}, node, { specifiers: newSpecifiers });
          const newCode = generate(newNode, ast._filePath);
          // let newCode = generate(newNode, babelGeneratorOptions).code;
          // newCode = format(newCode, ast._filePath, { insertFinalNewline: false }).formatted;
          // if (multilines) {
          //   newCode = formatMultilineImport(newCode);
          // }
          changes.push({
            start: node.start,
            end: node.end,
            replacement: newCode,
          });
        }
      },
    });
  
    if (changes.length === 0 && !sourceExisted) {
      // add new import declaration if module source doesn't exist
      const specifiers = [];
      if (defaultImport) {
        specifiers.push(t.importDefaultSpecifier(t.identifier(defaultImport)));
      }
      if (namespaceImport) {
        specifiers.push(t.importNamespaceSpecifier(t.identifier(namespaceImport)));
      }
  
      names.forEach(n => {
        const local = t.identifier(n);
        const imported = local;
        specifiers.push(t.importSpecifier(local, imported));
      });
  
      const node = t.importDeclaration(specifiers, t.stringLiteral(moduleSource));
      const newCode = generate(node, ast._filePath);
      changes.push({
        start: targetImportPos,
        end: targetImportPos,
        replacement: `${newCode}\n`,
      });
    }
  
    return changes;
  }