@markuplint/selector
Advanced tools
Comparing version 3.0.0-alpha.2105 to 3.0.0-rc.0
@@ -5,2 +5,4 @@ "use strict"; | ||
const aria_pseudo_class_1 = require("./extended-selector/aria-pseudo-class"); | ||
const aria_role_pseudo_class_1 = require("./extended-selector/aria-role-pseudo-class"); | ||
const content_model_pseudo_class_1 = require("./extended-selector/content-model-pseudo-class"); | ||
const selector_1 = require("./selector"); | ||
@@ -14,3 +16,5 @@ const caches = new Map(); | ||
instance = new selector_1.Selector(selector, { | ||
aria: (0, aria_pseudo_class_1.ariaPseudoClass)(specs), | ||
model: (0, content_model_pseudo_class_1.contentModelPseudoClass)(specs), | ||
aria: (0, aria_pseudo_class_1.ariaPseudoClass)(), | ||
role: (0, aria_role_pseudo_class_1.ariaRolePseudoClass)(specs), | ||
}); | ||
@@ -17,0 +21,0 @@ caches.set(selector, instance); |
import type { SelectorResult } from '../types'; | ||
import type { MLMLSpec } from '@markuplint/ml-spec'; | ||
export declare function ariaPseudoClass(specs: MLMLSpec): (content: string) => (el: Element) => SelectorResult; | ||
/** | ||
* Version Syntax is not support yet. | ||
*/ | ||
export declare function ariaPseudoClass(): (content: string) => (el: Element) => SelectorResult; |
@@ -5,29 +5,38 @@ "use strict"; | ||
const ml_spec_1 = require("@markuplint/ml-spec"); | ||
const roleIsRegxp = /^roleis/gi; | ||
function ariaPseudoClass(specs) { | ||
/** | ||
* Version Syntax is not support yet. | ||
*/ | ||
function ariaPseudoClass() { | ||
return (content) => (el) => { | ||
var _a, _b; | ||
const aria = ariaPseudoClassParser(content); | ||
const name = (0, ml_spec_1.getAccname)(el); | ||
switch (aria.type) { | ||
case 'hasName': { | ||
const name = (0, ml_spec_1.getAccname)(el); | ||
if (name) { | ||
return { | ||
specificity: [0, 1, 0], | ||
matched: true, | ||
nodes: [el], | ||
has: [], | ||
}; | ||
} | ||
return { | ||
specificity: [0, 1, 0], | ||
matched: !!name, | ||
matched: false, | ||
}; | ||
} | ||
case 'hasNoName': { | ||
const name = (0, ml_spec_1.getAccname)(el); | ||
if (!name) { | ||
return { | ||
specificity: [0, 1, 0], | ||
matched: true, | ||
nodes: [el], | ||
has: [], | ||
}; | ||
} | ||
return { | ||
specificity: [0, 1, 0], | ||
matched: !name, | ||
matched: false, | ||
}; | ||
} | ||
case 'roleIs': { | ||
const computed = (0, ml_spec_1.getComputedRole)(specs, el, (_a = aria.version) !== null && _a !== void 0 ? _a : '1.2'); | ||
return { | ||
specificity: [0, 1, 0], | ||
matched: ((_b = computed.role) === null || _b === void 0 ? void 0 : _b.name) === aria.role, | ||
}; | ||
} | ||
} | ||
@@ -55,14 +64,3 @@ }; | ||
} | ||
if (roleIsRegxp.test(query)) { | ||
const role = query.replace(roleIsRegxp, ''); | ||
if (!role) { | ||
throw new SyntaxError(`Unsupported syntax: ${syntax}`); | ||
} | ||
return { | ||
type: 'roleIs', | ||
role, | ||
version, | ||
}; | ||
} | ||
throw new SyntaxError(`Unsupported syntax: ${syntax}`); | ||
} |
import type { Specificity, RegexSelector } from './types'; | ||
export declare type SelectorMatches = SelectorMatched | SelectorUnmatched; | ||
declare type SelectorMatched = { | ||
export type SelectorMatches = SelectorMatched | SelectorUnmatched; | ||
type SelectorMatched = { | ||
matched: true; | ||
@@ -9,3 +9,3 @@ selector: string; | ||
}; | ||
declare type SelectorUnmatched = { | ||
type SelectorUnmatched = { | ||
matched: false; | ||
@@ -12,0 +12,0 @@ }; |
"use strict"; | ||
var _SelectorTarget_combinedFrom, _SelectorTarget_selector; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.matchSelector = void 0; | ||
const tslib_1 = require("tslib"); | ||
const is_1 = require("./is"); | ||
@@ -43,14 +45,15 @@ const regex_selector_matches_1 = require("./regex-selector-matches"); | ||
constructor(selector) { | ||
this._combinatedFrom = null; | ||
this._selector = selector; | ||
_SelectorTarget_combinedFrom.set(this, null); | ||
_SelectorTarget_selector.set(this, void 0); | ||
tslib_1.__classPrivateFieldSet(this, _SelectorTarget_selector, selector, "f"); | ||
} | ||
from(target, combinator) { | ||
this._combinatedFrom = { target, combinator }; | ||
tslib_1.__classPrivateFieldSet(this, _SelectorTarget_combinedFrom, { target, combinator }, "f"); | ||
} | ||
match(el) { | ||
const unitCheck = this._matchWithoutCombinateChecking(el); | ||
const unitCheck = this._matchWithoutCombineChecking(el); | ||
if (!unitCheck.matched) { | ||
return unitCheck; | ||
} | ||
if (!this._combinatedFrom) { | ||
if (!tslib_1.__classPrivateFieldGet(this, _SelectorTarget_combinedFrom, "f")) { | ||
return unitCheck; | ||
@@ -61,3 +64,3 @@ } | ||
} | ||
const { target, combinator } = this._combinatedFrom; | ||
const { target, combinator } = tslib_1.__classPrivateFieldGet(this, _SelectorTarget_combinedFrom, "f"); | ||
switch (combinator) { | ||
@@ -137,11 +140,12 @@ // Descendant combinator | ||
default: { | ||
throw new Error(`Unsupported ${this._combinatedFrom.combinator} combinator in selector`); | ||
throw new Error(`Unsupported ${tslib_1.__classPrivateFieldGet(this, _SelectorTarget_combinedFrom, "f").combinator} combinator in selector`); | ||
} | ||
} | ||
} | ||
_matchWithoutCombinateChecking(el) { | ||
return uncombinatedRegexSelect(el, this._selector); | ||
_matchWithoutCombineChecking(el) { | ||
return uncombinedRegexSelect(el, tslib_1.__classPrivateFieldGet(this, _SelectorTarget_selector, "f")); | ||
} | ||
} | ||
function uncombinatedRegexSelect(el, selector) { | ||
_SelectorTarget_combinedFrom = new WeakMap(), _SelectorTarget_selector = new WeakMap(); | ||
function uncombinedRegexSelect(el, selector) { | ||
if (!(0, is_1.isElement)(el)) { | ||
@@ -148,0 +152,0 @@ return { |
@@ -6,3 +6,3 @@ "use strict"; | ||
const res = {}; | ||
const pattern = toRegxp(reg); | ||
const pattern = toRegexp(reg); | ||
const regex = new RegExp(pattern instanceof RegExp ? pattern : `^${pattern.trim()}$`, ignoreCase ? 'i' : undefined); | ||
@@ -20,3 +20,3 @@ const matched = regex.exec(raw); | ||
exports.regexSelectorMatches = regexSelectorMatches; | ||
function toRegxp(pattern) { | ||
function toRegexp(pattern) { | ||
const matched = pattern.match(/^\/(.+)\/([ig]*)$/i); | ||
@@ -23,0 +23,0 @@ if (matched) { |
import type { SelectorResult, Specificity } from './types'; | ||
declare type ExtendedPseudoClass = Record<string, (content: string) => (el: Element) => SelectorResult>; | ||
type ExtendedPseudoClass = Record<string, (content: string) => (el: Element) => SelectorResult>; | ||
export declare class Selector { | ||
@@ -7,3 +7,4 @@ #private; | ||
match(el: Node, scope?: ParentNode | null): Specificity | false; | ||
search(el: Node, scope?: ParentNode | null): SelectorResult[]; | ||
} | ||
export {}; |
"use strict"; | ||
var _Selector_ruleset, _Ruleset_selectorGroup, _StructuredSelector_selector, _StructuredSelector_edge, _SelectorTarget_extended, _SelectorTarget_combinatedFrom, _SelectorTarget_isAdded; | ||
var _Selector_ruleset, _Ruleset_selectorGroup, _StructuredSelector_edge, _StructuredSelector_selector, _SelectorTarget_combinedFrom, _SelectorTarget_extended, _SelectorTarget_isAdded; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Selector = void 0; | ||
const tslib_1 = require("tslib"); | ||
const ml_spec_1 = require("@markuplint/ml-spec"); | ||
const postcss_selector_parser_1 = tslib_1.__importStar(require("postcss-selector-parser")); | ||
@@ -19,3 +20,3 @@ const compare_specificity_1 = require("./compare-specificity"); | ||
match(el, scope = (0, is_1.isElement)(el) ? el : null) { | ||
const results = tslib_1.__classPrivateFieldGet(this, _Selector_ruleset, "f").match(el, scope); | ||
const results = this.search(el, scope); | ||
for (const result of results) { | ||
@@ -28,2 +29,5 @@ if (result.matched) { | ||
} | ||
search(el, scope = (0, is_1.isElement)(el) ? el : null) { | ||
return tslib_1.__classPrivateFieldGet(this, _Selector_ruleset, "f").match(el, scope); | ||
} | ||
} | ||
@@ -33,2 +37,17 @@ exports.Selector = Selector; | ||
class Ruleset { | ||
static parse(selector, extended) { | ||
const selectors = []; | ||
try { | ||
(0, postcss_selector_parser_1.default)(root => { | ||
selectors.push(...root.nodes); | ||
}).processSync(selector); | ||
} | ||
catch (e) { | ||
if (e instanceof Error) { | ||
throw new Error(`${e.message} At the selector: "${selector}"`); | ||
} | ||
throw e; | ||
} | ||
return new Ruleset(selectors, extended, 0); | ||
} | ||
constructor(selectors, extended, depth) { | ||
@@ -45,9 +64,2 @@ _Ruleset_selectorGroup.set(this, []); | ||
} | ||
static parse(selector, extended) { | ||
const selectors = []; | ||
(0, postcss_selector_parser_1.default)(root => { | ||
selectors.push(...root.nodes); | ||
}).processSync(selector); | ||
return new Ruleset(selectors, extended, 0); | ||
} | ||
match(el, scope) { | ||
@@ -66,4 +78,4 @@ (0, debug_1.log)('<%s> (%s)', (0, is_1.isElement)(el) ? el.localName : el.nodeName, scope ? ((0, is_1.isElement)(scope) ? scope.localName : scope.nodeName) : null); | ||
constructor(selector, depth, extended) { | ||
_StructuredSelector_edge.set(this, void 0); | ||
_StructuredSelector_selector.set(this, void 0); | ||
_StructuredSelector_edge.set(this, void 0); | ||
tslib_1.__classPrivateFieldSet(this, _StructuredSelector_selector, selector, "f"); | ||
@@ -79,5 +91,5 @@ tslib_1.__classPrivateFieldSet(this, _StructuredSelector_edge, new SelectorTarget(extended, depth), "f"); | ||
case 'combinator': { | ||
const combinatedTarget = new SelectorTarget(extended, depth); | ||
combinatedTarget.from(tslib_1.__classPrivateFieldGet(this, _StructuredSelector_edge, "f"), node); | ||
tslib_1.__classPrivateFieldSet(this, _StructuredSelector_edge, combinatedTarget, "f"); | ||
const combinedTarget = new SelectorTarget(extended, depth); | ||
combinedTarget.from(tslib_1.__classPrivateFieldGet(this, _StructuredSelector_edge, "f"), node); | ||
tslib_1.__classPrivateFieldSet(this, _StructuredSelector_edge, combinedTarget, "f"); | ||
break; | ||
@@ -108,11 +120,11 @@ } | ||
} | ||
_StructuredSelector_selector = new WeakMap(), _StructuredSelector_edge = new WeakMap(); | ||
_StructuredSelector_edge = new WeakMap(), _StructuredSelector_selector = new WeakMap(); | ||
class SelectorTarget { | ||
constructor(extended, depth) { | ||
_SelectorTarget_extended.set(this, void 0); | ||
_SelectorTarget_combinatedFrom.set(this, null); | ||
_SelectorTarget_isAdded.set(this, false); | ||
this.attr = []; | ||
this.class = []; | ||
_SelectorTarget_combinedFrom.set(this, null); | ||
_SelectorTarget_extended.set(this, void 0); | ||
this.id = []; | ||
_SelectorTarget_isAdded.set(this, false); | ||
this.pseudo = []; | ||
@@ -150,3 +162,3 @@ this.tag = null; | ||
from(target, combinator) { | ||
tslib_1.__classPrivateFieldSet(this, _SelectorTarget_combinatedFrom, { target, combinator }, "f"); | ||
tslib_1.__classPrivateFieldSet(this, _SelectorTarget_combinedFrom, { target, combinator }, "f"); | ||
} | ||
@@ -158,3 +170,3 @@ match(el, scope, count) { | ||
const nodeName = el.nodeName; | ||
const selector = ((_a = tslib_1.__classPrivateFieldGet(this, _SelectorTarget_combinatedFrom, "f")) === null || _a === void 0 ? void 0 : _a.target.toString()) || this.toString(); | ||
const selector = ((_a = tslib_1.__classPrivateFieldGet(this, _SelectorTarget_combinedFrom, "f")) === null || _a === void 0 ? void 0 : _a.target.toString()) || this.toString(); | ||
const combinator = result.combinator ? ` ${result.combinator}` : ''; | ||
@@ -169,8 +181,18 @@ selLog('The %s element by "%s" => %s (%d)', nodeName, `${selector}${combinator}`, result.matched, count); | ||
} | ||
toString() { | ||
var _a, _b; | ||
return [ | ||
(_b = (_a = this.tag) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : '', | ||
this.id.map(id => `#${id.value}`).join(''), | ||
this.class.map(c => `.${c.value}`).join(''), | ||
this.attr.map(attr => `[${attr.toString()}]`).join(''), | ||
this.pseudo.map(pseudo => pseudo.value).join(''), | ||
].join(''); | ||
} | ||
_match(el, scope, count) { | ||
const unitCheck = this._matchWithoutCombinateChecking(el, scope); | ||
const unitCheck = this._matchWithoutCombineChecking(el, scope); | ||
if (!unitCheck.matched) { | ||
return unitCheck; | ||
} | ||
if (!tslib_1.__classPrivateFieldGet(this, _SelectorTarget_combinatedFrom, "f")) { | ||
if (!tslib_1.__classPrivateFieldGet(this, _SelectorTarget_combinedFrom, "f")) { | ||
return unitCheck; | ||
@@ -181,8 +203,10 @@ } | ||
} | ||
const { target, combinator } = tslib_1.__classPrivateFieldGet(this, _SelectorTarget_combinatedFrom, "f"); | ||
const { target, combinator } = tslib_1.__classPrivateFieldGet(this, _SelectorTarget_combinedFrom, "f"); | ||
switch (combinator.value) { | ||
// Descendant combinator | ||
case ' ': { | ||
const matchedNodes = []; | ||
const has = []; | ||
const not = []; | ||
let ancestor = el.parentElement; | ||
let matched = false; | ||
let specificity; | ||
@@ -199,4 +223,10 @@ while (ancestor) { | ||
if (res.matched) { | ||
matched = true; | ||
matchedNodes.push(...res.nodes); | ||
has.push(...res.has); | ||
} | ||
else { | ||
if (res.not) { | ||
not.push(...res.not); | ||
} | ||
} | ||
ancestor = ancestor.parentElement; | ||
@@ -212,6 +242,16 @@ } | ||
} | ||
if (matchedNodes.length) { | ||
return { | ||
combinator: '␣', | ||
specificity, | ||
matched: true, | ||
nodes: matchedNodes, | ||
has, | ||
}; | ||
} | ||
return { | ||
combinator: '␣', | ||
specificity, | ||
matched, | ||
matched: false, | ||
not, | ||
}; | ||
@@ -221,3 +261,5 @@ } | ||
case '>': { | ||
let matched; | ||
const matchedNodes = []; | ||
const has = []; | ||
const not = []; | ||
const specificity = unitCheck.specificity; | ||
@@ -230,3 +272,11 @@ const parentNode = el.parentElement; | ||
specificity[2] += res.specificity[2]; | ||
matched = res.matched; | ||
if (res.matched) { | ||
matchedNodes.push(...res.nodes); | ||
has.push(...res.has); | ||
} | ||
else { | ||
if (res.not) { | ||
not.push(...res.not); | ||
} | ||
} | ||
} | ||
@@ -238,8 +288,17 @@ else { | ||
specificity[2] += res.specificity[2]; | ||
matched = false; | ||
} | ||
if (matchedNodes.length) { | ||
return { | ||
combinator: '>', | ||
specificity, | ||
matched: true, | ||
nodes: matchedNodes, | ||
has, | ||
}; | ||
} | ||
return { | ||
combinator: '>', | ||
specificity, | ||
matched, | ||
matched: false, | ||
not, | ||
}; | ||
@@ -249,3 +308,5 @@ } | ||
case '+': { | ||
let matched; | ||
const matchedNodes = []; | ||
const has = []; | ||
const not = []; | ||
const specificity = unitCheck.specificity; | ||
@@ -257,3 +318,11 @@ if (el.previousElementSibling) { | ||
specificity[2] += res.specificity[2]; | ||
matched = res.matched; | ||
if (res.matched) { | ||
matchedNodes.push(...res.nodes); | ||
has.push(...res.has); | ||
} | ||
else { | ||
if (res.not) { | ||
not.push(...res.not); | ||
} | ||
} | ||
} | ||
@@ -265,8 +334,17 @@ else { | ||
specificity[2] += res.specificity[2]; | ||
matched = false; | ||
} | ||
if (matchedNodes.length) { | ||
return { | ||
combinator: '+', | ||
specificity, | ||
matched: true, | ||
nodes: matchedNodes, | ||
has, | ||
}; | ||
} | ||
return { | ||
combinator: '+', | ||
specificity, | ||
matched, | ||
matched: false, | ||
not, | ||
}; | ||
@@ -276,4 +354,6 @@ } | ||
case '~': { | ||
const matchedNodes = []; | ||
const has = []; | ||
const not = []; | ||
let prev = el.previousElementSibling; | ||
let matched = false; | ||
let specificity; | ||
@@ -290,4 +370,10 @@ while (prev) { | ||
if (res.matched) { | ||
matched = true; | ||
matchedNodes.push(...res.nodes); | ||
has.push(...res.has); | ||
} | ||
else { | ||
if (res.not) { | ||
not.push(...res.not); | ||
} | ||
} | ||
prev = prev.previousElementSibling; | ||
@@ -303,6 +389,16 @@ } | ||
} | ||
if (matchedNodes.length) { | ||
return { | ||
combinator: '~', | ||
specificity, | ||
matched: true, | ||
nodes: matchedNodes, | ||
has, | ||
}; | ||
} | ||
return { | ||
combinator: '~', | ||
specificity, | ||
matched, | ||
matched: false, | ||
not, | ||
}; | ||
@@ -315,17 +411,8 @@ } | ||
default: { | ||
throw new Error(`Unsupported ${tslib_1.__classPrivateFieldGet(this, _SelectorTarget_combinatedFrom, "f").combinator.value} combinator in selector`); | ||
throw new Error(`Unsupported ${tslib_1.__classPrivateFieldGet(this, _SelectorTarget_combinedFrom, "f").combinator.value} combinator in selector`); | ||
} | ||
} | ||
} | ||
toString() { | ||
var _a, _b; | ||
return [ | ||
(_b = (_a = this.tag) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : '', | ||
this.id.map(id => `#${id.value}`).join(''), | ||
this.class.map(c => `.${c.value}`).join(''), | ||
this.attr.map(attr => `[${attr.toString()}]`).join(''), | ||
this.pseudo.map(pseudo => pseudo.value).join(''), | ||
].join(''); | ||
} | ||
_matchWithoutCombinateChecking(el, scope) { | ||
_matchWithoutCombineChecking(el, scope) { | ||
var _a; | ||
const specificity = [0, 0, 0]; | ||
@@ -338,2 +425,4 @@ if (!(0, is_1.isElement)(el)) { | ||
} | ||
const has = []; | ||
const not = []; | ||
// @ts-ignore | ||
@@ -383,3 +472,7 @@ if (this.tag && this.tag._namespace) { | ||
specificity[2] += pseudoRes.specificity[2]; | ||
if (!pseudoRes.matched) { | ||
if (pseudoRes.matched) { | ||
has.push(...pseudoRes.has); | ||
} | ||
else { | ||
not.push(...((_a = pseudoRes.not) !== null && _a !== void 0 ? _a : [])); | ||
matched = false; | ||
@@ -400,14 +493,29 @@ } | ||
} | ||
if (matched) { | ||
return { | ||
specificity, | ||
matched, | ||
nodes: [el], | ||
has, | ||
}; | ||
} | ||
return { | ||
specificity, | ||
matched, | ||
not, | ||
}; | ||
} | ||
} | ||
_SelectorTarget_extended = new WeakMap(), _SelectorTarget_combinatedFrom = new WeakMap(), _SelectorTarget_isAdded = new WeakMap(); | ||
_SelectorTarget_combinedFrom = new WeakMap(), _SelectorTarget_extended = new WeakMap(), _SelectorTarget_isAdded = new WeakMap(); | ||
function attrMatch(attr, el) { | ||
return Array.from(el.attributes).some(attrOfEl => { | ||
if (attr.attribute !== attrOfEl.name) { | ||
if (attr.attribute !== attrOfEl.localName) { | ||
return false; | ||
} | ||
if (attr.namespace != null && attr.namespace !== true && attr.namespace !== '*') { | ||
const ns = (0, ml_spec_1.resolveNamespace)(attrOfEl.localName, attrOfEl.namespaceURI); | ||
if (attr.namespace !== ns.namespace) { | ||
return false; | ||
} | ||
} | ||
if (attr.value != null) { | ||
@@ -473,6 +581,9 @@ let value = attr.value; | ||
while (parent) { | ||
if (ruleset.match(parent, scope).some(r => r.matched)) { | ||
const matched = ruleset.match(parent, scope).filter((r) => r.matched); | ||
if (matched.length) { | ||
return { | ||
specificity, | ||
matched: true, | ||
nodes: [el], | ||
has: matched, | ||
}; | ||
@@ -494,6 +605,15 @@ } | ||
const specificity = getSpecificity(resList); | ||
const matched = resList.every(r => !r.matched); | ||
const not = resList.filter((r) => r.matched); | ||
if (not.length === 0) { | ||
return { | ||
specificity, | ||
matched: true, | ||
nodes: [el], | ||
has: [], | ||
}; | ||
} | ||
return { | ||
specificity, | ||
matched, | ||
matched: false, | ||
not, | ||
}; | ||
@@ -505,6 +625,8 @@ } | ||
const specificity = getSpecificity(resList); | ||
const matched = resList.some(r => r.matched); | ||
const matched = resList.filter((r) => r.matched); | ||
return { | ||
specificity, | ||
matched, | ||
matched: !!matched.length, | ||
nodes: matched.map(m => m.nodes).flat(), | ||
has: matched.map(m => m.has).flat(), | ||
}; | ||
@@ -518,13 +640,33 @@ } | ||
case '~': { | ||
const matched = getSiblings(el).some(sib => ruleset.match(sib, el).some(m => m.matched)); | ||
const has = getSiblings(el) | ||
.map(sib => ruleset.match(sib, el).filter((m) => m.matched)) | ||
.flat(); | ||
if (has.length) { | ||
return { | ||
specificity, | ||
matched: true, | ||
nodes: [el], | ||
has, | ||
}; | ||
} | ||
return { | ||
specificity, | ||
matched, | ||
matched: false, | ||
}; | ||
} | ||
default: { | ||
const matched = getDescendants(el).some(desc => ruleset.match(desc, el).some(m => m.matched)); | ||
const has = getDescendants(el) | ||
.map(sib => ruleset.match(sib, el).filter((m) => m.matched)) | ||
.flat(); | ||
if (has.length) { | ||
return { | ||
specificity, | ||
matched: true, | ||
nodes: [el], | ||
has, | ||
}; | ||
} | ||
return { | ||
specificity, | ||
matched, | ||
matched: false, | ||
}; | ||
@@ -537,6 +679,8 @@ } | ||
const resList = ruleset.match(el, scope); | ||
const matched = resList.some(r => r.matched); | ||
const matched = resList.filter((r) => r.matched); | ||
return { | ||
specificity: [0, 0, 0], | ||
matched, | ||
matched: !!matched.length, | ||
nodes: matched.map(m => m.nodes).flat(), | ||
has: matched.map(m => m.has).flat(), | ||
}; | ||
@@ -549,2 +693,4 @@ } | ||
matched: true, | ||
nodes: [el], | ||
has: [], | ||
}; | ||
@@ -562,2 +708,4 @@ } | ||
matched: true, | ||
nodes: [el], | ||
has: [], | ||
}; | ||
@@ -648,13 +796,13 @@ } | ||
} | ||
function getSpecificity(result) { | ||
function getSpecificity(results) { | ||
let specificity; | ||
for (const res of result) { | ||
for (const result of results) { | ||
if (specificity) { | ||
const order = (0, compare_specificity_1.compareSpecificity)(specificity, res.specificity); | ||
const order = (0, compare_specificity_1.compareSpecificity)(specificity, result.specificity); | ||
if (order === -1) { | ||
specificity = res.specificity; | ||
specificity = result.specificity; | ||
} | ||
} | ||
else { | ||
specificity = res.specificity; | ||
specificity = result.specificity; | ||
} | ||
@@ -661,0 +809,0 @@ } |
@@ -1,7 +0,15 @@ | ||
export declare type Specificity = [number, number, number]; | ||
export declare type SelectorResult = { | ||
export type Specificity = [number, number, number]; | ||
export type SelectorResult = SelectorMatchedResult | SelectorUnmatchedResult; | ||
export type SelectorMatchedResult = { | ||
specificity: Specificity; | ||
matched: boolean; | ||
matched: true; | ||
nodes: (Element | Text)[]; | ||
has: SelectorMatchedResult[]; | ||
}; | ||
export declare type RegexSelector = RegexSelectorWithoutCompination & { | ||
export type SelectorUnmatchedResult = { | ||
specificity: Specificity; | ||
matched: false; | ||
not?: SelectorMatchedResult[]; | ||
}; | ||
export type RegexSelector = RegexSelectorWithoutCombination & { | ||
combination?: { | ||
@@ -11,4 +19,4 @@ combinator: RegexSelectorCombinator; | ||
}; | ||
export declare type RegexSelectorCombinator = ' ' | '>' | '+' | '~' | ':has(+)' | ':has(~)'; | ||
export declare type RegexSelectorWithoutCompination = { | ||
export type RegexSelectorCombinator = ' ' | '>' | '+' | '~' | ':has(+)' | ':has(~)'; | ||
export type RegexSelectorWithoutCombination = { | ||
nodeName?: string; | ||
@@ -15,0 +23,0 @@ attrName?: string; |
{ | ||
"name": "@markuplint/selector", | ||
"version": "3.0.0-alpha.2105+6cde1134", | ||
"description": "W3C Selector and Regex selector", | ||
"version": "3.0.0-rc.0", | ||
"description": "Extended W3C Selectors matcher", | ||
"repository": "git@github.com:markuplint/markuplint.git", | ||
@@ -25,8 +25,8 @@ "author": "Yusuke Hirao <yusukehirao@me.com>", | ||
"devDependencies": { | ||
"@markuplint/ml-spec": "3.0.0-alpha.82+6cde1134", | ||
"@markuplint/ml-spec": "3.0.0-rc.0", | ||
"@types/debug": "^4.1.7", | ||
"@types/jsdom": "^16.2.14", | ||
"jsdom": "^19.0.0" | ||
"@types/jsdom": "16", | ||
"jsdom": "19" | ||
}, | ||
"gitHead": "6cde113402758a8fdbd6a0fcf98e78efd2cdb778" | ||
"gitHead": "f2cf8f0da3900539568e2e8345bf201d41196c1f" | ||
} |
# @markuplint/selector | ||
[](https://www.npmjs.com/package/@markuplint/selector) | ||
[](https://travis-ci.org/markuplint/markuplint) | ||
[](https://coveralls.io/github/markuplint/markuplint?branch=main) | ||
## Install | ||
**Extended [W3C Selectors](https://www.w3.org/TR/selectors-4/) matcher** | ||
```sh | ||
$ npm install @markuplint/selector | ||
$ yarn add @markuplint/selector | ||
``` | ||
## [W3C Selectors](https://www.w3.org/TR/selectors-4/) matcher | ||
Supported selectors and operators: | ||
@@ -77,5 +67,7 @@ | ||
| Selector Type | Code Example | | ||
| ----------------- | ----------------- | | ||
| ARIA pseudo-class | `:aria(has name)` | | ||
| Selector Type | Code Example | | ||
| -------------------------- | --------------------- | | ||
| ARIA pseudo-class | `:aria(has name)` | | ||
| ARIA Role pseudo-class | `:role(heading)` | | ||
| Content Model pseudo-class | `:model(interactive)` | | ||
@@ -86,11 +78,29 @@ ### ARIA pseudo-class | ||
:aria(syntax) | ||
:aria(syntax/version) | ||
``` | ||
| Syntax | Example | Description | | ||
| -------------- | ------------------------------------------------------- | ------------------------------- | | ||
| `has name` | `:aria(has name)`<br>`:aria(has name/1.1)` | It has accessible name | | ||
| `has no name` | `:aria(has no name)`<br>`:aria(has no name/1.1)` | It does'nt have accessible name | | ||
| `role is Role` | `:aria(role is banner)`<br>`:aria(role is generic/1.2)` | It matches the specfied role | | ||
| Syntax | Example | Description | | ||
| ------------- | -------------------- | ---------------------------------------------- | | ||
| `has name` | `:aria(has name)` | Matches the element has accessible name | | ||
| `has no name` | `:aria(has no name)` | Matches the element has **no** accessible name | | ||
### ARIA Role pseudo-class | ||
``` | ||
:role(roleName) | ||
:role(roleName|version) | ||
``` | ||
For example, `:role(button)` matches `<button>` and `<div role="button">`. | ||
You can specify the version of WAI-ARIA by separating the pipe like `:role(form|1.1)`. | ||
### Content Model pseudo-class | ||
``` | ||
:model(interactive) | ||
:model(palpable) | ||
``` | ||
For example, `:role(interactive)` matches `<a>`(with `href` attr), `<button>`, and so on. | ||
## Regex Selector | ||
@@ -105,1 +115,16 @@ | ||
``` | ||
## Install | ||
[`markuplint`](https://www.npmjs.com/package/markuplint) package includes this package. | ||
<details> | ||
<summary>If you are installing purposely, how below:</summary> | ||
```sh | ||
$ npm install @markuplint/selector | ||
$ yarn add @markuplint/selector | ||
``` | ||
</details> |
Sorry, the diff of this file is not supported yet
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
128099
1384
128
0