2017-01-10 8 views
2

JavaScriptオブジェクトを通じてglobstarスタイルの**検索をサポートするにはどうすればよいですか?オブジェクトにglob **を実装する方法は?

これは、照合対象にこれらの特殊な***のプロパティが含まれていて、正確に一致しない場合に一致するという点を除いて、lodashの_.getのようなものです。以下のコード例で

{ **: { middleName: 3 }}ルールは、次のパスと一致する必要があり:

['middleName'] 
['clients', 'middleName'] 
['clients', '0', 'middleName'] 

**ためマッチ0以上の要素なので、{**: { middleName: x }}が本質的'middleName'で終わる任意の配列と一致し、xを返しています。単一レベル(正確に1つの要素の任意の値を有する)と一致*ルールがありますので

しかし、それは第二の経路ではなく、{ lastName: 2 }と評価させ、**よりも優先すべきです。

実際には、重複する「ルール」を書くべきではないので、あまり優先順位を気にしませんが、**の実装方法を理解することはできません。

もっと実践的な例が必要な場合は、これを使用する予定です:1,2,3の数字はバリデータ関数に置き換えられ、 "パス"は<input>の名前になります。このようにして、自分のフォームの検証ルールを指定できます。

また、私は葉ノードを返すことしか望んでいないので、それらのうちの1つが{ lastName: 2 }を返すという事実は奇妙なものですが、私はそれほど心配していません。それが葉とノードのマッチだから**がこれよりも優先されたとすれば、それはもっと良いと思います。

コード:

function glob(object, path, defaultValue) { 
 
    let [first, ...rest] = path; 
 
    let value = object[first]; 
 
    if (value === undefined) { 
 
    value = object['*']; 
 
    if (value === undefined) { 
 
     // TODO: support ** 
 
     return defaultValue; 
 
    } 
 
    } 
 
    if (rest.length) { 
 
    return glob(value, rest, defaultValue); 
 
    } 
 
    return value; 
 
} 
 

 
let rules = { 
 
    firstName: 1, // matches ['firstName'] 
 
    clients: { 
 
    '*': { 
 
     lastName: 2, // matches ['clients', anything, 'lastName'] 
 
    } 
 
    }, 
 
    '**': { 
 
    middleName: 3, // matches [...anything, 'middleName'] 
 
    } 
 
} 
 

 
console.log(glob(rules, ['firstName'])); // 1 
 
console.log(glob(rules, ['clients', '0', 'lastName'])); // 2 
 
console.log(glob(rules, ['clients', '0', 'middleName'])); // should be 3 
 
console.log(glob(rules, ['clients', 'middleName'])); // should be { lastName: 2 } or 3, whatever's easier to implement 
 
console.log(glob(rules, ['middleName'])); // should be 3

+0

「JavaScriptオブジェクトを通じてglobstarスタイルの**検索をサポートするにはどうすればよいですか?」あなたは文字列(あなたは "パス"を参照してください)の配列を検索していませんか?問題文はあまり混乱しないかもしれません。 – spinkus

+0

@spinkusええ、私はそれが少し混乱していることを知っています。私は配列/パスを通して検索していません - パスはオブジェクトのキーとして使用されます。オブジェクトにこれらの特別な '*'と '' ** 'キーを入れることができる点を除けば、これはlodashの[_.get](https://lodash.com/docs/4.17.2#get)のようなものです。 – mpen

答えて

2

問題たくさんグロブファイルパスのように思えます。コード内のルールオブジェクトはちょっと変わったようです。あなたがそれをどうやって終わったのか、そのより広い目的が何であるかはわかりませんが...私はあなたのルールをオブジェクトからグローバルパスにリファクタリングできると思います。グッビングのためのJSパッケージがたくさんあります。以下はminimatch globberを使ったリファクタです(元のリストにルールを追加して、glob式で冗長性を減らす方法を示しています)。それはより多くの機能をサポートしているので、より複雑以外 -

var minimatch = require("minimatch") 
var _ = require('underscore') 

rules = { 
    'firstName': 1, 
    'clients/*/lastName': 2, 
    '**/middleName': 3, 
    'people/*/+(middleName|lastName)': 4, 
} 
rule_keys = _.keys(rules).sort().reverse() // Force a well defined match order. 

function glob(rules, path) { 
    path = path.join('/') 
    for(r of rule_keys) { 
    if(minimatch(path, r)) { 
     return rules[r]; 
    } 
    } 
} 

paths = [ 
    [['firstName'], "1"], 
    [['clients', '0', 'lastName'], "2"], 
    [['clients', '0', 'middleName'], "should be 3"], 
    [['clients', 'middleName'], "should be 2|3"], 
    [['middleName'], "should be 3"], 
    [['people', '0', 'middleName'], "should be 4"], 
]; 

for(p in paths) { 
    console.log(glob(rules, paths[p][0]), paths[p][1]); 
} 

実際、minimatch実装は、おそらくあなたが示したものに似たオブジェクトに文字列式を解釈します。

+0

はい、ファイルパスグロビングと似ています。そのためグロビングと呼ばれています:-)ルールフォーマットは、あなたがそこに持っているもののネストされたバージョンであり、多くのルールを追加すると冗長性が少し減ります私は '/'の代わりにセパレータとして '.'を使用しています。なぜなら、実際にはファイルパスではなく、オブジェクトパスであり、ドットはJSや他のプログラミング言語でより一般的です。私は実際にminimatchを使用するとは考えていませんでした。私が望むやり方で動作させるためには、たくさんのオプションを無効にしなければならないと思います。しかし、私の構文を変更する必要はありませんのファン。 – mpen

+1

@mpen "ルール形式は...多くのルールを追加すると冗長性が少し減ります"。 minimatchは括弧と "extglob"(+(a | b)のような)拡張をサポートして冗長性を減らします。これらの拡張はおそらくオブジェクトフォーマットnoよりも冗長性を改善するでしょうか?例を示す答えが更新されました。 – spinkus

+0

しかし、プロパティ値は異なる可能性があります。 1つのルールで両方を照合するのは理想的ではありません。 – mpen

関連する問題