2016-07-17 4 views
2

ストーリー:CSSセレクタからクラス名を抽出する方法は?

私は現在、CSSセレクタロケータ内のブートストラップレイアウト指向と角技術的なクラスを使用することについて警告するESLintルールを構築しています。現在、私は文字列のアプローチで単純な部分文字列を使用しています:

for (var i = 0; i < prohibitedClasses.length; i++) { 
    if (node.arguments[0].value.indexOf(prohibitedClasses[i]) >= 0) { 
    context.report({ 
     node: node, 
     message: 'Unexpected Bootstrap class "' + prohibitedClasses[i] + '" inside a CSS selector' 
    }) 
    } 

しかし、信頼性が証明されていません。たとえば、.col-sm-offset-11 CSSセレクタでエラーが2回発生すると、col-sm-offset-1col-sm-offset-11の両方が使用されます。複数の疑似クラスを使用して、より複雑なセレクタを簡単に破ることができます。


質問:

CSSセレクタからクラス名を抽出する最も信頼性の高いな方法は何ですか?ここで


は(改善すべき)私たちがカバーすべきサンプルテストリストです:私たちは~=を残し^=$=*=部分クラスのフィルタ値をスキップする必要が

.col-sm-push-4     // -> ['col-sm-push-4'] 
.myclass.col-lg-pull-8   // -> ['myclass', 'col-lg-pull-8'] 
[class*='col-md-offset-4']  // -> [] 
[class$=col-md-offset-11]  // -> [] 
[class~="col-md-10"] .myclass // -> ['col-md-10', 'myclass'] 
.col-md-10,.col-md-11   // -> ['col-md-10', 'col-md-11'] 

注意(感謝コメントのために)。

+2

私は@adeneoに同意します。興味深い質問ですが、* "このライブラリを使用する" *の答えはあまりありません。 「どのように」の問題に直接対処するものではありません。 –

+0

@squint良い点。私は完全に "方法"に対処する答えに開いています。面白い問題と私がそれに近づいたやり方を分かち合いたい。ありがとう! – alecxe

+0

クラス名が* =と$ =属性セレクタから抽出されるのは、これらの部分文字列を含むクラス名と要素が一致しないが、それらと等しくないと思わない限り、クラス名を抽出することは信頼できません。 – BoltClock

答えて

1

node-css-selector-parserという名前のパッケージには、クラス名を抽出するための「使い方」の部分が欠けています。ギャップを埋め、ここに私が問題にそれを適用した方法です。 node-css-selector-parser

、我々はドット(例えば.myclass)で使用されるクラス名や属性セレクタ(例えば[class*=test])内部で使用されるクラス名を解析するCSSセレクタを解析し、結果の型に基づいてすることができます

// setup up CSS selector parser 
var CssSelectorParser = require('css-selector-parser').CssSelectorParser 
var parser = new CssSelectorParser() 

parser.registerSelectorPseudos('has', 'contains') 
parser.registerNestingOperators('>', '+', '~') 
parser.registerAttrEqualityMods('^', '$', '*', '~') 
parser.enableSubstitutes() 

function extractClassNames (rule) { 
    var classNames = [] 
    // extract class names defined with ".", e.g. .myclass 
    if (rule.classNames) { 
    classNames.push.apply(classNames, rule.classNames) 
    } 

    // extract class names defined in attributes, e.g. [class*=myclass] 
    if (rule.attrs) { 
    rule.attrs.forEach(function (attr) { 
     if (attr.name === 'class') { 
     classNames.push(attr.value) 
     } 
    }) 
    } 

    return classNames 
} 

module.exports = function (cssSelector) { 
    try { 
    var result = parser.parse(cssSelector) 
    } catch (err) { 
    // ignore parsing errors - we don't want it to fail miserably on a target machine during a ESLint run 
    console.log('Parsing CSS selector: "' + cssSelector + '". ' + err) 
    return [] 
    } 

    // handling empty inputs 
    if (!result) { 
    return [] 
    } 

    var classNames = [] 

    if (result.type === 'ruleSet') { 
    var rule = result.rule 
    while (rule) { 
     classNames.push.apply(classNames, extractClassNames(rule)) 
     rule = rule.rule 
    } 
    } else if (result.type === 'selectors' && result.selectors) { 
    result.selectors.forEach(function (selector) { 
     classNames.push.apply(classNames, extractClassNames(selector.rule)) 
    }) 
    } 
    return classNames 
} 

standardコードスタイルが使用されているため、たとえば、行末には;がありません)。

これは私にとってはうまくいくことがわかりました。この状態では、このコードは、理想的にスキップする必要がある^=,$=および*=に渡される部分クラス値も抽出することに注意してください。

関連する問題