0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Generator が生成するコードの不自然な位置のコメントの比較 JavaScript AST API

Last updated at Posted at 2022-04-17
  • ジェネレーターは、関数の引数の中間などのコメントを移動させることがある
  • ジェネレーターによっては、不自然な位置のコメントを失うことがある
  • ジェネレーターは、互換性のあるパーサーを使用する必要がある

使用する JavaScript コード

すべての単語の間にコメントを入れている。
最初の //a は、テストコードが動作しているかを確かめるため。

コメントあり

//a
/*b*/function/*c*/fn/*d*/(/*e*/x/*f*/,/*g*/y/*h*/)/*i*/{/*j*/}/*k*/

コメントなし


function fn(x,y){}

ジェネレーターが生成したコード

acorn 8.7.0 + astravel 0.6.1 + astring 1.8.1

ソース:

let acorn = require("acorn");
const { attachComments } = require('astravel')
const astring = require('astring')

const code = `//a\n/*b*/function/*c*/fn/*d*/(/*e*/x/*f*/,/*g*/y/*h*/)/*i*/{/*j*/}/*k*/`

const comments = []

var ast = acorn.parse(code, {
  ecmaVersion: 2020,
  onComment: comments,
})

attachComments(ast, comments)

var formattedCode =
  astring.generate(ast, {
    comments: true,
  })

console.log(formattedCode)

出力:

// a
/*b*/
function fn(x, y) {
  /*c*/
  /*d*/
  /*e*/
  /*f*/
  /*g*/
  /*h*/
  /*i*/
  /*j*/
}
/*k*/

meriyah 4.2.1 + astravel 0.6.1 + astring 1.8.1

ソース:

const { parse } = require('meriyah')
const { attachComments } = require('astravel')
const astring = require('astring')

const code = `//a\n/*b*/function/*c*/fn/*d*/(/*e*/x/*f*/,/*g*/y/*h*/)/*i*/{/*j*/}/*k*/`
const comments = []

ast = parse(code, {
  ranges: true,
  onComment: comments,
})

attachComments(ast, comments)

var formattedCode =
  astring.generate(ast, {
    comments: true,
  })

console.log(formattedCode)

出力:

// a
/*b*/
function fn(x, y) {
  /*c*/
  /*d*/
  /*e*/
  /*f*/
  /*g*/
  /*h*/
  /*i*/
  /*j*/
}
/*k*/

esprima 4.0.1 + escodegen 2.0.0

astravel で生成したコメントは、
escodegen で使用されないため、
esprima をパーサーに使用した。

一部のコメントが生成されなかった。

ソース:

var esprima = require('esprima')
const es = require('escodegen')

const code = `//a\n/*b*/function/*c*/fn/*d*/(/*e*/x/*f*/,/*g*/y/*h*/)/*i*/{/*j*/}/*k*/`

let ast = esprima.parse(code, {range: true, tokens: true, comment: true})
ast = es.attachComments(ast, ast.comments, ast.tokens)

var formattedCode =
  es.generate(ast, {
    comment: true,
  })

console.log(formattedCode)

出力:

//a
/*b*/
function fn(x, y)
    /*i*/
    {
    }    /*k*/

esprima 4.0.1 + escodegen 2.0.0 + @babel/generator 7.17.9

Meriyah + astravel で生成したASTでは、
@babel/generator でコメントが生成されないため、
esprima をパーサーに使用した。

esprima のコメントは @babel/generator では使用されないため、
escodegen を使ってコメントを抽出する。

@babel/generator で生成することで、
escodegen でもコメントを生成することができた。
ただし、jだけ出力されていない。

ソース:

var esprima = require('esprima')
const es = require('escodegen')
const generate = require('@babel/generator').default

const code = `//a\n/*b*/function/*c*/fn/*d*/(/*e*/x/*f*/,/*g*/y/*h*/)/*i*/{/*j*/}/*k*/`

let ast = esprima.parse(code, { range: true, tokens: true, comment: true })
ast = es.attachComments(ast, ast.comments, ast.tokens)

ast = { type: 'File', sourceType: 'script', program: ast }

var formattedCode =
  generate(ast).code

console.log(formattedCode)

出力:

//a
//b

function //c
fn //d
( //e
x //f
, //g
y //h
) //i
{} //k

uglify-js 3.15.4

元のコードに近いが、iが出力されていない。
ただし、コメントが失われる場合がある。
その場合は、オプションに compress: { unused: false } を追加すると保存される。

引数の変数名が変わらないよう、 mangle: false をオプションに追加している。

ソース:

var UglifyJS = require('uglify-js')

const code = `//a\n/*b*/function/*c*/fn/*d*/(/*e*/x/*f*/,/*g*/y/*h*/)/*i*/{/*j*/}/*k*/`

var formattedCode =
  UglifyJS.minify(code, {
    mangle: false,
    output: {
      comments: true
    },
  }).code

console.log(formattedCode)

出力:

//a
/*b*/function/*c*/fn/*d*/(/*e*/x/*f*/,/*g*/y/*h*/){/*j*/}/*k*/

terser 5.12.1

terser は uglify-es のフォーク。
結果は uglify-js と同様。

ソース:

const { minify } = require('terser')

const code = `//a\n/*b*/function/*c*/fn/*d*/(/*e*/x/*f*/,/*g*/y/*h*/)/*i*/{/*j*/}/*k*/`

async function asyncCall() {
  var result = await minify(code, {
    mangle: false,
    output: {
      comments: true
    },
  });
  console.log(result.code);
}

asyncCall();

出力:

//a
/*b*/function/*c*/fn/*d*/(/*e*/x/*f*/,/*g*/y/*h*/){/*j*/}/*k*/

prettier 2.6.2

全然きれいじゃない(コードのせい)。

ソース:

const prettier = require("prettier")

const code = `//a\n/*b*/function/*c*/fn/*d*/(/*e*/x/*f*/,/*g*/y/*h*/)/*i*/{/*j*/}/*k*/`

var formattedCode =
  prettier.format(code, { parser: "babel" })

console.log(formattedCode)

出力:

//a
/*b*/ function /*c*/ fn /*d*/(/*e*/ x /*f*/, /*g*/ y /*h*/) /*i*/ {
  /*j*/
} /*k*/

sucrase 3.21.0

コード:

const {transform} = require('sucrase')

const code = `//a\n/*b*/function/*c*/fn/*d*/(/*e*/x/*f*/,/*g*/y/*h*/)/*i*/{/*j*/}/*k*/`

var formattedCode =
  transform(code, {transforms: ["typescript", "imports"]}).code

console.log(formattedCode)

出力:

"use strict";//a
/*b*/function/*c*/fn/*d*/(/*e*/x/*f*/,/*g*/y/*h*/)/*i*/{/*j*/}/*k*/
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?