MathJaxをデバッグしてJavaScriptの理解を深める

提供:yonewiki

VScodeで簡易WebServerの元でデバッグに戻る。


概要

 JavaScriptで書かれたMathJaxライブラリは、TeXのような組版処理をサービスを提供しているCDN(Content Delivery Network:コンテンツ配信サービス)あるいは自前のサーバーに配置するかするようにして構築するものです。主に数式の組版をするために提供されているサービスです。


 このような組版処理はいくらやってもらってもいいという感じで、楽譜とかも組版出来たらいいのにと夢みたいなことをおもっていたのですが、一部には実際に楽譜が組めるようになっているサービスもあるようですが、なっとくいかない仕上がりです。納得しろやオマエ。って思うでしょ。そうなんすよ。作れないくせになっとくしてないんすよ。もっとやりたいことは簡単な楽譜処理なんすよ。そういうのはおいといて、数式の組版を実現したMathJaxはスゴイと思います。それで、これを理解したら自分にも役に立つJavaScriptが作れるようになるんじゃないかと思ったりしました。JavaScript初心者ですよ。


 MathJaxに使われている技術を理解してく記事です。そして理解するための工夫や解析によってわかったMathJaxの考え方をここで書いていきます。自分が使ったことのあるのはMathJaxの中の/es5/tex-mml-chtml.jsで、これをちょろっと除くとまぁエグイ。一行目で終わってるプログラム。さすが、一行の長さがエグイ。インデントしてみたら5万行にもわたるプログラムが1行になってる。改行なしのプログラムあるんだなぁ。


 まずは、インデント処理を自動でやってくれるサービスと出会うことから始めました。


いろいろなプログラムを自動整形するサービス

 MathJaxを理解する作業をはじめて、いきなりありがたいサービスにまた出会う。このサービスのプログラムもすごいね。完璧すぎる自動整形インデント処理をしてくれます。そのJavaScriptの自動整形サイトが以下です。


  • Online Javascript Beautifier - BeautifyConverter.com
https://www.beautifyconverter.com/javascript-beautifier.php


 他にもBeautifier Minifier/CSV/Excel/TSV/HTML/JSON/SQL/XML/YAML/Validators/CSS/Gen/Unit/Escape/IMG/PDF/IP/Color/Othersという整形処理ができる。自分で作ったプログラムが画期的である場合にはこのような自動整形処理を他人に任せるのは知的財産の流出の危険があるので、気を付けてください。信頼できるサイトもあるかもしれませんが、自分は知りません。サービス自体はありがたい。Microsoftがこういう機能をVisualStudioCodeにつけていたら楽だったのにな。あるっちゃあるんすよ。Shift+Alt+Fらしい。あまり自動整形されないっす。


 とはいいつつも自動整形が必要なのはここまでヒドイと思ったプログラムだけですけどね。自分でプログラム作成して整形したものが最高に美しい。余計なことをするのがMicrosoftのエディタって感じですけど、Microsoftの考え方と共鳴しながらのコーディングをして、美しさを求めるのが自分流。MathJaxを自動整形して見えてくるものはある。最初の方に関数が連想配列でつめこまれて1000から3000くらいの関数が配列化されている。しかも番号だけで管理している。手ごわい。いみわからん。まったくいみわからん。変数名も1文字が多い。意味わからん。そんなことできるの?ってぐらいスゴイ。なんかそういう風にプログラムを意味わからんくする自動ツールがあるのかもしれん。でも自動整形したら少しましになった。あー、ありましたねminifyとかってサービスこれのことかな。意味のあるプログラム変数名を圧縮してしまう技。こういうのを使ってるのかもしれない。でもソースで配布してるのおかしくね。MathJaxの中の人。ちがうのか。謎のままおいておこう。

 

デバッグ環境を整える

 基本的にはVScodeで簡易WebServerの元でデバッグで記述した方法によってVSCodeでデバッグします。ソースのダウンロードにはGitコマンドっていうのを使いたくて、Git for Windowsみたいなのをインストールしました。Gitのインストーラーがややこしい。Ver2.38.1ですが、CommandPromptでGitコマンドが使えりゃいいかなと思ったりするだけなんですけど、ややこしい。基本デフォルト設定でインストールするだけかなと思ったんですけどところどころ触ってやらないとCommandPromptで使えるような状態にはならないらしい。インストーラはhttps://gitforwindows.org/からデカデカとあるDownloadから入手。手を加えたところを太字にするとして、おおまかな流れは


 実行→アプリがデバイスに変更[はい]→ライセンス確認[I Agree]→インストール先[Next]→フォルダ作成確認[はい]→ インストールオプション[Next](右クリックメニューにGitShell起動とGitBash起動を追加/大きいファイルサポート/*.gitファイルをテキストエディタで編集/*.shファイルをGitBashで起動)→スタートメニューのグループ名(GITのまま)[Next]→コミットメッセージで使うエディタは何[Use Vim(the ubiquitous text editor) as Git's default editor]-[Next]→Git initで作られるブランチ名(master (Let Git Decide:Gitに決定させよう))[Next]→パスの設定[Git from the command line and also from 3rd-party software(path追加Gitインストール先\Git\cmd)]-[Next]→OpenSSHのインストール[Use bundled OpenSSH]-[Next]→HTTPSリモートリポジトリ接続[Use the OpenSSL library]-[Next]→改行コード自動変換[Checkout Windows-style,commit Unix-style line endings(コミット処理でなんかうまくいかないときはこの設定が邪魔していることも覚えておかないといけませんよ。あまり使わない機能なので大丈夫だと思いますけど)]-[Next]→Git Bashターミナルを選択[Use MinTTY]-[Next]→Git pullの設定[Default(git pull --ff)]-[Next]→Credentioal設定[Git CredentialManager]-[Next]→オプション[Enable file system caching のみ ON]-[Next]→試験運用オプション[check無し]-[Install]


 あらゆるプロジェクトにおいて、GitHubでソースコードを管理する波は来ています。確実に。Gitコマンドつかえるようになったほうが良いと思います。GitHubの一人勝ちだな。一般向けに最初に納得いくものを作った人たち偉い。会社には会社の中のコード管理があると思います。Visual Source Safeなつかしい。そんなのつかっているひといるのかな。ソース管理とかしたことないからわからないことばかりだけど、必要だよね。


 例えばC:¥JavaScriptフォルダを作って、そこにソースをダウンロードする場合。


cd C:¥JavaScript
git clone git://github.com/mathjax/MathJax.git MathJax


 これだけでC:¥JavaScript¥MathJaxが出来て、その中にes5フォルダが出来上がります。es5とはEcmaScriptというJavaScriptのもう一つの規格名がありまして、これにしたがっているのがes5です。何がどう違うかは自分は完全には理解していません。これに対応している関数や配列なんかには __esModule= true という値が取得できるようになっていたりします。高度なJavaScriptではこの値を制御するみたいな記事もあります。自分はまだ理解していません。


 いろいろな種類の動作を確認するサンプルもダウンロードしましょう。MathJaxの多くの機能を網羅するようなSampleってのはありがたいものです。以下のアドレスから取得できます。



 同じフォルダ(例C:\JavaScript\MathJax)にDownloadしましょう。結果的にC:\JavaScript\MathJax\MathJax-Example\MathJax-base\index.htmlのようなものにアクセスできるようになります。このindex.htmlには2次方程式の解の公式がサンプル表示されるようになっています。Mathjaxのプログラムの参照部分が ../MathJax.js になっているので、 ../../es5/tex-mml-chtml.js のように書き換える必要があります。全部のファイルで書き換えないとだめなのでちょっと辛いですけど、やってみましょう。ファイルによっては違うプログラムを参照した方がいいようなものもあります。これで関連記事のようなVSCodeを設定をするとデバッグができるようになります。

 


軽く追いかけてみる

序盤その1

 自動整形で変換したtex-mml-chtml.jsの1行目の (function(){ にブレークポイントを設定して、プライマリサイドバーの上から4つめ実行とデバッグを選択して、launch.jsonを作ったら、Open index.html の横にある 蛍光色黄緑 ▷ のボタンを押します。ブラウザが起動して、VisualStudioCodeのtex-mml-chtml.jsの1行目で止まります。


 最初の行に"use strict";とあるので、このプログラムでは、強制的に構文チェックをするモードになり、変数定義を正式に実施していないとエラーになるモードになります。


 次に __webpack_modules__ 代入処理で配列が定義されます。 {351 : … とあるので、351が最初に定義される関数みたいですね。何に使うものなのか、この番号からはあまり想像つきません。ものすごい数の配列になってそう。__webpack_modules__はいわば、関数群ですね。


 次に __webpack_module_cache__ = {}; という上記関数群のためのcacheと思われる変数への初期化がされます。プログラムが進むとここにいろいろ設定されていくのでしょう。よく使うやつとかがこんなかにはいるのかな。__webpack_modules__はものスゴイ数の関数がありますので。


 次に function __webpack_require__(t){ … } があるので、tという変数の引数を受け取る__webpack_require__関数が定義されています。短いです。


	function __webpack_require__(t) {
		var e = __webpack_module_cache__[t];
		if(void 0 !== e) return e.exports;
		var r = __webpack_module_cache__[t] = {
			exports: {}
		};
		return __webpack_modules__[t].call(r.exports, r, r.exports, __webpack_require__), r.exports
	}


 ペロッと貼っておきました。cacheの中に設定されている連想配列キー変数 t の配列値を e に取得して何もなければ t の配列値にexports : {} という連想配列を代入して、その値を更に r で覚えさせておくみたいだね。そして、最初に登場にした巨大な関数群を格納している配列 t を実行しています。 返却する値として .call は連想配列値を実行ですね。連想配列にプログラムを格納しておくという技なんだな。なるほど。その引数は、たった今、{exports:{}}とした r の exports キーの値 {} と r 全体 と また同じ、r の exports キーの値 {} と この関数全体の値 __webpack_require__ も引数にしていて4つが引数になっています。この関数群の中のひとつの実行結果が返り値の一つ目、そしてもうひとつ何回も登場するr の exports キーの値 {} を返却するみたい。


 次に__webpack_require__に.gというメンバ変数をつくって、これに何やら設定する関数が実行されます。


	__webpack_require__.g = function() {
		if("object" == typeof globalThis) return globalThis;
		try {
			return this || new Function("return this")()
		} catch(t) {
			if("object" == typeof window) return window
		}
	}();


 ここは単純だな。globalThisという値を __webpack_require__.g に代入する処理なんだけど、ちゃんとobjectとして存在しているかを確認して代入している慎重さがある。globalThisというオブジェクトが無い場合は例外処理付の次の処理を実施します。tryはエラーが発生する可能性がある処理で、エラーが発生したらcatchの処理をするという感じです。返却される可能性のある値は、this || new Function("return this")() エラーになった場合は、window ですね。とにかく取得できる環境変数は取るみたいな処理ですね。catch(t)のtはエラー情報格納変数です。eを使う人も多い印象だけど、tでもいいんだね。


 勉強になるのは this || new Function("return this")() っていう部分が無駄に感じるけど、Debugしてみると単純なthisはundefinedで、new Function("return this")()だとwindowオブジェクトがかえってきたりして、意味が違うんだなって思ったことです。そして、この場合の || の使い方がむずい。なんじゃコレ。論理和演算だからどっちかがtrueになったらtrueが返却され、両方がfalseならfalseがかえるのだろう。それも動かないときはwindowオブジェクトで扱う。


 まだわからないのは

  • new Function("return this")()の後ろのカッコの有り無しの違い
  • 関数構文の中のthisとfunction(){}の中のthisの違い。

 また今度だな。

 

序盤その2

 次にvar __webpack_exports__ = {}; で __webpack_exports__ の連想配列変数を初期化。


 次はちょっと特殊 !function(){}という関数の実行処理です。戻り値のBool値が反転しそうだ。論理否定付きの関数。こんなこともできるんだな。なるほどなるほど。function xxx = {} や var xxx = { zzz : function(x,x,x) = {} }なら関数定義だけfunction(){ }なら実行する内容になるんだね。定義だけか関数だよといいながらも即実行。


 次の部分からは __webpack_require__(t 【←数値】 )で5つの値 t, e, r, n, o を定義。なんの処理の関数を結び付けるのやら、みてもわからんだろうな。9515, 3282, 235, 265, 2388 暗号だな。さっきしらべたとおり __webpack_require__(t) を呼ぶと、__webpack_modules__[t].call(xx,xx,xx,xx)が実行される。__webpack_modules_cache__[t]には{ exports:{ } }が作成されている状態です。


 他にも、undefinedで変数が沢山認識される。


 _, _e, _n, _r, _t, _$, $r, $t, a, A, ae, Ae, an, ar, Ar, at, At, b, B, Be, bn, br, Br, bt, Bt, c, C, ce, Ce, cn, cr, Cr, ct, Ct, d, D, de, De, dn, dr, Dr, dt, Dt, e, E, ee, Ee, en, er, Er, et, Et, f, F, fe, Fe, fn, fr, Fr, ft, Ft, g, G, ge, Ge, gn, gr, Gr, gt, Gt, h, H, he, He, hn, hr, Hr, ht, Ht, i, I, ie, Ie, ir, Ir, it, It, j, J, je, Je, jr, Jr, jt, Jt, k, K, ke, Ke, kr, Kr, kt, Kt, l, L, le, Le, ln, lr, Lr, lt, Lt, m, M, me, Me, mn, mr, Mr, mt, Mt, n, N, ne, Ne, nn, nr, Nr, nt, Nt, o, O, oe, Oe, on, or, Or, ot, Ot, p, P, pe, Pe, pn, pr, Pr, pt, Pt, q, Q, qe, Qe, qr, Qr, qt, Qt, r, R, re, Re, rn, rr, Rr, rt, Rt, s, S, se, Se, sn, Sn, sr, Sr, st, St, t, T, te, Te, this, tn tr, Tr, tt, Tt, u, U, ue, Ue, un, ur, Ur, ut, Ut, v, V, ve, Ve, vn, vr, Vr, vt Vt, w, W, we, We, wr, Wr, wt, Wt, x, X, xe, Xe, xr, Xr, xt, Xt, y, Y, ye, Ye, yn, yr, Yr, yt, Yt, z, Z, ze, Ze, zr, Zr, zt, Zt


 上記ぐらいが定義される。アルファベット全部の小文字(26)、大文字(26)と、アルファベット小文字or大文字に続いて[e,r,t]((26x2)x3=156) アルファベット小文字に続いて n (52)。n だけ大文字との組み合わせ変数が無い。意味深。全部使うのかな?この変数たち。


 うち、Sn と i は使われていた。

Sn:Sn(t, e) {
  (null == e || e > t.length) && (e = t.length);
  for(var r = 0, n = new Array(e); r < e; r++)
    n[r] = t[r];
  return n
}
i:i(t, e) {
  (null == e || e > t.length) && (e = t.length);
  for(var r = 0, n = new Array(e); r < e; r++) 
    n[r] = t[r];
  return n
}

 だけ、定義済みでした。まったく同じ関数。


 この関数が呼ばれるときの t は、  t:(30) ['[tex]/action', '[tex]/ams', '[tex]/amscd', '[tex]/bbox', '[tex]/boldsymbol', '[tex]/braket', '[tex]/bussproofs', '[tex]/cancel', '[tex]/centernot', '[tex]/color', '[tex]/colortbl', '[tex]/configmacros', '[tex]/enclose', '[tex]/extpfeil', '[tex]/html', '[tex]/mathtools', '[tex]/mhchem', '[tex]/newcommand', '[tex]/noerrors', '[tex]/noundefined', '[tex]/physics', '[tex]/require', '[tex]/setoptions', '[tex]/tagformat', '[tex]/textcomp', '[tex]/textmacros', '[tex]/unicode', '[tex]/verb', '[tex]/cases', '[tex]/empheq']

で、e は undefined だから e は t の配列の要素数(30)になります。n は 要素数30の配列になって、r が 0 から 29 まで変動して、n[r] = r[r]; なので配列のコピーですね。コピーした n を返します。


 何やってるか、想像がつきそうなのが2個3個あればいいな。

 

__webpack_modules__[9515].call(r.exports, r, r.exports, __webpack_require__)

			9515: function(t, e, r) {
				var n = this && this.__values || function(t) {
					var e = "function" == typeof Symbol && Symbol.iterator,
						r = e && t[e],
						n = 0;
					if(r) return r.call(t);
					if(t && "number" == typeof t.length) return {
						next: function() {
							return t && n >= t.length && (t = void 0), {
								value: t && t[n++],
								done: !t
							}
						}
					};
					throw new TypeError(e ? "Object is not iterable." : "Symbol.iterator is not defined.")
				};
				Object.defineProperty(e, "__esModule", {
					value: !0
				}), e.MathJax = e.combineWithMathJax = e.combineDefaults = e.combineConfig = e.isObject = void 0;
				var o = r(3282);

				function i(t) {
					return "object" == typeof t && null !== t
				}

				function s(t, e) {
					var r, o;
					try {
						for(var a = n(Object.keys(e)), l = a.next(); !l.done; l = a.next()) {
							var c = l.value;
							"__esModule" !== c && (!i(t[c]) || !i(e[c]) || e[c] instanceof Promise ? null !== e[c] && void 0 !== e[c] && (t[c] = e[c]) : s(t[c], e[c]))
						}
					} catch(t) {
						r = {
							error: t
						}
					} finally {
						try {
							l && !l.done && (o = a.return) && o.call(a)
						} finally {
							if(r) throw r.error
						}
					}
					return t
				}
				e.isObject = i, e.combineConfig = s, e.combineDefaults = function t(e, r, o) {
					var s, a;
					e[r] || (e[r] = {}), e = e[r];
					try {
						for(var l = n(Object.keys(o)), c = l.next(); !c.done; c = l.next()) {
							var u = c.value;
							i(e[u]) && i(o[u]) ? t(e, u, o[u]) : null == e[u] && null != o[u] && (e[u] = o[u])
						}
					} catch(t) {
						s = {
							error: t
						}
					} finally {
						try {
							c && !c.done && (a = l.return) && a.call(l)
						} finally {
							if(s) throw s.error
						}
					}
					return e
				}, e.combineWithMathJax = function(t) {
					return s(e.MathJax, t)
				}, void 0 === r.g.MathJax && (r.g.MathJax = {}), r.g.MathJax.version || (r.g.MathJax = {
					version: o.VERSION,
					_: {},
					config: r.g.MathJax
				}), e.MathJax = r.g.MathJax
			},


 なかなかわけわからん。

var n = this && this.__values || function(t){}

 グローバルオブジェクトだからthisはWindowオブジェクトなんだけど、strictモードなので、. の前が省略されているので、undefined だね。だから、値だけを取り出す、this.__values も undefined。n は function(t) があるから true かな。論理演算している意味が謎だわ。何がしたいんだろう。ま、あとあと何回か呼び出されるんだろうと思って、ブレークポイントを設定したら、謎のコードが33回呼ばれる。おいかけきれるかこれ? t には何かのキーワードみたいなのが入って呼ばれるね。呼び出されるときの t の値を記録してみるか。


 追記※1 : やっぱり論理演算にはJavaScript特有の動作がありました。論理和の場合は、左から0 や null や undefinedのような値が続いて、一番最初に左側に現れた値をそのまま返すんだそうな。なので、最初の値がオブジェクトや関数や変数ならばそのまま、その値が返るそうです。論理積の場合は左側に 1 や true がある場合は最初のオブジェクト値や関数や変数値がかえるそうなのです。


エグイ仕様だな。もう比較する必要ないね。みたいなサバサバ系の処理だ。これは専門家じゃないとむずいな。JavaScript末恐ろしい。自分なんかは知らないことだらけなんじゃね。と、思えてきた。深い!JavaScript。勉強しがいがある! 追記※1ここまで。


 1回目 (10) ['paths', 'source', 'dependencies', 'provides', 'load', 'ready', 'failed', 'require', 'pathFilters', 'versionWarnings']
 2回目 ( 1) ['loader']
 3回目 ( 9) ['input', 'output', 'handler', 'adaptor', 'document', 'elements', 'typeset', 'ready', 'pageReady']
 4回目 ( 2) ['startup', 'options']
 5回目 ( 2) ['startup', 'options']
 6回目 (1) ['_']
 7回目 (1) ['components']
 8回目 (37) ['a11y/semantic-enrich', 'a11y/complexity', 'a11y/explorer', '[mml]/mml3', '[tex]/all-packages', '[tex]/action', '[tex]/autoload', '[tex]/ams', '[tex]/amscd', '[tex]/bbox', '[tex]/boldsymbol', '[tex]/braket', '[tex]/bussproofs', '[tex]/cancel', '[tex]/centernot', '[tex]/color', '[tex]/colorv2', '[tex]/colortbl', '[tex]/configmacros', '[tex]/enclose', '[tex]/extpfeil', '[tex]/html', '[tex]/mathtools', '[tex]/mhchem', '[tex]/newcommand', '[tex]/noerrors', '[tex]/noundefined', '[tex]/physics', '[tex]/require', '[tex]/setoptions', '[tex]/tagformat', '[tex]/textcomp', '[tex]/textmacros', '[tex]/unicode', '[tex]/verb', '[tex]/cases', '[tex]/empheq']
 9回目 (3) ['tex', 'mml', 'sre']
10回目 (4) ['startup', 'input/tex', 'input/tex-full', '[tex]/all-packages']
11回目 (4) ['[tex]/amsCd', '[tex]/colorV2', '[tex]/configMacros', '[tex]/tagFormat']
12回目 (1) ['_']
13回目 (6) ['adaptors', 'components', 'core', 'handlers', 'mathjax', 'util']
14回目 (1) ['global']
15回目 (1) ['_']
16回目 (1) ['input']
17回目 (1) ['_']
18回目 (1) ['input']
19回目 (2) ['mathml_ts', 'mathml']
20回目 (1) ['_']
21回目 (1) ['output']
22回目 (1) ['checkReady']
23回目 (1) ['_']
24回目 (1) ['output']
25回目 (2) ['chtml', 'common']
26回目 (1) ['fonts']
27回目 (1) ['fonts']
28回目 (1) ['fontURL']
29回目 (1) ['font']
30回目 (1) ['_']
31回目 (1) ['ui']
32回目 (1) ['_']
33回目 (1) ['a11y']


 呼ばれるのは、この9515をコールしたときではなく、後で、違う方法で実行されるように呼ばれるようだ。そのときに、このような引数が渡されて実行される。でも、デバッガによると n には、この関数全体が格納される。おそらく n によってこの関数が実行されるんだろう。論理演算ってそういう解釈があるんだなとは疑問に思いつつも納得しようと思う。調べないとな。33回も呼ばれるんだから、後で、こんなのあったなぁってなるんだろう。先に進もう。


 次に実行されるのはObject.defineProperty(e, "__esModule", { value: !0 })で、Object.defineProperty()はオブジェクトの定義をする命令で、第一引数のオブジェクトに、第二引数のメンバ変数に第三引数を値として設定している。つまり、e.__esModule = {value : !0}としている。なんで!0なんだろう。!0 って true のことだと思うので、e.__esModule = {value : true}って感じだと思う。 __esModule は、EcmaScriptに準拠したモジュールかを設定しているとか説明があった。変数 e の扱いを決定するものだな。でも、e.__esModule = true じゃなくて{value : true} なんだな。


 続けて、xxx = void 0;を設定という形式で

e.MathJax = undefined;
e.combineWithMathJax = undefined;
e.combineDefaults = undefined;
e.combineConfig = undefined;
e.isObject = undefined;

 としている。e は、どうやら環境変数って意味っぽいな Environments の e だな。MathJax は、このプログラムの核となる設定でcombineは結合とか混合って意味でwithMathJaxはMathJaxと結合するもの。Defaults規定値で結合するもの。Configは設定で結合するもの、isObjectはオブジェクトかどうか。って感じかな。ひとつ感じるのは、まだ何も始まってすらいないという感じだな。これだけおおがかりなことやっていながら、設定するのは、undefined だもんな。


 次は var o = r(3282);が実行されます。rは関数が格納されていて、__webpack_require__です。いやはや、この__webpack_require__(9515)を通じて、__webpack_modules__[9515].call()がされて今にいたっているのに、それが終わるのを待たずして、関数の内で、また新しく__webpack_require__(3282)を実行するようなものですね。確か、この__webpack_require__(9515)の後も同じように__webpack_require__(3282)が実行される流れになっていたような。ここでも実行しようとするんだね。3282は関数の内容が少ない。 o = { VERSION: "3.2.2", __esModule : true } になる。でも、次に呼ばれる__webpack_require__(3282)の結果は e 配列に追加格納されるような。さっき環境変数の e にいくつかundefined値が設定されたものもあったな。そして o にも同じような値を持たせるんだな。今、結構1文字の変数埋まってきてるな。環境変数っぽい e 。今しがた論理演算で込みなのに取得された n 。そして、o 。それから__webpack_require__が格納された r 。9515のcall内での t は r.export r という引数で{ Exports : {} }に対応する。eは r.Exportsの{}に対応しているがeには値が設定されてExports値の中身が増えていくはず。呼ばれる前は t は配列番号の9515を保持するモノとして使われていた。


この後、さらに2つの1文字変数に関数が格納されます。 i 短い関数function i(t) { return "object" == typeof t && null !== t }、そして s には割かし長めの関数がfunction s(t, e) { }


 そして今しがた獲得したiとsの関数をちょっと前に登場した環境変数に格納する。グローバル系の処理が多いね。これって、なんか違うjava Scriptを同時に動かしているsiteなら、変数が重複して動かなくなりそうなもんだけど大丈夫なのかな。


e.isObject = i; 
e.combineConfig = s;


 に格納している。確かにe.isObject(t)は動かすと、t がオブジェクトなのかを識別して、オブジェクトなら1と返却するし、違うなら0になるね。combineConfig は長いよね。簡単にながめてみると。


 関数 s は for文で 論理演算の元で格納された関数 n に引数 o を与えながら全ての o の要素分だけ繰り返す。o は Version と __esModuleだけだし、たいした繰り返し処理ではなさそうだ。それよか、この for 文がエグイ記述だな。

var a = n(Object.keys(e)), l = a.next(); !l.done; l = a.next()

 ということなんだけど、初期値がカンマ区切りで2個設定されている l = a.next()は次の値なのかな。繰り返し条件の !l.done だから、l.done が 0 の間は、!l.done が 1 なので、繰り返す。l.done が 1 なら終了で、増分は l= a.next で次の配列値が l に入るみたいな感じだな。 ややこしい。e の配列には今は以下の通りになっていて、順番に実行されるのかな。

e.MathJax = undefined;
e.combineWithMathJax = undefined;
e.combineDefaults = undefined;
e.combineConfig = s;
e.isObject = i;

 こんな感じの環境変数のキーを一個づつ a に取得 l には次の値。繰り返したい要素 2つの値を同時に処理できるというのは斬新だけどやりたい処理ってのは c には 次のキー値 l.value の値が入りつつ、論理演算で、__esModuleという文字列値でないときにtrueである且つ、e[c] instanceof Promise ? null !== e[c] && void 0 !== e[c] && (t[c] = e[c]) : s(t[c], e[c])?instanceof Promise?ムズッ。Promiseってのは非同期・同期処理についてキャストできたかというのを判定する処理らしい。なんだよ非同期とか同期とか。関数によっては時間がかかるものとかは、順番に処理されることなく、次々と時間がかからない処理を進めていく。非同期。それを順番に処理するのは、同期処理。と言っていると思います。Promiseは処理をするタイミングを調整するものです。そういった関数であるかどうかを判定しているらしい。いづれにしても何がしたいのかわからない。論理演算だけをして、特に代入することもないという。わからん。e[c] instanceof Promiseの結果が true なら null !== e[c] && void 0 !== e[c] && (t[c] = e[c]) で false ならs(t[c], e[c])で、再帰処理がされる。いやそもそも i(t[c]) とか i(e[c]) とか t[c] とか e[c] とか なんだろうね。i(…) は引数がオブジェクトかどうかを判定する関数でした。cは、 MathJax/combineWithMathJax/combineDefaults/combineConfig/isObject/…esModule/で終了条件にesModuleというキーが使われている予感。他のものの場合は、それがオブジェクトなのかを判断するi(e[c])。t[c]。おいておくか。ちょろっとここにブレークポイントを設定してどういうものが実行されるかみてみてみましょう。


実行されるときには t の内容は以下のような値になっているようです。

{version: '3.2.2', _: {}, config: {paths: {mathjax: 'http://localhost:5500/es5'}, source: {}, dependencies: {}, provides: { }, load: Array(0), …}}


 eは{loader: {versions: Map(0), ready: ƒ, load: ƒ, preLoad: ƒ, defaultReady: ƒ, …}}で、a = n(Object.key(e)) の a はn('loader')になります。nはちょっと前にあった関数が入っていて、


function(t /* ← 'loader' */) {
  var e = "function" == typeof Symbol && Symbol.iterator,
  	r = e && t[e],/* e : Symbol(Symbol.iterator) && 'loader'[Symbol(Symbol.iterator)] → r : ƒ values() */
  	n = 0;
  if(r) return r.call(t); /* r = function( t /='loader'=/ ){return t /='loader'=/ } → return 'loader' */
  if(t && "number" == typeof t.length) return {
  	next: function() {
  		return t && n >= t.length && (t = void 0), {
  			value: t && t[n++],
  			done: !t
  		}
  	}
  };
  throw new TypeError(e ? "Object is not iterable." : "Symbol.iterator is not defined.")
}

でした。この t が'loader'ってことですね。 l は { value: "loader", done: false, } になります。for文の中身の

var a = n(Object.keys(e)), l = a.next(); !l.done; l = a.next()

 この l です。a は {} です。Array Iterator と表現されます。このfor文の使い方は難しい。理解できない。lの中身がそうなる理由が見えてこない。初期値は長い関数によって帰ってくる値で n('loader') の結果が {} で、l = a.next() なんだけど、{ value: "loader", done: false, }っつうね。終了条件の l.done がどこからきたかはわかっていないけど、最初は false なので 1回は処理されるというね。で、おわるとl = a.next() が実行されて次の処理になる。

 c = l.Value は最初は 'loader'

t[c] = undefined
e[c] = {versions: Map(0), ready: ƒ, load: ƒ, preLoad: ƒ, defaultReady: ƒ, …} これは e['loader']の値です。
e[c] instanceof Promise : false

 falseなので、再帰部分が呼ばれる。s(t[c], e[c])。ふむ。いずれにしても、ここでは論理式が書かれているだけで、処理はなにもされなくて、これがエラーにならないかどうかを確かめているだけなのだろう。何もなければ、t そのものが返却される。うまくいかないとエラーになる。


 c はこの後 'loader' → 'versions' → 'ready' → 'load' → 'preLoad' → 'defaultReady' → 'getRoot' → 'pathFilter' → 'item' → '0' → 'item' → … になる。


 こんな、調子だとわからないことだらけだな!


 なんしか、e.combineDefaults = function t(e, r, o) { … } もおなじような試みの関数が設定される。

e.combineDefaults = t; また t が使われた。
e.combineConfig = s;
e.isObject = i;

 次に、e.combineWithMathJax = function(t) { return s(e.MathJax, t) }が設定される。あ!!あー!これ今作ったばっかりの関数 s が呼ばれてる!でも、実行されるのはもっと後だな。でも引数は e.MathJax, t だ。s(t, e)だからな。でも、t が e.MathJax で、 e が t か。また t が引数。このときの t は {'loader' : {versions: Map(0), ready: ƒ, load: ƒ, preLoad: ƒ, defaultReady: ƒ, this : {} }}みたいな値です。


void 0 === r.g.MathJax && (r.g.MathJax = {}),
r.g.MathJax.version || (
  r.g.MathJax = {
    version: o.VERSION,
    _: {},
    config: r.g.MathJax
  }
), 
e.MathJax = r.g.MathJax


 あーそうか。呼び出される前に、var r =__webpack_module_cache__[t] = { exports: {} };処理やってるから2回目は、少なくともexportsの空の値に e 返す。っていう処理になるんだな。この後 3282 。で呼ばれても、同じ処理をするわけではないんだな。

 

 

__webpack_modules__[3282].call(r.exports, r, r.exports, __webpack_require__)

			3282: function(t, e) {
				Object.defineProperty(e, "__esModule", {
					value: !0
				}), e.VERSION = void 0, e.VERSION = "3.2.2"
			},

 9515の中のoに設定したのと同じ要領で、e に設定するのかと思いきや、知らぬ間に __webpack_module_cache__ に{ 3282 : Exports : { version : '3.2.2', __esModule : true }, 9515 : {isObject: ƒ, combineConfig: ƒ, combineDefaults: ƒ, combineWithMathJax: ƒ, MathJax: {…}, …} }ってのが出来上がってた。だから、3282は __webpack_module__[3282]は呼ばれず、__webpack_module_cache__[3282]のreturn で e.Exports = { version : '3.2.2', __esModule : true } が返却される。つまり実行済みだからもう一度やり直しにはならない。__webpack_module_cache__ は優秀な仕組み。9515でいろいろやっている内に設定されたのは自分の知能不足。__webpack_modules__のcallは、最初の一つ目の引数は呼ばれた関数のthisになるオブジェクトを指定している。その後に最大3つの引数が設定されていて、t = r, e = r.Exports, n = __webpack_require__ として処理されることは覚えておいてよいね。r に何が設定されているかで、処理が決まるといってもいい。そして、どこで r や r.Exports が変化するかを抑えないと駄目だ。このあたりがこのプログラムを理解するうえで重要そうだ。

 

__webpack_modules__[235].call(r.exports, r, r.exports, __webpack_require__)

235: function(t, e, r) {
	var n, o, i = this && this.__values || function(t) {
		var e = "function" == typeof Symbol && Symbol.iterator,
			r = e && t[e],
			n = 0;
		if(r) return r.call(t);
		if(t && "number" == typeof t.length) return {
			next: function() {
				return t && n >= t.length && (t = void 0), {
					value: t && t[n++],
					done: !t
				}
			}
		};
		throw new TypeError(e ? "Object is not iterable." : "Symbol.iterator is not defined.")
	};
	Object.defineProperty(e, "__esModule", {
		value: !0
	}), e.CONFIG = e.MathJax = e.Loader = e.PathFilters = e.PackageError = e.Package = void 0;
	var s = r(9515),
		a = r(265),
		l = r(265);
	Object.defineProperty(e, "Package", {
		enumerable: !0,
		get: function() {
			return l.Package
		}
	}), Object.defineProperty(e, "PackageError", {
		enumerable: !0,
		get: function() {
			return l.PackageError
		}
	});
	var c, u = r(7525);
	if(
		e.PathFilters = {
			source: function(t) {
				return e.CONFIG.source.hasOwnProperty(t.name) && (t.name = e.CONFIG.source[t.name]), !0
			},
			normalize: function(t) {
				var e = t.name;
				return e.match(/^(?:[a-z]+:\/)?\/|[a-z]:\\|\[/i) || (t.name = "[mathjax]/" + e.replace(/^\.\//, "")), t.addExtension && !e.match(/\.[^\/]+$/) && (t.name += ".js"), !0
			},
			prefix: function(t) {
			  for(var r;
				  (r = t.name.match(/^\[([^\]]*)\]/)) && 
					e.CONFIG.paths.hasOwnProperty(r[1]);
				) 
				  t.name = e.CONFIG.paths[r[1]] + t.name.substr(r[0].length);
				return !0
		  }
		}, 
		function(t) {
			var r = s.MathJax.version;
			  t.versions = new Map, 
				t.ready = function() {
				for(var t, e, r = [], n = 0; n < arguments.length; n++) r[n] = arguments[n];
				0 === r.length && (r = Array.from(a.Package.packages.keys()));
				var o = [];
				try {
					for(var s = i(r), l = s.next(); !l.done; l = s.next()) {
						var c = l.value,
							u = a.Package.packages.get(c) || new a.Package(c, !0);
						o.push(u.promise)
					}
				} catch(e) {
					t = {
						error: e
					}
				} finally {
					try {
						l && !l.done && (e = s.return) && e.call(s)
					} finally {
						if(t) throw t.error
					}
				}
				return Promise.all(o)
			}, 
			t.load = function() {
				for(var r, n, o = [], s = 0; s < arguments.length; s++)
				  o[s] = arguments[s];
				if(0 === o.length)
				  return Promise.resolve();
				var l = [],
				c = function(r) {
					var n = a.Package.packages.get(r);
					n || 
					(n = new a.Package(r)).provides(e.CONFIG.provides[r]), 
						n.checkNoLoad(), 
						l.push(n.promise.then(
						  (
								function() {
							    e.CONFIG.versionWarnings && 
								  n.isLoaded && 
								  !t.versions.has(a.Package.resolvePath(r)) && 
								  console.warn("No version information available for component ".concat(r))
						    }
						  )
						)
					)
				};
				try {
					for(var u = i(o), p = u.next(); !p.done; p = u.next()) {
						var h = p.value;
						c(h)
					}
				} 
				catch(t) {
					r = {	error: t }
				} 
				finally {
					try {
						p && !p.done && (n = u.return) && n.call(u)
					} 
					finally {
						if(r) 
						  throw r.error
					}
				}
				return a.Package.loadAll(), Promise.all(l)
			}, 
			t.preLoad = function() {
				for(var t, r, n = [], o = 0; o < arguments.length; o++) 
				  n[o] = arguments[o];
				  try {
					  for(var s = i(n), l = s.next(); !l.done; l = s.next()) {
						  var c = l.value,
							  u = a.Package.packages.get(c);
						    u || (u = new a.Package(c, !0)).provides(e.CONFIG.provides[c]), u.loaded()
					  }
				  } 
				  catch(e) {
					  t = { error: e }
				  }
					finally {
					  try {
						  l && !l.done && (r = s.return) && r.call(s)
					  } 
					  finally {
						  if(t) 
							  throw t.error
					}
				}
			}, 
			t.defaultReady = function() {
				void 0 !== e.MathJax.startup && e.MathJax.config.startup.ready()
			}, 
			t.getRoot = function() {
				var t = "//../../es5";
				if("undefined" != typeof document) {
					var e = document.currentScript || document.getElementById("MathJax-script");
					e && (t = e.src.replace(/\/[^\/]*$/, ""))
				}
				return t
			}, 
			t.checkVersion = function(n, o, i) {
				return t.versions.set(a.Package.resolvePath(n), r),
				  !(!e.CONFIG.versionWarnings || o === r) && (console.warn("Component ".concat(n, " uses ").concat(o, " of MathJax; version in use is ").concat(r)), !0)
			},
			t.pathFilters = new u.FunctionList, 
			t.pathFilters.add(e.PathFilters.source,     0), 
			t.pathFilters.add(e.PathFilters.normalize, 10), 
			t.pathFilters.add(e.PathFilters.prefix,    20)
		}
		(c = e.Loader || (e.Loader = {})), 
		  e.MathJax = s.MathJax,
			void 0 === e.MathJax.loader /*だいぶ前のif文の比較演算子の対象。カンマ構文の最後*/
	) 
	{   /* e.MathJax.loader が undefined のときの処理 */
		(	0, s.combineDefaults )( /* s.combineDefaults メンバ関数の引数開始 */
          e.MathJax.config, 
          "loader", 
		  {
			  paths: {
				  mathjax: c.getRoot()
			  },
			  source: {},
			  dependencies: {},
			  provides: {},
			  load: [],
			  ready: c.defaultReady.bind(c),
			  failed: function(t) {
			  	return console.log("MathJax(" . concat(t.package || "?", "): ") . concat(t.message))
			  },
			  require: null,
			  pathFilters: [],
			  versionWarnings: !0
		  }
		), 
		(0, s.combineWithMathJax)( /* combineWithMathJax メンバ関数の引数開始 */
			{	
				loader: c	
			}
		); //長かったカンマ構文終わり。
		try {
			for(var p = i(e.MathJax.config.loader.pathFilters), h = p.next(); !h.done; h = p.next()) {
				var f = h.value;
				Array.isArray(f) ? c.pathFilters.add(f[0], f[1]) : c.pathFilters.add(f)
			}
		} 
		catch(t) {
			n = { error: t }
		} 
		finally {
			try {
				h && !h.done && (o = p.return) && o.call(p)
			} 
			finally {
				if(n) 
				  throw n.error
			}
		}
	}
	e.CONFIG = e.MathJax.config.loader
},

 ここでも9515とよく似た処理がされるね。t = r.Exports ⇔ {exports: {…}, undefined: undefined}, e = r ⇔ {}, r = r.Exports ⇔ ƒ __webpack_require__(t) { … } の3つの引数が使われる。引数の対応すら違っているな、__webpack_modules__[t].call(r.exports, r, r.exports, __webpack_require__)


 ん?あ、callの処理を勘違いしているんだな。ちょっと調べてみる。おー。第一引数は呼び出した関数のthisとなるものらしい。nullとundefined(void 0)を設定すると、グローバルのthisになってWindowオブジェクトが返ってくるんだそうな。今回の場合はr.exportsがthisってことだな。なので、t = r ⇔ {exports: {…}, undefined: undefined}, e = r.exports ⇔ {}, r = __webpack_require__ ⇔ ƒ __webpack_require__(t) { … } ってことだ。おーちょっと解決。勘違い恐るべし。


 t は this。e は Environments。r は result という意味かな? r.Exports を 格納する result。


 以下のような値が設定されます。

e.CONFIG = undefined;
e.MathJax = undefined;
e.Loader = undefined;
e.PathFilters = undefined;
e.PackageError = undefined; 
e.Package = undefined;  


 そして、

var s = r(9515);{isObject: ƒ, combineConfig: ƒ, combineDefaults: ƒ, combineWithMathJax: ƒ, MathJax: {version: '3.2.2', _: {…}, config: {…}}}
var a = r(265); {PackageError: ƒ, Package: ƒ, __esModule: true}
var l = r(265); {PackageError: ƒ, Package: ƒ, __esModule: true}

 の結果をs, a, l にそれぞれ格納。

 r() で その時点で Exports されている値が取得できるんだね。

 Object.defineProperty で e.Packageとe.PackageErrorに値と関数を設定。

 
{
  enumerable : true
  get        : function() { return l.Package (e.PackageErrorはl.PackageError) }
}


 そして

var u = r(7525); {FunctionList: ƒ, __esModule: true}

 の結果を u に格納。


 次に無駄に長い if 文。カンマ区切り構文が続く、評価されるのは一番最後(右側)の値。e.PathFilters={source:function(t){},normalize:function(t){},prefix:function(t){}},…まだ続く。


 まずはキー source からで e.CONFIG.source.hasOwnProperty(t.name) で t.name を作り、 t.name = e.CONFIG.source[t.name]を設定し、常に!0つまりtrueを返却するキー名sourceの値に結び付いた関数。

 normalize は t.nameがパターンマッチで、/^(?:[a-z]+:\/)?\/|[a-z]:\\|\[/i つまり、先頭が(?:[a-z]+:\/)で始まるかを判定。例えばc:abcd:\やc:abcd:abcd:abcd:\みたいに:で始まって、aからzのアルファベットの連続があったあとに来て:\で閉じられるものもしくは、先頭からじゃなくても、aからzの1文字:\もしくは [ があるかを判定。i オプションなので大文字と小文字の区別をしないというマッチングになります。おそらくドライブ文字のようなものにマッチングしようとしていると推測されます。"[mathjax]/" + e.replace(/^\.\//, "") は、t.name の値として [mathjax]/を先頭に付け足して、最初の./を取っ払ったものに置換しています。末尾が ./**** に一致しなければ、.jsを付け足す。という処理をするようです。先に ./ があったら取っ払っていますので、拡張子が既につけられていないことを確認しているものですね。一行でやりたいことをまとめれるって素敵ですね。自分だったらもっと何段階かにわけないと駄目だな。で、見てみたんですけど、e は startup のとき t は { name: '[mathjax]/startup.js', original: 'startup', addExtension: true} となり、startup を [mathjax]/startup.js に置換・格納する処理になっています。


 prefixはfor文の終了条件でパターンマッチングし [] の中が先頭から ] 以外の文字で最長マッチングした値を r[1] に取得。ようするに[]の中の文字列を r へ格納して、マッチングの結果 r[1] という名前のメンバがある限り繰り返し処理。r[0]には[xxxx]のように最長マッチングが取得できて、要するに r[0] は [] 付き、r[1] は [] 無しの文字列が取得できる。[] 無しの文字列をプログラム中では prefix プレフィックス:接頭辞と呼んでいるようで、その終わる部分の長さ以降からの文字を e.config.path['mathjax']の値、つまり http://localhosts:5500/es5 の後ろに startup.js 付け足す処理をします。


 ふむー。具体的に何をするんだろうな。先頭から追っていくと、何に使われるかわからない関数の準備ばっかりになるんだろうか。すさまじいコード量だ。作った人すげー。日々、痛感させられる。自分は何かここまで頑張りとおしたことはあるだろうかと、過去への振り返りさえ発生する。見習いたいものだ。


 とはいいつつも次の関数定義もざっと見ておく。


 次の関数は割かし眺めだ。しかもやっぱりわけがわからない。こういうときは動かしてみてどうなるか見てみる。ひとついえるのは動かしてみてとはいうものの、この関数が呼ばれる保証はない。ただ、まだ前半なのプログラムの根幹をなす関数を定義している気がする。


 動かすと t の値が {versions: Map(0) {size: 0}, ready: ƒ, load: ƒ, preLoad: ƒ, defaultReady: ƒ} こうなった。Version Map0とは?配列の便利なタイプがMapというものらしく、.set('xxx',{yyy:xxx,zzz:xxx}) や .get('xxx') や .has('xxx') といったメソッドや.size といったものがあります。Version番号くらいしか設定されないところに Map というのが不可解なくらいですね。あとは、動作した後に中々、多くの関数が定義されたなという印象。あとはカンマ構文は、セミコロンにできるだけ焼き直した方がデバッグしやすいけど、うかつに分解すると不具合が発生する元にもなるという諸刃の剣。でもちょっと分解しないとデバッグしておいかけにくい。自分みたいな素人が改造して使わないようにデバッグしにくいようにしてるんだろうなぁ。


 さっそく、このあたりの定義されるだけの関数の中のプログラムにブレークポイントを設定してみました。一番最初に呼ばれたのは、t.getRoot の部分です。ふむ。なにげに気になっていた部分 //../../es5/とハードコーディングされているパスがあるが、MathJaxはどこにあるhtmlから呼ばれるかわからない構造のはずだし、このtex-mml-chtml.jsファイル自体からのパスだとしてもそんなところにはes5はない。おー。すぐに t は上書きされますね。 document.getElementById("MathJax-script") = null で e = document.currentScript で e.src は http://localhost:5500/es5/tex-mml-chtml.js になりました。そうすると。これの e.src.replace(/\/[^\/]*$/, "") は http://localhost:5500/es5/ です。/[/以外]末尾 で末尾の / から以外っていみで、後ろのファイル名が取り除かれた名前になります。t.getRoot に http://localhost:5500/es5/ がセットされます。 おー。やるなMathJax。


 次に呼ばれたのは、t.preload です。o < Argument.length の間、繰り返します。Argument は 大きさ9の要素になっています。2つの連想配列があります。キーはcalleeとSymbol(Symbol.iterator)です。Arguments(9) ['loader', 'startup', 'core', 'input/tex', 'input/mml', 'output/chtml', 'output/chtml/fonts/tex.js', 'ui/menu', 'a11y/assistive-mml', callee: <accessor>, Symbol(Symbol.iterator): ƒ] で、繰り返し処理によってn[0]~n[8]の9個が Argument からコピーされます。

 e.CONFIG = 
{
 paths           : {mathjax: 'http://localhost:5500/es5'},
 failed          : {   ƒ (t) {
                           \treturn console.log("MathJax(" . concat(t.package || "?", "): ") . concat(t.message))
                       }
                   },
 source          : {}, 
 dependencies    : {}, 
 provides        : {}, 
 load            : Array(0), 
 versionWarnings : true
}


 やっぱり、for文に.next()が使われるパターンの深い理解が必要だな。かなりの頻度で使われる。ふむhttps://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Generator/next によると、next()を使うと、value 実際に使いたい次々に取り出す配列値 と done 終了フラグ を返すそうな。終わったら true だそうです。

for(var arraydata = arrayobject, countobject = arraydata.next(); !countobject.done; countobject = arraydata.next()){ ; var contentvalue= countobject.value; }

 for文はこの形式で構成されます。初期値の処理が二つになります。配列や連想配列構造のオブジェクトarrayobjectをarraydataに受け取り、この値に対してarraydata.next()を呼び出すたびに次の配列値へと移動しますが、最初の値の取り出しでもarraydata.next()が必要なので、実行して、実際に使う変数値として、countobject に保持させます。これがfor文の初期動作です。終了条件は、実際に使う値の countobject のメンバ関数 done(ダン) を監視すればよいことになります。最後の値を処理したら、true になります。なので、終了条件は !countobject.done となります。そして、次の値を実際に使用する変数 countobject に代入しつつも、arraydata.next() を呼び出せばいいです。for文の中では実際に使う値を、contentvalue = countobject.valueのように取り出すことをするでしょう。実際、mathjax でも、実にオーソドックスに配列の値を使ったfor文を処理しています。一方で、もうちょっと変わった連想配列の繰り返し処理中で特殊なfor文(for of:キー値のみ取り出し/for in:値の取り出し)は使っていないようです。for in だと関数内で追加で定義宣言(これをよくプロトタイプ関数と言っています。)した関数が配列の中の要素として使われるので、値が関数でないかを確認しなくてはいけなくなったりします。複雑なプログラムでは実は意外と使いにくいfor in。for of で配列値を指定した場合はキーではなく、配列値が使えます。for(var val of/in】 Array){…}


 以上の事を踏まえると、t.ready と t.preLoad と t.defaultReady と t.getRoot と t.checkVersion と t.pathFileters関数が作られて、これがどこから何回呼ばれるのかを確認することで、大部分を把握できて、if(void 0 === e.mathJax.loader) が成立したとき、つまり e.MathJax.loader が undefined のときに s.combineDefaults と s.combineWithMathJax に複雑な引数が渡される処理を実施して、最後に、 i(e.MathJax.config.loader.pathFilters) の結果得られる要素全てについての処理を行う処理が実施されるので、この動きを見極めればよいことになる。


t.ready

 

t.preLoad

 

t.getRoot

 

t.checkVersion

 

t.pathFileters

 

s.combineDefaults

 

s.combineWithMathJax

 

i(e.MathJax.config.loader.pathFilters)

   

__webpack_modules__[265].call(r.exports, r, r.exports, __webpack_require__)

			265: function(t, e, r) {
				var n, o = this && this.__extends || (n = function(t, e) {
						return n = Object.setPrototypeOf || {
							__proto__: []
						}
						instanceof Array && function(t, e) {
							t.__proto__ = e
						} || function(t, e) {
							for(var r in e) Object.prototype.hasOwnProperty.call(e, r) && (t[r] = e[r])
						}, n(t, e)
					}, function(t, e) {
						if("function" != typeof e && null !== e) throw new TypeError("Class extends value " + String(e) + " is not a constructor or null");

						function r() {
							this.constructor = t
						}
						n(t, e), t.prototype = null === e ? Object.create(e) : (r.prototype = e.prototype, new r)
					}),
					i = this && this.__values || function(t) {
						var e = "function" == typeof Symbol && Symbol.iterator,
							r = e && t[e],
							n = 0;
						if(r) return r.call(t);
						if(t && "number" == typeof t.length) return {
							next: function() {
								return t && n >= t.length && (t = void 0), {
									value: t && t[n++],
									done: !t
								}
							}
						};
						throw new TypeError(e ? "Object is not iterable." : "Symbol.iterator is not defined.")
					},
					s = this && this.__read || function(t, e) {
						var r = "function" == typeof Symbol && t[Symbol.iterator];
						if(!r) return t;
						var n, o, i = r.call(t),
							s = [];
						try {
							for(;
								(void 0 === e || e-- > 0) && !(n = i.next()).done;) s.push(n.value)
						} catch(t) {
							o = {
								error: t
							}
						} finally {
							try {
								n && !n.done && (r = i.return) && r.call(i)
							} finally {
								if(o) throw o.error
							}
						}
						return s
					},
					a = this && this.__spreadArray || function(t, e, r) {
						if(r || 2 === arguments.length)
							for(var n, o = 0, i = e.length; o < i; o++) !n && o in e || (n || (n = Array.prototype.slice.call(e, 0, o)), n[o] = e[o]);
						return t.concat(n || Array.prototype.slice.call(e))
					};
				Object.defineProperty(e, "__esModule", {
					value: !0
				}), e.Package = e.PackageError = void 0;
				var l = r(235),
					c = function(t) {
						function e(e, r) {
							var n = t.call(this, e) || this;
							return n.package = r, n
						}
						return o(e, t), e
					}(Error);
				e.PackageError = c;
				var u = function() {
					function t(e, r) {
						void 0 === r && (r = !1), this.isLoaded = !1, this.isLoading = !1, this.hasFailed = !1, this.dependents = [], this.dependencies = [], this.dependencyCount = 0, this.provided = [], this.name = e, this.noLoad = r, t.packages.set(e, this), this.promise = this.makePromise(this.makeDependencies())
					}
					return Object.defineProperty(t.prototype, "canLoad", {
						get: function() {
							return 0 === this.dependencyCount && !this.noLoad && !this.isLoading && !this.hasFailed
						},
						enumerable: !1,
						configurable: !0
					}), t.resolvePath = function(t, e) {
						void 0 === e && (e = !0);
						var r = {
							name: t,
							original: t,
							addExtension: e
						};
						return l.Loader.pathFilters.execute(r), r.name
					}, t.loadAll = function() {
						var t, e;
						try {
							for(var r = i(this.packages.values()), n = r.next(); !n.done; n = r.next()) {
								var o = n.value;
								o.canLoad && o.load()
							}
						} catch(e) {
							t = {
								error: e
							}
						} finally {
							try {
								n && !n.done && (e = r.return) && e.call(r)
							} finally {
								if(t) throw t.error
							}
						}
					}, t.prototype.makeDependencies = function() {
						var e, r, n = [],
							o = t.packages,
							c = this.noLoad,
							u = this.name,
							p = [];
						l.CONFIG.dependencies.hasOwnProperty(u) ? p.push.apply(p, a([], s(l.CONFIG.dependencies[u]), !1)) : "core" !== u && p.push("core");
						try {
							for(var h = i(p), f = h.next(); !f.done; f = h.next()) {
								var d = f.value,
									m = o.get(d) || new t(d, c);
								this.dependencies.indexOf(m) < 0 && (m.addDependent(this, c), this.dependencies.push(m), m.isLoaded || (this.dependencyCount++, n.push(m.promise)))
							}
						} catch(t) {
							e = {
								error: t
							}
						} finally {
							try {
								f && !f.done && (r = h.return) && r.call(h)
							} finally {
								if(e) throw e.error
							}
						}
						return n
					}, t.prototype.makePromise = function(t) {
						var e = this,
							r = new Promise((function(t, r) {
								e.resolve = t, e.reject = r
							})),
							n = l.CONFIG[this.name] || {};
						return n.ready && (r = r.then((function(t) {
							return n.ready(e.name)
						}))), t.length && (t.push(r), r = Promise.all(t).then((function(t) {
							return t.join(", ")
						}))), n.failed && r.catch((function(t) {
							return n.failed(new c(t, e.name))
						})), r
					}, t.prototype.load = function() {
						if(!this.isLoaded && !this.isLoading && !this.noLoad) {
							this.isLoading = !0;
							var e = t.resolvePath(this.name);
							l.CONFIG.require ? this.loadCustom(e) : this.loadScript(e)
						}
					}, t.prototype.loadCustom = function(t) {
						var e = this;
						try {
							var r = l.CONFIG.require(t);
							r instanceof Promise ? r.then((function() {
								return e.checkLoad()
							})).catch((function(r) {
								return e.failed("Can't load \"" + t + '"\n' + r.message.trim())
							})) : this.checkLoad()
						} catch(t) {
							this.failed(t.message)
						}
					}, t.prototype.loadScript = function(t) {
						var e = this,
							r = document.createElement("script");
						r.src = t, r.charset = "UTF-8", r.onload = function(t) {
							return e.checkLoad()
						}, r.onerror = function(r) {
							return e.failed("Can't load \"" + t + '"')
						}, document.head.appendChild(r)
					}, t.prototype.loaded = function() {
						var t, e, r, n;
						this.isLoaded = !0, this.isLoading = !1;
						try {
							for(var o = i(this.dependents), s = o.next(); !s.done; s = o.next()) {
								s.value.requirementSatisfied()
							}
						} catch(e) {
							t = {
								error: e
							}
						} finally {
							try {
								s && !s.done && (e = o.return) && e.call(o)
							} finally {
								if(t) throw t.error
							}
						}
						try {
							for(var a = i(this.provided), l = a.next(); !l.done; l = a.next()) {
								l.value.loaded()
							}
						} catch(t) {
							r = {
								error: t
							}
						} finally {
							try {
								l && !l.done && (n = a.return) && n.call(a)
							} finally {
								if(r) throw r.error
							}
						}
						this.resolve(this.name)
					}, t.prototype.failed = function(t) {
						this.hasFailed = !0, this.isLoading = !1, this.reject(new c(t, this.name))
					}, t.prototype.checkLoad = function() {
						var t = this;
						((l.CONFIG[this.name] || {}).checkReady || function() {
							return Promise.resolve()
						})().then((function() {
							return t.loaded()
						})).catch((function(e) {
							return t.failed(e)
						}))
					}, t.prototype.requirementSatisfied = function() {
						this.dependencyCount && (this.dependencyCount--, this.canLoad && this.load())
					}, t.prototype.provides = function(e) {
						var r, n;
						void 0 === e && (e = []);
						try {
							for(var o = i(e), s = o.next(); !s.done; s = o.next()) {
								var a = s.value,
									c = t.packages.get(a);
								c || (l.CONFIG.dependencies[a] || (l.CONFIG.dependencies[a] = []), l.CONFIG.dependencies[a].push(a), (c = new t(a, !0)).isLoading = !0), this.provided.push(c)
							}
						} catch(t) {
							r = {
								error: t
							}
						} finally {
							try {
								s && !s.done && (n = o.return) && n.call(o)
							} finally {
								if(r) throw r.error
							}
						}
					}, t.prototype.addDependent = function(t, e) {
						this.dependents.push(t), e || this.checkNoLoad()
					}, t.prototype.checkNoLoad = function() {
						var t, e;
						if(this.noLoad) {
							this.noLoad = !1;
							try {
								for(var r = i(this.dependencies), n = r.next(); !n.done; n = r.next()) {
									n.value.checkNoLoad()
								}
							} catch(e) {
								t = {
									error: e
								}
							} finally {
								try {
									n && !n.done && (e = r.return) && e.call(r)
								} finally {
									if(t) throw t.error
								}
							}
						}
					}, t.packages = new Map, t
				}();
				e.Package = u
			},
			2388: function(t, e, r) {
				var n = this && this.__assign || function() {
						return n = Object.assign || function(t) {
							for(var e, r = 1, n = arguments.length; r < n; r++)
								for(var o in e = arguments[r]) Object.prototype.hasOwnProperty.call(e, o) && (t[o] = e[o]);
							return t
						}, n.apply(this, arguments)
					},
					o = this && this.__values || function(t) {
						var e = "function" == typeof Symbol && Symbol.iterator,
							r = e && t[e],
							n = 0;
						if(r) return r.call(t);
						if(t && "number" == typeof t.length) return {
							next: function() {
								return t && n >= t.length && (t = void 0), {
									value: t && t[n++],
									done: !t
								}
							}
						};
						throw new TypeError(e ? "Object is not iterable." : "Symbol.iterator is not defined.")
					},
					i = this && this.__read || function(t, e) {
						var r = "function" == typeof Symbol && t[Symbol.iterator];
						if(!r) return t;
						var n, o, i = r.call(t),
							s = [];
						try {
							for(;
								(void 0 === e || e-- > 0) && !(n = i.next()).done;) s.push(n.value)
						} catch(t) {
							o = {
								error: t
							}
						} finally {
							try {
								n && !n.done && (r = i.return) && r.call(i)
							} finally {
								if(o) throw o.error
							}
						}
						return s
					},
					s = this && this.__spreadArray || function(t, e, r) {
						if(r || 2 === arguments.length)
							for(var n, o = 0, i = e.length; o < i; o++) !n && o in e || (n || (n = Array.prototype.slice.call(e, 0, o)), n[o] = e[o]);
						return t.concat(n || Array.prototype.slice.call(e))
					};
				Object.defineProperty(e, "__esModule", {
					value: !0
				}), e.CONFIG = e.MathJax = e.Startup = void 0;
				var a, l = r(9515),
					c = r(8666),
					u = r(7233);
				! function(t) {
					var a, l, u = new c.PrioritizedList;

					function h(e) {
						return a.visitTree(e, t.document)
					}

					function f() {
						a = new e.MathJax._.core.MmlTree.SerializedMmlVisitor.SerializedMmlVisitor, l = e.MathJax._.mathjax.mathjax, t.input = v(), t.output = _(), t.adaptor = S(), t.handler && l.handlers.unregister(t.handler), t.handler = M(), t.handler && (l.handlers.register(t.handler), t.document = O())
					}

					function d() {
						var e, r;
						t.input && t.output && m();
						var n = t.output ? t.output.name.toLowerCase() : "";
						try {
							for(var i = o(t.input), s = i.next(); !s.done; s = i.next()) {
								var a = s.value,
									l = a.name.toLowerCase();
								g(l, a), b(l, a), t.output && y(l, n, a)
							}
						} catch(t) {
							e = {
								error: t
							}
						} finally {
							try {
								s && !s.done && (r = i.return) && r.call(i)
							} finally {
								if(e) throw e.error
							}
						}
					}

					function m() {
						e.MathJax.typeset = function(e) {
							void 0 === e && (e = null), t.document.options.elements = e, t.document.reset(), t.document.render()
						}, e.MathJax.typesetPromise = function(e) {
							return void 0 === e && (e = null), t.document.options.elements = e, t.document.reset(), l.handleRetriesFor((function() {
								t.document.render()
							}))
						}, e.MathJax.typesetClear = function(e) {
							void 0 === e && (e = null), e ? t.document.clearMathItemsWithin(e) : t.document.clear()
						}
					}

					function y(r, n, o) {
						var i = r + "2" + n;
						e.MathJax[i] = function(e, r) {
							return void 0 === r && (r = {}), r.format = o.name, t.document.convert(e, r)
						}, e.MathJax[i + "Promise"] = function(e, r) {
							return void 0 === r && (r = {}), r.format = o.name, l.handleRetriesFor((function() {
								return t.document.convert(e, r)
							}))
						}, e.MathJax[n + "Stylesheet"] = function() {
							return t.output.styleSheet(t.document)
						}, "getMetricsFor" in t.output && (e.MathJax.getMetricsFor = function(e, r) {
							return t.output.getMetricsFor(e, r)
						})
					}

					function g(r, n) {
						var o = e.MathJax._.core.MathItem.STATE;
						e.MathJax[r + "2mml"] = function(e, r) {
							return void 0 === r && (r = {}), r.end = o.CONVERT, r.format = n.name, h(t.document.convert(e, r))
						}, e.MathJax[r + "2mmlPromise"] = function(e, r) {
							return void 0 === r && (r = {}), r.end = o.CONVERT, r.format = n.name, l.handleRetriesFor((function() {
								return h(t.document.convert(e, r))
							}))
						}
					}

					function b(t, r) {
						e.MathJax[t + "Reset"] = function() {
							for(var t = [], e = 0; e < arguments.length; e++) t[e] = arguments[e];
							return r.reset.apply(r, s([], i(t), !1))
						}
					}

					function v() {
						var r, n, i = [];
						try {
							for(var s = o(e.CONFIG.input), a = s.next(); !a.done; a = s.next()) {
								var l = a.value,
									c = t.constructors[l];
								if(!c) throw Error('Input Jax "' + l + '" is not defined (has it been loaded?)');
								i.push(new c(e.MathJax.config[l]))
							}
						} catch(t) {
							r = {
								error: t
							}
						} finally {
							try {
								a && !a.done && (n = s.return) && n.call(s)
							} finally {
								if(r) throw r.error
							}
						}
						return i
					}

					function _() {
						var r = e.CONFIG.output;
						if(!r) return null;
						var n = t.constructors[r];
						if(!n) throw Error('Output Jax "' + r + '" is not defined (has it been loaded?)');
						return new n(e.MathJax.config[r])
					}

					function S() {
						var r = e.CONFIG.adaptor;
						if(!r || "none" === r) return null;
						var n = t.constructors[r];
						if(!n) throw Error('DOMAdaptor "' + r + '" is not defined (has it been loaded?)');
						return n(e.MathJax.config[r])
					}

					function M() {
						var r, n, i = e.CONFIG.handler;
						if(!i || "none" === i || !t.adaptor) return null;
						var s = t.constructors[i];
						if(!s) throw Error('Handler "' + i + '" is not defined (has it been loaded?)');
						var a = new s(t.adaptor, 5);
						try {
							for(var l = o(u), c = l.next(); !c.done; c = l.next()) {
								a = c.value.item(a)
							}
						} catch(t) {
							r = {
								error: t
							}
						} finally {
							try {
								c && !c.done && (n = l.return) && n.call(l)
							} finally {
								if(r) throw r.error
							}
						}
						return a
					}

					function O(r) {
						return void 0 === r && (r = null), l.document(r || e.CONFIG.document, n(n({}, e.MathJax.config.options), {
							InputJax: t.input,
							OutputJax: t.output
						}))
					}
					t.constructors = {}, t.input = [], t.output = null, t.handler = null, t.adaptor = null, t.elements = null, t.document = null, t.promise = new Promise((function(e, r) {
						t.promiseResolve = e, t.promiseReject = r
					})), t.pagePromise = new Promise((function(t, e) {
						var n = r.g.document;
						if(n && n.readyState && "complete" !== n.readyState && "interactive" !== n.readyState) {
							var o = function() {
								return t()
							};
							n.defaultView.addEventListener("load", o, !0), n.defaultView.addEventListener("DOMContentLoaded", o, !0)
						} else t()
					})), t.toMML = h, t.registerConstructor = function(e, r) {
						t.constructors[e] = r
					}, t.useHandler = function(t, r) {
						void 0 === r && (r = !1), e.CONFIG.handler && !r || (e.CONFIG.handler = t)
					}, t.useAdaptor = function(t, r) {
						void 0 === r && (r = !1), e.CONFIG.adaptor && !r || (e.CONFIG.adaptor = t)
					}, t.useInput = function(t, r) {
						void 0 === r && (r = !1), p && !r || e.CONFIG.input.push(t)
					}, t.useOutput = function(t, r) {
						void 0 === r && (r = !1), e.CONFIG.output && !r || (e.CONFIG.output = t)
					}, t.extendHandler = function(t, e) {
						void 0 === e && (e = 10), u.add(t, e)
					}, t.defaultReady = function() {
						f(), d(), t.pagePromise.then((function() {
							return e.CONFIG.pageReady()
						})).then((function() {
							return t.promiseResolve()
						})).catch((function(e) {
							return t.promiseReject(e)
						}))
					}, t.defaultPageReady = function() {
						return e.CONFIG.typeset && e.MathJax.typesetPromise ? e.MathJax.typesetPromise(e.CONFIG.elements) : Promise.resolve()
					}, t.getComponents = f, t.makeMethods = d, t.makeTypesetMethods = m, t.makeOutputMethods = y, t.makeMmlMethods = g, t.makeResetMethod = b, t.getInputJax = v, t.getOutputJax = _, t.getAdaptor = S, t.getHandler = M, t.getDocument = O
				}(a = e.Startup || (e.Startup = {})), e.MathJax = l.MathJax, void 0 === e.MathJax._.startup && ((0, l.combineDefaults)(e.MathJax.config, "startup", {
					input: [],
					output: "",
					handler: null,
					adaptor: null,
					document: "undefined" == typeof document ? "" : document,
					elements: null,
					typeset: !0,
					ready: a.defaultReady.bind(a),
					pageReady: a.defaultPageReady.bind(a)
				}), (0, l.combineWithMathJax)({
					startup: a,
					options: {}
				}), e.MathJax.config.startup.invalidOption && (u.OPTIONS.invalidOption = e.MathJax.config.startup.invalidOption), e.MathJax.config.startup.optionError && (u.OPTIONS.optionError = e.MathJax.config.startup.optionError)), e.CONFIG = e.MathJax.config.startup;
				var p = 0 !== e.CONFIG.input.length
			},

 

関連情報

 MathJax

 

VScodeで簡易WebServerの元でデバッグに戻る。