@babel/types#importDeclaration TypeScript Examples

The following examples show how to use @babel/types#importDeclaration. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: code-utils.ts    From plasmic with MIT License 7 votes vote down vote up
function findImportSpecifierWithAlias(
  importDecl: ImportDeclaration,
  local: string
) {
  for (const spec of importDecl.specifiers) {
    if (spec.type === "ImportSpecifier" && spec.local.name === local) {
      return spec;
    }
  }
  return undefined;
}
Example #2
Source File: code-utils.ts    From plasmic with MIT License 7 votes vote down vote up
export function ensureImportSpecifierWithAlias(
  decl: ImportDeclaration,
  imported: string,
  alias: string
) {
  const existing = findImportSpecifierWithAlias(decl, alias);
  if (existing) {
    if (existing.imported.type === "Identifier") {
      existing.imported.name = imported;
    } else {
      existing.imported.value = imported;
    }
  } else {
    decl.specifiers = decl.specifiers.filter((specifier) => {
      if (
        specifier.type === "ImportDefaultSpecifier" &&
        specifier.local.name === alias
      ) {
        // If we are importing a default for a name that will collide with our
        // desired alias, then the default import is wrong and we skip it.
        return false;
      }
      return true;
    });
    decl.specifiers.push(
      babel.types.importSpecifier(
        babel.types.identifier(alias),
        babel.types.identifier(imported)
      )
    );
  }
}
Example #3
Source File: code-utils.ts    From plasmic with MIT License 7 votes vote down vote up
export function ensureImportDefaultSpecifier(
  decl: ImportDeclaration,
  defaultExport: string
) {
  const existing = findImportDefaultSpecifier(decl);
  if (existing) {
    existing.local.name = defaultExport;
  } else {
    decl.specifiers.splice(
      0,
      0,
      babel.types.importDefaultSpecifier(babel.types.identifier(defaultExport))
    );
  }
}
Example #4
Source File: code-utils.ts    From plasmic with MIT License 7 votes vote down vote up
function tryParsePlasmicImportSpec(node: ImportDeclaration) {
  const c = node.trailingComments?.[0];
  if (!c) {
    return undefined;
  }
  const m = c.value.match(
    /plasmic-import:\s+([\w-]+)(?:\/(component|css|render|globalVariant|projectcss|defaultcss|icon|picture|jsBundle|codeComponent|globalContext))?/
  );
  if (m) {
    return { id: m[1], type: m[2] as PlasmicImportType } as PlasmicImportSpec;
  }
  return undefined;
}
Example #5
Source File: remove-nodes-from-original-code.ts    From prettier-plugin-sort-imports with Apache License 2.0 6 votes vote down vote up
removeNodesFromOriginalCode = (
    code: string,
    nodes: (
        | Statement
        | CommentBlock
        | CommentLine
        | ImportDeclaration
        | InterpreterDirective
    )[],
) => {
    let text = code;
    for (const node of nodes) {
        const start = Number(node.start);
        const end = Number(node.end);
        if (Number.isSafeInteger(start) && Number.isSafeInteger(end)) {
            text = text.replace(
                // only replace imports at the beginning of the line (ignoring whitespace)
                // otherwise matching commented imports will be replaced
                new RegExp(
                    '^\\s*' + escapeRegExp(code.substring(start, end)),
                    'm',
                ),
                '',
            );
        }
    }
    return text;
}
Example #6
Source File: get-import-nodes-matched-group.ts    From prettier-plugin-sort-imports with Apache License 2.0 6 votes vote down vote up
getImportNodesMatchedGroup = (
    node: ImportDeclaration,
    importOrder: string[],
) => {
    const groupWithRegExp = importOrder.map((group) => ({
        group,
        regExp: new RegExp(group),
    }));

    for (const { group, regExp } of groupWithRegExp) {
        const matched = node.source.value.match(regExp) !== null;
        if (matched) return group;
    }

    return THIRD_PARTY_MODULES_SPECIAL_WORD;
}
Example #7
Source File: get-import-nodes.ts    From prettier-plugin-sort-imports with Apache License 2.0 6 votes vote down vote up
getImportNodes = (code: string, options?: ParserOptions) => {
    const importNodes: ImportDeclaration[] = [];
    const ast = babelParser(code, {
        ...options,
        sourceType: 'module',
    });

    traverse(ast, {
        ImportDeclaration(path: NodePath<ImportDeclaration>) {
            const tsModuleParent = path.findParent((p) =>
                isTSModuleDeclaration(p),
            );
            if (!tsModuleParent) {
                importNodes.push(path.node);
            }
        },
    });

    return importNodes;
}
Example #8
Source File: get-sorted-import-specifiers.ts    From prettier-plugin-sort-imports with Apache License 2.0 6 votes vote down vote up
getSortedImportSpecifiers = (node: ImportDeclaration) => {
    node.specifiers.sort((a, b) => {
        if (a.type !== b.type) {
            return a.type === 'ImportDefaultSpecifier' ? -1 : 1;
        }

        return naturalSort(a.local.name, b.local.name);
    });
    return node;
}
Example #9
Source File: plugin.ts    From vite-react-jsx with MIT License 6 votes vote down vote up
/**
 * Replace this:
 *
 *     import { jsx as _jsx } from "react/jsx-runtime"
 *
 * with this:
 *
 *     var _jsx = require("react/jsx-runtime").jsx
 */
export function babelImportToRequire({
  types: t,
}: typeof import('@babel/core')) {
  return {
    visitor: {
      ImportDeclaration(path: NodePath) {
        const decl = path.node as ImportDeclaration
        const spec = decl.specifiers[0] as ImportSpecifier

        path.replaceWith(
          t.variableDeclaration('var', [
            t.variableDeclarator(
              spec.local,
              t.memberExpression(
                t.callExpression(t.identifier('require'), [decl.source]),
                spec.imported
              )
            ),
          ])
        )
      },
    },
  }
}
Example #10
Source File: get-sorted-nodes-group.ts    From prettier-plugin-sort-imports with Apache License 2.0 6 votes vote down vote up
function namespaceSpecifierSort(a: ImportDeclaration, b: ImportDeclaration) {
    const aFirstSpecifier = a.specifiers.find(
        (s) => s.type === 'ImportNamespaceSpecifier',
    )
        ? 1
        : 0;
    const bFirstSpecifier = b.specifiers.find(
        (s) => s.type === 'ImportNamespaceSpecifier',
    )
        ? 1
        : 0;
    return bFirstSpecifier - aFirstSpecifier;
}
Example #11
Source File: get-all-comments-from-nodes.spec.ts    From prettier-plugin-sort-imports with Apache License 2.0 6 votes vote down vote up
getSortedImportNodes = (code: string, options?: ParserOptions) => {
    const importNodes: ImportDeclaration[] = getImportNodes(code, options);

    return getSortedNodes(importNodes, {
        importOrder: [],
        importOrderCaseInsensitive: false,
        importOrderSeparation: false,
        importOrderGroupNamespaceSpecifiers: false,
        importOrderSortSpecifiers: false,
    });
}
Example #12
Source File: get-sorted-nodes-group.ts    From prettier-plugin-sort-imports with Apache License 2.0 6 votes vote down vote up
getSortedNodesGroup = (
    imports: ImportDeclaration[],
    options: Pick<PrettierOptions, 'importOrderGroupNamespaceSpecifiers'>,
) => {
    return imports.sort((a, b) => {
        if (options.importOrderGroupNamespaceSpecifiers) {
            const diff = namespaceSpecifierSort(a, b);
            if (diff !== 0) return diff;
        }

        return naturalSort(a.source.value, b.source.value);
    });
}
Example #13
Source File: index.ts    From plasmic with MIT License 6 votes vote down vote up
mergePlasmicImports = (
  mergedFile: babel.types.File,
  parsedNew: PlasmicComponentSkeletonFile,
  parsedEdited: PlasmicComponentSkeletonFile
) => {
  const newImports = parsedNew.file.program.body.filter(
    (stmt) => stmt.type === "ImportDeclaration"
  ) as ImportDeclaration[];
  const editedImports = parsedEdited.file.program.body.filter(
    (stmt) => stmt.type === "ImportDeclaration"
  ) as ImportDeclaration[];
  const firstImport = mergedFile.program.body.findIndex(
    (stmt) => stmt.type === "ImportDeclaration"
  );
  mergedFile.program.body = mergedFile.program.body.filter(
    (stmt) => stmt.type !== "ImportDeclaration"
  );

  const mergedImports: Array<ImportDeclaration> = [];
  for (const editedImport of editedImports) {
    const newImportAt = newImports.findIndex(
      (newImport) => editedImport.source.value === newImport.source.value
    );
    if (newImportAt !== -1) {
      const newImport = newImports[newImportAt];
      newImports.splice(newImportAt, 1);
      mergedImports.push(mergeImports(editedImport, newImport));
    } else {
      mergedImports.push(editedImport);
    }
  }
  mergedImports.push(...newImports);
  const insertMergedImportsAt = firstImport > -1 ? firstImport : 0;
  mergedFile.program.body.splice(insertMergedImportsAt, 0, ...mergedImports);
}
Example #14
Source File: get-sorted-nodes.spec.ts    From prettier-plugin-sort-imports with Apache License 2.0 6 votes vote down vote up
test('it returns all sorted nodes with namespace specifiers at the top', () => {
    const result = getImportNodes(code);
    const sorted = getSortedNodes(result, {
        importOrder: [],
        importOrderCaseInsensitive: false,
        importOrderSeparation: false,
        importOrderGroupNamespaceSpecifiers: true,
        importOrderSortSpecifiers: false,
    }) as ImportDeclaration[];

    expect(getSortedNodesNames(sorted)).toEqual([
        'a',
        'x',
        'BY',
        'Ba',
        'XY',
        'Xa',
        'c',
        'g',
        'k',
        't',
        'z',
    ]);
});
Example #15
Source File: code-utils.ts    From plasmic with MIT License 6 votes vote down vote up
function findImportDefaultSpecifier(importDecl: ImportDeclaration) {
  for (const spec of importDecl.specifiers) {
    if (spec.type === "ImportDefaultSpecifier") {
      return spec;
    }
  }
  return undefined;
}
Example #16
Source File: addPathImport.ts    From engine with MIT License 6 votes vote down vote up
addPathImport: AddPathImport = (babel, state, ref) => {
  const producerName = "@c11/engine.producer";
  const pathImport = importDeclaration(
    [importSpecifier(identifier("path"), identifier("path"))],
    stringLiteral(producerName)
  );

  const program = ref.findParent((p) => p.isProgram());

  if (!program) {
    throw new Error("Internal error. Cannot find program node");
  }

  const macroImport = program.get("body").find((p) => {
    const result =
      p.isImportDeclaration() &&
      p.node.source.value.indexOf("@c11/engine.macro") !== -1;
    return result;
  });

  if (macroImport) {
    // @ts-ignore
    macroImport.insertAfter(pathImport);
  }
}
Example #17
Source File: babel-polyfill.ts    From nota with MIT License 6 votes vote down vote up
importDeclaration = (
  specifiers: Array<ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier>,
  source: StringLiteral
): ImportDeclaration => ({
  type: "ImportDeclaration",
  specifiers,
  source,
  ...baseNode,
})
Example #18
Source File: addWildcardImport.ts    From engine with MIT License 6 votes vote down vote up
addWildcardImport: AddWildcardImport = (babel, state, ref) => {
  const producerName = "@c11/engine.producer";
  const pathImport = importDeclaration(
    [importSpecifier(identifier("wildcard"), identifier("wildcard"))],
    stringLiteral(producerName)
  );
  const program = ref.findParent((p) => p.isProgram());
  if (!program) {
    throw new Error("");
  }

  const macroImport = program.get("body").find((p) => {
    const result =
      p.isImportDeclaration() &&
      p.node.source.value.indexOf("@c11/engine.macro") !== -1;
    return result;
  });

  if (macroImport) {
    // @ts-ignore
    macroImport.insertAfter(pathImport);
  }
}
Example #19
Source File: get-sorted-nodes.spec.ts    From prettier-plugin-sort-imports with Apache License 2.0 6 votes vote down vote up
test('it returns all sorted nodes with custom third party modules', () => {
    const result = getImportNodes(code);
    const sorted = getSortedNodes(result, {
        importOrder: ['^a$', '<THIRD_PARTY_MODULES>', '^t$', '^k$'],
        importOrderSeparation: false,
        importOrderCaseInsensitive: true,
        importOrderGroupNamespaceSpecifiers: false,
        importOrderSortSpecifiers: false,
    }) as ImportDeclaration[];
    expect(getSortedNodesNames(sorted)).toEqual([
        'a',
        'Ba',
        'BY',
        'c',
        'g',
        'x',
        'Xa',
        'XY',
        'z',
        't',
        'k',
    ]);
});
Example #20
Source File: get-sorted-nodes-names.ts    From prettier-plugin-sort-imports with Apache License 2.0 5 votes vote down vote up
getSortedNodesNames = (imports: ImportDeclaration[]) =>
    imports
        .filter((i) => i.type === 'ImportDeclaration')
        .map((i) => i.source.value)
Example #21
Source File: get-sorted-nodes.spec.ts    From prettier-plugin-sort-imports with Apache License 2.0 5 votes vote down vote up
test('it returns all sorted nodes case-insensitive', () => {
    const result = getImportNodes(code);
    const sorted = getSortedNodes(result, {
        importOrder: [],
        importOrderCaseInsensitive: true,
        importOrderSeparation: false,
        importOrderGroupNamespaceSpecifiers: false,
        importOrderSortSpecifiers: false,
    }) as ImportDeclaration[];

    expect(getSortedNodesNames(sorted)).toEqual([
        'a',
        'Ba',
        'BY',
        'c',
        'g',
        'k',
        't',
        'x',
        'Xa',
        'XY',
        'z',
    ]);
    expect(
        sorted
            .filter((node) => node.type === 'ImportDeclaration')
            .map((importDeclaration) =>
                getSortedNodesModulesNames(importDeclaration.specifiers),
            ),
    ).toEqual([
        ['a'],
        ['Ba'],
        ['BY'],
        ['c', 'cD'],
        ['g'],
        ['k', 'kE', 'kB'],
        ['tC', 'tA', 'tB'],
        ['x'],
        ['Xa'],
        ['XY'],
        ['z'],
    ]);
});
Example #22
Source File: prepareForEngine.ts    From engine with MIT License 5 votes vote down vote up
prepareForEngine: PrepareForEngine = (babel, state, ref, type) => {
  const validation = validateRef(ref);
  if (validation.error) {
    throw new Error(validation.errorMessage);
  }

  const config = getConfig(state);

  const op = parseRef(babel, state, ref);
  const props = structOperationCompiler(op);
  const parent = ref.findParent((p) => p.isVariableDeclarator());
  if (!parent) {
    throw new Error(
      "Misuse of the view/producer keyword. It needs to be a variable declaration e.g. let foo: view = ..."
    );
  }
  const node = parent.node as VariableDeclarator;
  const fn = node.init as ArrowFunctionExpression;

  fn.params = paramsCompiler(op);
  const result = objectExpression([
    objectProperty(identifier("props"), props),
    objectProperty(identifier("fn"), fn),
  ]);

  if (type === TransformType.PRODUCER) {
    node.init = result;
  } else if (type === TransformType.VIEW) {
    const viewCall = callExpression(identifier("view"), [result]);
    node.init = viewCall;
    const viewImport = config.view.importFrom;
    const program = ref.findParent((p) => p.isProgram());
    if (!program) {
      throw new Error("Internal error. Cannot find program node");
    }
    const macroImport = program.get("body").find((p) => {
      const result =
        p.isImportDeclaration() &&
        p.node.source.value.indexOf("@c11/engine.macro") !== -1;
      return result;
    });

    const engineImport = program.get("body").find((p) => {
      const result =
        p.isImportDeclaration() &&
        p.node.source.value.indexOf(viewImport) !== -1;
      return result;
    });

    if (macroImport) {
      if (!engineImport) {
        const importView = importDeclaration(
          [importSpecifier(identifier("view"), identifier("view"))],
          stringLiteral(viewImport)
        );
        // @ts-ignore
        macroImport.insertAfter(importView);
      } else {
        const node = engineImport.node as ImportDeclaration;
        const viewNode = node.specifiers.find((node) => {
          return (
            isImportSpecifier(node) &&
            isIdentifier(node.imported) &&
            node.imported.name === "view"
          );
        });
        if (!viewNode) {
          node.specifiers.push(
            importSpecifier(identifier("view"), identifier("view"))
          );
        }
      }
    } else {
      throw new Error("Could not find macro import");
    }
  }
}
Example #23
Source File: get-sorted-nodes.spec.ts    From prettier-plugin-sort-imports with Apache License 2.0 5 votes vote down vote up
test('it returns all sorted import nodes with sorted import specifiers with case-insensitive ', () => {
    const result = getImportNodes(code);
    const sorted = getSortedNodes(result, {
        importOrder: ['^a$', '^t$', '^k$', '^B'],
        importOrderCaseInsensitive: true,
        importOrderSeparation: false,
        importOrderGroupNamespaceSpecifiers: false,
        importOrderSortSpecifiers: true,
    }) as ImportDeclaration[];
    expect(getSortedNodesNames(sorted)).toEqual([
        'c',
        'g',
        'x',
        'Xa',
        'XY',
        'z',
        'a',
        't',
        'k',
        'Ba',
        'BY',
    ]);
    expect(
        sorted
            .filter((node) => node.type === 'ImportDeclaration')
            .map((importDeclaration) =>
                getSortedNodesModulesNames(importDeclaration.specifiers),
            ),
    ).toEqual([
        ['c', 'cD'],
        ['g'],
        ['x'],
        ['Xa'],
        ['XY'],
        ['z'],
        ['a'],
        ['tA', 'tB', 'tC'],
        ['k', 'kB', 'kE'],
        ['Ba'],
        ['BY'],
    ]);
});
Example #24
Source File: get-sorted-nodes.spec.ts    From prettier-plugin-sort-imports with Apache License 2.0 5 votes vote down vote up
test('it returns all sorted import nodes with sorted import specifiers', () => {
    const result = getImportNodes(code);
    const sorted = getSortedNodes(result, {
        importOrder: ['^a$', '^t$', '^k$', '^B'],
        importOrderCaseInsensitive: false,
        importOrderSeparation: false,
        importOrderGroupNamespaceSpecifiers: false,
        importOrderSortSpecifiers: true,
    }) as ImportDeclaration[];
    expect(getSortedNodesNames(sorted)).toEqual([
        'XY',
        'Xa',
        'c',
        'g',
        'x',
        'z',
        'a',
        't',
        'k',
        'BY',
        'Ba',
    ]);
    expect(
        sorted
            .filter((node) => node.type === 'ImportDeclaration')
            .map((importDeclaration) =>
                getSortedNodesModulesNames(importDeclaration.specifiers),
            ),
    ).toEqual([
        ['XY'],
        ['Xa'],
        ['c', 'cD'],
        ['g'],
        ['x'],
        ['z'],
        ['a'],
        ['tA', 'tB', 'tC'],
        ['k', 'kB', 'kE'],
        ['BY'],
        ['Ba'],
    ]);
});
Example #25
Source File: get-sorted-nodes.spec.ts    From prettier-plugin-sort-imports with Apache License 2.0 5 votes vote down vote up
test('it returns all sorted nodes with sort order case-insensitive', () => {
    const result = getImportNodes(code);
    const sorted = getSortedNodes(result, {
        importOrder: ['^a$', '^t$', '^k$', '^B'],
        importOrderCaseInsensitive: true,
        importOrderSeparation: false,
        importOrderGroupNamespaceSpecifiers: false,
        importOrderSortSpecifiers: false,
    }) as ImportDeclaration[];
    expect(getSortedNodesNames(sorted)).toEqual([
        'c',
        'g',
        'x',
        'Xa',
        'XY',
        'z',
        'a',
        't',
        'k',
        'Ba',
        'BY',
    ]);
    expect(
        sorted
            .filter((node) => node.type === 'ImportDeclaration')
            .map((importDeclaration) =>
                getSortedNodesModulesNames(importDeclaration.specifiers),
            ),
    ).toEqual([
        ['c', 'cD'],
        ['g'],
        ['x'],
        ['Xa'],
        ['XY'],
        ['z'],
        ['a'],
        ['tC', 'tA', 'tB'],
        ['k', 'kE', 'kB'],
        ['Ba'],
        ['BY'],
    ]);
});
Example #26
Source File: get-sorted-nodes.spec.ts    From prettier-plugin-sort-imports with Apache License 2.0 5 votes vote down vote up
test('it returns all sorted nodes with sort order', () => {
    const result = getImportNodes(code);
    const sorted = getSortedNodes(result, {
        importOrder: ['^a$', '^t$', '^k$', '^B'],
        importOrderCaseInsensitive: false,
        importOrderSeparation: false,
        importOrderGroupNamespaceSpecifiers: false,
        importOrderSortSpecifiers: false,
    }) as ImportDeclaration[];

    expect(getSortedNodesNames(sorted)).toEqual([
        'XY',
        'Xa',
        'c',
        'g',
        'x',
        'z',
        'a',
        't',
        'k',
        'BY',
        'Ba',
    ]);
    expect(
        sorted
            .filter((node) => node.type === 'ImportDeclaration')
            .map((importDeclaration) =>
                getSortedNodesModulesNames(importDeclaration.specifiers),
            ),
    ).toEqual([
        ['XY'],
        ['Xa'],
        ['c', 'cD'],
        ['g'],
        ['x'],
        ['z'],
        ['a'],
        ['tC', 'tA', 'tB'],
        ['k', 'kE', 'kB'],
        ['BY'],
        ['Ba'],
    ]);
});
Example #27
Source File: get-sorted-nodes.spec.ts    From prettier-plugin-sort-imports with Apache License 2.0 5 votes vote down vote up
test('it returns all sorted nodes', () => {
    const result = getImportNodes(code);
    const sorted = getSortedNodes(result, {
        importOrder: [],
        importOrderCaseInsensitive: false,
        importOrderSeparation: false,
        importOrderGroupNamespaceSpecifiers: false,
        importOrderSortSpecifiers: false,
    }) as ImportDeclaration[];

    expect(getSortedNodesNames(sorted)).toEqual([
        'BY',
        'Ba',
        'XY',
        'Xa',
        'a',
        'c',
        'g',
        'k',
        't',
        'x',
        'z',
    ]);
    expect(
        sorted
            .filter((node) => node.type === 'ImportDeclaration')
            .map((importDeclaration) =>
                getSortedNodesModulesNames(importDeclaration.specifiers),
            ),
    ).toEqual([
        ['BY'],
        ['Ba'],
        ['XY'],
        ['Xa'],
        ['a'],
        ['c', 'cD'],
        ['g'],
        ['k', 'kE', 'kB'],
        ['tC', 'tA', 'tB'],
        ['x'],
        ['z'],
    ]);
});
Example #28
Source File: preprocessor.ts    From prettier-plugin-sort-imports with Apache License 2.0 5 votes vote down vote up
export function preprocessor(code: string, options: PrettierOptions) {
    const {
        importOrderParserPlugins,
        importOrder,
        importOrderCaseInsensitive,
        importOrderSeparation,
        importOrderGroupNamespaceSpecifiers,
        importOrderSortSpecifiers,
    } = options;

    const importNodes: ImportDeclaration[] = [];
    const parserOptions: ParserOptions = {
        sourceType: 'module',
        plugins: getExperimentalParserPlugins(importOrderParserPlugins),
    };

    const ast = babelParser(code, parserOptions);
    const interpreter = ast.program.interpreter;

    traverse(ast, {
        ImportDeclaration(path: NodePath<ImportDeclaration>) {
            const tsModuleParent = path.findParent((p) =>
                isTSModuleDeclaration(p),
            );
            if (!tsModuleParent) {
                importNodes.push(path.node);
            }
        },
    });

    // short-circuit if there are no import declaration
    if (importNodes.length === 0) return code;

    const allImports = getSortedNodes(importNodes, {
        importOrder,
        importOrderCaseInsensitive,
        importOrderSeparation,
        importOrderGroupNamespaceSpecifiers,
        importOrderSortSpecifiers,
    });

    return getCodeFromAst(allImports, code, interpreter);
}
Example #29
Source File: index.ts    From plasmic with MIT License 5 votes vote down vote up
mergeImports = (
  editedImport: ImportDeclaration,
  newImport: ImportDeclaration
) => {
  if (
    editedImport.specifiers.find((s) => s.type === "ImportNamespaceSpecifier")
  ) {
    return cloneDeep(editedImport);
  }
  if (newImport.specifiers.find((s) => s.type === "ImportNamespaceSpecifier")) {
    return cloneDeep(newImport);
  }
  const cloned = cloneDeep(editedImport);
  for (const s2 of newImport.specifiers) {
    if (s2.type === "ImportDefaultSpecifier") {
      if (
        editedImport.specifiers.find(
          (s1) =>
            s1.type === "ImportDefaultSpecifier" &&
            s1.local.name === s2.local.name
        )
      ) {
        continue;
      }
      cloned.specifiers.push(s2);
    } else if (s2.type === "ImportSpecifier") {
      if (
        editedImport.specifiers.find(
          (s1) =>
            s1.type === "ImportSpecifier" &&
            s1.local.name === s2.local.name &&
            importedName(s1) === importedName(s2)
        )
      ) {
        continue;
      }
      cloned.specifiers.push(s2);
    } else {
      assert(s2.type === "ImportNamespaceSpecifier");
      // Plasmic doesn't generate namespace import statement.
      cloned.specifiers.push(s2);
    }
  }
  return cloned;
}