JavaScriptに色を付けるの3

昨日の続き。 今日はSafari以外でも動くようにする。

動かない要因は各ブラウザではっきりしているので、それを取り除くだけの簡単な作業なのだが、基本的に長ったらしい記述になるのが面倒なんだよな。 ちょっと前まではなんとも思わずに書いてたものが、ちょっと楽を覚えたらもう戻れない。 まあ、システム屋としては正しい姿なんだけどさ。

なんて言いながら、やるのは手動トランスパイル。 システム屋としてはあまり宜しくない姿なのだが、現時点では正規表現のsフラグに対応しているトランスパイラがなさそうなのでしょうがない。 以下、実際にやったこと。

s flag

正規表現で任意の1文字を示す . に改行も含めるのがsフラグ。 これをやめて、改行を含めるつもりで書いているパターン中の . を、改行含む空白文字と空白じゃない文字のセット [\s\S] に置き換えた。

置き換える場所の特定が地味に面倒な作業だが、これをやることで Chrome と FireFox と Edge で動くようになった。 この時点でデスクトップ用ブラウザのカバー率およそ90%。

arrow function

アロー表記していた関数を function と書く形式に置き換えた。

ほぼ定型作業なのだが、高確率で return を書き忘れて、テストする度に undefined が顔を出す始末。 この書き忘れは、多分俺の認識のせい。 アロー表記の関数を、俺は 「何かを受け取って何かを返す処理」 ではなく 「何かを何かに変換する規則」 と考えて書いているように思う。

しかし、アロー表記だと色々省略できて書くのが楽なのだが、省略できない形式の方が読むのは楽かもしれないな。

template literal

テンプレートを分解して、文字列結合に置き換えた。

変更したのは一箇所だが、感覚的にはこれが一番面倒だった。 テンプレートの便利さを思い知らされた。 きっともう戻れない。

class

昔ながらの function がコンストラクタを兼ねる形式に書き換えた。

クラスを使ったのは、表に出なくても良いものをまとめる器として。 この用途なら、従来の関数オブジェクト方式でも、記述量の面でも使いやすさの面でも大差ないだろうと思ったら正解だった。 精神的にもノーダメージ。

default parameter

現時点のJavaScriptで効果があるとは思えないが、やっぱり末尾再帰の方が良いような気がして、所謂アキュムレーターを置いていた。 このアキュムレーターが指定されない場合、というのは外部からの呼び出しの場合なのだが、空の文字列となるようにデフォルト引数を指定していた。

これを、外向きのインターフェースと内部処理とを分けるように変更した。 内部処理でアキュムレーターを使うのはそのままだが、初回呼び出し時にも明示的に引数で空の文字列を指定するようにした。

値が設定されていなければ、つまり undefined だったら空の文字列にするというコードを書いても良いのだが、再帰呼び出しの度に初回呼び出しでしか意味がない処理を書くのもどうかと思って。 いや、デフォルト引数がやってるのはそういうことなのだが、言語側がやってくれのと自前で書くのとでは、気分が違うというか、ねえ。

使っていたのは一箇所だけ、しかも 「=""」 というたった3文字だったのだが、このための変更は大きかった。

ここまで来てようやく IE11 でも動くようになった。

const jsDefs = [ [ /^([\s\S]*?)(\/\*[\s\S]*?\*\/)([\s\S]*)$/ , "comment" ], [ /^([\s\S]*?)(\/\/.*?)(\n[\s\S]*)$/ , "comment" ], [ /^([^"]*?)("(?:\\[\s\S]|[^"\\])*")([\s\S]*)$/ , "string" ], [ /^([^']*?)('(?:\\[\s\S]|[^'\\])*')([\s\S]*)$/ , "string" ], [ /^([^`]*?)(`(?:\\[\s\S]|[^`\\])*`)([\s\S]*)$/ , "string" ], [ /^([^\/]*?)(\/[^\/\*](?:\\.|[^\/\\])*\/)([\s\S]*)$/ , "regexp" ], [ /^([\s\S]*?)\b(break)\b([\s\S]*)$/ , "keyword" ], [ /^([\s\S]*?)\b(case|catch|class|const|continue)\b([\s\S]*)$/ , "keyword" ], [ /^([\s\S]*?)\b(debugger|default|delete|do)\b([\s\S]*)$/ , "keyword" ], [ /^([\s\S]*?)\b(else|enum|export|extends)\b([\s\S]*)$/ , "keyword" ], [ /^([\s\S]*?)\b(finally|for|function)\b([\s\S]*)$/ , "keyword" ], [ /^([\s\S]*?)\b(if|import|in|instanceof)\b([\s\S]*)$/ , "keyword" ], [ /^([\s\S]*?)\b(let)\b([\s\S]*)$/ , "keyword" ], [ /^([\s\S]*?)\b(new)\b([\s\S]*)$/ , "keyword" ], [ /^([\s\S]*?)\b(return)\b([\s\S]*)$/ , "keyword" ], [ /^([\s\S]*?)\b(super|switch)\b([\s\S]*)$/ , "keyword" ], [ /^([\s\S]*?)\b(this|throw|try|typeof)\b([\s\S]*)$/ , "keyword" ], [ /^([\s\S]*?)\b(var|void)\b([\s\S]*)$/ , "keyword" ], [ /^([\s\S]*?)\b(while|with)\b([\s\S]*)$/ , "keyword" ], [ /^([\s\S]*?)\b(yield)\b([\s\S]*)$/ , "keyword" ], [ /^([\s\S]*?)\b(false|null|true|undefined)\b([\s\S]*)$/ , "keyvalue" ], ]; function Parser( defs ) { const finders = defs.map( function ( d ) { return function ( text ) { const matched = text.match( d[0] ); return matched ? { pre : matched[1], got : "<span class='" + d[1] + "'>" + matched[2] + "</span>", pst : matched[3] } : { pre : text, got : "", pst : "" } } } ); function findFirst( text ) { return this.finders .map( function ( f ) { return f( text ); } ) .reduce( function ( r0, r1 ) { return r0.pre.length < r1.pre.length ? r0 : r1; } ) } function stepParse( text, acc ) { const r = findFirst( text ); if ( !r.got ) { return acc + r.pre; } return this.parse( r.pst, acc + r.pre + r.got ); } this.parse = function ( text ) { return stepParse( text, "" ); }; } function setColor() { const jsParser = new Parser( jsDefs ); const elm = document.getElementById( "smpl01" ); elm.innerHTML = jsParser.parse( elm.innerHTML ); document.getElementById( "btn01" ).disabled = true; }

上のボタンをクリックすると、上記処理を上記ソースコード表示に適用して色を付ける。 Safari, Chrome, FireFox, Edge, IE11 でいけるはず。

とまあ、なんとか自宅環境にあるブラウザ全てに対応したのだが、したことで一つ決心もできた。

やっぱりIE11は捨てよう。 面倒臭い。

現時点でSafariしか対応していない正規表現のsフラグは、きっと長くても半年待てば、他のブラウザでも対応されるだろう。 だがIE11に先の展望は無い。 sフラグ以外の要素についても、規格の発表からもう数年経つのに未だサポートされないまま。 提供元のMicrosoftがもう捨ててくれと言ってるのだから、セキュリティ対策以外で、新たに機能が追加されることはないだろう。 そもそもの話、IE11の実行環境であるWindows7のサポートがとっくに終了しているはずだったのだし。

ということで上のは捨てて、昨日のをベースに、並んだ割り算と正規表現リテラルを区別することを考える。 続きは明日。