正規表現でカラーコードの場合のみダブルクーテーションを外すJavaScriptを書く

前提

現在、arm-band/kiribi_ususamaで、ejsの変数とScssで共通の値を使用したいと考え、1つのYAMLファイル(commonvar.yml)に記述する方法を採用しています。

commonvar.ymlはヘッダの高さやメインカラーなどを記述しています。

color: "#333"
bg-color: "#fff"
main-color: "#00f"
navbar-height: 80px

ejsにcommonvar.ymlの内容を渡すために、gulp-ejsを使用して以下のようなタスクを組んでいます(簡略化のために途中関係のないところは省略したり修正したりしています)。

gulp.task('ejs', () => {
    const strOrigin = fs.readFileSync(FILEPATH + 'commonvar.yml', { encoding: 'UTF-8' })
    const commonVar = yaml.parse(strOrigin)
    return gulp.src(${SRC_EJS_PATH}/**/*.ejs)
    .pipe(plumber())
    .pipe(data((file) => {
        return { 'filename': file.path }
    }))
    .pipe(ejs({ commonVar }))
    .pipe(rename({ extname: '.html' }))
    .pipe(gulp.dest(DIST_HTML_PATH))
})

fs.readFileSyncを利用してファイルを読み込み、yamlとしてパースしてcommonVarに代入。.pipe(ejs({ commonVar }))でejsに渡す、と。

一方、Scssは直接渡す方法がなさそうなので、以下のようにしています。

gulp.task('yaml2sass', done => {
    const strOrigin = fs.readFileSync(FILEPATH + 'commonvar.yml', { encoding: 'UTF-8' })
    let strDist = ''
    let strArray = strOrigin.split("\n")
    for(let i = 0; i < strArray.length; i++) {
        if(!(i === strArray.length - 1 && strArray[i].length === 0)) { //最後の空行以外
            strDist += `$${strArray[i]};\n` //`$VARIABLE-NAME: VALUE;`と最初に`$`、最後に`;`を付ける形にする
        }
    }
    strDist = strDist.replace(/\"/g, '') //ダブルクォーテーションを外す
    fs.writeFileSync(`${SRC_SCSS_PATH}/_var.scss`, strDist) //`_var.scss`として出力
    done()
})

commonvar.ymlをテキストファイルとして読み込み、Scssの構文に(無理やり)変換し、scssファイルとして出力、と。もっと上手い方法があれば良いのですが……。

経緯

ここまでの前提を基に、今回は以下のようなニーズを満たしたいと考えました。

  1. キービジュアルで使うキャッチコピー的なテキストが存在、かつ1文字ずつspanタグを付与したい(ejsでfor文で回す)
  2. Scssで一文字ずつエフェクトを付けたい(animation-delayを1.のspanごとにずらしたいので、Scssで文字数カウント(str-length)をしたい)

そこで、「commonvar.ymlにキャッチコピーを記述しておけば、両方で使えるのではないか?」と考えたわけです。

color: "#333"
bg-color: "#fff"
main-color: "#3dfa7a"
navbar-height: 80px
catch1: "\"オブジェクト\"を制する者は、"
catch2: "JavaScriptを制する!"

例えばこんな感じで、catch1, catch2を追加したわけです。

ただ、このままだとダブルクォーテーションは全て外されてしまうので、Scss側でcatch1, catch2は構文エラーになってしまいます。

そこで、yaml2sassタスクの中のダブルクォーテーションを外す処理をなくして、commonvar.ymlのカラーコードのダブルクォーテーションを外してしまえば良さそうです。

color: #333
bg-color: #fff
main-color: #3dfa7a
navbar-height: 80px
catch1: "\"オブジェクト\"を制する者は、"
catch2: "JavaScriptを制する!"

しかし、これではejsタスクでカラーコードが上手く認識されず、theme-colorが空文字列になってしまいました。

課題

前置きが長くなりました。やっと本題です。

ここまでの経緯を踏まえて、この課題を解決するためにcommonvar.ymlのうち、「値がカラーコードであるもののみダブルクォーテーションを外す」ようにyaml2sassタスクの中の処理を変更することにしました。

ということで、修正した結果が以下のコードとなります。

//元のコード
    strDist = strDist.replace(/\"/g, '')
//今回修正したコード
    strDist = strDist.replace(/\"#([\da-fA-F]{6}|[\da-fA-F]{3})\"/g, function() {
        return arguments[0].replace(/\"/g, '')
    })

コールバック関数はtestmatchにはなさそうだったので、replaceを二段構えにする形となりました。

外側のreplaceの第一引数が正規表現で(前後にダブルクーテーション付きの)カラーコードを判定している部分。

条件にマッチした場合にコールバック関数に入り、内側のarguments[0]にマッチした部分の文字列が入っています。

そのため、arguments[0]のダブルクォーテーションを外せば、課題で上げた「値がカラーコードであるもののみダブルクォーテーションを外す」という処理が実現できます。

ということで、これでテストプログラムを書いてOKだったので、採用。無事にニーズを満たすことができました。

参考

この記事を書いた人

アルム=バンド

フロントエンド・バックエンド・サーバエンジニア。LAMPやNodeからWP、Gulpを使ってejs,Scss,JSのコーディングまで一通り。たまにRasPiで遊んだり、趣味で開発したり。