変奏現実

パソコンやMMORPGのことなどを思いつくまま・・・記載されている会社名・製品名・システム名などは、各社の商標、または登録商標です。

この画面は、簡易表示です

[javascript]XmlDocument?

XmlDocumentの構成とかjavascriptでの読み方とか

xmlData.getElementsByTagName("要素名")[0]
とか
xmlData.querySelect(セレクター)
とか

な感じで検索する記事はあるけど、ザーット表示する記事はなかった。

ま、ブラウザで表示すればいいからね。

でも自作のTreeViewもどきで作った

APIはまだ無いので自力でTreeViewにHTMLobjectを書き込まないといけない。

    <div class="tree_view">
        <!-- level 1 -->
        <div class="element open"><tag-name attr-name1="xxxxxx" attr-name2="xxxxxx" >
            <div class="contener">
                <!-- level 2 -->
                <div class="context">テキスト1</div>
                <div class="context">テキスト2</div>
                <div class="context">テキスト3</div>
                <div class="context">テキスト4</div>
                <div><tag-name2/></div>
            </div>
            <div class="element-end"></tag-name1></div>
        </div>
        <!-- level 1 -->

な感じでHTMLを作ると

な雰囲気で表示するところまで地味にcssを書いて

body {
    background-color: antiquewhite;
}
div.tree_view {
    background-color: burlywood;
    font-family: 'メイリオ', 'Meiryo', 'MS ゴシック', 'Hiragino Kaku Gothic ProN', 'ヒラギノ角ゴ ProN W3', sans-serif;
    font-size: 10pt;
    height: 100%; width: calc(100% - 20px);
    margin: 10px; border: solid black 1px; padding-left: 1em;    
}
div.marker {
    vertical-align: top;
    display: inline-block;
    width: 1em;
    border: solid blue 1px;
}
div.element {
    margin-right: 6px;
}
(省略)

点線も描いて

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
	<path d="M 0,0,0,9,14,9" fill="none" stroke="gray" stroke-dasharray="2" />
</svg>

後は、XMLファイルを読んで終了。

  ・・・
    /**
     * ファイルボタンのファイル選択イベント 
     * @param {*} event 
     */
    onSelectedFile = (event) => {
        // A file selection event occurred.
        console.log(`file selection event occurred. '${Array.from(event.target.files).map((a) => a.name).join(', ')}'`);
        // Get a file object.
        const fileObjects = event.target.files;
        // 過去歴をクリア
        this.xmlDocuments = [];
        clearnHtmlObjectTextContent(this.outputHtmlObject);
        // Load file 
        this.loadFiles(fileObjects, this.readXml, this.outputHtmlObject);
    };
    /**
     * load fileObject
     * @param {FileList} fileObjects 
     * @param {*} contextReader 
     * @param {*} outputHtmlObject
     */
    loadFiles = (fileObjects, contextReader, outputHtmlObject) => {
        Array.from(fileObjects).map((fileObject) => {
            const fr = new FileReader();
            fr.addEventListener('load', (event) => {
                // ファイルのテキストを取得
                const xmlContext = event.target.result;
                contextReader(xmlContext, outputHtmlObject);
            });
            fr.readAsText(fileObject);
        });
    }
  (省略)
// setup
window.addEventListener("load", () => {
    const xmlView = new TreeView(document.querySelector(`#file`), document.querySelector(`.tree_view`));
    // tree_view の▼と▶の切替
    window.addEventListener("click", (event) => {
        if (Array.from(event.target.classList).some((e) => e === 'element')) {
            const target = event.target; target.classList.toggle('open');
            const chLst = Array.from(target.childNodes).filter((ch) => {
                return ((!ch.classList) ? false : Array.from(ch.classList).some((cl) => cl === 'contener'));
            });
            (chLst).forEach(ch => ch.classList.toggle('hidden'));
        };
    });
});

のハズだったけど、

new DOMParser().parseFromString(xmlText, ‘application/xml’)で得られる

XmlDocumentのMDNの説明はDocument→Nodeクラスの派生型です。(説明終わり

仕方なく汎用XML解析ルーチンaddTreeListByXmlを作ることに

tagNameが無い場合はnodeNameが「#TEXT」なんで、テキストコンテキストノードっぽいのでtextContentのみ設定とかXMLを読んだ結果を見ながら行き当たりばったりで書いた。

配下のオブジェクトはchildListかなと思ったけど、childNodesの方だった。

属性はgetAttributeNames()で属性名を取得してgetAttribute(属性名)で値が判る。

そんな雰囲気なので作ってみた感想は目新しいメソッドも特に無いから

XmlDocumentクラスはDocument→Nodeクラスの派生です。

という説明で充分かもしれない。

TreeViewのAPIもWindowsのみたいに細かく作るよりJSON形式のデータを渡すとそれっぽく表示する程度で充分かな

ps.2025/4/22:カスタムエレメント化した。

<body>
    <label for="fileXmlDom">parseFromString(fileText)</label><input type="file" id="fileXmlDom" value="XmlDom"><br />
    <label for="fileXmlText">replaceAll(/x/g,xmlReplacer)</label><input type="file" id="fileXmlText" value="XmlText">
    <tree-view id="tree_view_sample" width="500px" height="600px" tabindex="1" resize="both" overflow="auto">
    </tree-view>
</body>

String.replaceAll({正規表現パターン、置換処理})の結果をinnerHTMLで展開

XMLParserのparseFromString({XMLテキスト})の結果(DOMツリー)を展開

いづれも長いコード書かないとツリービュー化できないでいる。

ReplaceAllの方はHTMLも読めなくもないが、末端に正しく(?)「/>」が入っていないと南京玉簾になる。

とりあえず、オブジェクトだったら配下のオブジェクトを調べる方法を画一化(childListとか)してみたい。



[javascript]コードハイライト(途中経過)

<body>
・・・
<input type="text" id="regexp_pattern" size="80" autocomplete="on" />
<input type="text" id="regexp_option" size="16" autocomplete="on" />
・・・
<input type="button" id="text_color_regexp_text" value="名前付きキャプチャグループ名で色付け" /></br>
結果:<div class="result" id="result"></div>
・・・
</body>
/**
 * サンプルコードのオブジェクトを作成
 */
const regExpSample = new class RegExpSample {
 ・・・
  /**
   * 初期化
   * @memberof RegExpSample
   */
  setup = () => {
    // イベントリスナー登録
    ・・・
    document.querySelector('#text_color_regexp_text').addEventListener("click", this.textColorFromClickButton);
  ・・・
  };
 ・・・
  /**
   * 【名前付きキャプチャグループ名で色付け】ボタンクリック処理
   * @memberof RegExpSample
   */
  textColorFromClickButton = () => {
    try {
      clearnHtmlObjectTextContent('result');
      // 結果を格納するdiv
      const divResult = document.querySelector('#result');
      // サンプル ※関数の引数の初期値に割り当てたら、画面初期表示時の空っぽだった件
      let text = document.querySelector('#regexp_text').value; //.replace('\r\n', '\n');
      // RegExpのパターンとオプションからRegExpクラスのオブジェクトを作成する
      const re = createRegexpPattern();
      // RegExpクラスのオブジェクトを渡しtextColorにお任せ
      let result = textColor(text, re);
      // 読み飛ばした箇所に背景色(黒)を付ける
      result = this.setBackColor(result);
      // textColorの結果を画面に出力
      result = result.replaceAll(/[\r\n]/g, '<br/>');
      divResult.innerHTML = result;
    } catch (ex) {
      console.error(`textColorFromClickButton : ${ex}`);
    }
  };
 ・・・
};
// 初期化
window.addEventListener("load", () => {
  regExpSample.setup();
});

ここまでは、そこそこ簡略化できてる(と思う

/**
 * 色名
 */
const colors = ['black', 'silver', 'gray', 'white', 'maroon', 'red', 'purple', 'fuchsia', 'green', 'lime', 'olive', 'yellow', 'navy', 'blue', 'teal', 'aqua', 'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure', 'beige', 'bisque', 'black', 'blanchedalmond', 'blue', 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse', 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson', 'cyan', 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgreen', 'darkgrey', 'darkkhaki', 'darkmagenta', 'darkolivegreen', 'darkorange', 'darkorchid', 'darkred', 'darksalmon', 'darkseagreen', 'darkslateblue', 'darkslategray', 'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink', 'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue', 'firebrick', 'floralwhite', 'forestgreen', 'fuchsia', 'gainsboro', 'ghostwhite', 'gold', 'goldenrod', 'gray', 'green', 'greenyellow', 'grey', 'honeydew', 'hotpink', 'indianred', 'indigo', 'ivory', 'khaki', 'lavender', 'lavenderblush', 'lawngreen', 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan', 'lightgoldenrodyellow', 'lightgray', 'lightgreen', 'lightgrey', 'lightpink', 'lightsalmon', 'lightseagreen', 'lightskyblue', 'lightslategray', 'lightslategrey', 'lightsteelblue', 'lightyellow', 'lime', 'limegreen', 'linen', 'magenta', 'maroon', 'mediumaquamarine', 'mediumblue', 'mediumorchid', 'mediumpurple', 'mediumseagreen', 'mediumslateblue', 'mediumspringgreen', 'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream', 'mistyrose', 'moccasin', 'navajowhite', 'navy', 'oldlace', 'olive', 'olivedrab', 'orange', 'orangered', 'orchid', 'palegoldenrod', 'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip', 'peachpuff', 'peru', 'pink', 'plum', 'powderblue', 'purple', 'rebeccapurple', 'red', 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown', 'seagreen', 'seashell', 'sienna', 'silver', 'skyblue', 'slateblue', 'slategray', 'slategrey', 'snow', 'springgreen', 'steelblue', 'tan', 'teal', 'thistle', 'tomato', 'transparent', 'turquoise', 'violet', 'wheat', 'white', 'whitesmoke', 'yellow', 'yellowgreen',];
/**
 * textColorReplacer内で使用する初期色
 */
const defaultColor = new DefaultColor();
/**
 * テキストに色を付ける正規表現のリプレサー
 * replace関数のリプレサーのパラメータは以下の通り
 * @param {string} match   一致した部分文字列
 * @param {string} rs1     1番目のキャプチャグループの結果
 * @param {string} rs2     2番目のキャプチャグループの結果
 * ・・・
 * @param {string} rsN     N番目のキャプチャグループの結果
 * @param {integer} index  分析中の文字列の開始位置
 * @param {string} string  分析中の文字列全体
 * @param {object} groups  キャプチャグループ全体の抽出結果 {blue: undefined, red= 'false' }
 * @returns 置換テキスト
 */
const textColorReplacer = (...args) => {
  const match = args.shift(); // argsの先頭から取出す => 一致した部分文字列
  const groups = args.pop();  // argsの末尾から取出す => キャプチャグループ全体の抽出結果
  const string = args.pop();  // argsの末尾から取出す => 分析中の文字列全体
  const index = args.pop();  // argsの末尾から取出す => 分析中の文字列の開始位置
  // 残りのパラメータは、各キャプチャグループの結果(正規表現での記載順)
  const capGrpResList = args;  // キャプチャグループの結果(配列)
  /**
   * グループ名からテキストを色付け
   * @param {string} groupName 
   * @param {string} match 
   * @returns 色付けしたテキスト
   */
  const colorGroupText = (groupName, match) => {
    // グループ名を分割
    const re = groupName.split('_');
    let element_color = [], not_element_color = [], italic = undefined, underline = undefined, strikethrough = undefined, bold = undefined;
    // reを分析
    groupName = '';
    re.forEach((elm) => {
      if (elm === '') { // '' is undefined.
        element_color.push(undefined);
      } else if (isHex(elm)) { // hex is color code.
        element_color.push(`#${elm}`);
      } else if (colors.some(col => (col === elm))) {
        element_color.push(elm);
        if (element_color.length > 2) { element_color.shift(); /* 先頭を削除 */ }
      } else {
        switch (elm) {
          case 'italic': italic = true; break;
          case 'underline': underline = true; break;
          case 'strikethrough': strikethrough = true; break;
          case 'bold': bold = true; break;
          default:
            not_element_color.push(elm);
            break;
        }
      }
    });
    // 色情報抜きのグループ名からクラス名を作る
    const className = (not_element_color.length > 0) ? (not_element_color.join('_')) : element_color[0];
    // 設定内容からfcol,bcolを決定
    const fcol = (element_color.length > 0) ? (element_color[0] ? element_color[0] : defaultColor.get(match)) : defaultColor.get(match);
    const bcol = (element_color.length > 1) ? (element_color[1]) : 'burlywood';
    // fcol, bcol, italicからstyle属性を決定
    const style = `${(fcol) ? `color:${fcol}; ` : ''}${(bcol) ? `background-color:${bcol};` : ''}${(italic) ? "font-style:italic;" : ''}`;
    // pri, pro
    let pri = '', pro = '';
    // styleが有効ならspan化
    pri = `<span${(className) ? ` class="${className}"` : ''}${(style) ? ` style ="${style}"` : ''}>`; pro = '</span>';
    // 修飾名の場合、pri, proに修飾内容を追記
    if (underline) { pri += `<u>`; pro = '</u>' + pro; }
    if (strikethrough) { pri += `<s>`; pro = '</s>' + pro; }
    if (bold) { pri += `<b>`; pro = '</b>' + pro; };
    //
    return `${pri}${htmlEscape(match)}${pro}`;
  };
  // 内容が格納されているグループのみテキスト化
  const result = Object.keys(groups).reduce((o, groupName) => {
    if (groups[groupName]) { o += colorGroupText(groupName, groups[groupName]) }
    return o;
  }, '');
  return result;
}; // end of textColorReplacer.
/**
 * テキストに色を付ける
 * @param {any} text  テキスト(ハズ
 * @param {RegExp} regExp  色付け正規表現 ※未指定時は適当な正規表現を割り当てる
 * @return {string}      色付け後テキスト
 */
const textColor = (text, re = /(?<blue>true)|(?<red>false)|(?<green>\d+)/gi) => {
  text = `${text}`; // 一応テキスト化しておく
  let preTag = '', proTag = '';
  // 置換してみる
  const result = text.replace(re, textColorReplacer);
  return result;
}; // end of textColor.

colorGroupText関数正規表現をデバッグしやすくなると思った機能を入れすぎたかな



[javscript]RegExpよりリテラルの方がムズイ

あいかわらず、javascriptのソースコードをreplaceAll(/…/g, myReplacer)で色付けしているうちに

`・・・`の器用な使い方を発見

const date = () => {
    const date = new Date();
    return new Intl.DateTimeFormat("ja-JP-u-ca-japanese", {
        dateStyle: "full",        timeStyle: undefined,        timeZone: "Asia/Tokyo",
    }).format(date);
};
const time = () => {
    const date = new Date();
    return new Intl.DateTimeFormat("ja-JP-u-ca-japanese", {
        dateStyle: undefined,        timeStyle: "full",        timeZone: "Asia/Tokyo",
    }).format(date);
};
const test1 (type) => {
  let result = '';
    if(type==='date') { result = `${ date() }`;
    if(type==='time') { result = `${ time() }`};
  return result;
}
test1('date');
test1('time');

すこし粘ってみる

・・・
(type) => {
  let result = `
    ${(type==='date')? `${ date() }` : ''}
    ${(type==='time')? `${ time() }` : ''}
    `;
  return result;
}

で通るらしい。

つまり、

`...${...`.....`...}..${...`.....`...}....`

とバッククォータ・リテラルの中で${…}すると、その中で また ` …..` が作れてしまう。

これをRegExp.replaceAll(text)で字句解析するのは無理っぽいなぁ

RegExp.exec(text)で1トークンごとに読んで、(`)バッククォート来た!別のRegExpに差し替えて・・・末端までたどりついたら、元のRegExpに戻りindexを差替えて・・・かな。

spreadSheetのパーサコンビネーションみたいに、

複数のRegExpパターンでimports/exportsみたいなことをする方が無難かな

# exmport:BQLITERAL
BQLITERAL:  ( ` ( '${'  |  '}'  | '.*' )*  ` )
# exmport:.
# main
COMMENT:    (/{2}.*$|\/\*\/?([^/]|[^*]\/|\r|\n)*\*\/)
・・・
BQLITERAL:  (`) # import(BQLITERAL)
 👈多分この部分は RegExp.exec()の戻り値のgroupsにBQLITERALがあったら、サブルーチン呼び出しみたいな感じかな
# .

それもつらいなぁ

( ( ?<= $ { ] ) | ( ・・・ ) | (?= } ) )

で逃げ切れるかな?

とりあえず今はこの辺

ps.すこし粘ってみた

((\$\{)([^\}]*)(\}))

この${…}パターンを

BQLITERALパターンに

BQLITERAL:  (`(\\\\|\\`|[^`]|\r|\n)*`)

組み込んで

(new)BQLITERAL:  (`(((\${)([^\}]*)(\}))|(\\\\|\\`|[^`]|\r|\n))*`)

みた。

試してみる

---`aaa${222`333444555`666}aaaa$bbbb${222`333444555`666}`---------
---`aaa${222`333${222`333444555`666}444555`666}aaaa$bbbb${222`333444555`666}`---------

サンプル1では

・・・
[BQLITERAL] : '`aaa${222`'
[SYMBOLE] : '333444555'
[BQLITERAL] : '`666}aaaa$bbbb${222`'
[SYMBOLE] : '333444555'
[BQLITERAL] : '`666}`'
・・・
[BQLITERAL] : '`aaa${222`'
[SYMBOLE] : '333$'
[L_BRACE] : '{'
[SYMBOLE] : '222'
[BQLITERAL] : '`333444555`'
[SYMBOLE] : '666'
[R_BRACE] : '}'
[SYMBOLE] : '444555'
[BQLITERAL] : '`666}aaaa$bbbb${222`'
[SYMBOLE] : '333444555'
[BQLITERAL] : '`666}`'
・・・

から

・・・
[BQLITERAL] : '`aaa${222`333444555`666}aaaa$bbbb${222`333444555`666}`'
・・・
[BQLITERAL] : '`aaa${222`333${222`333444555`666}444555`'
・・・

と多少改善はできてる。

けど、サンプル2では

---`aaa${222`333444555`666}aaaa$bbbb${222`333444555`666}`---------
---`aaa${222`333${222`333${222`333444555`666}444555`666}444555`666}aaaa$bbbb${222`333444555`666}`---------
・・・
[BQLITERAL] : '`aaa${222`333444555`666}aaaa$bbbb${222`333444555`666}`'
・・・
[BQLITERAL] : '`aaa${222`333${222`333${222`333444555`666}444555`'
・・・
[BQLITERAL] : '`666}aaaa$bbbb${222`333444555`666}`'
・・・

つまり${…} のネストは3段目でかなり厳しい。

`...${...`...`...}...${...`...`...}...`
や
`...${...`...${...`...`...}...`...}...${...`...`...}...` ※旧よりはマシな結果
`...${...`...${...`...${...`...`...}...`...}...`...}...${...`...`...}...`

色付けで確認してみると

「BQLITERAL_white_black」と色指定の名前に変えて

【↓組み合わせ】ボタンで正規表現を更新して

【色付け】ボタンを押すと・・・

多少は、マシってだけ。



[html]Quirks Mode

DevToolsに

Page layout may be unexpected due to Quirks Mode

ちゃんと

<DOCTYPE html>

あるけど・・・

<!DOCTYPE html>

が正解だった。

あれ?正解だと目立たない配色に

で灰色一色だったコードを貼ってみる。

って参照パーツの後のマージンが本体サイズ。

WP6.8ってBUGが多すぎな気がする。


/**
 * JSON.stringifyのreplacer
 * @param {*} key 
 * @param {*} value 
 */
const stringifyReplacer = (key, value) => {
  if (key !== '' && !value) {
    value = 'undefined';
  }
  return value;
};
/**
 * オブジェクトのプロパティを列挙
 * @param {object} object オブジェクト
 */
const objectPropertyStringify = (object) => {
  let ar = {};
  // for(..in object)
  for (const id in object) { ar[id] = object[id]; }
  // Object.keys(object)
  const keys = Object.keys(object);
  keys.forEach((id) => { ar[id] = JSON.stringify(object[id], stringifyReplacer, 0); });
  // Object.getOwnPropertyNames(object)
  const props = Object.getOwnPropertyNames(object);
  props.forEach((id) => { ar[id] = JSON.stringify(object[id], stringifyReplacer, 0); });
  // Object.getOwnPropertyNames(obj.__proto__)
  const prototypeProps = Object.getOwnPropertyNames(object.__proto__);
  prototypeProps.forEach((id) => { ar[id] = JSON.stringify(object[id], stringifyReplacer, 0); });
  // 纏め
  const txts = [];
  for (const id in ar) {
    // typeof value !== 'function' で メソッドを排除
    if (typeof object[id] !== 'function') {
      txts.push(`${id}:${textColor(ar[id])}`);
    }
  }
  //
  return `<ul><li>${txts.join('</li><li>')}</li></ul>`.replace('<li></li>', '');
};

チャント配色(コードハイライト)してくれてる!

何かバグってたのか。

JSだけでもちゃんと字句解析できたら自作でコードハイライトさせてみるか?

ちゃんと字句解析できたら???

ps.2025/4/18:とりあえずJavaScriptだけはString.replaceAll(RegExp,replacer)で字句解析できる範囲でコードハイライトが出来そう正規表現ができたみたいだから、WordPressのプラグインの作り方ってどうなってるのかな? 出来はまだまだだった


  • カテゴリー:
  • HTML

[WordPress]6.8の現状

まだまだ未テスト状態のプラグインだらけ

それでも動くなら問題ないけど

残念な結果になったプラグインは・・・

  1. Lite Syntax Highlighting
    • 【有効化】したら
      • 「重大な何たらがエラー発生」してページが真っ白
        • 削除済(合掌
  2. My WP Customize
    • 更新が来たので【更新】すると終わらない
    • 諦めて【削除】すると終わらない
    • pluginsフォルダからmy-wpフォルダを削除(合掌

記事の読み書きに支障はないけど

クイック編集の「保存」すると終わらない

データベースプラグイン画面のテーブル一覧がなかなか表示しない(遅

以前は/etc/hostsに自分のサーバー名を書いて無かったせいで自分へのセルフループが失敗してたが、今回は設定済。

WordPress関連のファイルを一式別の仮想ディスクにコピーって稼働させたら、設定の保存で書込み失敗するプラグインがでた。ファイルの所有者がrootだったせいでapacheに変更。



「javascript」失敗したら即throwしたい

try {
・・・
  const divSample1 = document.getElementById('sample1');
  if (!divSample1) {
    throw new Error('divタグ(id:sample1)が見つかりません');
  }
  const divSample2 = document.getElementById('sample2');
  if (!divSample2) {
    throw new Error('divタグ(id:sample2)が見つかりません');
  }
  ・・・
  const divSampleN = document.getElementById('sampleN');
  if (!divSampleN) {
    throw new Error('divタグ(id:sampleN)が見つかりません');
  }
・・・
} catch (ex) {
  console.error(ex.message);
}

と書きたくないのでNull 合体演算子 (??)を使って

try {
  ・・・
  const divSample = document.getElementById('sample1') ?? throw new Error('divタグ(id:sample1)が見つかりません');}
  const divSample = document.getElementById('sample2') ?? throw new Error('divタグ(id:sample2)が見つかりません');}
  ・・・
  const divSample = document.getElementById('sampleN') ?? throw new Error('divタグ(id:sampleN)が見つかりません');}
  ・・・
} catch (ex) {
  console.error(ex.message);
}

と書くと「throw」に赤い下線が付いて「式が必要です。ts(1109)」とエラるので・・・

/**
 * 投げだす
 * @param {string} msg 
 */
const throwMsg = (msg) => {
  throw new Error(msg);
}
・・・
try {
  ・・・
  const divSample = document.getElementById('sample1') ?? throwMsg ('divタグ(id:sample1)が見つかりません');}
  const divSample = document.getElementById('sample2') ?? throwMsg ('divタグ(id:sample2)が見つかりません');}
  ・・・
  const divSample = document.getElementById('sampleN') ?? throwMsg ('divタグ(id:sampleN)が見つかりません');}
  ・・・
} catch (ex) {
  console.error(ex.message);
}

で誤魔化せた。

式が必要な深い意味は思いつかないので、単に「throw」を式として認識してないダケだろう。

多用するとメンドクサイ事になるのは避けられないが・・・

※{美しくない}

とか言われそう。

心配なのはデバッグ中に式でExceptionすると

javascriptが処理を「本当」に投げ出す事がマレになるコトかな?(フッ



[apache]パスに.を含むurl

.backupとか見せたくないフォルダとかファイルを個別に.htaccessを作って書くのも面倒なんで

apacheのconfファイルに

## フルパス名にドットで始まるディレクトリィやファイルはブラウザから禁止
  <Directory ~ "\/\..+\/">
    Require all denied
  </Directory>
  <Files ~ "\/\..+\/">
    Require all denied
  </Files>
## .

って書くのはうまくいかないかな?matchなんで正規表現なんでディレクトリィやファイルのフルパス名のどこかに「.で始まる」ディレクトリィがあったらブラウザから禁止にできたっぽい。

ただ、

apacheでは短いパスでいくら禁止しても

そこから続く長いパスでRequireしたら通ってしまうが

単に合致したパターンの長さで判定してないとは「断定しにくい」・・・

何とも(判らん

## フルパス名にドットで始まるディレクトリィやファイルは外部から禁止
  <Directory ~ "\/\..+\/">
    Require all denied
    Require ip 192.168.xxx.xxx/24
  </Directory>
  <Files ~ "\/\..+\/">
    Require all denied
    Require ip 192.168.xxx.xxx/24
  </Files>
## .

と書き加えてreloadしたらLANから見えるので効果はあるっぽい。



[javascript]正規表現

以前作ったJSのUTF-16をSJISに変換するサンプルが時代の波にモマれ動かなくなってたので作り直し。

それにつけても非推奨が増える一方な感じがするJS。

同様に正規表現のデバッガも動かなくなっていた。(【javascript】 RegExp 正規表現デバッガ

でも正規表現で名前付きキャプショングループを使える様になってきたみたいだから良しとしよう。

※2016年の記事(9年も前か!)だし、単に使いこなせなかったかもしれないけどね。

今回は名前付きキャプショングループのおかげで内容をとても単純になった。

正規表現の/…/の中のパターンとオプションを手入力して【チェック】ボタンを押すと

new RegExp({正規表現パターン}, {オプション})

が動き、RegExpオブジェクトのプロパティを画面下の結果欄に表示する。

だけのハズだったが、

実際 サンプルをRegExe.execメソッドに与えてみないと

文法上正しいだけの正規表現になってしまうので、

【RegExp.exec(サンプル)をループ実行】ボタン

whie(true) {
  if({正規表現パターン}.exec({サンプル}) {
    #結果に出力を追記
  } else {
    break;
  }
  {無限ループチェック}
}

を追加した。

空の正規表現パターンを無限ループ内のexecメソッドに与えると空振りし続け

CPUファンが最大回転数になる上にブラウザが「メモリが~メッセージ」を出すので

空回りしない様にしてる。(つもり

名前付きキャプチャグループ名をCSSの色名にすれば、replaceメソッドに正規表現とリプレッサーを組み込めば、簡単にテキストの色付けができる様になってた。(笑

前回の苦労は何だったのかな?(只の徒労だな(昔は大変だったよね?(笑って忘れよう

【名前付きキャプチャグループ名で色付け】ボタン

{サンプル} .replace ( /{正規表現パターン}/{オプション} , {名前付きキャプチャグループ名で色付けする処理} )       

も追加した。

正規表現パターンを拡張しテキストの文字を全て色付けできたら「完成」なんだろうなぁ~

正規表現パターンが完璧なのにテキスト中に色指定無しがあれば、多分「シンタックスエラー」だから

replaceで「<span style=”color: xxx”>・・・</span>」部分を消去すれば、エラってる箇所を抽出できそうダケど、色指定をdarkgrayに差し替えるか色指定が無い部分に下線属性を付加した方が見つけやすそう。

正規表現の最後に何でもヒットするパターンに下線の名前を付ければ、

(?<blue>true)|(?<red>false)|(?<green>\d+)|(?<underline>.+)
で
aaaatruebbbbfalsecccc1234dddd
を色分けしてみると?

予想外の部分に下線が付くと思ったら、全部下線が付いてしまった(合掌

ま、気軽に進めよう(笑

以下、サンプルデータ。

(?<blue>true)|(?<red>false)|(?<green>\d+)
gi
aaaatruebbbbfalsecccc1234dddd

最後に画面が寂しいのでtitleとplaceholder属性を追記した。

今はtitle内容を改行して表示させるには\nと書いてもブラウザが”\n”と思ってしまうので、

テキストエディタ上で直にLFコードを入れる(Enterキー押下)しかなけど、気が付いたら\nって書けば改行してくれる様な気がする。

最近のテキストエディタは「Enterキー」入力をCR、LF、CRLFのいづれかに変更する機能を持つものが多いので何とかなるけどね。

ps.2025/4/16

画面はサンプルなデータを初期表示して試しやすく(具体的にはデバッグ)した。コードも少し変えてみた

結果にオブジェクトの内容を表示する処理を共通化してみた

JSONなオブジェクトでは十分だけど、

for(const propertyName in oobject)

クラスでは静的なプロパティしか見せたくないらしく出てこない。


/**
 * JSON.stringifyのreplacer
 * @param {*} key 
 * @param {*} value 
 */
const stringifyReplacer = (key, value) => {
  if (key !== '' && !value) {
    value = 'undefined';
  }
  return value;
};
/**
 * オブジェクトのプロパティを列挙
 * @param {object} object オブジェクト
 */
const objectPropertyStringify = (object) => {
  let ar = {};
  // for(..in object)
  for (const id in object) { ar[id] = object[id]; }
  // Object.keys(object)
  const keys = Object.keys(object);
  keys.forEach((id) => { ar[id] = JSON.stringify(object[id], stringifyReplacer, 0); });
  // Object.getOwnPropertyNames(object)
  const props = Object.getOwnPropertyNames(object);
  props.forEach((id) => { ar[id] = JSON.stringify(object[id], stringifyReplacer, 0); });
  // Object.getOwnPropertyNames(obj.__proto__)
  const prototypeProps = Object.getOwnPropertyNames(object.__proto__);
  prototypeProps.forEach((id) => { ar[id] = JSON.stringify(object[id], stringifyReplacer, 0); });
  // 纏め
  const txts = [];
  for (const id in ar) {
    // typeof value !== 'function' で メソッドを排除
    if (typeof object[id] !== 'function') {
      txts.push(`${id}:${textColor(ar[id])}`);
    }
  }
  //
  return `<ul><li>${txts.join('</li><li>')}</li></ul>`.replace('<li></li>', '');
};

アレレ?配色が効かない!

/**
 * JSON.stringifyのreplacer
 * @param {*} key 
 * @param {*} value 
 */
const stringifyReplacer = (key, value) => {
  if (key !== '' && !value) {
    value = 'undefined';
  }
  return value;
};
/**
 * オブジェクトのプロパティを列挙
 * @param {object} object オブジェクト
 */
const objectPropertyStringify = (object) => {
  let ar = {};
  // for(..in object)
  for (const id in object) { ar[id] = object[id]; }
  // Object.keys(object)
  const keys = Object.keys(object);
  keys.forEach((id) => { ar[id] = JSON.stringify(object[id], stringifyReplacer, 0); });
  // Object.getOwnPropertyNames(object)
  const props = Object.getOwnPropertyNames(object);
  props.forEach((id) => { ar[id] = JSON.stringify(object[id], stringifyReplacer, 0); });
  // Object.getOwnPropertyNames(obj.__proto__)
  const prototypeProps = Object.getOwnPropertyNames(object.__proto__);
  prototypeProps.forEach((id) => { ar[id] = JSON.stringify(object[id], stringifyReplacer, 0); });
  // 纏め
  const txts = [];
  for (const id in ar) {
    // typeof value !== 'function' で メソッドを排除
    if (typeof object[id] !== 'function') {
      txts.push(`${id}:${textColor(ar[id])}`);
    }
  }
  //
  return `<ul><li>${txts.join('</li><li>')}</li></ul>`.replace('<li></li>', '');
};

にしている。

後、文法解析用の字句解析にReExpの(…)|(…)|…|(…)な書き方用【↓組み合わせ】機能も追加。

ちゃんと字句解析できてるかと思いきや「初期色」が読み飛ばされていた。

キャプチャー名が名前以外の場合は適当に色を割り当ててます。(今は2色を交互に使ってる。

※2025/4/17 : 配色が赤・緑・赤・赤・緑・赤・赤・緑と変なので修正、空白にも配色してたので修正。読飛ばされた箇所は背景色を黒にしてみた。早速「:」忘れてたのに気が付く。

長いログを見ても判りにくいのでexecを実行させる際に「macthしたテキストのみ」結果に出るチェックボックスを追加してみた。

※2025/4/17 : 名無しキャプチャーグループのみの正規表現でも表示する様に修正

なるほど、BINOP単項演算子に見えたか

完成までの道程はまだ遠い

※適当なソースを貼って遊ぶとオモシロイかもしれないけど、ページを「保存」してローカルで遊びましょう。

/* ・・・ */の複数行コメントの字句解析が思わしくない。

  • Windowsから貼ると改行がCRLFになると正規表現のmオプションが暴走しやすい
    • 仕方がないからCRLFはLFに置換
  • /* コメント1 */ コード /* コメント2 */」と複数のコメントがあると
    • /* コメント1 */ コード /* コメント2 */」と一括りにしてしまう
  • /* コメント1 / コード / コメント2 /コード / コメント3 /」と複数のコメントがあると
    • / コメント1 / コード / コメント2 /コード / コメント3 */」と一括りにしてしまう
  • パターンを先読みアサーション((?=))、([\s\S]*)、後読みアサーション((?<=))
    • (?=ここから/*) ([\s\S]*) (?=*/ここまで)」も
    • ここから/* * */ここまで * ここから/* * */ここまで」と一括りにしてしまう
  • 初期表示のサンプルは/* … */は1つだけなので2度コピペすると↑を際限できます
  • とりあえず良さげなパターンが見つかった。
    • COMMENT: (/{2}.$|\/\*\/?([^/]|[^*]\/|\r|\n)*\*\/)
      • \/\*:つまり / *
      • [ \ s | \S ]* を使うと 最後に見つけた * / までブチ抜けくので
      • \/?([^/]|[^*]\/|\r|\n)* で頑張る
        • 先頭の\/?:/*直後に/があった場合のお守り
        • ([^/]|[^*]\/|\r|\n)*: */ 以外のパターンのつもり
          • ( ) * で中のパターンを0回以上繰り返し
            • [^/] | [^*] \/ | \r | \n
            • 非 / or 非 * and / or CR or LF  であるから
          • 非 / 非 * and / 改行のパターンを0回以上繰り返すパターンの意味
      • \*\/:つまり * /
    • CR: ([\r|\n]+)
    • 記事にペーストなんか違う?勝手に斜体になってる???
    • まさかWordPressの記事入力のエスケープシーケンスまで絡んでくるとは思わなんだ

結果に改行がそのまま出力してたので<br/>に変えた。

ついでに空白も&nbsp;や&emsp;に変えたらなぜか色設定が消えた!(あ、タグの中に空白がいっぱい

font-familyの設定もイジることにした見やすくなった。(結果オーライ

ps,2025/4/18

’ ・・・ ’の字句解析が思わしくない。

  • \’ ・・・・ ‘ も判定してしまう。
    • LITERAL:    (‘[^’]*’) では不完全らしいから
      • WQLITERAL:  (“[^”]*”) や QLITERAL:   (‘[^’]*’) もダメだろう。
  • でも普通はいきなり \’ なんて出てこない

コードの中の正規表現の後がズタズタだった・・・(涙

spreadSheetを作ってた時もBNF記述でハマってた。パーサーコンビネーターで作ってたから厳密な字句解析をすっ飛ばして token === ‘/.*/{flags}’ でいいや的な誤魔化しができた。

正規表現でコードハイライトのラスボスは正規表現

嫌すぎ

ps.2025/4/18:多少改善できたので更新。

TODO:/\\/な正規表現が苦手で、以下ボロボロになる。

text = text
  .replaceAll(/\\/g, '\\\\') 👈今この辺で滞っている
  .replaceAll(/\"/g, '\\"')
  ;
copyClipboardText(`new RegExp("${text}", "${flags}");`);

やっと片付いた(かもしれない

COMMENT:    (\/{2}.*$|\\/\\*\\/?([^/]|[^*]\\/|\\r|\\n)*\\*\\/)
CR:         ([\\r|\\n]+)
SPACE:      ([\\s]+)
BQLITERAL:  (\`(\\\\\\\\|\\\\\`|[^\`]|\\r|\\n)*\`)
LITERAL:    (\'(\\\\\\\\|\\\\\'|[^'])*\')
WQLITERAL:  ("(\\\\\\\\|\\\\"|[^"])*")
REGEXP:     (\\/(\\\\\\\\|\\\\/|[^\\/])*\\/[a-z]*)
REGION_B:   (s*#regions+[a-zA-Z0-9]+.*$)
REGION_E:   (s*#endregion$)
L_BRACE:    ({)
R_BRACE:    (})
L_PAREN:    (\\()
R_PAREN:    (\\))
L_BRACKET:  (\\[)
R_BRACKET:  (\\])
COMMMA:     (,)
COLON:      (:)
DOT:        (\\.)
BINOP:      (\\|\\||&&|===|!==|!=|==|\\+|<|>|\\?|<=|>=|-|\\*|\\/|%|=|!)
DELIMITER:  (;)
NULL:       (null)
VALUE_TYPE: (void|integer|bool|string)
SCOPE:      (public|private|friend|static)
THIS:       (this)
NEW:        (new)
BOOL:       (true|false)
SYMBOLE:    ([_a-zA-Z0-9]+)
NUMBER:     ([1-9][0-9]*[.]?[0-9]*)
※オプションは「gim」指定時のみ有効。

から【↓組合せ】ボタンで論理和で結合したパターンを貼り付ける。

このパターンとオプションからVScodeに貼ると、自動的にフォーマッタが働きグチャグチャになるので

"・・・"

とペーストする部分をクリックした後にそ~っとペーストしなければいけない。

※【コピー】ボタンでエスケープ処理済みのテキスト(↓参照)をクリップボードにコピーさせてからファイルにペースト。

const re = new RegExp(
  "/(?<COMMENT>\\/{2}.*$|\\/\\*\\/?([^/]|[^*]\\/|\\r|\\n)*\\*\\/)|(?<CR>[\\r|\\n]+)|(?<SPACE>[\\s]+)|(?<BQLITERAL>`(\\\\\\\\|\\\\`|[^`]|\\r|\\n)*`)|(?<LITERAL>'(\\\\\\\\|\\\\'|[^'])*')|(?<WQLITERAL>\"(\\\\\\\\|\\\\\"|[^\"])*\")|(?<REGEXP>\\/(\\\\\\\\|\\\\\\/|[^\\/])*\\/[a-z]*)|(?<REGION_B>s*#regions+[a-zA-Z0-9]+.*$)|(?<REGION_E>s*#endregion$)|(?<L_BRACE>{)|(?<R_BRACE>})|(?<L_PAREN>\\()|(?<R_PAREN>\\))|(?<L_BRACKET>\\[)|(?<R_BRACKET>\\])|(?<COMMMA>,)|(?<COLON>:)|(?<DOT>\\.)|(?<BINOP>\\|\\||&&|===|!==|!=|==|\\+|<|>|\\?|<=|>=|-|\\*|\\/|%|=|!)|(?<DELIMITER>;)|(?<NULL>null)|(?<VALUE_TYPE>void|integer|bool|string)|(?<SCOPE>public|private|friend|static)|(?<THIS>this)|(?<NEW>new)|(?<BOOL>true|false)|(?<SYMBOLE>[_a-zA-Z0-9]+)|(?<NUMBER>[1-9][0-9]*[.]?[0-9]*)",
  "gim");

な感じなら、使用しているjavascriptファイルは大体OK(だと思う

リテラル系の「 \ \ \ \ \ \ \ \ 」:「\」8キャラが酷い。

  • javascriptファイル上の「 \ \ \ \ \ \ \ \ 」:「\」8キャラ
    • をjavascriptエンジンが読み込んで
    • 「\\」を「\」に変換するので
    • \ \ \ \ 」:「\」4キャラのデータになる
      • これを渡されたRegExpクラスも
      • 「\\」を「\」に変換するので
      • \ \ 」:「\」2キャラのデータになる。

なのでRegExpに「 \ 」を2キャラ渡すために

javascriptのソースコードには「 \ \ \ \ \ \ \ \ 」と8キャラ書くことになる

なんてこったい。(知ってたけど

ついでにココ(段落)に貼るとWordPressのエスケープシーケンスが即反応するので、専用のプラグインに貼る方がいい。

ps.2025/4/19:少し調整

・テキストエリアでタブキーを入力できる様にした

・正規表現のキャプチャーグループ名に文字色と背景色を指定できるようした

COMMENT_RED_000000 な感じに書くと

色付け処理で、

グループ名を(_)で区切って「グループ名_文字色_背景色」な感じで色付けできる。

色番号の「#」はキャプチャーグループ名に使えないので「#」を除いた16進表記のみ書く。

これで、ちょっと「(」が読みにくいので色を変えるとかが簡単になった。

ps.2025/4/23

XMLのツリービュー表示で使う正規表現のデバッグをしていたら

正規表現
(?<attr_name>[-:a-z]+)(?<attr_sep>=)(?<attr_value>"[^"]*")|(?<attr_name>[-:a-z]+)|(?<SP>[\t\s\r\n]+)
サンプル
<style:style style:family="paragraph" style:name="a213">

一度のexec実行で複数のグループがヒットする正規表現の場合には・・・

[attr_name, attr_sep, attr_value] : '{attr_nameの抽出結果のみ}'

と最初の抽出結果しか表示してないコトに気付いたので

[キャプチャ1名]:'{キャプチャ1抽出結果}'、・・・[キャプチャn名]:'{キャプチャn抽出結果}'

の様な感じに変更した。

隣の「色付け」ボタンを押すとキャプチャ対象外の文字は赤で背景色が黒で表示するので、

あ、「<」と「>」を無視してるじゃん!

とか判りやすいと思う。



[javascript]コードは短い方が良い(かもしれない

const divMatchPattern = document.getElementById('matchPattern');
const txtMatchPattern = "/(\\/\\*[\\s\\S]*?\\*\\/|\\/{2,}・・・/g\n";
divMatchPattern.value = txtMatchPattern.toString();

というコードがあって、

id=matchPatternなオブジェクトが無い場合があるので

const divMatchPattern = document.getElementById('matchPattern'); if(divMatchPattern){
const txtMatchPattern = "/(\\/\\*[\\s\\S]*?\\*\\/|\\/{2,}・・・/g\n";
divMatchPattern.value = txtMatchPattern.toString(); }

とすると読みにくいから「保存(Ctrl+S)」すると

const divMatchPattern = document.getElementById('matchPattern');
if(divMatchPattern){
    const txtMatchPattern = "/(\\/\\*[\\s\\S]*?\\*\\/|\\/{2,}・・・/g\n";
    divMatchPattern.value = txtMatchPattern.toString();
}

となって長くなるから1行でも短くしようと捻って

for (const divMatchPattern of document.querySelectorAll('#matchPattern')) {
  const txtMatchPattern = "/(\\/\\*[\\s\\S]*?\\*\\/|\\/{2,}・・・/g\n";
  divMatchPattern.value = txtMatchPattern.toString();
}

とか

document.querySelectorAll('#matchPattern').forEach((divMatchPattern) => {
  const txtMatchPattern = "/(\\/\\*[\\s\\S]*?\\*\\/|\\/{2,}・・・/g\n";
  divMatchPattern.value = txtMatchPattern.toString();
});

とか

try {
  document.querySelector('#matchPattern').value = "/(\\/\\*[\\s\\S]*?\\*\\/|\\/{2,}・・・/g\n";
} catch() {}; ※とミスっても原因が~になるパターン

とか最後には

document.querySelector('#matchPattern') {左辺がnullじゃなければ右辺も続けて評価する演算子} .value = "/(\\/\\*[\\s\\S]*?\\*\\/|\\/{2,}・・・/g\n";

があったらいいなぁとか思う。

Null合体演算子(??)が近いけど、基本は || なので

const 結論=(Aプラン) ?? (Bプラン) ?? (冗談ではない)

的に

const ストーリィ展開=(なんだかわかないけど) ?? (なんかわかった) ?? もうどうなってもいいや

の様に使うものなので、

document.querySelector('#matchPattern') ?? .value = "/(\\/\\*[\\s\\S]*?\\*\\/|\\/{2,}・・・/g\n";

は期待通りには動かない。

「.」を「.$.」にすると左辺がnullだったらもうどうなってもいいやドット演算子があったらいいな

document.querySelector('#matchPattern').$.value = "/(\\/\\*[\\s\\S]*?\\*\\/|\\/{2,}・・・/g\n";

一応、try ・・・ catchで包まれていたらthrowするけど

try {
   document.querySelector('#matchPattern').$.value = "/(\\/・・・"; ※中で throw(undefined)する
   ※Throw.resume()で、ここに戻る
} catch (ex, stack) {
  if(ex) console.log(ex) ※ ex が undefinedなので
  else stack.resume();   ※ throwした直後に戻る。
                         ※ 状況は stack.stackを読む
                         ※  行番号とかカラムとかnullな処理箇所が判ると助かる
}

だといいな。

あとドット演算子(.)とアロー演算子(->)の違いの記事を読んだ感想。

昔のC言語では、メモリがとっても少なかったので作りがとても簡素で

簡素な構文解析に落とし込まないとメモリに入らない

というゲーム制作みたいな理由。

変数は基本的にアドレス+オフセット+サイズとして考えるポインタ変数でプリミティブな型変数はオフセットが0でサイズがプリセットで決まっているポインタ変数。

このため、構造体のドット演算子もポインタ変数のアロー演算子も「この変数の構造(オフセット)を見てオフセットを計算してね」という意味では同じだから一緒で良かったハズ。

しかし、基本な皆中身がポインタ変数なので、内部構造であるハズのポインタ変数を明示的に使われるとコンパイラは

  • 普通の変数は梱包済み
  • ポインタ変数は開梱済み

を切り分けて処理するのも面倒なので

※2通りの変数の種別があると毎度毎度似た様な処理が4通り必要になるのでウザい

仕方なく演算子(という表現上で人が指示する様に)を分けた様に思える。

昔のソースって概ね一本の長さが80列×25行程度に収まってたのもあるけどね。



[xterm.js]ssh接続その4

段々複雑になってきたので

xterm.jsの画面からは

  1. 画面からWebSocketで何か送信する
    • {
      • ssh : {
        • logon : {
          • username : xxxx
          • etc.
    • }…}
  2. ホスト側で受信
  3. JSONデータをアドオンのエイリアス(ssh)で配分する
    • { ssh : ・・・
    • sshエイリアスなアドオンのjsonRequestを呼び出す
  4. アドオンは受け取ったJSONデータから機能を実行する
    • { logon : ・・・
    • 処理名(logon)を読み取ってlogon処理を実行する
    • logon処理
      • { username : xxxx, …}
  5. 処理名が何か出力したらWebSocketで返信する

にすると後付けが楽な気がしたので、NodeJsで動く部分をアドオン化してみたら更に複雑になった。

├── package.json
├── package-lock.json
├── index.js
├── lock_file.js
├── tree.txt
├── web_socket_entity.js
└── addon
  ├── package.json
  ├── base_addon.js
  ├── js_yaml
  │├── package.json
  │└── js_yaml.js
  └── ssh_client
    ├── package.json
    ├── package-lock.json
    └── ssh_client.js

アドオンフォルダ(./addon)にプロジェクトごとコピーする方式。

AddonManagerのsetupで、アドオンフォルダ(./addon)の中のフォルダにある

package.jsonのmainかexportをからモジュールのjsファイルを見つけて

エイリアス付きでtypeListsにリストアップするダケなのにとっても長い。

/**
 * アドオンマネジャクラス
 */
export class AddonManager extends BaseAddon {
 ・・・省略・・・
  /**
   * リスト
   */
  typeLists = {};
 ・・・省略・・・
  /**
   * コンストラクタ
   */
  constructor() {
    super();
  };
  /**
   * ./addonディレクトリィのパッケージを検索
   * @param (*) pathAddonsDir
   */
  setup = (pathAddonsDir, allAddonInfo) => {
    this.allAddonInfo = allAddonInfo;
    return new Promise((resolve, reject) => {
      fs.readdir(pathAddonsDir, { encoding: 'utf-8', withFileTypes: true, recursive: false },
        (err, dirents) => {
          /**
           * error
           */
          if (err) {
            console.error(err);
            reject(err);
            return;
          }
          /**
           * ディレクトリィのみに絞込む
           */
          dirents = dirents.filter((d) => d.isDirectory());
          /**
           * とりあえず配列分ループ
           */
          const arP = dirents.map((dirent) => {
            return new Promise((resolve, reject) => {
              const addonPath = `${pathAddonsDir}/${dirent.name}`;
              console.log(addonPath);
              // dirent配下のpackage.jsonを読む
              const packageJsonPathname = `${addonPath}/package.json`;
              const packageJsonText = fs.readFileSync(packageJsonPathname);
              const packageJson = JSON.parse(packageJsonText);
              const mainFile = packageJson.main || packageJson.exports;
              if (mainFile !== undefined) {
                const mainFilePathname = `${addonPath}/${mainFile}`;
                import(mainFilePathname)
                  .then((module) => {
                    // 動的に読み込まれたモジュール
                    const addonModule = new module.default;
                    // アドオンリストに追加
                    this.setAddonList(addonModule.addonAlias, addonModule);
                    resolve(true);
                  })
                  .catch((ex) => {
                    console.error(ex);
                    reject(ex);
                  });
              } else {
                console.error(`addonSetup : ${packageJsonPathname} not found main or exports`);
              }
            });
          });
          Promise.all(arP)
            .then((values) => {
              resolve(true);
            });
        }
        // end of for (const dirent of dirents)
      );
    });
  };
 ・・・省略・・・
};

アドオンを呼び出す時は

AddonManager::getAddonObject({アドオンのエイリアス})でオブジェクトを取得

  /**
   * アドオン・オブジェクトを取得
   * @param {*} alias 
   * @returns addon
   */
  getAddonObject = (alias) => {
    const addonInfo = this.typeLists['addon'][alias];
    if (addonInfo) {
      const object = new addonInfo.constructor(this.allAddonInfo[alias]);
      return object;
    } else {
      return undefined;
    }
  };

画面からの要求を{アドオンのオブジェクト}::jsonRequest(WebSocket, json)から

アドオンオブジェクトを作成し実行させている。

  /**
   * JSONリクエスト処理
   * @param {*} webSocketEntity 
   * @param {*} json 
   * @param {*} addonObjectList 
   */
  jsonRequest = (webSocketEntity, json, addonObjectList) => {
    const addonModules = this.typeLists['addon'];
    for (const alias in json) {
      const addon = addonObjectList[alias] ?? this.getAddonObject(alias);
      if (!addonObjectList[alias]) { addonObjectList[alias] = addon; }
      if (addon) {
        try {
          addon.request(webSocketEntity, json[alias]);
        } catch (ex) {
          console.log(`AddonManager::jsonRequest : unknown addon alias  '${alias}'`);
        }
      } else {
        console.log(`AddonManager::jsonRequest : unknown addon alias  '${alias}'`);
      }
    }
  };

レスポンスはアドオンオブジェクトにWebSocket宛に送信してもらった。

  /**
   * クライアントに返信する処理
   * @param {string} type 
   * @param {string} commandName 
   * @param {any} data 
   */
  sendClient = (type, commandName, data) => {
    //console.log(`${commandName} : ${data}`);
    const responce = {};
    responce[type] = data;
    const blob = new Blob([JSON.stringify(responce)], { type: "application/json" });
    this.connect.send(blob);
  };

やっと画面側もtype毎に処理を分けないといけない事に気が付く。

めんど




top