astring icon indicating copy to clipboard operation
astring copied to clipboard

Control of semicolon behaviour

Open eddiesholl opened this issue 8 years ago • 5 comments

Motivation

I'm using astring as part of an atom plugin to help with code generation. It would be great to be able to control whether semicolons are emitted, so that I can match the current style directives of the current project. Right now, semicolons are implemented as a whole bunch of state.write(';') instances.

It would be awesome to have a config option to control semicolon emission. I'm thinking that you could replace all those writes with a semantic state.terminate(), which can check if it should print a semicolon or not.

The only alternative to control this is to basically fork the entire baseGenerator, so you can remove all those writes.

eddiesholl avatar Jun 19 '17 11:06 eddiesholl

This could be handled through a custom output stream, that removes semicolons:

const output = {
  code: '',
  write(code) {
    switch (code) {
      case ';':
        break
      case ');':
        this.code += ')'
        break
      case 'debugger;':
        this.code += 'debugger'
        break
      default:
        this.code += code
        break
    }
  },
}

const { code } = astring.generate(ast, { output })

console.log('Code without semicolons:', code)

There are however two known issues to this:

  1. Not all semicolons can be removed, in particular, when the next expression starts with a parenthesis.
  2. Using a custom output stream has some performance hits.

Thus, a more precise handling is required. This could be a first step towards version 2. Pull requests are welcome.

davidbonnet avatar Jun 23 '17 21:06 davidbonnet

+1 ! I was just about to go for "The only alternative to control this" according to @eddiesholl before checking the issues here.

I will submit a PR right after

Mouradif avatar Jul 04 '19 15:07 Mouradif

I looked at this issue and it isn't super hard to implement. For example use an extra function param on statement level. noSemi.

Then in BlockStatement and Program within the iteration loop set the param value to either true or false. Depends if the element is the last one in that array.

Before looping you always set the value to false.

Then you can print semi only if noSemi is falsy.

Don't forget the IfStatement edge case!

Regarding parents. For example as in this example this will be smashed into one, but still valid JS.

{
 (Foo)
Bar
} `

KFlash avatar Sep 22 '20 20:09 KFlash

Quick follow up. If you want an option to enable the semis it's possible if you avoid printing the semicolon if .!Opt.Semi || noSemi.

Also be aware that noSemi has to be falsy before entering any blocks.

KFlash avatar Sep 24 '20 20:09 KFlash

@KFlash did you check my PR above ?

Mouradif avatar Oct 01 '20 07:10 Mouradif