@asamuzakjp/dom-selector 4.5.0 → 4.6.0-b.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -23
- package/dist/cjs/js/constant.js.map +1 -1
- package/dist/cjs/js/dom-util.js +1 -1
- package/dist/cjs/js/dom-util.js.map +3 -3
- package/dist/cjs/js/finder.js +1 -1
- package/dist/cjs/js/finder.js.map +3 -3
- package/dist/cjs/js/parser.js.map +2 -2
- package/package.json +2 -2
- package/src/js/constant.js +1 -1
- package/src/js/dom-util.js +61 -25
- package/src/js/finder.js +16 -13
- package/src/js/parser.js +4 -2
- package/types/js/dom-util.d.ts +1 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/js/parser.js"],
|
|
4
|
-
"sourcesContent": ["/**\n * parser.js\n */\n\n/* import */\nimport { findAll, parse, toPlainObject, walk } from 'css-tree';\n\n/* constants */\nimport {\n BIT_01, BIT_02, BIT_04, BIT_08, BIT_16, BIT_32, BIT_FFFF, BIT_HYPHEN,\n DUO, EMPTY, HEX, REG_CHILD_INDEXED, REG_HEX, REG_INVALID_SELECTOR,\n REG_LANG_QUOTED, REG_LOGICAL_COMPLEX_A, REG_LOGICAL_COMPLEX_B,\n REG_LOGICAL_COMPOUND, REG_LOGICAL_EMPTY, REG_LOGICAL_KEY, REG_LOGICAL_PSEUDO,\n REG_SHADOW_PSEUDO, SELECTOR, SELECTOR_ATTR, SELECTOR_CLASS, SELECTOR_ID,\n SELECTOR_PSEUDO_CLASS, SELECTOR_PSEUDO_ELEMENT, SELECTOR_TYPE, SYNTAX_ERR,\n TYPE_FROM, TYPE_TO, U_FFFD\n} from './constant.js';\n\n/**\n * unescape selector\n * @param {string} selector - CSS selector\n * @returns {?string} - unescaped selector\n */\nexport const unescapeSelector = (selector = '') => {\n if (typeof selector === 'string' && selector.indexOf('\\\\', 0) >= 0) {\n const arr = selector.split('\\\\');\n const l = arr.length;\n for (let i = 1; i < l; i++) {\n let item = arr[i];\n if (item === '' && i === l - 1) {\n item = U_FFFD;\n } else {\n const hexExists = REG_HEX.exec(item);\n if (hexExists) {\n const [, hex] = hexExists;\n let str;\n try {\n const low = parseInt('D800', HEX);\n const high = parseInt('DFFF', HEX);\n const deci = parseInt(hex, HEX);\n if (deci === 0 || (deci >= low && deci <= high)) {\n str = U_FFFD;\n } else {\n str = String.fromCodePoint(deci);\n }\n } catch (e) {\n str = U_FFFD;\n }\n let postStr = '';\n if (item.length > hex.length) {\n postStr = item.substring(hex.length);\n }\n item = `${str}${postStr}`;\n // whitespace\n } else if (/^[\\n\\r\\f]/.test(item)) {\n item = '\\\\' + item;\n }\n }\n arr[i] = item;\n }\n selector = arr.join('');\n }\n return selector;\n};\n\n/**\n * preprocess\n * @see https://drafts.csswg.org/css-syntax-3/#input-preprocessing\n * @param {...*} args - arguments\n * @returns {string} - filtered selector string\n */\nexport const preprocess = (...args) => {\n if (!args.length) {\n throw new TypeError('1 argument required, but only 0 present.');\n }\n let [selector] = args;\n if (typeof selector === 'string') {\n let index = 0;\n while (index >= 0) {\n index = selector.indexOf('#', index);\n if (index < 0) {\n break;\n }\n const preHash = selector.substring(0, index + 1);\n let postHash = selector.substring(index + 1);\n // @see https://drafts.csswg.org/selectors/#id-selectors\n // @see https://drafts.csswg.org/css-syntax-3/#ident-token-diagram\n if (/^\\d$/.test(postHash.substring(0, 1))) {\n throw new DOMException(`Invalid selector ${selector}`, SYNTAX_ERR);\n }\n const codePoint = postHash.codePointAt(0);\n if (codePoint === BIT_HYPHEN) {\n if (/^\\d$/.test(postHash.substring(1, 2))) {\n throw new DOMException(`Invalid selector ${selector}`, SYNTAX_ERR);\n }\n // escape char above 0xFFFF\n } else if (codePoint > BIT_FFFF) {\n const str = `\\\\${codePoint.toString(HEX)} `;\n if (postHash.length === DUO) {\n postHash = str;\n } else {\n postHash = `${str}${postHash.substring(DUO)}`;\n }\n }\n selector = `${preHash}${postHash}`;\n index++;\n }\n selector = selector.replace(/\\f|\\r\\n?/g, '\\n')\n .replace(/[\\0\\uD800-\\uDFFF]|\\\\$/g, U_FFFD);\n } else if (selector === undefined || selector === null) {\n selector = Object.prototype.toString.call(selector)\n .slice(TYPE_FROM, TYPE_TO).toLowerCase();\n } else if (Array.isArray(selector)) {\n selector = selector.join(',');\n } else if (Object.prototype.hasOwnProperty.call(selector, 'toString')) {\n selector = selector.toString();\n } else {\n throw new DOMException(`Invalid selector ${selector}`, SYNTAX_ERR);\n }\n return selector;\n};\n\n/**\n * create AST from CSS selector\n * @param {string} selector - CSS selector\n * @returns {object} - AST\n */\nexport const parseSelector = selector => {\n selector = preprocess(selector);\n // invalid selectors\n if (REG_INVALID_SELECTOR.test(selector)) {\n throw new DOMException(`Invalid selector ${selector}`, SYNTAX_ERR);\n }\n let res;\n try {\n const ast = parse(selector, {\n context: 'selectorList',\n parseCustomProperty: true\n });\n res = toPlainObject(ast);\n } catch (e) {\n const { message } = e;\n // workaround for https://github.com/csstree/csstree/issues/265\n if (message === 'Identifier is expected' &&\n REG_LANG_QUOTED.test(selector)) {\n const [, lang, range] = REG_LANG_QUOTED.exec(selector);\n const escapedRange =\n range.replaceAll('*', '\\\\*').replace(/^\"/, '').replace(/\"$/, '');\n let escapedLang = lang.replace(range, escapedRange);\n if (escapedLang === ':lang()') {\n escapedLang = `:lang(${EMPTY})`;\n }\n res = parseSelector(selector.replace(lang, escapedLang));\n } else if (/^(?:Identifier|Selector) is expected$/.test(message) &&\n REG_LOGICAL_EMPTY.test(selector)) {\n const [, sel, name] = REG_LOGICAL_EMPTY.exec(selector);\n res = parseSelector(selector.replace(sel, `:${name}(${EMPTY})`));\n } else if (/^(?:\"\\]\"|Attribute selector [()\\s,=~^$*|]+) is expected$/.test(message) &&\n !selector.endsWith(']')) {\n const index = selector.lastIndexOf('[');\n const sel = selector.substring(index);\n if (sel.includes('\"')) {\n const quotes = sel.match(/\"/g).length;\n if (quotes % 2) {\n res = parseSelector(`${selector}\"]`);\n } else {\n res = parseSelector(`${selector}]`);\n }\n } else {\n res = parseSelector(`${selector}]`);\n }\n } else if (message === '\")\" is expected' && !selector.endsWith(')')) {\n res = parseSelector(`${selector})`);\n } else {\n throw new DOMException(message, SYNTAX_ERR);\n }\n }\n return res;\n};\n\n/**\n * walk AST\n * @param {object} ast - AST\n * @returns {Array.<object|undefined>} - collection of AST branches\n */\nexport const walkAST = (ast = {}) => {\n const branches = new Set();\n const info = new Map();\n const opt = {\n enter: node => {\n if (node.type === SELECTOR) {\n branches.add(node.children);\n } else if (node.type === SELECTOR_PSEUDO_CLASS) {\n info.set('hasPseudo', true);\n if (REG_LOGICAL_PSEUDO.test(node.name)) {\n info.set('hasPseudoFunc', true);\n if (node.name === 'has') {\n info.set('hasHasPseudoFunc', true);\n }\n }\n } else if (node.type === SELECTOR_PSEUDO_ELEMENT) {\n info.set('hasPseudo', true);\n if (REG_SHADOW_PSEUDO.test(node.name)) {\n info.set('hasPseudoFunc', true);\n }\n } else if (node.type === SELECTOR_ATTR && node.matcher === '|=') {\n info.set('hasHyphenSepAttr', true);\n }\n }\n };\n walk(ast, opt);\n if (info.get('hasPseudoFunc')) {\n findAll(ast, (node, item, list) => {\n if (list) {\n if (node.type === SELECTOR_PSEUDO_CLASS &&\n REG_LOGICAL_PSEUDO.test(node.name)) {\n const itemList = list.filter(i => {\n const { name, type } = i;\n const res =\n type === SELECTOR_PSEUDO_CLASS && REG_LOGICAL_PSEUDO.test(name);\n return res;\n });\n for (const { children } of itemList) {\n // SelectorList\n for (const { children: grandChildren } of children) {\n // Selector\n for (const { children: greatGrandChildren } of grandChildren) {\n if (branches.has(greatGrandChildren)) {\n branches.delete(greatGrandChildren);\n }\n }\n }\n }\n } else if (node.type === SELECTOR_PSEUDO_ELEMENT &&\n REG_SHADOW_PSEUDO.test(node.name)) {\n const itemList = list.filter(i => {\n const { name, type } = i;\n const res =\n type === SELECTOR_PSEUDO_ELEMENT && REG_SHADOW_PSEUDO.test(name);\n return res;\n });\n for (const { children } of itemList) {\n // Selector\n for (const { children: grandChildren } of children) {\n if (branches.has(grandChildren)) {\n branches.delete(grandChildren);\n }\n }\n }\n }\n }\n });\n }\n return {\n branches: [...branches],\n info: Object.fromEntries(info)\n };\n};\n\n/**\n * sort AST\n * @param {Array.<object>} asts - collection of AST\n * @returns {Array.<object>} - collection of sorted AST\n */\nexport const sortAST = asts => {\n const arr = [...asts];\n if (arr.length > 1) {\n const order = new Map([\n [SELECTOR_PSEUDO_ELEMENT, BIT_01],\n [SELECTOR_ID, BIT_02],\n [SELECTOR_CLASS, BIT_04],\n [SELECTOR_TYPE, BIT_08],\n [SELECTOR_ATTR, BIT_16],\n [SELECTOR_PSEUDO_CLASS, BIT_32]\n ]);\n arr.sort((a, b) => {\n const { type: typeA } = a;\n const { type: typeB } = b;\n const bitA = order.get(typeA);\n const bitB = order.get(typeB);\n let res;\n if (bitA === bitB) {\n res = 0;\n } else if (bitA > bitB) {\n res = 1;\n } else {\n res = -1;\n }\n return res;\n });\n }\n return arr;\n};\n\n/**\n * parse AST name - e.g. ns|E -> { prefix: ns, localName: E }\n * @param {string} selector - type selector\n * @returns {object} - node properties\n */\nexport const parseAstName = selector => {\n let prefix;\n let localName;\n if (selector && typeof selector === 'string') {\n if (selector.indexOf('|') > -1) {\n [prefix, localName] = selector.split('|');\n } else {\n prefix = '*';\n localName = selector;\n }\n } else {\n throw new DOMException(`Invalid selector ${selector}`, SYNTAX_ERR);\n }\n return {\n prefix,\n localName\n };\n};\n\n/**\n * filter selector (for nwsapi)\n * @param {string} selector - selector\n * @param {object} opt - options\n * @returns {boolean} - result\n */\nexport const filterSelector = (selector, opt = {}) => {\n if (!selector || typeof selector !== 'string') {\n return false;\n }\n // filter missing close square bracket\n if (selector.includes('[')) {\n const index = selector.lastIndexOf('[');\n const sel = selector.substring(index);\n if (sel.lastIndexOf(']') < 0) {\n return false;\n }\n }\n // filter namespaced selectors, e.g. ns|E, pseudo-element selectors and\n // attribute selectors with case flag, e.g. [attr i], and unclosed quotes\n if (/\\||::|\\[\\s*[\\w$*=^|~-]+(?:(?:\"[\\w$*=^|~\\s'-]+\"|'[\\w$*=^|~\\s\"-]+')?(?:\\s+[\\w$*=^|~-]+)+|\"[^\"\\]]{1,255}|'[^'\\]]{1,255})\\s*\\]/.test(selector)) {\n return false;\n }\n // filter pseudo-classes\n if (selector.includes(':')) {\n let reg;\n if (REG_LOGICAL_KEY.test(selector)) {\n // filter empty :is() and :where()\n if (REG_LOGICAL_EMPTY.test(selector)) {\n return false;\n }\n const { complex, descendant } = opt;\n if (complex && descendant) {\n reg = REG_LOGICAL_COMPLEX_A;\n } else if (complex) {\n reg = REG_LOGICAL_COMPLEX_B;\n } else {\n reg = REG_LOGICAL_COMPOUND;\n }\n } else {\n reg = REG_CHILD_INDEXED;\n }\n if (reg.test(selector)) {\n return false;\n }\n }\n return true;\n};\n\n/* export */\nexport { generate as generateCSS } from 'css-tree';\n"],
|
|
5
|
-
"mappings": "4ZAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,oBAAAE,EAAA,4CAAAC,EAAA,kBAAAC,EAAA,eAAAC,EAAA,YAAAC,EAAA,qBAAAC,EAAA,YAAAC,IAAA,eAAAC,EAAAT,GAKA,IAAAU,EAAoD,oBAGpDC,EAQO,
|
|
4
|
+
"sourcesContent": ["/**\n * parser.js\n */\n\n/* import */\nimport { findAll, parse, toPlainObject, walk } from 'css-tree';\n\n/* constants */\nimport {\n BIT_01, BIT_02, BIT_04, BIT_08, BIT_16, BIT_32, BIT_FFFF, BIT_HYPHEN,\n DUO, EMPTY, HEX, REG_CHILD_INDEXED, REG_HEX, REG_INVALID_SELECTOR,\n REG_LANG_QUOTED, REG_LOGICAL_COMPLEX_A, REG_LOGICAL_COMPLEX_B,\n REG_LOGICAL_COMPOUND, REG_LOGICAL_EMPTY, REG_LOGICAL_KEY, REG_LOGICAL_PSEUDO,\n REG_SHADOW_PSEUDO, SELECTOR, SELECTOR_ATTR, SELECTOR_CLASS, SELECTOR_ID,\n SELECTOR_PSEUDO_CLASS, SELECTOR_PSEUDO_ELEMENT, SELECTOR_TYPE, SYNTAX_ERR,\n TYPE_FROM, TYPE_TO, U_FFFD\n} from './constant.js';\n\n/**\n * unescape selector\n * @param {string} selector - CSS selector\n * @returns {?string} - unescaped selector\n */\nexport const unescapeSelector = (selector = '') => {\n if (typeof selector === 'string' && selector.indexOf('\\\\', 0) >= 0) {\n const arr = selector.split('\\\\');\n const l = arr.length;\n for (let i = 1; i < l; i++) {\n let item = arr[i];\n if (item === '' && i === l - 1) {\n item = U_FFFD;\n } else {\n const hexExists = REG_HEX.exec(item);\n if (hexExists) {\n const [, hex] = hexExists;\n let str;\n try {\n const low = parseInt('D800', HEX);\n const high = parseInt('DFFF', HEX);\n const deci = parseInt(hex, HEX);\n if (deci === 0 || (deci >= low && deci <= high)) {\n str = U_FFFD;\n } else {\n str = String.fromCodePoint(deci);\n }\n } catch (e) {\n str = U_FFFD;\n }\n let postStr = '';\n if (item.length > hex.length) {\n postStr = item.substring(hex.length);\n }\n item = `${str}${postStr}`;\n // whitespace\n } else if (/^[\\n\\r\\f]/.test(item)) {\n item = '\\\\' + item;\n }\n }\n arr[i] = item;\n }\n selector = arr.join('');\n }\n return selector;\n};\n\n/**\n * preprocess\n * @see https://drafts.csswg.org/css-syntax-3/#input-preprocessing\n * @param {...*} args - arguments\n * @returns {string} - filtered selector string\n */\nexport const preprocess = (...args) => {\n if (!args.length) {\n throw new TypeError('1 argument required, but only 0 present.');\n }\n let [selector] = args;\n if (typeof selector === 'string') {\n let index = 0;\n while (index >= 0) {\n index = selector.indexOf('#', index);\n if (index < 0) {\n break;\n }\n const preHash = selector.substring(0, index + 1);\n let postHash = selector.substring(index + 1);\n // @see https://drafts.csswg.org/selectors/#id-selectors\n // @see https://drafts.csswg.org/css-syntax-3/#ident-token-diagram\n if (/^\\d$/.test(postHash.substring(0, 1))) {\n throw new DOMException(`Invalid selector ${selector}`, SYNTAX_ERR);\n }\n const codePoint = postHash.codePointAt(0);\n if (codePoint === BIT_HYPHEN) {\n if (/^\\d$/.test(postHash.substring(1, 2))) {\n throw new DOMException(`Invalid selector ${selector}`, SYNTAX_ERR);\n }\n // escape char above 0xFFFF\n } else if (codePoint > BIT_FFFF) {\n const str = `\\\\${codePoint.toString(HEX)} `;\n if (postHash.length === DUO) {\n postHash = str;\n } else {\n postHash = `${str}${postHash.substring(DUO)}`;\n }\n }\n selector = `${preHash}${postHash}`;\n index++;\n }\n selector = selector.replace(/\\f|\\r\\n?/g, '\\n')\n .replace(/[\\0\\uD800-\\uDFFF]|\\\\$/g, U_FFFD);\n } else if (selector === undefined || selector === null) {\n selector = Object.prototype.toString.call(selector)\n .slice(TYPE_FROM, TYPE_TO).toLowerCase();\n } else if (Array.isArray(selector)) {\n selector = selector.join(',');\n } else if (Object.prototype.hasOwnProperty.call(selector, 'toString')) {\n selector = selector.toString();\n } else {\n throw new DOMException(`Invalid selector ${selector}`, SYNTAX_ERR);\n }\n return selector;\n};\n\n/**\n * create AST from CSS selector\n * @param {string} selector - CSS selector\n * @returns {object} - AST\n */\nexport const parseSelector = selector => {\n selector = preprocess(selector);\n // invalid selectors\n if (REG_INVALID_SELECTOR.test(selector)) {\n throw new DOMException(`Invalid selector ${selector}`, SYNTAX_ERR);\n }\n let res;\n try {\n const ast = parse(selector, {\n context: 'selectorList',\n parseCustomProperty: true\n });\n res = toPlainObject(ast);\n } catch (e) {\n const { message } = e;\n // workaround for https://github.com/csstree/csstree/issues/265\n if (message === 'Identifier is expected' &&\n REG_LANG_QUOTED.test(selector)) {\n const [, lang, range] = REG_LANG_QUOTED.exec(selector);\n const escapedRange =\n range.replaceAll('*', '\\\\*').replace(/^\"/, '').replace(/\"$/, '');\n let escapedLang = lang.replace(range, escapedRange);\n if (escapedLang === ':lang()') {\n escapedLang = `:lang(${EMPTY})`;\n }\n res = parseSelector(selector.replace(lang, escapedLang));\n } else if (/^(?:Identifier|Selector) is expected$/.test(message) &&\n REG_LOGICAL_EMPTY.test(selector)) {\n const [, sel, name] = REG_LOGICAL_EMPTY.exec(selector);\n res = parseSelector(selector.replace(sel, `:${name}(${EMPTY})`));\n } else if (/^(?:\"\\]\"|Attribute selector [()\\s,=~^$*|]+) is expected$/.test(message) &&\n !selector.endsWith(']')) {\n const index = selector.lastIndexOf('[');\n const sel = selector.substring(index);\n if (sel.includes('\"')) {\n const quotes = sel.match(/\"/g).length;\n if (quotes % 2) {\n res = parseSelector(`${selector}\"]`);\n } else {\n res = parseSelector(`${selector}]`);\n }\n } else {\n res = parseSelector(`${selector}]`);\n }\n } else if (message === '\")\" is expected' && !selector.endsWith(')')) {\n res = parseSelector(`${selector})`);\n } else {\n throw new DOMException(message, SYNTAX_ERR);\n }\n }\n return res;\n};\n\n/**\n * walk AST\n * @param {object} ast - AST\n * @returns {Array.<object|undefined>} - collection of AST branches\n */\nexport const walkAST = (ast = {}) => {\n const branches = new Set();\n const info = new Map();\n const opt = {\n enter: node => {\n if (node.type === SELECTOR) {\n branches.add(node.children);\n } else if (node.type === SELECTOR_PSEUDO_CLASS) {\n info.set('hasPseudo', true);\n if (REG_LOGICAL_PSEUDO.test(node.name)) {\n info.set('hasPseudoFunc', true);\n if (node.name === 'has') {\n info.set('hasHasPseudoFunc', true);\n }\n }\n } else if (node.type === SELECTOR_PSEUDO_ELEMENT) {\n info.set('hasPseudo', true);\n if (REG_SHADOW_PSEUDO.test(node.name)) {\n info.set('hasPseudoFunc', true);\n }\n } else if (node.type === SELECTOR_ATTR && node.matcher === '|=') {\n info.set('hasHyphenSepAttr', true);\n }\n }\n };\n walk(ast, opt);\n if (info.get('hasPseudoFunc')) {\n findAll(ast, (node, item, list) => {\n if (list) {\n if (node.type === SELECTOR_PSEUDO_CLASS &&\n REG_LOGICAL_PSEUDO.test(node.name)) {\n const itemList = list.filter(i => {\n const { name, type } = i;\n const res =\n type === SELECTOR_PSEUDO_CLASS && REG_LOGICAL_PSEUDO.test(name);\n return res;\n });\n for (const { children } of itemList) {\n // SelectorList\n for (const { children: grandChildren } of children) {\n // Selector\n for (const { children: greatGrandChildren } of grandChildren) {\n if (branches.has(greatGrandChildren)) {\n branches.delete(greatGrandChildren);\n }\n }\n }\n }\n } else if (node.type === SELECTOR_PSEUDO_ELEMENT &&\n REG_SHADOW_PSEUDO.test(node.name)) {\n const itemList = list.filter(i => {\n const { name, type } = i;\n const res =\n type === SELECTOR_PSEUDO_ELEMENT && REG_SHADOW_PSEUDO.test(name);\n return res;\n });\n for (const { children } of itemList) {\n // Selector\n for (const { children: grandChildren } of children) {\n if (branches.has(grandChildren)) {\n branches.delete(grandChildren);\n }\n }\n }\n }\n }\n });\n }\n return {\n branches: [...branches],\n info: Object.fromEntries(info)\n };\n};\n\n/**\n * sort AST\n * @param {Array.<object>} asts - collection of AST\n * @returns {Array.<object>} - collection of sorted AST\n */\nexport const sortAST = asts => {\n const arr = [...asts];\n if (arr.length > 1) {\n const order = new Map([\n [SELECTOR_PSEUDO_ELEMENT, BIT_01],\n [SELECTOR_ID, BIT_02],\n [SELECTOR_CLASS, BIT_04],\n [SELECTOR_TYPE, BIT_08],\n [SELECTOR_ATTR, BIT_16],\n [SELECTOR_PSEUDO_CLASS, BIT_32]\n ]);\n arr.sort((a, b) => {\n const { type: typeA } = a;\n const { type: typeB } = b;\n const bitA = order.get(typeA);\n const bitB = order.get(typeB);\n let res;\n if (bitA === bitB) {\n res = 0;\n } else if (bitA > bitB) {\n res = 1;\n } else {\n res = -1;\n }\n return res;\n });\n }\n return arr;\n};\n\n/**\n * parse AST name - e.g. ns|E -> { prefix: ns, localName: E }\n * @param {string} selector - type selector\n * @returns {object} - node properties\n */\nexport const parseAstName = selector => {\n let prefix;\n let localName;\n if (selector && typeof selector === 'string') {\n if (selector.indexOf('|') > -1) {\n [prefix, localName] = selector.split('|');\n } else {\n prefix = '*';\n localName = selector;\n }\n } else {\n throw new DOMException(`Invalid selector ${selector}`, SYNTAX_ERR);\n }\n return {\n prefix,\n localName\n };\n};\n\n/**\n * filter selector (for nwsapi)\n * @param {string} selector - selector\n * @param {object} opt - options\n * @returns {boolean} - result\n */\nexport const filterSelector = (selector, opt = {}) => {\n if (!selector || typeof selector !== 'string') {\n return false;\n }\n // filter missing close square bracket\n if (selector.includes('[')) {\n const index = selector.lastIndexOf('[');\n const sel = selector.substring(index);\n if (sel.lastIndexOf(']') < 0) {\n return false;\n }\n }\n // filter namespaced selectors, e.g. ns|E\n // filter pseudo-element selectors\n // filter attribute selectors with case flag, e.g. [attr i]\n // filter unclosed quotes\n if (/\\||::|\\[\\s*[\\w$*=^|~-]+(?:(?:\"[\\w$*=^|~\\s'-]+\"|'[\\w$*=^|~\\s\"-]+')?(?:\\s+[\\w$*=^|~-]+)+|\"[^\"\\]]{1,255}|'[^'\\]]{1,255})\\s*\\]/.test(selector)) {\n return false;\n }\n // filter pseudo-classes\n if (selector.includes(':')) {\n let reg;\n if (REG_LOGICAL_KEY.test(selector)) {\n // filter empty :is() and :where()\n if (REG_LOGICAL_EMPTY.test(selector)) {\n return false;\n }\n const { complex, descendant } = opt;\n if (complex && descendant) {\n reg = REG_LOGICAL_COMPLEX_A;\n } else if (complex) {\n reg = REG_LOGICAL_COMPLEX_B;\n } else {\n reg = REG_LOGICAL_COMPOUND;\n }\n } else {\n reg = REG_CHILD_INDEXED;\n }\n if (reg.test(selector)) {\n return false;\n }\n }\n return true;\n};\n\n/* export */\nexport { generate as generateCSS } from 'css-tree';\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["parser_exports", "__export", "filterSelector", "parseAstName", "parseSelector", "preprocess", "sortAST", "unescapeSelector", "walkAST", "__toCommonJS", "import_css_tree", "import_constant", "selector", "arr", "l", "item", "hexExists", "hex", "str", "low", "high", "deci", "postStr", "args", "index", "preHash", "postHash", "codePoint", "res", "ast", "e", "message", "lang", "range", "escapedRange", "escapedLang", "sel", "name", "branches", "info", "node", "list", "itemList", "i", "type", "children", "grandChildren", "greatGrandChildren", "asts", "order", "a", "b", "typeA", "typeB", "bitA", "bitB", "prefix", "localName", "opt", "reg", "complex", "descendant"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"eslint": "^8.57.0",
|
|
39
39
|
"eslint-config-standard": "^17.1.0",
|
|
40
40
|
"eslint-plugin-import": "^2.29.1",
|
|
41
|
-
"eslint-plugin-jsdoc": "^48.5.
|
|
41
|
+
"eslint-plugin-jsdoc": "^48.5.2",
|
|
42
42
|
"eslint-plugin-regexp": "^2.6.0",
|
|
43
43
|
"eslint-plugin-unicorn": "^54.0.0",
|
|
44
44
|
"happy-dom": "^14.12.3",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"tsc": "node scripts/index clean --dir=types -i && npx tsc",
|
|
61
61
|
"update-wpt": "git submodule update --init --recursive --remote"
|
|
62
62
|
},
|
|
63
|
-
"version": "4.
|
|
63
|
+
"version": "4.6.0-b.1"
|
|
64
64
|
}
|
package/src/js/constant.js
CHANGED
|
@@ -64,7 +64,7 @@ export const ANB =
|
|
|
64
64
|
// N_TH: excludes An+B with selector list, e.g. :nth-child(2n+1 of .foo)
|
|
65
65
|
export const N_TH =
|
|
66
66
|
`nth-(?:last-)?(?:child|of-type)\\(\\s*(?:even|odd|${ANB})\\s*\\)`;
|
|
67
|
-
// SUB_TYPE: attr, id, class, pseudo-class
|
|
67
|
+
// SUB_TYPE: attr, id, class, pseudo-class, note that [foo|=bar] is excluded
|
|
68
68
|
export const SUB_TYPE = '\\[[^|\\]]+\\]|[#.:][\\w-]+';
|
|
69
69
|
// TAG_TYPE: *, tag
|
|
70
70
|
export const TAG_TYPE = '\\*|[A-Za-z][\\w-]*';
|
package/src/js/dom-util.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
/* import */
|
|
6
6
|
import bidiFactory from 'bidi-js';
|
|
7
|
+
import isCustomElementName from 'is-potential-custom-element-name';
|
|
7
8
|
|
|
8
9
|
/* constants */
|
|
9
10
|
import {
|
|
@@ -83,12 +84,11 @@ export const resolveContent = node => {
|
|
|
83
84
|
* @returns {?object} - current node
|
|
84
85
|
*/
|
|
85
86
|
export const traverseNode = (node, walker) => {
|
|
87
|
+
let current;
|
|
86
88
|
if (!node || !node.nodeType) {
|
|
87
89
|
// throws
|
|
88
90
|
verifyNode(node);
|
|
89
|
-
}
|
|
90
|
-
let current;
|
|
91
|
-
if (walker?.currentNode) {
|
|
91
|
+
} else if (walker?.currentNode) {
|
|
92
92
|
let refNode = walker.currentNode;
|
|
93
93
|
if (refNode === node) {
|
|
94
94
|
current = refNode;
|
|
@@ -126,19 +126,53 @@ export const traverseNode = (node, walker) => {
|
|
|
126
126
|
return current ?? null;
|
|
127
127
|
};
|
|
128
128
|
|
|
129
|
+
/**
|
|
130
|
+
* is custom element
|
|
131
|
+
* @param {object} node - Element node
|
|
132
|
+
* @param {object} opt - options
|
|
133
|
+
* @returns {boolean} - result;
|
|
134
|
+
*/
|
|
135
|
+
export const isCustomElement = (node, opt = {}) => {
|
|
136
|
+
let bool;
|
|
137
|
+
if (!node || !node.nodeType) {
|
|
138
|
+
// throws
|
|
139
|
+
verifyNode(node);
|
|
140
|
+
} else if (node.nodeType === ELEMENT_NODE) {
|
|
141
|
+
const { localName, ownerDocument } = node;
|
|
142
|
+
const { formAssociated } = opt;
|
|
143
|
+
const window = ownerDocument.defaultView;
|
|
144
|
+
let elmConstructor;
|
|
145
|
+
const attr = node.getAttribute('is');
|
|
146
|
+
if (attr) {
|
|
147
|
+
elmConstructor =
|
|
148
|
+
isCustomElementName(attr) && window.customElements.get(attr);
|
|
149
|
+
} else {
|
|
150
|
+
elmConstructor =
|
|
151
|
+
isCustomElementName(localName) && window.customElements.get(localName);
|
|
152
|
+
}
|
|
153
|
+
if (elmConstructor) {
|
|
154
|
+
if (formAssociated) {
|
|
155
|
+
bool = elmConstructor.formAssociated;
|
|
156
|
+
} else {
|
|
157
|
+
bool = true;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return !!bool;
|
|
162
|
+
};
|
|
163
|
+
|
|
129
164
|
/**
|
|
130
165
|
* is in shadow tree
|
|
131
166
|
* @param {object} node - node
|
|
132
167
|
* @returns {boolean} - result;
|
|
133
168
|
*/
|
|
134
169
|
export const isInShadowTree = node => {
|
|
135
|
-
|
|
170
|
+
let bool;
|
|
171
|
+
if (!node || !node.nodeType) {
|
|
136
172
|
// throws
|
|
137
173
|
verifyNode(node);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (node.nodeType === ELEMENT_NODE ||
|
|
141
|
-
node.nodeType === DOCUMENT_FRAGMENT_NODE) {
|
|
174
|
+
} else if (node.nodeType === ELEMENT_NODE ||
|
|
175
|
+
node.nodeType === DOCUMENT_FRAGMENT_NODE) {
|
|
142
176
|
let refNode = node;
|
|
143
177
|
while (refNode) {
|
|
144
178
|
const { host, mode, nodeType, parentNode } = refNode;
|
|
@@ -159,12 +193,11 @@ export const isInShadowTree = node => {
|
|
|
159
193
|
* @returns {?string} - text content
|
|
160
194
|
*/
|
|
161
195
|
export const getSlottedTextContent = node => {
|
|
196
|
+
let res;
|
|
162
197
|
if (!node || !node.nodeType) {
|
|
163
198
|
// throws
|
|
164
199
|
verifyNode(node);
|
|
165
|
-
}
|
|
166
|
-
let res;
|
|
167
|
-
if (node.localName === 'slot' && isInShadowTree(node)) {
|
|
200
|
+
} else if (node.localName === 'slot' && isInShadowTree(node)) {
|
|
168
201
|
const nodes = node.assignedNodes();
|
|
169
202
|
if (nodes.length) {
|
|
170
203
|
for (const item of nodes) {
|
|
@@ -187,12 +220,11 @@ export const getSlottedTextContent = node => {
|
|
|
187
220
|
* @returns {?string} - 'ltr' / 'rtl'
|
|
188
221
|
*/
|
|
189
222
|
export const getDirectionality = node => {
|
|
223
|
+
let res;
|
|
190
224
|
if (!node || !node.nodeType) {
|
|
191
225
|
// throws
|
|
192
226
|
verifyNode(node);
|
|
193
|
-
}
|
|
194
|
-
let res;
|
|
195
|
-
if (node.nodeType === ELEMENT_NODE) {
|
|
227
|
+
} else if (node.nodeType === ELEMENT_NODE) {
|
|
196
228
|
const { dir: nodeDir, localName, parentNode } = node;
|
|
197
229
|
const { getEmbeddingLevels } = bidiFactory();
|
|
198
230
|
if (REG_DIR.test(nodeDir)) {
|
|
@@ -312,12 +344,11 @@ export const getDirectionality = node => {
|
|
|
312
344
|
* @returns {boolean} - result
|
|
313
345
|
*/
|
|
314
346
|
export const isContentEditable = node => {
|
|
347
|
+
let res;
|
|
315
348
|
if (!node || !node.nodeType) {
|
|
316
349
|
// throws
|
|
317
350
|
verifyNode(node);
|
|
318
|
-
}
|
|
319
|
-
let res;
|
|
320
|
-
if (node.nodeType === ELEMENT_NODE) {
|
|
351
|
+
} else if (node.nodeType === ELEMENT_NODE) {
|
|
321
352
|
if (typeof node.isContentEditable === 'boolean') {
|
|
322
353
|
res = node.isContentEditable;
|
|
323
354
|
} else if (node.ownerDocument.designMode === 'on') {
|
|
@@ -348,12 +379,17 @@ export const isContentEditable = node => {
|
|
|
348
379
|
* @returns {?string} - namespace URI
|
|
349
380
|
*/
|
|
350
381
|
export const getNamespaceURI = (ns, node) => {
|
|
351
|
-
if (!node || !node.nodeType) {
|
|
352
|
-
// throws
|
|
353
|
-
verifyNode(node);
|
|
354
|
-
}
|
|
355
382
|
let res;
|
|
356
|
-
if (
|
|
383
|
+
if (typeof ns !== 'string' || !node || !node.nodeType) {
|
|
384
|
+
if (typeof ns !== 'string') {
|
|
385
|
+
const type = Object.prototype.toString.call(ns).slice(TYPE_FROM, TYPE_TO);
|
|
386
|
+
const msg = `Unexpected type ${type}`;
|
|
387
|
+
throw new TypeError(msg);
|
|
388
|
+
} else {
|
|
389
|
+
// throws
|
|
390
|
+
verifyNode(node);
|
|
391
|
+
}
|
|
392
|
+
} else if (ns && node.nodeType === ELEMENT_NODE) {
|
|
357
393
|
const { attributes } = node;
|
|
358
394
|
for (const attr of attributes) {
|
|
359
395
|
const { name, namespaceURI, prefix, value } = attr;
|
|
@@ -401,15 +437,15 @@ export const isNamespaceDeclared = (ns = '', node = {}) => {
|
|
|
401
437
|
* @returns {boolean} - result
|
|
402
438
|
*/
|
|
403
439
|
export const isPreceding = (nodeA, nodeB) => {
|
|
440
|
+
let res;
|
|
404
441
|
if (!nodeA || !nodeA.nodeType) {
|
|
405
442
|
// throws
|
|
406
443
|
verifyNode(nodeA);
|
|
407
444
|
} else if (!nodeB || !nodeB.nodeType) {
|
|
408
445
|
// throws
|
|
409
446
|
verifyNode(nodeB);
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
if (nodeA.nodeType === ELEMENT_NODE && nodeB.nodeType === ELEMENT_NODE) {
|
|
447
|
+
} else if (nodeA.nodeType === ELEMENT_NODE &&
|
|
448
|
+
nodeB.nodeType === ELEMENT_NODE) {
|
|
413
449
|
const posBit = nodeB.compareDocumentPosition(nodeA);
|
|
414
450
|
res = posBit & DOCUMENT_POSITION_PRECEDING ||
|
|
415
451
|
posBit & DOCUMENT_POSITION_CONTAINS;
|
package/src/js/finder.js
CHANGED
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
/* import */
|
|
6
|
-
import isCustomElementName from 'is-potential-custom-element-name';
|
|
7
6
|
import nwsapi from '@asamuzakjp/nwsapi';
|
|
8
7
|
import {
|
|
9
|
-
isContentEditable, isInShadowTree, resolveContent,
|
|
10
|
-
verifyNode
|
|
8
|
+
isContentEditable, isCustomElement, isInShadowTree, resolveContent,
|
|
9
|
+
sortNodes, traverseNode, verifyNode
|
|
11
10
|
} from './dom-util.js';
|
|
12
11
|
import { matcher } from './matcher.js';
|
|
13
12
|
import {
|
|
@@ -875,6 +874,15 @@ export class Finder {
|
|
|
875
874
|
}
|
|
876
875
|
break;
|
|
877
876
|
}
|
|
877
|
+
case 'state': {
|
|
878
|
+
if (isCustomElement(node)) {
|
|
879
|
+
const [{ value: stateValue }] = astChildren;
|
|
880
|
+
if (stateValue && node[stateValue]) {
|
|
881
|
+
matched.add(node);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
break;
|
|
885
|
+
}
|
|
878
886
|
case 'current':
|
|
879
887
|
case 'nth-col':
|
|
880
888
|
case 'nth-last-col': {
|
|
@@ -1065,7 +1073,8 @@ export class Finder {
|
|
|
1065
1073
|
break;
|
|
1066
1074
|
}
|
|
1067
1075
|
case 'disabled': {
|
|
1068
|
-
if (REG_FORM_CTRL.test(localName) ||
|
|
1076
|
+
if (REG_FORM_CTRL.test(localName) ||
|
|
1077
|
+
isCustomElement(node, { formAssociated: true })) {
|
|
1069
1078
|
if (node.disabled || node.hasAttribute('disabled')) {
|
|
1070
1079
|
matched.add(node);
|
|
1071
1080
|
} else {
|
|
@@ -1092,7 +1101,7 @@ export class Finder {
|
|
|
1092
1101
|
}
|
|
1093
1102
|
case 'enabled': {
|
|
1094
1103
|
if ((REG_FORM_CTRL.test(localName) ||
|
|
1095
|
-
|
|
1104
|
+
isCustomElement(node, { formAssociated: true })) &&
|
|
1096
1105
|
!(node.disabled && node.hasAttribute('disabled'))) {
|
|
1097
1106
|
matched.add(node);
|
|
1098
1107
|
}
|
|
@@ -1561,14 +1570,8 @@ export class Finder {
|
|
|
1561
1570
|
break;
|
|
1562
1571
|
}
|
|
1563
1572
|
case 'defined': {
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
if (isCustomElementName(attr) &&
|
|
1567
|
-
this.#window.customElements.get(attr)) {
|
|
1568
|
-
matched.add(node);
|
|
1569
|
-
}
|
|
1570
|
-
} else if (isCustomElementName(localName)) {
|
|
1571
|
-
if (this.#window.customElements.get(localName)) {
|
|
1573
|
+
if (node.hasAttribute('is') || localName.includes('-')) {
|
|
1574
|
+
if (isCustomElement(node)) {
|
|
1572
1575
|
matched.add(node);
|
|
1573
1576
|
}
|
|
1574
1577
|
// NOTE: MathMLElement not implemented in jsdom
|
package/src/js/parser.js
CHANGED
|
@@ -334,8 +334,10 @@ export const filterSelector = (selector, opt = {}) => {
|
|
|
334
334
|
return false;
|
|
335
335
|
}
|
|
336
336
|
}
|
|
337
|
-
// filter namespaced selectors, e.g. ns|E
|
|
338
|
-
//
|
|
337
|
+
// filter namespaced selectors, e.g. ns|E
|
|
338
|
+
// filter pseudo-element selectors
|
|
339
|
+
// filter attribute selectors with case flag, e.g. [attr i]
|
|
340
|
+
// filter unclosed quotes
|
|
339
341
|
if (/\||::|\[\s*[\w$*=^|~-]+(?:(?:"[\w$*=^|~\s'-]+"|'[\w$*=^|~\s"-]+')?(?:\s+[\w$*=^|~-]+)+|"[^"\]]{1,255}|'[^'\]]{1,255})\s*\]/.test(selector)) {
|
|
340
342
|
return false;
|
|
341
343
|
}
|
package/types/js/dom-util.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export function verifyNode(node: any): object;
|
|
2
2
|
export function resolveContent(node: object): Array<object>;
|
|
3
3
|
export function traverseNode(node: object, walker: object): object | null;
|
|
4
|
+
export function isCustomElement(node: object, opt?: object): boolean;
|
|
4
5
|
export function isInShadowTree(node: object): boolean;
|
|
5
6
|
export function getSlottedTextContent(node: object): string | null;
|
|
6
7
|
export function getDirectionality(node: object): string | null;
|