晴耕雨読

working in the fields on fine days and reading books on rainy days

JSでヒアドキュメントのインデントを取り除く方法

JavaScriptでインデントがある状態でヒアドキュメント(テンプレートリテラルによる文字列)を作成すると、 インデントもヒアドキュメントの一部になってしまうので、それを取り除くする方法。

解決方法

次のようなインデントを取り除く関数 dedent を定義します。dedent は de-indent の略です。 ヘルパーメソッドとして、Array#min と Array#flatten を定義しています。

Array.prototype.min = function() {
  return Math.min.apply(null, this);
};

Array.prototype.flatten = function() {
  return Array.prototype.concat.apply([], this);
};

function dedent(str) {
  function scan(str, regex) {
    if (!regex.global) throw "regex must have 'global' flag set";
    var m, result = [];
    while (m = regex.exec(str)) {
      m.shift();
      result.push(m);
    }
    return result;
  }

  str = str.trim();
  var margin = scan(str, /^( +)/gm)
    .flatten()
    .map(line => line.length)
    .min();

  var result = str
    .replace(new RegExp(`^ {${margin}}`, 'gm'), '')
    .replace(/^\n/, '');

  return result;
}

使い方

上記の dedent を定義した上で、次のように使います。

class Foo {
  bar() {
    var desc = dedent(`
      Here documents

      To construct a here document, the << operator is followed by an identifier
      that marks the end of the here document. The end mark is called the terminator.
      The lines of text prior to the terminator are joined together, including
      the newlines and any other whitespace.
    `);
    return desc;
  }
}

console.log((new Foo).bar());
// => Here documents
// =>
// => To construct a here document, the << operator is followed by an identifier
// => that marks the end of the here document. The end mark is called the terminator.
// => The lines of text prior to the terminator are joined together, including
// => the newlines and any other whitespace.

感想

Ruby で dedent を書いたときは、便利なメソッドがたくさん使えたので楽でしたが、 JavaScript はいろいろメソッドがないですね… 今後の JavaScript(ECMAScript)に期待したいです。