Grid.jsの検索をOR検索に対応させる方法

# はじめに
Javascriptで表を表示するためにGrid.jsを使用していたが，標準仕様の検索ではOR検索に対応していない．
複数のキーワードを半角スペースで区切って入力することで，それらすべての単語を含む検索に対応させることにした．

# 動作環境
- Windows10
- VisualStudioCode v1.74.2
- Node.js v18.12.1
- npm v8.19.2
- Typescript v4.9.4

# やったこと
## ソースコードの取得
[GitHub](https://github.com/grid-js/gridjs "Grid.js(GitHub)")よりGrid.jsのソースコードを取得

## 変更するソースファイルの確認
変更するソースは```/src/operator/search.ts```
``` typescript: /src/operator/search.ts
import Tabular from '../tabular';
import { VNode } from 'preact';
import { HTMLContentProps } from '../view/htmlElement';
import { OneDArray, TCell, TColumn } from '../types';

export default function (
  keyword: string,
  columns: OneDArray<TColumn>,
  ignoreHiddenColumns: boolean,
  tabular: Tabular,
  selector?: (cell: TCell, rowIndex: number, cellIndex: number) => string,
): Tabular {
  // escape special regex chars
  keyword = keyword.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');

  return new Tabular(
        // 中略
        return new RegExp(keyword, 'gi').test(data);
      }),
    ),
  );
}
```

どうやら，正規表現RegExpに変数keywordで文字列を渡し，dataの中身に一致すればTrueを返すような仕組みで検索結果を判断しているらしい．
このkeywordで書かれた引数をor検索に対応させた文字列にすればうまくできそう．．．

## 対応方針
正規表現でのorは各キーワードをパイプ( | )で区切ればよいので，keywordとして渡っている変数をパイプで区切り，RegExpの引数として渡すことにする．
| 正規表現 | 意味 |
|:-:|:-:|
| AAA\|BBB  | AAAまたはBBB  |

## 変更内容
``` typescript: /src/operater/search.ts(変更後)
export default function (
  keyword: string,
  columns: OneDArray<TColumn>,
  ignoreHiddenColumns: boolean,
  tabular: Tabular,
  selector?: (cell: TCell, rowIndex: number, cellIndex: number) => string,
): Tabular {
  // ---変更箇所ここから ---
  keyword = keyword.replace(/[-[\]{}()*+?.,\\^$|#]/g, '\\$&');    
  while (keyword.indexOf('  ') !== -1) {
    keyword = keyword.replace('  ',' ');
  };
  let sp_key = keyword.split(' ');
  // ---変更箇所ここまで ---

  return new Tabular(
        // 省略
          data = String(cell.data);
        }
        
        // ---変更箇所ここから---
        return new RegExp(sp_key.join('|'), 'gi').test(data);
        // ---変更箇所ここまで ---
      }),
    ),
  );
}
```

## 変更内容の説明
オリジナル版ではkeywordに特殊文字が含まれていた場合，エスケープ用のバックスラッシュが挿入されるようになっていた．今回の変更では半角スペースの前にエスケープは不要なため，replace処理から半角スペース(\s)を除外する．
```diff_typescript
-  keyword = keyword.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
+  keyword = keyword.replace(/[-[\]{}()*+?.,\\^$|#]/g, '\\$&');    
```
while文を用いて，半角スペースが連続した場合に1つに変換する処理を追加した．半角スペース2個を1個に変換し，半角スペースが2連続している場所をindexOf関数で検索，該当箇所がない時にループを抜けるようにした．
```typescript
  // 半角スペース2個がkeywordの中にあるか判定(なければ-1を返す)
  while (keyword.indexOf('  ') !== -1) { 
    // 半角スペース2個を半角スペース1個に置換
    keyword = keyword.replace('  ',' ');
  };
```


最後に，splitに半角スペースを指定することで，文字列keywordを文字列配列sp_keyに分割した．
```typescript
  // 半角スペースで文字列を分割
  let sp_key = keyword.split(' ');
```
sp_keyのjoinメソッドにパイプを指定することで，文字列配列sp_keyをパイプ(|)で区切った文字列に変換し，RegExpの引数として渡す．
```diff_typescript
  return new Tabular(
        // 省略
          data = String(cell.data);
        }       
-        return new RegExp(keyword, 'gi').test(data);
+        return new RegExp(sp_key.join('|'), 'gi').test(data);
      }),
    ),
  );
}
```

## 動作確認
変更した```search.ts```を含むjsファイルをコンパイルして作成する．
コンパイルにはnpmを利用する．
ターミナルのカレントディレクトリにpackage.jsonのあるフォルダを指定し，以下を実行
```terminal: ターミナル
npm run build:grid
```

これにより，```/dist```フォルダ下にjsファイルが作成されるため，自分が使用したいjsファイルを呼び出す．

# 終わりに
初めてのJavascript，Typescriptでソースコードを読み解くのに手間取ったが，なんとか所望の処理を達成できて満足である．

今見返してみると，splitで配列に分割しなくてもreplaceで半角スペースをパイプに直接置換したほうが早かったかもしれない．．．