benjamn / recast

JavaScript syntax tree transformer, nondestructive pretty-printer, and automatic source map generator

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Local identifier from an import specifier is ignored

prantlf opened this issue · comments

When printing a modified AST, after removing one import specifier and inserting another one with different imported and local specifiers, the local identifier is ignored.

Original statement:

import { parse, print } from "fast-nls"

Desired statement:

import { load as $loadMessages$, print } from "fast-nls"

Obtained statement:

import { $loadMessages$, print } from "fast-nls"

The imported identifier load is missing.

Details

Let us remove the parse specifier and insert load as $loadMessages$:

const { parse, print, types } = require('recast')
const { builders: b } = types

let ast = parse('import { parse, print } from "fast-nls"')

let { specifiers } = ast.program.body[0]
specifiers.splice(0, 1)
specifiers.unshift(b.importSpecifier(
  b.identifier('load'), b.identifier('$loadMessages$')))
    
print(ast).code

Result:

import { $loadMessages$, print } from "fast-nls"

The imported identifier load was not included in the printed code.

When omitting the removal of parse:

  let { specifiers } = ast.program.body[0]
- specifiers.splice(0, 1)

The new import specifier becomes complete:

import { load as $loadMessages$, parse, print } from "fast-nls";

It appears, that if the count of import specifiers does not change, the presence of imported and local identifiers is not checked. If original import specifiers did not contain different imported and local identifiers, the newly inserted ones at the position of previous ones will be printed with local identifiers only.

Workaround - force recast to reprint the specifier, although it was newly created:

  specifiers.unshift(b.importSpecifier(
    b.identifier('load'), b.identifier('$loadMessages$')))
+ specifiers[0].original = null

I wonder why it works or what it breaks.