前の関連記事:linuxBean14.04(111)SyntaxHighlighter3.0.9をビルドする:成功編
SyntaxHighlighter3.0.93.0.83のshBrushXml.jsを使うhtmlファイルの作成
linuxBean14.04(111)SyntaxHighlighter3.0.9をビルドする:成功編でビルドしてできたpkgフォルダにある例でデバッグします。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>SyntaxHighlighter test</title> <script type="text/javascript" src="scripts/shCore.js"></script> <script type="text/javascript" src="scripts/shBrushXml.js"></script> <link type="text/css" rel="stylesheet" href="styles/shCoreEmacs.css"> <script type="text/javascript">SyntaxHighlighter.all();</script> <style type="text/css"> body { background: white; font-family: helvetica; } </style> </head> <body> <h1>SyntaxHighlighter test</h1> <pre class="brush: xml;"> <h4>3.08のブラシが動かない原因を探す</h4></pre> </html>pkgフォルダに3.0.9用のテストページindex9.htmlを作成しました。
7行目で3.0.9のshBrushXml.jsのブラシを指定してpreタグでそれを使っています。
今度はReleases · alexgorbatchev/syntaxhighlighterから3.0.83のソースをダウンロードしてそこからshBrushXml.jsを取り出してshBrushXml8.jsに改名してpkgフォルダ以下のscriptsfフォルダに移動させます。
index9.htmlをコピーしてindex8.htmlに改名して7行目でshBrushXml8.jsを指定するように変更しました。
今度はXmlのブラシが利いていません。
Chromiumでスタックトレースを表示させる
index8.htmlをChromiumで開いて右クリニック→検証。
エラーメッセージの右にでているエラー発生箇所をクリックすると、Console画面からSources画面に切替わってエラー箇所のshCore.jsが表示されます。
このvalueにlengthというプロパティが存在しなくてエラーになっているようです。
で、このvalueがどこ由来なのか調べないといけません。
Chromiumでindex8.htmlをリロードします。
今度はエラー表示の行頭にj黒三角形がでてくるのでそれをクリックするとエラーに至るまでの関数の呼び出し元がわかるスタックトレースが表示されます。
自分で書いたコードならこれだけでどこに問題点があるのかわかりそうですが、私はJavaScriptにはまだ不慣れなのでまずChromiumのデバッガを使ってエラーに至るまでの流れを把握しようと思います。
スタックトーレスを参考にブレークポイントを設定する
この章は原因追求とはあまり関係なくChromiumのデバッガの使い方メモになっています。
取りあえず流れを把握するために最初呼び出し部分のshCore.jsの1897行目にブレークポイントを設定しました。
ブレークポイントは行番号をクリックするだけで設定できます。
あとはChromiumでページをリロードします。
飛んだ先の1637行目には次のsh.highlightがあるので再度Step intoボタンをクリックします。
今度はsh.highlightの中である1569行目に飛ぶので次に飛ぶsh.Highlighter.getDivが出てくる1618行目までStep overボタンを使います。
sh.Highlighter.getDivがでてきたらStep intoして2924行目までまたStep over、といった調子で進んでいくとエラー箇所までたどり着けます。
途中ループがあって面倒なときはループを超えたところで右クリック→Continue to Here、とするとループがすっとばせますが、2595行目のgetMatchesはループ内にあるのでそういうわけにもいきません。
とりあえずfor文の前の2591行目にブレークポイントを設定してループを回してみるとiが2のときにエラーが発生することがわかりました。
エラーが起こる場合にだけgetMatchesにStep intoしたいので条件付きブレークポイントを設定します。
2595行目の行番号で右クリック→Add conditional breakpoint。
条件入力窓が出てくるので真になればブレークしたい条件を入力してEnter。
i==2、としました。
普通のブレークポイントを設定した行番号は青地に白抜き文字にですが、条件付きブレークポイントは橙色地に白抜き文字になりました。
デバッガのコントローラの下にあるブレークポイント一覧ではどれが条件付きブレークポイントかは区別されていませんでした。
これでリロードするとi = 2のときにブレークされていることがわかります。
ブレークした時に行末にでてくる変数の内容は便利なのですが、その行でブレークされた時の変数の状態ではなく、現在ブレークされている行まで到達したときの変数の状態になります。
2290行に飛びました。
2299行までStep overすればよいのですが今度はwhile文の中にあります。
while文の中で条件付きブレークポイントを設定するには条件に頭をひねらないといけませんが今回は1回目のループでエラーがでたので1回目のループでStep intoしました。
ようやくshBrushXml.jss(この場合はshBrushXml8.js)にたどり着きました。
Sources画面のCall Stackをクリックするとブレークしたところまでの呼び出し元がわかります。
SyntaxHighlighter3.0.83のshBrushXml.jsでは名前付きキャプチャが効いていない
syntaxhighlighter-3.0.9/src/jsにあるshCore.jsの構造は以下のようになっています。
if (typeof(SyntaxHighlighter) == 'undefined') var SyntaxHighlighter = function() { 略 var sh = { 略 }; // end of Highlighter return sh; }(); // end of anonymous functionグローバルスコープを侵さなくてよいように無名関数の中のローカル変数shに処理をすべて渡してそれを返してSyntaxHighlighterというグローバル変数に代入しています。
JavaScriptプロトタイプチェーン(6)プロトタイプの継承パターン(Prototypal Inheritance)の関数型継承パターンと同じような手法です。
なのでshCore.jsのローカルスコープのshはグローバルスコープではSyntaxHighlighterになります。
var constructor = SyntaxHighlighter.Match,ということで、shBrushXml.jsの10行目のSyntaxHighlighter.Matchはつまりsh.Matchであり、shBrushXml.jsではそれがconstructorになります。
これの第一引数のプロパティにlengthプロパティがなくてエラーになっていることは一番最初に確認済みです。
33行目にはブレークポイントを設定できないので32行目にブレークポイントを設定しています。
ここからStep overするとエラーが出て終了します。
Step intoするとshCore.jsの2448行目に飛びます。
そこから2450行目までStep overするとエラーがでて終了します。
constructorの第一引数をみるとundefinedになっています。
当然lengthプロパティはないわけです。
tagにはちゃんとオブジェクトが入っていますがnameプロパティがありません。
今度はindex9.htmlをChromiumで開いてshBrushXml.jss(この場合はshBrushXml9.js)の同じ部位に該当する50行目でブレイクしてtagの内容を確認してみます。
こちらはちゃんとnameプロパティがあります。
ということでSyntaxHighlighter3.0.83のshBrushXml.jsでは名前付きキャプチャが効いておらず、それがエラーの原因であることがわかりました。
XRegExp 2.0.0以降はRegExpのメソッドを上書きしなくなったのが原因
ソースを読むとSyntaxHighlighter3.0.83はXRegExp 1.5.0、SyntaxHighlighter3.0.9はXRegExp 2.0.0を使っていることがわかります。
変数tagを取得しているところを比較してみます。
shBrushXml8.js
tag = new XRegExp('(<|<)[\\s\\/\\?]*(?<name>[:\\w-\\.]+)', 'xg').exec(code),shBrushXml9.js
tag = XRegExp.exec(code, XRegExp('(<|<)[\\s\\/\\?!]*(?<name>[:\\w-\\.]+)', 'xg')),正規表現パターンも少し変わっていますが、これは今回のエラーの原因ではありませんでした。
大きく変わっているのはexecメソッドの使い方です。
shBrushXml8.jsではXRegExpをコンストラクタ関数として正規表現オブジェクトを生成し、そのオブジェクトのexec()メソッドでcodeを検索しています。
XRegExp(pattern, [flags])では標準ビルトインオブジェクトのRegExpを拡張した正規表現パターンとフラグを使えますが、返ってくる正規表現オブジェクトはRegExpが返すオブジェクトと同じものです。
なのでそのexec()メソッドはRegExp.prototype.exec()になるので名前付きキャプチャができません。
Version history :: XRegExpを読むとXRegExp 2.0.0以前はXRegExpが正規表現オブジェクトを返すときはRegExp.prototype.exec()をXRegExpのexec()メソッドで上書きしていたようです。
SyntaxHighlighter3.0.83はXRegExp 1.5.0なのでshBrushXml8.jsの書き方でも名前付きキャプチャができたわけですが、SyntaxHighlighter3.0.9ではXRegExp 2.0.0になっているのでRegExp.prototype.exec()が実行されて名前付きキャプチャができないわけです。
変数tagを取得している行でStep intoしていくと実際に確認できます。
shBrushXml9.jsではXRegExp.exec()メソッドを使って名前付きキャプチャしています。
SyntaxHighlighter3.0.9で使うために変更が必要なSyntaxHighlighter3.0.83のブラシ
SyntaxHighlighter3.0.83のブラシファイルを「new XRegExp(」で検索してみるとshBrushXml.jsだけしかひっかからなかったので、SyntaxHighlighter3.0.9で使えない付属のブラシはshBrushXml.jsだけのようです。
このブログで使っている[SyntaxHighlighter] jQuery用Brush (jQuery 1.9対応版) - ログろいども[SyntaxHighlighter] Windowsバッチファイル用Brush - ログろいどもXRegExpは使っていないのでSyntaxHighlighter3.0.9でも問題なく動くと思います。
参考にしたサイト
Releases · alexgorbatchev/syntaxhighlighter
SyntaxHighlighter3.0.83のソースのダウンロード元。
JavaScript Regex :: XRegExp
SyntaxHighlighterで使われている正規表現拡張ライブラリ。
API :: XRegExp
XRegExpのAPIリファンレス。
RegExp - JavaScript | MDN
JavaScriptの標準ビルトインオブジェクトRegExp。
[SyntaxHighlighter] jQuery用Brush (jQuery 1.9対応版) - ログろいど
jQuery 1.9用のブラシファイル。
[SyntaxHighlighter] Windowsバッチファイル用Brush - ログろいど
batファイル用のブラシファイル。
0 件のコメント:
コメントを投稿