├── src ├── assets │ └── logo.png ├── entry │ ├── popup.js │ ├── options.js │ ├── picker.css │ ├── background.js │ ├── content.js │ ├── CssSelector.js │ └── css_to_xpath.js ├── manifest.development.json ├── manifest.production.json └── view │ ├── popup.vue │ └── options.vue ├── babel.config.js ├── .gitignore ├── readme.md ├── package.json └── vue.config.js /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeneralNewsExtractor/GneList/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/entry/popup.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from '../view/popup.vue' 3 | import ElementUI from 'element-ui'; 4 | import 'element-ui/lib/theme-chalk/index.css'; 5 | 6 | Vue.use(ElementUI) 7 | 8 | Vue.config.productionTip = false 9 | 10 | new Vue({ 11 | render: (h) => h(App) 12 | }).$mount('#app') 13 | -------------------------------------------------------------------------------- /src/entry/options.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from '../view/options.vue' 3 | import ElementUI from 'element-ui'; 4 | import 'element-ui/lib/theme-chalk/index.css'; 5 | 6 | Vue.use(ElementUI) 7 | 8 | Vue.config.productionTip = false 9 | 10 | new Vue({ 11 | render: (h) => h(App) 12 | }).$mount('#app') 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | 25 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # gne-list 2 | 3 | ## 介绍与使用说明 4 | 5 | [GneList 来了!抓取列表页-极-其-简-单!](https://www.kingname.info/2022/03/09/this-is-gnelist/) 6 | 7 | ## Project setup 8 | ``` 9 | npm install 10 | ``` 11 | 12 | ### Compiles and minifies for production 13 | 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | yarn lint 21 | ``` 22 | 23 | -------------------------------------------------------------------------------- /src/manifest.development.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "GneList", 4 | "description": "Get list items XPath by mouse click.", 5 | "version": "0.0.1", 6 | "background": { 7 | "service_worker": "/js/background.js" 8 | }, 9 | "action": { 10 | "default_popup": "popup.html" 11 | }, 12 | "content_scripts": [ 13 | { 14 | "matches": [ 15 | "" 16 | ], 17 | "js": [ 18 | "/js/content.js" 19 | ] 20 | } 21 | ], 22 | "options_page": "options.html" 23 | } -------------------------------------------------------------------------------- /src/manifest.production.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "GneList", 4 | "description": "Get list items XPath by mouse click.", 5 | "version": "0.0.1", 6 | "background": { 7 | "service_worker": "/js/background.js" 8 | }, 9 | "action": { 10 | "default_popup": "popup.html" 11 | }, 12 | "content_scripts": [ 13 | { 14 | "matches": [ 15 | "" 16 | ], 17 | "js": [ 18 | "/js/CssSelector.js", 19 | "/js/css_to_xpath.js", 20 | "/js/content.js" 21 | ], 22 | "css": ["/css/picker.css"] 23 | } 24 | ], 25 | "permissions": [ 26 | "activeTab", "scripting", "tabs", "storage" 27 | ], 28 | "host_permissions": [ 29 | "*://*/*" 30 | ], 31 | "options_page": "options.html" 32 | } -------------------------------------------------------------------------------- /src/entry/picker.css: -------------------------------------------------------------------------------- 1 | .seleted-element-highlight { 2 | outline: 2px solid #C70000 !important; 3 | background-color: rgba(213, 0, 0, 0.2) !important; 4 | background: rgba(213, 0, 0, 0.2) !important; 5 | } 6 | 7 | .seleted-element-highlight * { 8 | background-color: rgba(213, 0, 0, 0.2) !important; 9 | background: rgba(213, 0, 0, 0.2) !important; 10 | } 11 | 12 | .hovered-element-highlight { 13 | outline: 2px solid green !important; 14 | background-color: rgba(0, 213, 0, 0.20) !important; 15 | background: rgba(0, 213, 0, 0.20) !important; 16 | } 17 | 18 | .hovered-element-highlight * { 19 | background-color: rgba(0, 213, 0, 0.20) !important; 20 | background: rgba(0, 213, 0, 0.20) !important; 21 | } 22 | 23 | .select-tool-bar{ 24 | z-index:99999; 25 | position: fixed; 26 | left:10px; 27 | bottom:20px; 28 | width: 100%; 29 | background-color: #FFF; 30 | } 31 | 32 | .select-tool-bar button{ 33 | color: #ffffff !important; 34 | -webkit-text-fill-color: #FFF !important; 35 | background-color: #3276b1 !important; 36 | cursor: pointer !important; 37 | width:130px !important; 38 | } 39 | 40 | .select-tool-bar input { 41 | width: 80%; 42 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gne-list", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint", 9 | "build-watch": "vue-cli-service --env.NODE_ENV=development build-watch --mode development" 10 | }, 11 | "dependencies": { 12 | "axios": "^0.26.0", 13 | "core-js": "^3.6.5", 14 | "element-ui": "^2.15.6", 15 | "vue": "^2.6.11" 16 | }, 17 | "devDependencies": { 18 | "@vue/cli-plugin-babel": "~4.5.12", 19 | "@vue/cli-plugin-eslint": "~4.5.12", 20 | "@vue/cli-service": "~4.5.12", 21 | "babel-eslint": "^10.1.0", 22 | "eslint": "^6.7.2", 23 | "eslint-plugin-vue": "^6.2.2", 24 | "vue-cli-plugin-chrome-extension-cli": "~1.1.1", 25 | "vue-template-compiler": "^2.6.11" 26 | }, 27 | "eslintConfig": { 28 | "root": true, 29 | "env": { 30 | "node": true, 31 | "webextensions": true 32 | }, 33 | "extends": [ 34 | "plugin:vue/essential", 35 | "eslint:recommended" 36 | ], 37 | "parserOptions": { 38 | "parser": "babel-eslint" 39 | }, 40 | "rules": {} 41 | }, 42 | "browserslist": [ 43 | "> 1%", 44 | "last 2 versions", 45 | "not dead" 46 | ] 47 | } 48 | -------------------------------------------------------------------------------- /src/view/popup.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 38 | 39 | 50 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const fs = require('fs') 3 | 4 | // Generate pages object 5 | const pages = {} 6 | 7 | function getEntryFile (entryPath) { 8 | let files = fs.readdirSync(entryPath) 9 | return files 10 | } 11 | 12 | const chromeName = getEntryFile(path.resolve(`src/entry`)) 13 | 14 | function getFileExtension (filename) { 15 | return /[.]/.exec(filename) ? /[^.]+$/.exec(filename)[0] : undefined 16 | } 17 | chromeName.forEach((name) => { 18 | const fileExtension = getFileExtension(name) 19 | const fileName = name.replace('.' + fileExtension, '') 20 | pages[fileName] = { 21 | entry: `src/entry/${name}`, 22 | template: 'public/index.html', 23 | filename: `${fileName}.html` 24 | } 25 | }) 26 | 27 | const isDevMode = process.env.NODE_ENV === 'development' 28 | 29 | module.exports = { 30 | pages, 31 | filenameHashing: false, 32 | chainWebpack: (config) => { 33 | config.plugin('copy').use(require('copy-webpack-plugin'), [ 34 | [ 35 | { 36 | from: path.resolve(`src/manifest.${process.env.NODE_ENV}.json`), 37 | to: `${path.resolve('dist')}/manifest.json` 38 | } 39 | ] 40 | 41 | ]) 42 | }, 43 | configureWebpack: { 44 | output: { 45 | filename: `js/[name].js`, 46 | chunkFilename: `[name].js` 47 | }, 48 | devtool: isDevMode ? 'inline-source-map' : false 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/entry/background.js: -------------------------------------------------------------------------------- 1 | let backend = 'http://127.0.0.1:8800/rule' 2 | 3 | function post_data_to_backend(msg) { 4 | var options = { 5 | method: "post", 6 | headers: { 7 | 'Accept': 'application/json', 8 | 'Content-Type': 'application/json;charset=UTF-8' 9 | }, 10 | body: JSON.stringify({data: msg}) 11 | } 12 | chrome.storage.sync.get('backend_address', ({backend_address}) => { 13 | if (backend_address) { 14 | backend = backend_address 15 | } 16 | console.log('send data to backend: ' + backend) 17 | fetch(backend, options) 18 | .then(response => response.json()) 19 | .then(response => { 20 | console.log(response) 21 | }).catch((err) => { 22 | console.log('xxxx', err) 23 | }) 24 | }) 25 | } 26 | 27 | chrome.runtime.onMessage.addListener( 28 | function(request, sender) { 29 | console.log(request, sender) 30 | // 这个函数目前只处理从content script传过来的 31 | //XPath信息,其它消息全部取消 32 | if (!sender.tab) { 33 | return 34 | } 35 | if (request.from !== 'picker') { 36 | return 37 | } 38 | 39 | var url = sender.url 40 | var xpath = request.message 41 | console.log('选择的xpath为:', request) 42 | var body = { 43 | url: url, 44 | xpath: xpath, 45 | name: request.name, 46 | dedup: request.dedup 47 | } 48 | post_data_to_backend(body) 49 | } 50 | ) -------------------------------------------------------------------------------- /src/view/options.vue: -------------------------------------------------------------------------------- 1 | 67 | 68 | 151 | 152 | 162 | -------------------------------------------------------------------------------- /src/entry/content.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | console.log('start to inject content js') 4 | var skip_class = ['select-tool-bar', 5 | 'done-select', 6 | 'show-select-xpath', 7 | 'select-parent', 8 | 'extract_data', 9 | 'cancel-select' 10 | ] 11 | var rule_name = '' 12 | var dedup = false // 是否根据 rule_name去重 13 | var CssSelector = window.CssSelector 14 | var selected_elements = [] 15 | var selector = new CssSelector({ 16 | parent: document, 17 | enableResultStripping: true, 18 | enableSmartTableSelector: true, 19 | allowMultipleSelectors: false, 20 | ignoredClasses: skip_class 21 | }) 22 | var top = 0 23 | var css_selector_result = '' 24 | var xpath_result = '' 25 | 26 | chrome.runtime.onMessage.addListener( 27 | function(request, sender) { 28 | console.log(sender.tab ? 29 | "from a content script:" + sender.tab.url : 30 | "from the extension"); 31 | if (request.command === 'trigger') { 32 | console.log('receive command to trigger...', request) 33 | rule_name = request.name 34 | dedup = request.dedup 35 | start_to_find_xpath() 36 | } 37 | if (request.command === 'close') { 38 | console.log('close picker') 39 | stop_finding_xpath() 40 | } 41 | return true 42 | } 43 | ) 44 | 45 | function send_message_to_background(message) { 46 | chrome.runtime.sendMessage(message) 47 | } 48 | 49 | function highlight(element, light_type){ 50 | if (element === null) { 51 | return 52 | } 53 | if (light_type === 'selected') { 54 | // 选中被高亮的元素可能有很多个 55 | // 同时也要取消hover的元素 56 | remove_highlight('hover') 57 | //remove_highlight('selected') 58 | element.classList.add('seleted-element-highlight') 59 | } else if (light_type === 'hover') { 60 | remove_highlight('hover') 61 | element.classList.add('hovered-element-highlight') 62 | } 63 | } 64 | 65 | function highlight_elements(elements) { 66 | for (var element of elements) { 67 | highlight(element) 68 | } 69 | } 70 | 71 | function highlight_selected(css_selector) { 72 | remove_highlight('selected') 73 | var elements = document.querySelectorAll(css_selector) 74 | elements.forEach(function(element) { 75 | element.classList.add('seleted-element-highlight') 76 | }) 77 | } 78 | 79 | function disable_a_link() { 80 | var a_tags = document.getElementsByTagName('a') 81 | for (var i=0; i { 105 | el.classList.remove('seleted-element-highlight') 106 | }) 107 | } 108 | } 109 | 110 | function get_current_element(event){ 111 | var x = event.clientX, y = event.clientY, 112 | element = document.elementFromPoint(x, y); 113 | return element 114 | } 115 | 116 | function track_mouse(event){ 117 | var elementMouseIsOver = get_current_element(event) 118 | if (!elementMouseIsOver) { 119 | return 120 | } 121 | var class_name = elementMouseIsOver.className 122 | if (class_name && skip_class.includes(class_name)) { 123 | return 124 | } 125 | highlight(elementMouseIsOver, 'hover') 126 | } 127 | 128 | function choose_element(event) { 129 | var element = get_current_element(event) 130 | if (!element) { 131 | return 132 | } 133 | 134 | var class_name = element.className 135 | if(class_name && skip_class.includes(class_name)) { 136 | return 137 | } 138 | remove_highlight('hover') 139 | if (selected_elements.length === 0) { 140 | selected_elements.push(element) 141 | result = selector.getCssSelector([element]) 142 | console.log('第一个元素选中:', result) 143 | } else { 144 | // selected_elements里面已经有一个节点了,那么 145 | // 要考虑现在是不是在点击列表页的连续两项,如果是, 146 | // 那么就要智能扩展到整个列表 147 | // element = merge_elements(element) 148 | result = selector.getCssSelector([selected_elements[0], element]) 149 | if (!element) { 150 | return 151 | } 152 | } 153 | highlight_selected(result) 154 | css_selector_result = result 155 | var xpath = window.cssxpath(result) 156 | console.log('the merged selector is :', xpath) 157 | xpath_result = xpath 158 | var input = document.querySelector('.show-select-xpath') 159 | input.value = result 160 | } 161 | 162 | function start_to_find_xpath(){ 163 | top = 0 164 | selected_elements = [] 165 | add_corner_button() 166 | disable_a_link() 167 | window.onmousemove = track_mouse 168 | window.onmousedown = choose_element 169 | } 170 | 171 | function stop_finding_xpath() { 172 | remove_highlight('selected') 173 | remove_highlight('hover') 174 | window.onmousedown = null 175 | window.onmousemove = null 176 | enable_a_link() 177 | var body = document.getElementsByTagName('body')[0] 178 | var done = document.querySelector('.select-tool-bar') 179 | body.removeChild(done) 180 | } 181 | 182 | function get_parent_element(element) { 183 | return element.parentNode 184 | } 185 | 186 | function select_done() { 187 | var msg_to_background = {from: 'picker', 'message': xpath_result, 'name': rule_name, 'dedup': dedup} 188 | console.log('msg_to_background:', msg_to_background) 189 | send_message_to_background(msg_to_background) 190 | stop_finding_xpath() 191 | 192 | } 193 | 194 | function select_parent() { 195 | top-- 196 | } 197 | 198 | function get_extracted_data() { 199 | var elements = document.querySelectorAll(css_selector_result) 200 | console.log('>>>', css_selector_result, elements) 201 | var extract_result = [] 202 | elements.forEach((row) => { 203 | var tag = row.tagName.toLowerCase() 204 | var inner_text = row.innerText 205 | var url = row.href 206 | console.log(tag, url, inner_text) 207 | extract_result.push({'tag': tag, text: inner_text, url: url}) 208 | }) 209 | alert(JSON.stringify(extract_result)) 210 | 211 | 212 | } 213 | 214 | function add_corner_button() { 215 | //在网页左下角添加一个按钮,用来细化picker的红框 216 | var done = document.createElement('button') 217 | var text = document.createTextNode('提交') 218 | done.appendChild(text) 219 | done.onclick = select_done 220 | done.setAttribute('class', 'done-select') 221 | 222 | var input = document.createElement('input') 223 | input.setAttribute('class', 'show-select-xpath') 224 | input.setAttribute('type', 'text') 225 | 226 | // var parent = document.createElement('button') 227 | // parent.appendChild(document.createTextNode('P')) 228 | // parent.setAttribute('class', 'select-parent') 229 | // parent.onclick = select_parent 230 | 231 | var cancel = document.createElement('button') 232 | cancel.appendChild(document.createTextNode('取消')) 233 | cancel.setAttribute('class', 'cancel-select') 234 | cancel.onclick = stop_finding_xpath 235 | 236 | var extract_data = document.createElement('button') 237 | extract_data.setAttribute('class', 'extract_data') 238 | extract_data.appendChild(document.createTextNode('测试')) 239 | extract_data.onclick = get_extracted_data 240 | 241 | var div = document.createElement('div') 242 | div.appendChild(input) 243 | div.appendChild(cancel) 244 | div.appendChild(done) 245 | div.appendChild(extract_data) 246 | div.setAttribute('class', 'select-tool-bar') 247 | var body = document.getElementsByTagName('body')[0] 248 | body.appendChild(div) 249 | } 250 | -------------------------------------------------------------------------------- /src/entry/CssSelector.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | "use strict"; 3 | console.log('css selector is injecting...') 4 | var CssSelector = function (options) { 5 | 6 | var me = this; 7 | 8 | // defaults 9 | this.ignoredTags = ['font', 'b', 'i', 's']; 10 | this.parent = document; 11 | this.ignoredClassBase = false; 12 | this.enableResultStripping = true; 13 | this.enableSmartTableSelector = false; 14 | this.ignoredClasses = []; 15 | this.allowMultipleSelectors = false; 16 | this.query = function (selector) { 17 | return me.parent.querySelectorAll(selector); 18 | }; 19 | 20 | // overrides defaults with options 21 | for (var i in options) { 22 | this[i] = options[i]; 23 | } 24 | 25 | // jquery parent selector fix 26 | if (this.query === window.jQuery) { 27 | this.query = function (selector) { 28 | return jQuery(me.parent).find(selector); 29 | }; 30 | } 31 | }; 32 | 33 | // TODO refactor element selector list into a ~ class 34 | var ElementSelector = function (element, ignoredClasses) { 35 | 36 | this.element = element; 37 | this.isDirectChild = true; 38 | this.tag = element.localName; 39 | this.tag = this.tag.replace(/:/g, '\\:'); 40 | 41 | // nth-of-child(n+1) 42 | this.indexn = null; 43 | this.index = 1; 44 | this.id = null; 45 | this.classes = new Array(); 46 | 47 | // do not add additinal info to html, body tags. 48 | // html:nth-of-type(1) cannot be selected 49 | if(this.tag === 'html' || this.tag === 'HTML' 50 | || this.tag === 'body' || this.tag === 'BODY') { 51 | this.index = null; 52 | return; 53 | } 54 | 55 | if (element.parentNode !== undefined) { 56 | // nth-child 57 | //this.index = [].indexOf.call(element.parentNode.children, element)+1; 58 | 59 | // nth-of-type 60 | for (var i = 0; i < element.parentNode.children.length; i++) { 61 | var child = element.parentNode.children[i]; 62 | if (child === element) { 63 | break; 64 | } 65 | if (child.tagName === element.tagName) { 66 | this.index++; 67 | } 68 | } 69 | } 70 | 71 | if (element.id !== '') { 72 | if (typeof element.id === 'string') { 73 | this.id = element.id; 74 | this.id = this.id.replace(/:/g, '\\:'); 75 | } 76 | } 77 | 78 | for (var i = 0; i < element.classList.length; i++) { 79 | var cclass = element.classList[i]; 80 | if (ignoredClasses.indexOf(cclass) === -1) { 81 | cclass = cclass.replace(/:/g, '\\:'); 82 | this.classes.push(cclass); 83 | } 84 | } 85 | }; 86 | 87 | var ElementSelectorList = function (CssSelector) { 88 | this.CssSelector = CssSelector; 89 | }; 90 | 91 | ElementSelectorList.prototype = new Array(); 92 | 93 | ElementSelectorList.prototype.getCssSelector = function () { 94 | 95 | var resultSelectors = []; 96 | 97 | // TDD 98 | for (var i = 0; i < this.length; i++) { 99 | var selector = this[i]; 100 | 101 | var isFirstSelector = i === this.length-1; 102 | var resultSelector = selector.getCssSelector(isFirstSelector); 103 | 104 | if (this.CssSelector.enableSmartTableSelector) { 105 | if (selector.tag === 'tr') { 106 | if (selector.element.children.length === 2) { 107 | if (selector.element.children[0].tagName === 'TD' 108 | || selector.element.children[0].tagName === 'TH' 109 | || selector.element.children[0].tagName === 'TR') { 110 | 111 | var text = selector.element.children[0].textContent; 112 | text = text.trim(); 113 | 114 | // escape quotes 115 | text.replace(/(\\*)(')/g, function (x) { 116 | var l = x.length; 117 | return (l % 2) ? x : x.substring(0, l - 1) + "\\'"; 118 | }); 119 | resultSelector += ":contains('" + text + "')"; 120 | } 121 | } 122 | } 123 | } 124 | 125 | resultSelectors.push(resultSelector); 126 | } 127 | 128 | var resultCSSSelector = resultSelectors.reverse().join(' '); 129 | return resultCSSSelector; 130 | }; 131 | 132 | ElementSelector.prototype = { 133 | 134 | getCssSelector: function (isFirstSelector) { 135 | 136 | if(isFirstSelector === undefined) { 137 | isFirstSelector = false; 138 | } 139 | 140 | var selector = this.tag; 141 | if (this.id !== null) { 142 | // id can not startswith number, it will break the selector 143 | if(/^\d/.test(this.id)) { 144 | selector += "[id='" + this.id + "']" 145 | } else { 146 | selector += '#' + this.id; 147 | } 148 | 149 | } 150 | if (this.classes.length) { 151 | for (var i = 0; i < this.classes.length; i++) { 152 | selector += "." + this.classes[i]; 153 | } 154 | } 155 | if (this.index !== null) { 156 | selector += ':nth-of-type(' + this.index + ')'; 157 | } 158 | if (this.indexn !== null && this.indexn !== -1) { 159 | selector += ':nth-of-type(n+' + this.indexn + ')'; 160 | } 161 | if(this.isDirectChild && isFirstSelector === false) { 162 | selector = "> "+selector; 163 | } 164 | 165 | return selector; 166 | }, 167 | // merges this selector with another one. 168 | merge: function (mergeSelector) { 169 | 170 | if (this.tag !== mergeSelector.tag) { 171 | throw "different element selected (tag)"; 172 | } 173 | 174 | if (this.index !== null) { 175 | if (this.index !== mergeSelector.index) { 176 | 177 | // use indexn only for two elements 178 | if (this.indexn === null) { 179 | var indexn = Math.min(mergeSelector.index, this.index); 180 | if (indexn > 1) { 181 | this.indexn = Math.min(mergeSelector.index, this.index); 182 | } 183 | } 184 | else { 185 | this.indexn = -1; 186 | } 187 | 188 | this.index = null; 189 | } 190 | } 191 | 192 | if(this.isDirectChild === true) { 193 | this.isDirectChild = mergeSelector.isDirectChild; 194 | } 195 | 196 | if (this.id !== null) { 197 | if (this.id !== mergeSelector.id) { 198 | this.id = null; 199 | } 200 | } 201 | 202 | if (this.classes.length !== 0) { 203 | var classes = new Array(); 204 | 205 | for (var i in this.classes) { 206 | var cclass = this.classes[i]; 207 | if (mergeSelector.classes.indexOf(cclass) !== -1) { 208 | classes.push(cclass); 209 | } 210 | } 211 | 212 | this.classes = classes; 213 | } 214 | } 215 | }; 216 | 217 | CssSelector.prototype = { 218 | mergeElementSelectors: function (newSelecors) { 219 | 220 | if (newSelecors.length < 1) { 221 | throw "No selectors specified"; 222 | } 223 | else if (newSelecors.length === 1) { 224 | return newSelecors[0]; 225 | } 226 | 227 | // check selector total count 228 | var elementCountInSelector = newSelecors[0].length; 229 | for (var i = 0; i < newSelecors.length; i++) { 230 | var selector = newSelecors[i]; 231 | if (selector.length !== elementCountInSelector) { 232 | throw "Invalid element count in selector"; 233 | } 234 | } 235 | 236 | // merge selectors 237 | var resultingElements = newSelecors[0]; 238 | for (var i = 1; i < newSelecors.length; i++) { 239 | var mergeElements = newSelecors[i]; 240 | 241 | for (var j = 0; j < elementCountInSelector; j++) { 242 | resultingElements[j].merge(mergeElements[j]); 243 | } 244 | } 245 | return resultingElements; 246 | }, 247 | stripSelector: function (selectors) { 248 | 249 | var cssSeletor = selectors.getCssSelector(); 250 | var baseSelectedElements = this.query(cssSeletor); 251 | 252 | var compareElements = function (elements) { 253 | if (baseSelectedElements.length !== elements.length) { 254 | return false; 255 | } 256 | 257 | for (var j = 0; j < baseSelectedElements.length; j++) { 258 | if ([].indexOf.call(elements, baseSelectedElements[j]) === -1) { 259 | return false; 260 | } 261 | } 262 | return true; 263 | }; 264 | // strip indexes 265 | for (var i = 0; i < selectors.length; i++) { 266 | var selector = selectors[i]; 267 | if (selector.index !== null) { 268 | var index = selector.index; 269 | selector.index = null; 270 | var cssSeletor = selectors.getCssSelector(); 271 | var newSelectedElements = this.query(cssSeletor); 272 | // if results doesn't match then undo changes 273 | if (!compareElements(newSelectedElements)) { 274 | selector.index = index; 275 | } 276 | } 277 | } 278 | 279 | // strip isDirectChild 280 | for (var i = 0; i < selectors.length; i++) { 281 | var selector = selectors[i]; 282 | if (selector.isDirectChild === true) { 283 | selector.isDirectChild = false; 284 | var cssSeletor = selectors.getCssSelector(); 285 | var newSelectedElements = this.query(cssSeletor); 286 | // if results doesn't match then undo changes 287 | if (!compareElements(newSelectedElements)) { 288 | selector.isDirectChild = true; 289 | } 290 | } 291 | } 292 | 293 | // strip ids 294 | for (var i = 0; i < selectors.length; i++) { 295 | var selector = selectors[i]; 296 | if (selector.id !== null) { 297 | var id = selector.id; 298 | selector.id = null; 299 | var cssSeletor = selectors.getCssSelector(); 300 | var newSelectedElements = this.query(cssSeletor); 301 | // if results doesn't match then undo changes 302 | if (!compareElements(newSelectedElements)) { 303 | selector.id = id; 304 | } 305 | } 306 | } 307 | 308 | // strip classes 309 | for (var i = 0; i < selectors.length; i++) { 310 | var selector = selectors[i]; 311 | if (selector.classes.length !== 0) { 312 | for (var j = selector.classes.length - 1; j > 0; j--) { 313 | var cclass = selector.classes[j]; 314 | selector.classes.splice(j, 1); 315 | var cssSeletor = selectors.getCssSelector(); 316 | var newSelectedElements = this.query(cssSeletor); 317 | // if results doesn't match then undo changes 318 | if (!compareElements(newSelectedElements)) { 319 | selector.classes.splice(j, 0, cclass); 320 | } 321 | } 322 | } 323 | } 324 | 325 | // strip tags 326 | for (var i = selectors.length - 1; i > 0; i--) { 327 | var selector = selectors[i]; 328 | selectors.splice(i, 1); 329 | var cssSeletor = selectors.getCssSelector(); 330 | var newSelectedElements = this.query(cssSeletor); 331 | // if results doesn't match then undo changes 332 | if (!compareElements(newSelectedElements)) { 333 | selectors.splice(i, 0, selector); 334 | } 335 | } 336 | 337 | return selectors; 338 | }, 339 | getElementSelectors: function (elements, top) { 340 | var elementSelectors = []; 341 | 342 | for (var i = 0; i < elements.length; i++) { 343 | var element = elements[i]; 344 | var elementSelector = this.getElementSelector(element, top); 345 | elementSelectors.push(elementSelector); 346 | } 347 | 348 | return elementSelectors; 349 | }, 350 | getElementSelector: function (element, top) { 351 | 352 | var elementSelectorList = new ElementSelectorList(this); 353 | while (true) { 354 | if (element === this.parent) { 355 | break; 356 | } 357 | else if (element === undefined || element === document) { 358 | throw 'element is not a child of the given parent'; 359 | } 360 | if (this.isIgnoredTag(element.tagName)) { 361 | 362 | element = element.parentNode; 363 | continue; 364 | } 365 | if (top > 0) { 366 | top--; 367 | element = element.parentNode; 368 | continue; 369 | } 370 | 371 | var selector = new ElementSelector(element, this.ignoredClasses); 372 | // document does not have a tagName 373 | if(element.parentNode === document || this.isIgnoredTag(element.parentNode.tagName)) { 374 | selector.isDirectChild = false; 375 | } 376 | 377 | elementSelectorList.push(selector); 378 | element = element.parentNode; 379 | } 380 | 381 | return elementSelectorList; 382 | }, 383 | 384 | /** 385 | * Compares whether two elements are similar. Similar elements should 386 | * have a common parrent and all parent elements should be the same type. 387 | * @param element1 388 | * @param element2 389 | */ 390 | checkSimilarElements: function(element1, element2) { 391 | 392 | while (true) { 393 | 394 | if(element1.tagName !== element2.tagName) { 395 | return false; 396 | } 397 | if(element1 === element2) { 398 | return true; 399 | } 400 | 401 | // stop at body tag 402 | if (element1 === undefined || element1.tagName === 'body' 403 | || element1.tagName === 'BODY') { 404 | return false; 405 | } 406 | if (element2 === undefined || element2.tagName === 'body' 407 | || element2.tagName === 'BODY') { 408 | return false; 409 | } 410 | 411 | element1 = element1.parentNode; 412 | element2 = element2.parentNode; 413 | } 414 | }, 415 | 416 | /** 417 | * Groups elements into groups if the emelents are not similar 418 | * @param elements 419 | */ 420 | getElementGroups: function(elements) { 421 | 422 | // first elment is in the first group 423 | // @TODO maybe i dont need this? 424 | var groups = [[elements[0]]]; 425 | 426 | for(var i = 1; i < elements.length; i++) { 427 | var elementNew = elements[i]; 428 | var addedToGroup = false; 429 | for(var j = 0; j < groups.length; j++) { 430 | var group = groups[j]; 431 | var elementGroup = group[0]; 432 | if(this.checkSimilarElements(elementNew, elementGroup)) { 433 | group.push(elementNew); 434 | addedToGroup = true; 435 | break; 436 | } 437 | } 438 | 439 | // add new group 440 | if(!addedToGroup) { 441 | groups.push([elementNew]); 442 | } 443 | } 444 | 445 | return groups; 446 | }, 447 | getCssSelector: function (elements, top) { 448 | 449 | top = top || 0; 450 | 451 | var enableSmartTableSelector = this.enableSmartTableSelector; 452 | if (elements.length > 1) { 453 | this.enableSmartTableSelector = false; 454 | } 455 | 456 | // group elements into similarity groups 457 | var elementGroups = this.getElementGroups(elements); 458 | 459 | var resultCSSSelector; 460 | 461 | if(this.allowMultipleSelectors) { 462 | 463 | var groupSelectors = []; 464 | 465 | for(var i = 0; i < elementGroups.length; i++) { 466 | var groupElements = elementGroups[i]; 467 | 468 | var elementSelectors = this.getElementSelectors(groupElements, top); 469 | var resultSelector = this.mergeElementSelectors(elementSelectors); 470 | if (this.enableResultStripping) { 471 | resultSelector = this.stripSelector(resultSelector); 472 | } 473 | 474 | groupSelectors.push(resultSelector.getCssSelector()); 475 | } 476 | 477 | resultCSSSelector = groupSelectors.join(', '); 478 | } 479 | else { 480 | if(elementGroups.length !== 1) { 481 | throw "found multiple element groups, but allowMultipleSelectors disabled"; 482 | } 483 | 484 | var elementSelectors = this.getElementSelectors(elements, top); 485 | var resultSelector = this.mergeElementSelectors(elementSelectors); 486 | if (this.enableResultStripping) { 487 | resultSelector = this.stripSelector(resultSelector); 488 | } 489 | 490 | resultCSSSelector = resultSelector.getCssSelector(); 491 | } 492 | 493 | this.enableSmartTableSelector = enableSmartTableSelector; 494 | 495 | // strip down selector 496 | return resultCSSSelector; 497 | }, 498 | isIgnoredTag: function (tag) { 499 | return this.ignoredTags.indexOf(tag.toLowerCase()) !== -1; 500 | } 501 | }; 502 | 503 | console.log('css selector injected done.') 504 | window.CssSelector = CssSelector -------------------------------------------------------------------------------- /src/entry/css_to_xpath.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i number}, 27 | terminals_: {associative list: number ==> name}, 28 | productions_: [...], 29 | performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$), 30 | table: [...], 31 | defaultActions: {...}, 32 | parseError: function(str, hash), 33 | parse: function(input), 34 | 35 | lexer: { 36 | EOF: 1, 37 | parseError: function(str, hash), 38 | setInput: function(input), 39 | input: function(), 40 | unput: function(str), 41 | more: function(), 42 | less: function(n), 43 | pastInput: function(), 44 | upcomingInput: function(), 45 | showPosition: function(), 46 | test_match: function(regex_match_array, rule_index), 47 | next: function(), 48 | lex: function(), 49 | begin: function(condition), 50 | popState: function(), 51 | _currentRules: function(), 52 | topState: function(), 53 | pushState: function(condition), 54 | 55 | options: { 56 | ranges: boolean (optional: true ==> token location info will include a .range[] member) 57 | flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match) 58 | backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code) 59 | }, 60 | 61 | performAction: function(yy, yy_, $avoiding_name_collisions, YY_START), 62 | rules: [...], 63 | conditions: {associative list: name ==> set}, 64 | } 65 | } 66 | 67 | 68 | token location info (@$, _$, etc.): { 69 | first_line: n, 70 | last_line: n, 71 | first_column: n, 72 | last_column: n, 73 | range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based) 74 | } 75 | 76 | 77 | the parseError function receives a 'hash' object with these members for lexer and parser errors: { 78 | text: (matched text) 79 | token: (the produced terminal token, if any) 80 | line: (yylineno) 81 | } 82 | while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: { 83 | loc: (yylloc) 84 | expected: (string describing the set of expected tokens) 85 | recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error) 86 | } 87 | */ 88 | var parser = (function(){ 89 | var parser = {trace: function trace() { }, 90 | yy: {}, 91 | symbols_: {"error":2,"expressions":3,"selector_list":4,"EOF":5,"comma":6,"selector":7,",":8,"S":9,"combinator_selector":10,"simple_selector":11,"element":12,"constraint_list":13,"padded_child_combinator":14,"padded_tilde":15,"padded_plus":16,">":17,"ident":18,"*":19,"constraint":20,"class":21,"hash":22,"attrib":23,"pseudo":24,".":25,"#":26,"IDENT":27,"n":28,"[":29,"padded_ident":30,"]":31,"=":32,"padded_ident_or_string":33,"CONTAINS":34,"DOES_NOT_CONTAIN":35,"CONTAINS_WORD":36,"CONTAINS_PREFIX":37,"STARTS_WITH":38,"ENDS_WITH":39,"string":40,"~":41,"+":42,"SINGLE_QUOTED_STRING":43,"DOUBLE_QUOTED_STRING":44,":":45,"func":46,"ODD_ARGUMENT":47,"EVEN_ARGUMENT":48,"(":49,"func_arguments":50,")":51,"INTEGER":52,"an_plus_b":53,"odd":54,"even":55,"negative_integer":56,"signed_integer":57,"positive_integer":58,"unsigned_integer":59,"-":60,"NEGATIVE_INTEGER":61,"POSITIVE_INTEGER":62,"$accept":0,"$end":1}, 92 | terminals_: {2:"error",5:"EOF",8:",",9:"S",17:">",19:"*",25:".",26:"#",27:"IDENT",28:"n",29:"[",31:"]",32:"=",34:"CONTAINS",35:"DOES_NOT_CONTAIN",36:"CONTAINS_WORD",37:"CONTAINS_PREFIX",38:"STARTS_WITH",39:"ENDS_WITH",41:"~",42:"+",43:"SINGLE_QUOTED_STRING",44:"DOUBLE_QUOTED_STRING",45:":",47:"ODD_ARGUMENT",48:"EVEN_ARGUMENT",49:"(",51:")",52:"INTEGER",54:"odd",55:"even",60:"-",61:"NEGATIVE_INTEGER",62:"POSITIVE_INTEGER"}, 93 | productions_: [0,[3,2],[4,3],[4,1],[6,1],[6,2],[7,1],[7,1],[11,2],[11,1],[11,1],[10,3],[10,3],[10,3],[10,3],[10,3],[10,2],[12,1],[12,1],[13,2],[13,1],[20,1],[20,1],[20,1],[20,1],[21,2],[22,2],[18,1],[18,1],[23,3],[23,5],[23,5],[23,5],[23,5],[23,5],[23,5],[23,5],[30,3],[30,2],[30,2],[30,1],[33,1],[33,3],[33,2],[33,2],[33,1],[14,3],[14,2],[14,2],[14,1],[15,3],[15,2],[15,2],[15,1],[16,3],[16,2],[16,2],[16,1],[40,1],[40,1],[24,2],[24,2],[46,2],[46,2],[46,4],[46,4],[46,3],[50,1],[50,1],[53,1],[53,1],[53,3],[53,3],[53,3],[53,3],[53,2],[53,2],[53,2],[57,1],[57,1],[56,1],[58,1],[59,1]], 94 | performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) { 95 | /* this == yyval */ 96 | 97 | var $0 = $$.length - 1; 98 | switch (yystate) { 99 | case 1: return $$[$0-1]; 100 | break; 101 | case 2: $$[$0-2].selectors.push($$[$0]); this.$ = $$[$0-2] 102 | break; 103 | case 3: this.$ = yy.create({ type: 'selector_list', selectors: [$$[$0]] }) 104 | break; 105 | case 8: $$[$0-1].constraints = $$[$0].constraints; this.$ = $$[$0-1] 106 | break; 107 | case 10: this.$ = yy.create( 108 | { type: 'constraint_list', constraints: $$[$0].constraints } 109 | ) 110 | 111 | break; 112 | case 11: this.$ = yy.create({ type: 'combinator_selector', left: $$[$0-2], right: $$[$0], combinator: 'child' }) 113 | break; 114 | case 12: this.$ = yy.create({ type: 'combinator_selector', left: $$[$0-2], right: $$[$0], combinator: 'descendant' }) 115 | break; 116 | case 13: this.$ = yy.create({ type: 'previous_sibling', left: $$[$0-2], right: $$[$0] }) 117 | break; 118 | case 14: this.$ = yy.create({ type: 'adjacent_sibling', left: $$[$0-2], right: $$[$0] }) 119 | break; 120 | case 15: this.$ = yy.create({ type: 'immediate_child', child: $$[$0], combinator: 'child' }) 121 | break; 122 | case 16: this.$ = yy.create({ type: 'immediate_child', child: $$[$0], combinator: 'child' }) 123 | break; 124 | case 17: this.$ = yy.create({ type: 'element', name: $$[$0], constraints: [] }) 125 | break; 126 | case 18: this.$ = yy.create({ type: 'element', name: $$[$0], constraints: [] }) 127 | break; 128 | case 19: $$[$0-1].constraints.push($$[$0]); this.$ = $$[$0-1] 129 | break; 130 | case 20: this.$ = yy.create({ type: 'constraint_list', constraints: [$$[$0]] }) 131 | break; 132 | case 25: this.$ = { type: 'class', name: $$[$0] } 133 | break; 134 | case 26: this.$ = { type: 'id', name: $$[$0] } 135 | break; 136 | case 29: this.$ = yy.create({ type: 'has_attribute', name: $$[$0-1] }) 137 | break; 138 | case 30: this.$ = yy.create({ type: 'attribute_equals', name: $$[$0-3], value: $$[$0-1] }) 139 | break; 140 | case 31: this.$ = yy.create({ type: 'attribute_contains', name: $$[$0-3], value: $$[$0-1] }) 141 | break; 142 | case 32: this.$ = yy.create({ type: 'attribute_does_not_contain', name: $$[$0-3], value: $$[$0-1] }) 143 | break; 144 | case 33: this.$ = yy.create({ type: 'attribute_contains_word', name: $$[$0-3], value: $$[$0-1] }) 145 | break; 146 | case 34: this.$ = yy.create({ type: 'attribute_contains_prefix', name: $$[$0-3], value: $$[$0-1] }) 147 | break; 148 | case 35: this.$ = yy.create({ type: 'attribute_starts_with', name: $$[$0-3], value: $$[$0-1] }) 149 | break; 150 | case 36: this.$ = yy.create({ type: 'attribute_ends_with', name: $$[$0-3], value: $$[$0-1] }) 151 | break; 152 | case 37: this.$ = $$[$0-1] 153 | break; 154 | case 38: this.$ = $$[$0] 155 | break; 156 | case 39: this.$ = $$[$0-1] 157 | break; 158 | case 40: this.$ = $$[$0] 159 | break; 160 | case 42: this.$ = $$[$0-2] 161 | break; 162 | case 43: this.$ = $$[$0] 163 | break; 164 | case 44: this.$ = $$[$0-1] 165 | break; 166 | case 45: this.$ = $$[$0] 167 | break; 168 | case 58: this.$ = $$[$0].substr(1, $$[$0].length - 2) 169 | break; 170 | case 59: this.$ = $$[$0].substr(1, $$[$0].length - 2) 171 | break; 172 | case 60: this.$ = yy.create({ type: 'pseudo_func', func: $$[$0] }) 173 | break; 174 | case 61: this.$ = yy.create({ type: 'pseudo_class', name: $$[$0] }) 175 | break; 176 | case 62: this.$ = { type: 'function', name: $$[$0-1], args: { type: 'odd' } } 177 | break; 178 | case 63: this.$ = { type: 'function', name: $$[$0-1], args: { type: 'even' } } 179 | break; 180 | case 64: this.$ = { type: 'function', name: $$[$0-3], args: $$[$0-1] } 181 | break; 182 | case 65: this.$ = { type: 'function', name: $$[$0-3], args: $$[$0-1] } 183 | break; 184 | case 66: this.$ = { type: 'function', name: $$[$0-2] } 185 | break; 186 | case 69: this.$ = { type: 'odd' } 187 | break; 188 | case 70: this.$ = { type: 'even' } 189 | break; 190 | case 71: this.$ = { type: 'an_plus_b', a: $$[$0-2], b: $$[$0] } 191 | break; 192 | case 72: this.$ = { type: 'an_plus_b', a: $$[$0-2], b: $$[$0] } 193 | break; 194 | case 73: this.$ = { type: 'an_plus_b', a: $$[$0-2], b: $$[$0] } 195 | break; 196 | case 74: this.$ = { type: 'an_plus_b', a: -1, b: $$[$0] } 197 | break; 198 | case 75: this.$ = { type: 'n_plus_b', b: $$[$0] } 199 | break; 200 | case 76: this.$ = { type: 'an', a: $$[$0-1] } 201 | break; 202 | case 77: this.$ = { type: 'an', a: $$[$0-1] } 203 | break; 204 | case 80: this.$ = Number($$[$0]) 205 | break; 206 | case 81: this.$ = Number($$[$0]) 207 | break; 208 | case 82: this.$ = Number($$[$0]) 209 | break; 210 | } 211 | }, 212 | table: [{3:1,4:2,7:3,10:4,11:5,12:7,13:8,17:[1,6],18:9,19:[1,10],20:11,21:14,22:15,23:16,24:17,25:[1,18],26:[1,19],27:[1,12],28:[1,13],29:[1,20],45:[1,21]},{1:[3]},{5:[1,22],6:23,8:[1,24]},{5:[2,3],8:[2,3],9:[1,26],14:25,15:27,16:28,17:[1,29],41:[1,30],42:[1,31],51:[2,3]},{5:[2,6],8:[2,6],9:[2,6],17:[2,6],41:[2,6],42:[2,6],51:[2,6]},{5:[2,7],8:[2,7],9:[2,7],17:[2,7],41:[2,7],42:[2,7],51:[2,7]},{9:[1,32],11:33,12:7,13:8,18:9,19:[1,10],20:11,21:14,22:15,23:16,24:17,25:[1,18],26:[1,19],27:[1,12],28:[1,13],29:[1,20],45:[1,21]},{5:[2,9],8:[2,9],9:[2,9],13:34,17:[2,9],20:11,21:14,22:15,23:16,24:17,25:[1,18],26:[1,19],29:[1,20],41:[2,9],42:[2,9],45:[1,21],51:[2,9]},{5:[2,10],8:[2,10],9:[2,10],17:[2,10],20:35,21:14,22:15,23:16,24:17,25:[1,18],26:[1,19],29:[1,20],41:[2,10],42:[2,10],45:[1,21],51:[2,10]},{5:[2,17],8:[2,17],9:[2,17],17:[2,17],25:[2,17],26:[2,17],29:[2,17],41:[2,17],42:[2,17],45:[2,17],51:[2,17]},{5:[2,18],8:[2,18],9:[2,18],17:[2,18],25:[2,18],26:[2,18],29:[2,18],41:[2,18],42:[2,18],45:[2,18],51:[2,18]},{5:[2,20],8:[2,20],9:[2,20],17:[2,20],25:[2,20],26:[2,20],29:[2,20],41:[2,20],42:[2,20],45:[2,20],51:[2,20]},{5:[2,27],8:[2,27],9:[2,27],17:[2,27],25:[2,27],26:[2,27],29:[2,27],31:[2,27],32:[2,27],34:[2,27],35:[2,27],36:[2,27],37:[2,27],38:[2,27],39:[2,27],41:[2,27],42:[2,27],45:[2,27],47:[2,27],48:[2,27],49:[2,27],51:[2,27]},{5:[2,28],8:[2,28],9:[2,28],17:[2,28],25:[2,28],26:[2,28],29:[2,28],31:[2,28],32:[2,28],34:[2,28],35:[2,28],36:[2,28],37:[2,28],38:[2,28],39:[2,28],41:[2,28],42:[2,28],45:[2,28],47:[2,28],48:[2,28],49:[2,28],51:[2,28]},{5:[2,21],8:[2,21],9:[2,21],17:[2,21],25:[2,21],26:[2,21],29:[2,21],41:[2,21],42:[2,21],45:[2,21],51:[2,21]},{5:[2,22],8:[2,22],9:[2,22],17:[2,22],25:[2,22],26:[2,22],29:[2,22],41:[2,22],42:[2,22],45:[2,22],51:[2,22]},{5:[2,23],8:[2,23],9:[2,23],17:[2,23],25:[2,23],26:[2,23],29:[2,23],41:[2,23],42:[2,23],45:[2,23],51:[2,23]},{5:[2,24],8:[2,24],9:[2,24],17:[2,24],25:[2,24],26:[2,24],29:[2,24],41:[2,24],42:[2,24],45:[2,24],51:[2,24]},{18:36,27:[1,12],28:[1,13]},{18:37,27:[1,12],28:[1,13]},{9:[1,39],18:40,27:[1,12],28:[1,13],30:38},{18:42,27:[1,12],28:[1,13],46:41},{1:[2,1]},{7:43,10:4,11:5,12:7,13:8,17:[1,6],18:9,19:[1,10],20:11,21:14,22:15,23:16,24:17,25:[1,18],26:[1,19],27:[1,12],28:[1,13],29:[1,20],45:[1,21]},{9:[1,44],17:[2,4],19:[2,4],25:[2,4],26:[2,4],27:[2,4],28:[2,4],29:[2,4],45:[2,4]},{11:45,12:7,13:8,18:9,19:[1,10],20:11,21:14,22:15,23:16,24:17,25:[1,18],26:[1,19],27:[1,12],28:[1,13],29:[1,20],45:[1,21]},{11:46,12:7,13:8,17:[1,47],18:9,19:[1,10],20:11,21:14,22:15,23:16,24:17,25:[1,18],26:[1,19],27:[1,12],28:[1,13],29:[1,20],41:[1,48],42:[1,49],45:[1,21]},{11:50,12:7,13:8,18:9,19:[1,10],20:11,21:14,22:15,23:16,24:17,25:[1,18],26:[1,19],27:[1,12],28:[1,13],29:[1,20],45:[1,21]},{11:51,12:7,13:8,18:9,19:[1,10],20:11,21:14,22:15,23:16,24:17,25:[1,18],26:[1,19],27:[1,12],28:[1,13],29:[1,20],45:[1,21]},{9:[1,52],19:[2,49],25:[2,49],26:[2,49],27:[2,49],28:[2,49],29:[2,49],45:[2,49]},{9:[1,53],19:[2,53],25:[2,53],26:[2,53],27:[2,53],28:[2,53],29:[2,53],45:[2,53]},{9:[1,54],19:[2,57],25:[2,57],26:[2,57],27:[2,57],28:[2,57],29:[2,57],45:[2,57]},{11:55,12:7,13:8,18:9,19:[1,10],20:11,21:14,22:15,23:16,24:17,25:[1,18],26:[1,19],27:[1,12],28:[1,13],29:[1,20],45:[1,21]},{5:[2,16],8:[2,16],9:[2,16],17:[2,16],41:[2,16],42:[2,16],51:[2,16]},{5:[2,8],8:[2,8],9:[2,8],17:[2,8],20:35,21:14,22:15,23:16,24:17,25:[1,18],26:[1,19],29:[1,20],41:[2,8],42:[2,8],45:[1,21],51:[2,8]},{5:[2,19],8:[2,19],9:[2,19],17:[2,19],25:[2,19],26:[2,19],29:[2,19],41:[2,19],42:[2,19],45:[2,19],51:[2,19]},{5:[2,25],8:[2,25],9:[2,25],17:[2,25],25:[2,25],26:[2,25],29:[2,25],41:[2,25],42:[2,25],45:[2,25],51:[2,25]},{5:[2,26],8:[2,26],9:[2,26],17:[2,26],25:[2,26],26:[2,26],29:[2,26],41:[2,26],42:[2,26],45:[2,26],51:[2,26]},{31:[1,56],32:[1,57],34:[1,58],35:[1,59],36:[1,60],37:[1,61],38:[1,62],39:[1,63]},{18:64,27:[1,12],28:[1,13]},{9:[1,65],31:[2,40],32:[2,40],34:[2,40],35:[2,40],36:[2,40],37:[2,40],38:[2,40],39:[2,40]},{5:[2,60],8:[2,60],9:[2,60],17:[2,60],25:[2,60],26:[2,60],29:[2,60],41:[2,60],42:[2,60],45:[2,60],51:[2,60]},{5:[2,61],8:[2,61],9:[2,61],17:[2,61],25:[2,61],26:[2,61],29:[2,61],41:[2,61],42:[2,61],45:[2,61],47:[1,66],48:[1,67],49:[1,68],51:[2,61]},{5:[2,2],8:[2,2],9:[1,26],14:25,15:27,16:28,17:[1,29],41:[1,30],42:[1,31],51:[2,2]},{17:[2,5],19:[2,5],25:[2,5],26:[2,5],27:[2,5],28:[2,5],29:[2,5],45:[2,5]},{5:[2,11],8:[2,11],9:[2,11],17:[2,11],41:[2,11],42:[2,11],51:[2,11]},{5:[2,12],8:[2,12],9:[2,12],17:[2,12],41:[2,12],42:[2,12],51:[2,12]},{9:[1,69],19:[2,47],25:[2,47],26:[2,47],27:[2,47],28:[2,47],29:[2,47],45:[2,47]},{9:[1,70],19:[2,51],25:[2,51],26:[2,51],27:[2,51],28:[2,51],29:[2,51],45:[2,51]},{9:[1,71],19:[2,55],25:[2,55],26:[2,55],27:[2,55],28:[2,55],29:[2,55],45:[2,55]},{5:[2,13],8:[2,13],9:[2,13],17:[2,13],41:[2,13],42:[2,13],51:[2,13]},{5:[2,14],8:[2,14],9:[2,14],17:[2,14],41:[2,14],42:[2,14],51:[2,14]},{19:[2,48],25:[2,48],26:[2,48],27:[2,48],28:[2,48],29:[2,48],45:[2,48]},{19:[2,52],25:[2,52],26:[2,52],27:[2,52],28:[2,52],29:[2,52],45:[2,52]},{19:[2,56],25:[2,56],26:[2,56],27:[2,56],28:[2,56],29:[2,56],45:[2,56]},{5:[2,15],8:[2,15],9:[2,15],17:[2,15],41:[2,15],42:[2,15],51:[2,15]},{5:[2,29],8:[2,29],9:[2,29],17:[2,29],25:[2,29],26:[2,29],29:[2,29],41:[2,29],42:[2,29],45:[2,29],51:[2,29]},{9:[1,74],18:40,27:[1,12],28:[1,13],30:73,33:72,40:75,43:[1,76],44:[1,77]},{9:[1,74],18:40,27:[1,12],28:[1,13],30:73,33:78,40:75,43:[1,76],44:[1,77]},{9:[1,74],18:40,27:[1,12],28:[1,13],30:73,33:79,40:75,43:[1,76],44:[1,77]},{9:[1,74],18:40,27:[1,12],28:[1,13],30:73,33:80,40:75,43:[1,76],44:[1,77]},{9:[1,74],18:40,27:[1,12],28:[1,13],30:73,33:81,40:75,43:[1,76],44:[1,77]},{9:[1,74],18:40,27:[1,12],28:[1,13],30:73,33:82,40:75,43:[1,76],44:[1,77]},{9:[1,74],18:40,27:[1,12],28:[1,13],30:73,33:83,40:75,43:[1,76],44:[1,77]},{9:[1,84],31:[2,38],32:[2,38],34:[2,38],35:[2,38],36:[2,38],37:[2,38],38:[2,38],39:[2,38]},{31:[2,39],32:[2,39],34:[2,39],35:[2,39],36:[2,39],37:[2,39],38:[2,39],39:[2,39]},{5:[2,62],8:[2,62],9:[2,62],17:[2,62],25:[2,62],26:[2,62],29:[2,62],41:[2,62],42:[2,62],45:[2,62],51:[2,62]},{5:[2,63],8:[2,63],9:[2,63],17:[2,63],25:[2,63],26:[2,63],29:[2,63],41:[2,63],42:[2,63],45:[2,63],51:[2,63]},{4:88,7:3,10:4,11:5,12:7,13:8,17:[1,6],18:9,19:[1,10],20:11,21:14,22:15,23:16,24:17,25:[1,18],26:[1,19],27:[1,12],28:[1,96],29:[1,20],45:[1,21],50:85,51:[1,87],52:[1,86],53:89,54:[1,90],55:[1,91],56:92,58:93,59:94,60:[1,95],61:[1,97],62:[1,98]},{19:[2,46],25:[2,46],26:[2,46],27:[2,46],28:[2,46],29:[2,46],45:[2,46]},{19:[2,50],25:[2,50],26:[2,50],27:[2,50],28:[2,50],29:[2,50],45:[2,50]},{19:[2,54],25:[2,54],26:[2,54],27:[2,54],28:[2,54],29:[2,54],45:[2,54]},{31:[1,99]},{31:[2,41]},{18:64,27:[1,12],28:[1,13],40:100,43:[1,76],44:[1,77]},{9:[1,101],31:[2,45]},{9:[2,58],31:[2,58]},{9:[2,59],31:[2,59]},{31:[1,102]},{31:[1,103]},{31:[1,104]},{31:[1,105]},{31:[1,106]},{31:[1,107]},{31:[2,37],32:[2,37],34:[2,37],35:[2,37],36:[2,37],37:[2,37],38:[2,37],39:[2,37]},{51:[1,108]},{28:[2,82],51:[1,109]},{5:[2,66],8:[2,66],9:[2,66],17:[2,66],25:[2,66],26:[2,66],29:[2,66],41:[2,66],42:[2,66],45:[2,66],51:[2,66]},{6:23,8:[1,24],51:[2,67]},{51:[2,68]},{51:[2,69]},{51:[2,70]},{28:[1,110]},{28:[1,111]},{28:[1,112]},{28:[1,113]},{8:[2,28],9:[2,28],17:[2,28],25:[2,28],26:[2,28],29:[2,28],41:[2,28],42:[2,28],45:[2,28],51:[2,28],56:116,57:114,58:115,61:[1,97],62:[1,98]},{28:[2,80],51:[2,80]},{28:[2,81],51:[2,81]},{5:[2,30],8:[2,30],9:[2,30],17:[2,30],25:[2,30],26:[2,30],29:[2,30],41:[2,30],42:[2,30],45:[2,30],51:[2,30]},{9:[1,117],31:[2,43]},{31:[2,44]},{5:[2,31],8:[2,31],9:[2,31],17:[2,31],25:[2,31],26:[2,31],29:[2,31],41:[2,31],42:[2,31],45:[2,31],51:[2,31]},{5:[2,32],8:[2,32],9:[2,32],17:[2,32],25:[2,32],26:[2,32],29:[2,32],41:[2,32],42:[2,32],45:[2,32],51:[2,32]},{5:[2,33],8:[2,33],9:[2,33],17:[2,33],25:[2,33],26:[2,33],29:[2,33],41:[2,33],42:[2,33],45:[2,33],51:[2,33]},{5:[2,34],8:[2,34],9:[2,34],17:[2,34],25:[2,34],26:[2,34],29:[2,34],41:[2,34],42:[2,34],45:[2,34],51:[2,34]},{5:[2,35],8:[2,35],9:[2,35],17:[2,35],25:[2,35],26:[2,35],29:[2,35],41:[2,35],42:[2,35],45:[2,35],51:[2,35]},{5:[2,36],8:[2,36],9:[2,36],17:[2,36],25:[2,36],26:[2,36],29:[2,36],41:[2,36],42:[2,36],45:[2,36],51:[2,36]},{5:[2,64],8:[2,64],9:[2,64],17:[2,64],25:[2,64],26:[2,64],29:[2,64],41:[2,64],42:[2,64],45:[2,64],51:[2,64]},{5:[2,65],8:[2,65],9:[2,65],17:[2,65],25:[2,65],26:[2,65],29:[2,65],41:[2,65],42:[2,65],45:[2,65],51:[2,65]},{51:[2,76],56:116,57:118,58:115,61:[1,97],62:[1,98]},{56:116,57:119,58:115,61:[1,97],62:[1,98]},{51:[2,77],56:116,57:120,58:115,61:[1,97],62:[1,98]},{56:116,57:121,58:115,61:[1,97],62:[1,98]},{51:[2,75]},{51:[2,78]},{51:[2,79]},{31:[2,42]},{51:[2,71]},{51:[2,72]},{51:[2,73]},{51:[2,74]}], 213 | defaultActions: {22:[2,1],73:[2,41],89:[2,68],90:[2,69],91:[2,70],101:[2,44],114:[2,75],115:[2,78],116:[2,79],117:[2,42],118:[2,71],119:[2,72],120:[2,73],121:[2,74]}, 214 | parseError: function parseError(str, hash) { 215 | if (hash.recoverable) { 216 | this.trace(str); 217 | } else { 218 | throw new Error(str); 219 | } 220 | }, 221 | parse: function parse(input) { 222 | var self = this, stack = [0], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1; 223 | var args = lstack.slice.call(arguments, 1); 224 | this.lexer.setInput(input); 225 | this.lexer.yy = this.yy; 226 | this.yy.lexer = this.lexer; 227 | this.yy.parser = this; 228 | if (typeof this.lexer.yylloc == 'undefined') { 229 | this.lexer.yylloc = {}; 230 | } 231 | var yyloc = this.lexer.yylloc; 232 | lstack.push(yyloc); 233 | var ranges = this.lexer.options && this.lexer.options.ranges; 234 | if (typeof this.yy.parseError === 'function') { 235 | this.parseError = this.yy.parseError; 236 | } else { 237 | this.parseError = Object.getPrototypeOf(this).parseError; 238 | } 239 | function popStack(n) { 240 | stack.length = stack.length - 2 * n; 241 | vstack.length = vstack.length - n; 242 | lstack.length = lstack.length - n; 243 | } 244 | function lex() { 245 | var token; 246 | token = self.lexer.lex() || EOF; 247 | if (typeof token !== 'number') { 248 | token = self.symbols_[token] || token; 249 | } 250 | return token; 251 | } 252 | var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected; 253 | while (true) { 254 | state = stack[stack.length - 1]; 255 | if (this.defaultActions[state]) { 256 | action = this.defaultActions[state]; 257 | } else { 258 | if (symbol === null || typeof symbol == 'undefined') { 259 | symbol = lex(); 260 | } 261 | action = table[state] && table[state][symbol]; 262 | } 263 | if (typeof action === 'undefined' || !action.length || !action[0]) { 264 | var errStr = ''; 265 | expected = []; 266 | for (p in table[state]) { 267 | if (this.terminals_[p] && p > TERROR) { 268 | expected.push('\'' + this.terminals_[p] + '\''); 269 | } 270 | } 271 | if (this.lexer.showPosition) { 272 | errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + this.lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\''; 273 | } else { 274 | errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\''); 275 | } 276 | this.parseError(errStr, { 277 | text: this.lexer.match, 278 | token: this.terminals_[symbol] || symbol, 279 | line: this.lexer.yylineno, 280 | loc: yyloc, 281 | expected: expected 282 | }); 283 | } 284 | if (action[0] instanceof Array && action.length > 1) { 285 | throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol); 286 | } 287 | switch (action[0]) { 288 | case 1: 289 | stack.push(symbol); 290 | vstack.push(this.lexer.yytext); 291 | lstack.push(this.lexer.yylloc); 292 | stack.push(action[1]); 293 | symbol = null; 294 | if (!preErrorSymbol) { 295 | yyleng = this.lexer.yyleng; 296 | yytext = this.lexer.yytext; 297 | yylineno = this.lexer.yylineno; 298 | yyloc = this.lexer.yylloc; 299 | if (recovering > 0) { 300 | recovering--; 301 | } 302 | } else { 303 | symbol = preErrorSymbol; 304 | preErrorSymbol = null; 305 | } 306 | break; 307 | case 2: 308 | len = this.productions_[action[1]][1]; 309 | yyval.$ = vstack[vstack.length - len]; 310 | yyval._$ = { 311 | first_line: lstack[lstack.length - (len || 1)].first_line, 312 | last_line: lstack[lstack.length - 1].last_line, 313 | first_column: lstack[lstack.length - (len || 1)].first_column, 314 | last_column: lstack[lstack.length - 1].last_column 315 | }; 316 | if (ranges) { 317 | yyval._$.range = [ 318 | lstack[lstack.length - (len || 1)].range[0], 319 | lstack[lstack.length - 1].range[1] 320 | ]; 321 | } 322 | r = this.performAction.apply(yyval, [ 323 | yytext, 324 | yyleng, 325 | yylineno, 326 | this.yy, 327 | action[1], 328 | vstack, 329 | lstack 330 | ].concat(args)); 331 | if (typeof r !== 'undefined') { 332 | return r; 333 | } 334 | if (len) { 335 | stack = stack.slice(0, -1 * len * 2); 336 | vstack = vstack.slice(0, -1 * len); 337 | lstack = lstack.slice(0, -1 * len); 338 | } 339 | stack.push(this.productions_[action[1]][0]); 340 | vstack.push(yyval.$); 341 | lstack.push(yyval._$); 342 | newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; 343 | stack.push(newState); 344 | break; 345 | case 3: 346 | return true; 347 | } 348 | } 349 | return true; 350 | }}; 351 | /* generated by jison-lex 0.2.1 */ 352 | var lexer = (function(){ 353 | var lexer = { 354 | 355 | EOF:1, 356 | 357 | parseError:function parseError(str, hash) { 358 | if (this.yy.parser) { 359 | this.yy.parser.parseError(str, hash); 360 | } else { 361 | throw new Error(str); 362 | } 363 | }, 364 | 365 | // resets the lexer, sets new input 366 | setInput:function (input) { 367 | this._input = input; 368 | this._more = this._backtrack = this.done = false; 369 | this.yylineno = this.yyleng = 0; 370 | this.yytext = this.matched = this.match = ''; 371 | this.conditionStack = ['INITIAL']; 372 | this.yylloc = { 373 | first_line: 1, 374 | first_column: 0, 375 | last_line: 1, 376 | last_column: 0 377 | }; 378 | if (this.options.ranges) { 379 | this.yylloc.range = [0,0]; 380 | } 381 | this.offset = 0; 382 | return this; 383 | }, 384 | 385 | // consumes and returns one char from the input 386 | input:function () { 387 | var ch = this._input[0]; 388 | this.yytext += ch; 389 | this.yyleng++; 390 | this.offset++; 391 | this.match += ch; 392 | this.matched += ch; 393 | var lines = ch.match(/(?:\r\n?|\n).*/g); 394 | if (lines) { 395 | this.yylineno++; 396 | this.yylloc.last_line++; 397 | } else { 398 | this.yylloc.last_column++; 399 | } 400 | if (this.options.ranges) { 401 | this.yylloc.range[1]++; 402 | } 403 | 404 | this._input = this._input.slice(1); 405 | return ch; 406 | }, 407 | 408 | // unshifts one char (or a string) into the input 409 | unput:function (ch) { 410 | var len = ch.length; 411 | var lines = ch.split(/(?:\r\n?|\n)/g); 412 | 413 | this._input = ch + this._input; 414 | this.yytext = this.yytext.substr(0, this.yytext.length - len - 1); 415 | //this.yyleng -= len; 416 | this.offset -= len; 417 | var oldLines = this.match.split(/(?:\r\n?|\n)/g); 418 | this.match = this.match.substr(0, this.match.length - 1); 419 | this.matched = this.matched.substr(0, this.matched.length - 1); 420 | 421 | if (lines.length - 1) { 422 | this.yylineno -= lines.length - 1; 423 | } 424 | var r = this.yylloc.range; 425 | 426 | this.yylloc = { 427 | first_line: this.yylloc.first_line, 428 | last_line: this.yylineno + 1, 429 | first_column: this.yylloc.first_column, 430 | last_column: lines ? 431 | (lines.length === oldLines.length ? this.yylloc.first_column : 0) 432 | + oldLines[oldLines.length - lines.length].length - lines[0].length : 433 | this.yylloc.first_column - len 434 | }; 435 | 436 | if (this.options.ranges) { 437 | this.yylloc.range = [r[0], r[0] + this.yyleng - len]; 438 | } 439 | this.yyleng = this.yytext.length; 440 | return this; 441 | }, 442 | 443 | // When called from action, caches matched text and appends it on next action 444 | more:function () { 445 | this._more = true; 446 | return this; 447 | }, 448 | 449 | // When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead. 450 | reject:function () { 451 | if (this.options.backtrack_lexer) { 452 | this._backtrack = true; 453 | } else { 454 | return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), { 455 | text: "", 456 | token: null, 457 | line: this.yylineno 458 | }); 459 | 460 | } 461 | return this; 462 | }, 463 | 464 | // retain first n characters of the match 465 | less:function (n) { 466 | this.unput(this.match.slice(n)); 467 | }, 468 | 469 | // displays already matched input, i.e. for error messages 470 | pastInput:function () { 471 | var past = this.matched.substr(0, this.matched.length - this.match.length); 472 | return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); 473 | }, 474 | 475 | // displays upcoming input, i.e. for error messages 476 | upcomingInput:function () { 477 | var next = this.match; 478 | if (next.length < 20) { 479 | next += this._input.substr(0, 20-next.length); 480 | } 481 | return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, ""); 482 | }, 483 | 484 | // displays the character position where the lexing error occurred, i.e. for error messages 485 | showPosition:function () { 486 | var pre = this.pastInput(); 487 | var c = new Array(pre.length + 1).join("-"); 488 | return pre + this.upcomingInput() + "\n" + c + "^"; 489 | }, 490 | 491 | // test the lexed token: return FALSE when not a match, otherwise return token 492 | test_match:function (match, indexed_rule) { 493 | var token, 494 | lines, 495 | backup; 496 | 497 | if (this.options.backtrack_lexer) { 498 | // save context 499 | backup = { 500 | yylineno: this.yylineno, 501 | yylloc: { 502 | first_line: this.yylloc.first_line, 503 | last_line: this.last_line, 504 | first_column: this.yylloc.first_column, 505 | last_column: this.yylloc.last_column 506 | }, 507 | yytext: this.yytext, 508 | match: this.match, 509 | matches: this.matches, 510 | matched: this.matched, 511 | yyleng: this.yyleng, 512 | offset: this.offset, 513 | _more: this._more, 514 | _input: this._input, 515 | yy: this.yy, 516 | conditionStack: this.conditionStack.slice(0), 517 | done: this.done 518 | }; 519 | if (this.options.ranges) { 520 | backup.yylloc.range = this.yylloc.range.slice(0); 521 | } 522 | } 523 | 524 | lines = match[0].match(/(?:\r\n?|\n).*/g); 525 | if (lines) { 526 | this.yylineno += lines.length; 527 | } 528 | this.yylloc = { 529 | first_line: this.yylloc.last_line, 530 | last_line: this.yylineno + 1, 531 | first_column: this.yylloc.last_column, 532 | last_column: lines ? 533 | lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : 534 | this.yylloc.last_column + match[0].length 535 | }; 536 | this.yytext += match[0]; 537 | this.match += match[0]; 538 | this.matches = match; 539 | this.yyleng = this.yytext.length; 540 | if (this.options.ranges) { 541 | this.yylloc.range = [this.offset, this.offset += this.yyleng]; 542 | } 543 | this._more = false; 544 | this._backtrack = false; 545 | this._input = this._input.slice(match[0].length); 546 | this.matched += match[0]; 547 | token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]); 548 | if (this.done && this._input) { 549 | this.done = false; 550 | } 551 | if (token) { 552 | return token; 553 | } else if (this._backtrack) { 554 | // recover context 555 | for (var k in backup) { 556 | this[k] = backup[k]; 557 | } 558 | return false; // rule action called reject() implying the next rule should be tested instead. 559 | } 560 | return false; 561 | }, 562 | 563 | // return next match in input 564 | next:function () { 565 | if (this.done) { 566 | return this.EOF; 567 | } 568 | if (!this._input) { 569 | this.done = true; 570 | } 571 | 572 | var token, 573 | match, 574 | tempMatch, 575 | index; 576 | if (!this._more) { 577 | this.yytext = ''; 578 | this.match = ''; 579 | } 580 | var rules = this._currentRules(); 581 | for (var i = 0; i < rules.length; i++) { 582 | tempMatch = this._input.match(this.rules[rules[i]]); 583 | if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { 584 | match = tempMatch; 585 | index = i; 586 | if (this.options.backtrack_lexer) { 587 | token = this.test_match(tempMatch, rules[i]); 588 | if (token !== false) { 589 | return token; 590 | } else if (this._backtrack) { 591 | match = false; 592 | continue; // rule action called reject() implying a rule MISmatch. 593 | } else { 594 | // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) 595 | return false; 596 | } 597 | } else if (!this.options.flex) { 598 | break; 599 | } 600 | } 601 | } 602 | if (match) { 603 | token = this.test_match(match, rules[index]); 604 | if (token !== false) { 605 | return token; 606 | } 607 | // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) 608 | return false; 609 | } 610 | if (this._input === "") { 611 | return this.EOF; 612 | } else { 613 | return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), { 614 | text: "", 615 | token: null, 616 | line: this.yylineno 617 | }); 618 | } 619 | }, 620 | 621 | // return next match that has a token 622 | lex:function lex() { 623 | var r = this.next(); 624 | if (r) { 625 | return r; 626 | } else { 627 | return this.lex(); 628 | } 629 | }, 630 | 631 | // activates a new lexer condition state (pushes the new lexer condition state onto the condition stack) 632 | begin:function begin(condition) { 633 | this.conditionStack.push(condition); 634 | }, 635 | 636 | // pop the previously active lexer condition state off the condition stack 637 | popState:function popState() { 638 | var n = this.conditionStack.length - 1; 639 | if (n > 0) { 640 | return this.conditionStack.pop(); 641 | } else { 642 | return this.conditionStack[0]; 643 | } 644 | }, 645 | 646 | // produce the lexer rule set which is active for the currently active lexer condition state 647 | _currentRules:function _currentRules() { 648 | if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) { 649 | return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules; 650 | } else { 651 | return this.conditions["INITIAL"].rules; 652 | } 653 | }, 654 | 655 | // return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available 656 | topState:function topState(n) { 657 | n = this.conditionStack.length - 1 - Math.abs(n || 0); 658 | if (n >= 0) { 659 | return this.conditionStack[n]; 660 | } else { 661 | return "INITIAL"; 662 | } 663 | }, 664 | 665 | // alias for begin(condition) 666 | pushState:function pushState(condition) { 667 | this.begin(condition); 668 | }, 669 | 670 | // return the number of states currently on the stack 671 | stateStackSize:function stateStackSize() { 672 | return this.conditionStack.length; 673 | }, 674 | options: {}, 675 | performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { 676 | 677 | var YYSTATE=YY_START; 678 | switch($avoiding_name_collisions) { 679 | case 0:return 28; 680 | break; 681 | case 1:return 27; 682 | break; 683 | case 2:return 5; 684 | break; 685 | case 3:return 36; 686 | break; 687 | case 4:return 34; 688 | break; 689 | case 5:return 37; 690 | break; 691 | case 6:return 35; 692 | break; 693 | case 7:return 38; 694 | break; 695 | case 8:return 39; 696 | break; 697 | case 9:return 43; 698 | break; 699 | case 10:return 44; 700 | break; 701 | case 11:return 62; 702 | break; 703 | case 12:return 61; 704 | break; 705 | case 13:return 52; 706 | break; 707 | case 14:return 47; 708 | break; 709 | case 15:return 48; 710 | break; 711 | case 16:return 26; 712 | break; 713 | case 17:return 8; 714 | break; 715 | case 18:return 25; 716 | break; 717 | case 19:return 29; 718 | break; 719 | case 20:return 31; 720 | break; 721 | case 21:return 32; 722 | break; 723 | case 22:return 45; 724 | break; 725 | case 23:return 49; 726 | break; 727 | case 24:return 51; 728 | break; 729 | case 25:return 17; 730 | break; 731 | case 26:return "'"; 732 | break; 733 | case 27:return 19; 734 | break; 735 | case 28:return 41; 736 | break; 737 | case 29:return 42; 738 | break; 739 | case 30:return 60; 740 | break; 741 | case 31:return 9; 742 | break; 743 | } 744 | }, 745 | rules: [/^(?:n\b)/,/^(?:[_a-zA-Z][_a-zA-Z0-9-]*)/,/^(?:$)/,/^(?:~=)/,/^(?:\*=)/,/^(?:\|=)/,/^(?:!=)/,/^(?:\^=)/,/^(?:\$=)/,/^(?:"[^\n\r\f\\"]*")/,/^(?:'[^\n\r\f\\']*')/,/^(?:\+\d+)/,/^(?:-\d+)/,/^(?:\d+)/,/^(?:\(odd\))/,/^(?:\(even\))/,/^(?:#)/,/^(?:,)/,/^(?:\.)/,/^(?:\[)/,/^(?:\])/,/^(?:=)/,/^(?::)/,/^(?:\()/,/^(?:\))/,/^(?:>)/,/^(?:')/,/^(?:\*)/,/^(?:~)/,/^(?:\+)/,/^(?:-)/,/^(?:\s+)/], 746 | conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31],"inclusive":true}} 747 | }; 748 | return lexer; 749 | })(); 750 | parser.lexer = lexer; 751 | function Parser () { 752 | this.yy = {}; 753 | } 754 | Parser.prototype = parser;parser.Parser = Parser; 755 | return new Parser; 756 | })(); 757 | 758 | 759 | if (typeof require !== 'undefined' && typeof exports !== 'undefined') { 760 | exports.parser = parser; 761 | exports.Parser = parser.Parser; 762 | exports.parse = function () { return parser.parse.apply(parser, arguments); }; 763 | exports.main = function commonjsMain(args) { 764 | if (!args[1]) { 765 | console.log('Usage: '+args[0]+' FILE'); 766 | process.exit(1); 767 | } 768 | var source = require('fs').readFileSync(require('path').normalize(args[1]), "utf8"); 769 | return exports.parser.parse(source); 770 | }; 771 | if (typeof module !== 'undefined' && require.main === module) { 772 | exports.main(process.argv.slice(1)); 773 | } 774 | } 775 | }).call(this)}).call(this,require('_process')) 776 | },{"_process":13,"fs":11,"path":12}],4:[function(require,module,exports){ 777 | (function() { 778 | var self = this; 779 | var parser, xpathBuilder, Expression, parse, convertToXpath; 780 | parser = require("bo-selector").parser; 781 | xpathBuilder = require("xpath-builder").dsl(); 782 | Expression = require("./expression"); 783 | parser.yy.create = function(data) { 784 | var self = this; 785 | return new Expression(data); 786 | }; 787 | parse = function(selector) { 788 | return parser.parse(selector).render(xpathBuilder, "descendant"); 789 | }; 790 | convertToXpath = function(selector) { 791 | return parse(selector).toXPath(); 792 | }; 793 | convertToXpath.parse = parse; 794 | convertToXpath.xPathBuilder = xpathBuilder; 795 | module.exports = convertToXpath; 796 | }).call(this); 797 | },{"./expression":5,"bo-selector":2,"xpath-builder":7}],5:[function(require,module,exports){ 798 | (function() { 799 | var self = this; 800 | var Renderer, Expression, extend; 801 | Renderer = require("./renderer"); 802 | Expression = function(data) { 803 | extend(this, data); 804 | return this; 805 | }; 806 | Expression.prototype.render = function(xpath, combinator) { 807 | var self = this; 808 | return new Renderer().render(self, xpath, combinator); 809 | }; 810 | extend = function(o, d) { 811 | var k; 812 | for (k in d) { 813 | (function(k) { 814 | o[k] = d[k]; 815 | })(k); 816 | } 817 | return void 0; 818 | }; 819 | module.exports = Expression; 820 | }).call(this); 821 | },{"./renderer":6}],6:[function(require,module,exports){ 822 | (function() { 823 | var self = this; 824 | var xpathBuilder, Renderer; 825 | xpathBuilder = require("xpath-builder").dsl(); 826 | Renderer = function() { 827 | return this; 828 | }; 829 | Renderer.prototype = { 830 | render: function(node, xpath, combinator) { 831 | var self = this; 832 | var fn; 833 | fn = self[node.type]; 834 | if (!fn) { 835 | throw new Error("No renderer for '" + node.type + "'"); 836 | } 837 | return fn.call(self, node, xpath, combinator); 838 | }, 839 | selector_list: function(node, xpath, combinator) { 840 | var self = this; 841 | var x, i; 842 | x = self.render(node.selectors[0], xpath, combinator); 843 | for (i = 1; i < node.selectors.length; ++i) { 844 | x = x.union(self.render(node.selectors[i], xpath, combinator)); 845 | } 846 | return x; 847 | }, 848 | constraint_list: function(node, xpath, combinator) { 849 | var self = this; 850 | return self.element(node, xpath, combinator); 851 | }, 852 | element: function(node, xpath, combinator) { 853 | var self = this; 854 | return self.applyConstraints(node, xpath[combinator].call(xpath, node.name || "*")); 855 | }, 856 | combinator_selector: function(node, xpath, combinator) { 857 | var self = this; 858 | var left; 859 | left = self.render(node.left, xpath, combinator); 860 | return self.render(node.right, left, node.combinator); 861 | }, 862 | immediate_child: function(node, xpath) { 863 | var self = this; 864 | return self.render(node.child, xpath, "child"); 865 | }, 866 | pseudo_func: function(node, xpath) { 867 | var self = this; 868 | var fn; 869 | fn = self[node.func.name.replace(/-/g, "_")]; 870 | if (fn) { 871 | return fn.call(self, node, xpath); 872 | } else { 873 | throw new Error("Unsupported pseudo function :" + node.func.name + "()"); 874 | } 875 | }, 876 | pseudo_class: function(node, xpath) { 877 | var self = this; 878 | var fn; 879 | fn = self[node.name.replace(/-/g, "_")]; 880 | if (fn) { 881 | return fn.call(self, node, xpath); 882 | } else { 883 | throw new Error("Unsupported pseudo class :" + node.name); 884 | } 885 | }, 886 | has: function(node, xpath) { 887 | var self = this; 888 | return self.render(node.func.args, xpathBuilder, "descendant"); 889 | }, 890 | not: function(node, xpath) { 891 | var self = this; 892 | var firstChild, childType; 893 | firstChild = node.func.args.selectors[0]; 894 | childType = firstChild.type; 895 | if (childType === "constraint_list") { 896 | return self.combineConstraints(firstChild, xpath).inverse(); 897 | } else { 898 | return self.matchesSelectorList(node.func.args, xpath).inverse(); 899 | } 900 | }, 901 | nth_child: function(node, xpath) { 902 | var self = this; 903 | return xpath.nthChild(Number(node.func.args)); 904 | }, 905 | first_child: function(node, xpath) { 906 | var self = this; 907 | return xpath.firstChild(); 908 | }, 909 | last_child: function(node, xpath) { 910 | var self = this; 911 | return xpath.lastChild(); 912 | }, 913 | nth_last_child: function(node, xpath) { 914 | var self = this; 915 | return xpath.nthLastChild(Number(node.func.args)); 916 | }, 917 | only_child: function(node, xpath) { 918 | var self = this; 919 | return xpath.onlyChild(); 920 | }, 921 | only_of_type: function(node, xpath) { 922 | var self = this; 923 | return xpath.onlyOfType(); 924 | }, 925 | nth_of_type: function(node, xpath) { 926 | var self = this; 927 | var type; 928 | type = node.func.args.type; 929 | if (type === "odd") { 930 | return xpath.nthOfTypeOdd(); 931 | } else if (type === "even") { 932 | return xpath.nthOfTypeEven(); 933 | } else if (type === "an") { 934 | return xpath.nthOfTypeMod(Number(node.func.args.a)); 935 | } else if (type === "n_plus_b") { 936 | return xpath.nthOfTypeMod(1, Number(node.func.args.b)); 937 | } else if (type === "an_plus_b") { 938 | return xpath.nthOfTypeMod(Number(node.func.args.a), Number(node.func.args.b)); 939 | } else { 940 | return xpath.nthOfType(Number(node.func.args)); 941 | } 942 | }, 943 | nth_last_of_type: function(node, xpath) { 944 | var self = this; 945 | var type; 946 | type = node.func.args.type; 947 | if (type === "odd") { 948 | return xpath.nthLastOfTypeOdd(); 949 | } else if (type === "even") { 950 | return xpath.nthLastOfTypeEven(); 951 | } else if (type === "an") { 952 | return xpath.nthLastOfTypeMod(Number(node.func.args.a)); 953 | } else if (type === "n_plus_b") { 954 | return xpath.nthLastOfTypeMod(1, Number(node.func.args.b)); 955 | } else if (type === "an_plus_b") { 956 | return xpath.nthLastOfTypeMod(Number(node.func.args.a), Number(node.func.args.b)); 957 | } else { 958 | return xpath.nthLastOfType(Number(node.func.args)); 959 | } 960 | }, 961 | last_of_type: function(node, xpath) { 962 | var self = this; 963 | return xpath.lastOfType(); 964 | }, 965 | empty: function(node, xpath) { 966 | var self = this; 967 | return xpath.empty(); 968 | }, 969 | has_attribute: function(node, xpath) { 970 | var self = this; 971 | return xpathBuilder.attr(node.name); 972 | }, 973 | attribute_equals: function(node, xpath) { 974 | var self = this; 975 | return xpathBuilder.attr(node.name).equals(node.value); 976 | }, 977 | attribute_contains: function(node, xpath) { 978 | var self = this; 979 | return xpathBuilder.attr(node.name).contains(node.value); 980 | }, 981 | attribute_contains_word: function(node, xpath) { 982 | var self = this; 983 | return xpath.concat(" ", xpathBuilder.attr(node.name).normalize(), " ").contains(" " + node.value + " "); 984 | }, 985 | attribute_contains_prefix: function(node) { 986 | var self = this; 987 | return xpathBuilder.attr(node.name).startsWith(node.value).or(xpathBuilder.attr(node.name).startsWith(node.value + "-")); 988 | }, 989 | attribute_starts_with: function(node, xpath) { 990 | var self = this; 991 | return xpathBuilder.attr(node.name).startsWith(node.value); 992 | }, 993 | attribute_ends_with: function(node) { 994 | var self = this; 995 | return xpathBuilder.attr(node.name).endsWith(node.value); 996 | }, 997 | "class": function(node) { 998 | var self = this; 999 | return self.attribute_contains_word({ 1000 | name: "class", 1001 | value: node.name 1002 | }, xpathBuilder); 1003 | }, 1004 | id: function(node) { 1005 | var self = this; 1006 | return xpathBuilder.attr("id").equals(node.name); 1007 | }, 1008 | previous_sibling: function(node, xpath, combinator) { 1009 | var self = this; 1010 | var left; 1011 | left = self.render(node.left, xpath, combinator); 1012 | return self.applyConstraints(node.right, left.axis("following-sibling", node.right.name)); 1013 | }, 1014 | adjacent_sibling: function(node, xpath, combinator) { 1015 | var self = this; 1016 | var left; 1017 | left = self.render(node.left, xpath, combinator); 1018 | return self.applyConstraints(node.right, left.axis("following-sibling::*[1]/self", node.right.name)); 1019 | }, 1020 | first_of_type: function(node, xpath) { 1021 | var self = this; 1022 | return xpath.firstOfType(); 1023 | }, 1024 | matchesSelectorList: function(node, xpath) { 1025 | var self = this; 1026 | var condition, i; 1027 | if (node.selectors.length > 0) { 1028 | condition = self.matchesSelector(node.selectors[0], xpathBuilder); 1029 | for (i = 1; i < node.selectors.length; ++i) { 1030 | condition = condition.or(self.matchesSelector(node.selectors[i], xpathBuilder)); 1031 | } 1032 | return condition; 1033 | } else { 1034 | return xpath; 1035 | } 1036 | }, 1037 | matchesSelector: function(node, xpath) { 1038 | var self = this; 1039 | return xpath.name().equals(node.name); 1040 | }, 1041 | combineConstraints: function(node, xpath) { 1042 | var self = this; 1043 | var condition, i; 1044 | condition = self.render(node.constraints[0], xpath); 1045 | for (i = 1; i < node.constraints.length; ++i) { 1046 | condition = condition.and(self.render(node.constraints[i], condition)); 1047 | } 1048 | return condition; 1049 | }, 1050 | applyConstraints: function(node, xpath) { 1051 | var self = this; 1052 | if (node.constraints.length > 0) { 1053 | return xpath.where(self.combineConstraints(node, xpath)); 1054 | } else { 1055 | return xpath; 1056 | } 1057 | } 1058 | }; 1059 | module.exports = Renderer; 1060 | }).call(this); 1061 | },{"xpath-builder":7}],7:[function(require,module,exports){ 1062 | (function() { 1063 | var self = this; 1064 | var expression, Literal, topLevelMethods, expressionLevelMethods, literals, TopLevel, ExpressionLevel, method, Expression, Union; 1065 | expression = require("./expression"); 1066 | Literal = require("./literal").Literal; 1067 | topLevelMethods = { 1068 | current: function() { 1069 | var self = this; 1070 | return new Expression("thisNode"); 1071 | }, 1072 | name: function() { 1073 | var self = this; 1074 | return new Expression("nodeName", self.current()); 1075 | }, 1076 | descendant: function() { 1077 | var self = this; 1078 | var elementNames = Array.prototype.slice.call(arguments, 0, arguments.length); 1079 | return new Expression("descendant", self.current(), literals(elementNames)); 1080 | }, 1081 | child: function() { 1082 | var self = this; 1083 | var elementNames = Array.prototype.slice.call(arguments, 0, arguments.length); 1084 | return new Expression("child", self.current(), literals(elementNames)); 1085 | }, 1086 | axis: function(name, tagName) { 1087 | var self = this; 1088 | return new Expression("axis", self.current(), new Literal(name), new Literal(tagName || "*")); 1089 | }, 1090 | nextSibling: function() { 1091 | var self = this; 1092 | var names = Array.prototype.slice.call(arguments, 0, arguments.length); 1093 | return new Expression("nextSibling", self.current(), literals(names)); 1094 | }, 1095 | previousSibling: function() { 1096 | var self = this; 1097 | var names = Array.prototype.slice.call(arguments, 0, arguments.length); 1098 | return new Expression("previousSibling", self.current(), literals(names)); 1099 | }, 1100 | anywhere: function() { 1101 | var self = this; 1102 | var names = Array.prototype.slice.call(arguments, 0, arguments.length); 1103 | return new Expression("anywhere", literals(names)); 1104 | }, 1105 | attr: function(name) { 1106 | var self = this; 1107 | return new Expression("attribute", self.current(), new Literal(name)); 1108 | }, 1109 | contains: function(expression) { 1110 | var self = this; 1111 | return new Expression("contains", self.current(), expression); 1112 | }, 1113 | startsWith: function(expression) { 1114 | var self = this; 1115 | return new Expression("startsWith", self.current(), expression); 1116 | }, 1117 | endsWith: function(expression) { 1118 | var self = this; 1119 | return new Expression("endsWith", self.current(), expression); 1120 | }, 1121 | text: function() { 1122 | var self = this; 1123 | return new Expression("text", self.current()); 1124 | }, 1125 | string: function() { 1126 | var self = this; 1127 | return new Expression("stringFunction", self.current()); 1128 | }, 1129 | substring: function(expressionA, expressionB) { 1130 | var self = this; 1131 | var expressions; 1132 | expressions = [ expressionA ]; 1133 | if (expressionB) { 1134 | expressions.push(expressionB); 1135 | } 1136 | return new Expression("substringFunction", self.current(), expressions); 1137 | }, 1138 | stringLength: function() { 1139 | var self = this; 1140 | return new Expression("stringLengthFunction", self.current()); 1141 | }, 1142 | literal: function(string) { 1143 | var self = this; 1144 | return new Literal(string); 1145 | }, 1146 | concat: function() { 1147 | var self = this; 1148 | var expressions = Array.prototype.slice.call(arguments, 0, arguments.length); 1149 | return new Expression("concatFunction", expressions); 1150 | }, 1151 | nthChild: function(n) { 1152 | var self = this; 1153 | return new Expression("nthChild", n); 1154 | }, 1155 | nthLastChild: function(n) { 1156 | var self = this; 1157 | return new Expression("nthLastChild", n); 1158 | }, 1159 | firstChild: function() { 1160 | var self = this; 1161 | return new Expression("firstChild"); 1162 | }, 1163 | lastChild: function() { 1164 | var self = this; 1165 | return new Expression("lastChild"); 1166 | }, 1167 | onlyChild: function() { 1168 | var self = this; 1169 | return new Expression("onlyChild"); 1170 | }, 1171 | onlyOfType: function() { 1172 | var self = this; 1173 | return new Expression("onlyOfType"); 1174 | }, 1175 | firstOfType: function() { 1176 | var self = this; 1177 | return new Expression("nthOfType", 1); 1178 | }, 1179 | lastOfType: function() { 1180 | var self = this; 1181 | return new Expression("lastOfType"); 1182 | }, 1183 | nthOfType: function(n) { 1184 | var self = this; 1185 | return new Expression("nthOfType", n); 1186 | }, 1187 | nthLastOfType: function(n) { 1188 | var self = this; 1189 | return new Expression("nthLastOfType", n); 1190 | }, 1191 | nthOfTypeMod: function(m, n) { 1192 | var self = this; 1193 | return new Expression("nthOfTypeMod", m, n || 0); 1194 | }, 1195 | nthOfTypeOdd: function() { 1196 | var self = this; 1197 | return new Expression("nthOfTypeOdd"); 1198 | }, 1199 | nthOfTypeEven: function() { 1200 | var self = this; 1201 | return new Expression("nthOfTypeEven"); 1202 | }, 1203 | nthLastOfTypeMod: function(m, n) { 1204 | var self = this; 1205 | return new Expression("nthLastOfTypeMod", m, n || 0); 1206 | }, 1207 | nthLastOfTypeOdd: function() { 1208 | var self = this; 1209 | return new Expression("nthLastOfTypeOdd"); 1210 | }, 1211 | nthLastOfTypeEven: function() { 1212 | var self = this; 1213 | return new Expression("nthLastOfTypeEven"); 1214 | }, 1215 | empty: function() { 1216 | var self = this; 1217 | return new Expression("empty"); 1218 | } 1219 | }; 1220 | expressionLevelMethods = { 1221 | where: function(expression) { 1222 | var self = this; 1223 | return new Expression("where", self.current(), expression); 1224 | }, 1225 | oneOf: function() { 1226 | var self = this; 1227 | var expressions = Array.prototype.slice.call(arguments, 0, arguments.length); 1228 | return new Expression("oneOf", self.current(), expressions); 1229 | }, 1230 | equals: function(expression) { 1231 | var self = this; 1232 | return new Expression("equality", self.current(), expression); 1233 | }, 1234 | is: function(expression) { 1235 | var self = this; 1236 | return new Expression("is", self.current(), expression); 1237 | }, 1238 | or: function(expression) { 1239 | var self = this; 1240 | return new Expression("or", self.current(), expression); 1241 | }, 1242 | and: function(expression) { 1243 | var self = this; 1244 | return new Expression("and", self.current(), expression); 1245 | }, 1246 | union: function() { 1247 | var self = this; 1248 | var expressions = Array.prototype.slice.call(arguments, 0, arguments.length); 1249 | return new Union([ self ].concat(expressions)); 1250 | }, 1251 | inverse: function() { 1252 | var self = this; 1253 | return new Expression("inverse", self.current()); 1254 | }, 1255 | stringLiteral: function() { 1256 | var self = this; 1257 | return new Expression("stringLiteral", self); 1258 | }, 1259 | normalize: function() { 1260 | var self = this; 1261 | return new Expression("normalizedSpace", self.current()); 1262 | }, 1263 | n: function() { 1264 | var self = this; 1265 | return self.normalize(); 1266 | }, 1267 | add: function(number) { 1268 | var self = this; 1269 | return new Expression("addition", self.current(), number); 1270 | }, 1271 | subtract: function(number) { 1272 | var self = this; 1273 | return new Expression("subtraction", self.current(), number); 1274 | }, 1275 | count: function() { 1276 | var self = this; 1277 | return new Expression("countFunction", self.current()); 1278 | } 1279 | }; 1280 | literals = function(items) { 1281 | return items.map(function(item) { 1282 | return new Literal(item); 1283 | }); 1284 | }; 1285 | TopLevel = function() { 1286 | return this; 1287 | }; 1288 | TopLevel.prototype = topLevelMethods; 1289 | ExpressionLevel = function() { 1290 | return this; 1291 | }; 1292 | ExpressionLevel.prototype = new TopLevel(); 1293 | for (method in expressionLevelMethods) { 1294 | (function(method) { 1295 | ExpressionLevel.prototype[method] = expressionLevelMethods[method]; 1296 | })(method); 1297 | } 1298 | Expression = expression.createExpression(ExpressionLevel.prototype); 1299 | Union = function(expressions) { 1300 | this.expression = "union"; 1301 | this.args = expressions; 1302 | return this; 1303 | }; 1304 | Union.prototype = Expression.prototype; 1305 | exports.dsl = function() { 1306 | var self = this; 1307 | return new TopLevel(); 1308 | }; 1309 | }).call(this); 1310 | },{"./expression":8,"./literal":9}],8:[function(require,module,exports){ 1311 | (function() { 1312 | var self = this; 1313 | var Renderer, createExpression; 1314 | Renderer = require("./renderer").Renderer; 1315 | createExpression = function(prototype) { 1316 | var Expression; 1317 | Expression = function(expression) { 1318 | var args = Array.prototype.slice.call(arguments, 1, arguments.length); 1319 | this.expression = expression; 1320 | this.args = args; 1321 | return this; 1322 | }; 1323 | Expression.prototype = prototype; 1324 | Expression.prototype.isExpression = true; 1325 | Expression.prototype.toXPath = function(type) { 1326 | var self = this; 1327 | return Renderer.render(self, type); 1328 | }; 1329 | Expression.prototype.toString = function() { 1330 | var self = this; 1331 | return self.toXPath(); 1332 | }; 1333 | Expression.prototype.inspect = function() { 1334 | var self = this; 1335 | return self.toXPath(); 1336 | }; 1337 | Expression.prototype.current = function() { 1338 | var self = this; 1339 | return self; 1340 | }; 1341 | return Expression; 1342 | }; 1343 | exports.createExpression = createExpression; 1344 | }).call(this); 1345 | },{"./renderer":10}],9:[function(require,module,exports){ 1346 | (function() { 1347 | var self = this; 1348 | var Literal; 1349 | Literal = function(value) { 1350 | this.value = value; 1351 | this.isLiteral = true; 1352 | return this; 1353 | }; 1354 | Literal.prototype.isLiteral = true; 1355 | exports.Literal = Literal; 1356 | }).call(this); 1357 | },{}],10:[function(require,module,exports){ 1358 | (function() { 1359 | var self = this; 1360 | var Renderer; 1361 | Renderer = function(type) { 1362 | this.type = type; 1363 | return this; 1364 | }; 1365 | Renderer.prototype = { 1366 | render: function(node) { 1367 | var self = this; 1368 | var a; 1369 | a = node.args.map(function(arg) { 1370 | return self.convertArgument(arg); 1371 | }); 1372 | return self[node.expression].apply(self, a); 1373 | }, 1374 | convertArgument: function(argument) { 1375 | var self = this; 1376 | if (argument.isExpression || argument.isUnion) { 1377 | return self.render(argument); 1378 | } else if (argument instanceof Array) { 1379 | return argument.map(function(e) { 1380 | return self.convertArgument(e); 1381 | }); 1382 | } else if (typeof argument === "string") { 1383 | return self.stringLiteral(argument); 1384 | } else if (typeof argument === "number") { 1385 | return argument; 1386 | } else if (argument.isLiteral) { 1387 | return argument.value; 1388 | } else { 1389 | return argument.toString(); 1390 | } 1391 | }, 1392 | stringLiteral: function(string) { 1393 | var self = this; 1394 | if (string.indexOf("'") > -1) { 1395 | string = string.split("'", -1).map(function(substr) { 1396 | return "'" + substr + "'"; 1397 | }).join(',"\'",'); 1398 | return "concat(" + string + ")"; 1399 | } else { 1400 | return "'" + string + "'"; 1401 | } 1402 | }, 1403 | thisNode: function() { 1404 | var self = this; 1405 | return "."; 1406 | }, 1407 | descendant: function(parent, elementNames) { 1408 | var self = this; 1409 | var names; 1410 | if (elementNames.length === 1) { 1411 | return parent + "//" + elementNames[0]; 1412 | } else if (elementNames.length > 1) { 1413 | names = elementNames.map(function(e) { 1414 | return "self::" + e; 1415 | }); 1416 | return parent + "//*[" + names.join(" | ") + "]"; 1417 | } else { 1418 | return parent + "//*"; 1419 | } 1420 | }, 1421 | child: function(parent, elementNames) { 1422 | var self = this; 1423 | var names; 1424 | if (elementNames.length === 1) { 1425 | return parent + "/" + elementNames[0]; 1426 | } else if (elementNames.length > 1) { 1427 | names = elementNames.map(function(e) { 1428 | return "self::" + e; 1429 | }); 1430 | return parent + "/*[" + names.join(" | ") + "]"; 1431 | } else { 1432 | return parent + "/*"; 1433 | } 1434 | }, 1435 | axis: function(parent, name, tagName) { 1436 | var self = this; 1437 | return parent + "/" + name + "::" + tagName; 1438 | }, 1439 | nodeName: function(current) { 1440 | var self = this; 1441 | return "name(" + current + ")"; 1442 | }, 1443 | where: function(on, condition) { 1444 | var self = this; 1445 | return on + "[" + condition + "]"; 1446 | }, 1447 | attribute: function(current, name) { 1448 | var self = this; 1449 | return current + "/@" + name; 1450 | }, 1451 | equality: function(one, two) { 1452 | var self = this; 1453 | return one + " = " + two; 1454 | }, 1455 | addition: function(one, two) { 1456 | var self = this; 1457 | return one + " + " + two; 1458 | }, 1459 | subtraction: function(one, two) { 1460 | var self = this; 1461 | return one + " - " + two; 1462 | }, 1463 | is: function(one, two) { 1464 | var self = this; 1465 | if (self.type === "exact") { 1466 | return self.equality(one, two); 1467 | } else { 1468 | return self.contains(one, two); 1469 | } 1470 | }, 1471 | variable: function(name) { 1472 | var self = this; 1473 | return "%{" + name + "}"; 1474 | }, 1475 | text: function(current) { 1476 | var self = this; 1477 | return current + "/text()"; 1478 | }, 1479 | normalizedSpace: function(current) { 1480 | var self = this; 1481 | return "normalize-space(" + current + ")"; 1482 | }, 1483 | literal: function(node) { 1484 | var self = this; 1485 | return node; 1486 | }, 1487 | union: function() { 1488 | var self = this; 1489 | var expressions = Array.prototype.slice.call(arguments, 0, arguments.length); 1490 | return expressions.join(" | "); 1491 | }, 1492 | anywhere: function(elementNames) { 1493 | var self = this; 1494 | var names; 1495 | if (elementNames.length === 1) { 1496 | return "//" + elementNames[0]; 1497 | } else if (elementNames.length > 1) { 1498 | names = elementNames.map(function(e) { 1499 | return "self::" + e; 1500 | }).join(" | "); 1501 | return "//*[" + names + "]"; 1502 | } else { 1503 | return "//*"; 1504 | } 1505 | }, 1506 | contains: function(current, value) { 1507 | var self = this; 1508 | return "contains(" + current + ", " + value + ")"; 1509 | }, 1510 | startsWith: function(current, value) { 1511 | var self = this; 1512 | return "starts-with(" + current + ", " + value + ")"; 1513 | }, 1514 | endsWith: function(current, value) { 1515 | var self = this; 1516 | return "substring(" + current + ", string-length(" + current + ") - string-length(" + value + ") + 1, string-length(" + current + ")) = " + value; 1517 | }, 1518 | and: function(one, two) { 1519 | var self = this; 1520 | return "(" + one + " and " + two + ")"; 1521 | }, 1522 | or: function(one, two) { 1523 | var self = this; 1524 | return "(" + one + " or " + two + ")"; 1525 | }, 1526 | oneOf: function(current, values) { 1527 | var self = this; 1528 | return values.map(function(value) { 1529 | return current + " = " + value; 1530 | }).join(" or "); 1531 | }, 1532 | nextSibling: function(current, elementNames) { 1533 | var self = this; 1534 | var names; 1535 | if (elementNames.length === 1) { 1536 | return current + "/following-sibling::*[1]/self::" + elementNames[0]; 1537 | } else if (elementNames.length > 1) { 1538 | names = elementNames.map(function(e) { 1539 | return "self::" + e; 1540 | }); 1541 | return current + "/following-sibling::*[1]/self::*[" + names.join(" | ") + "]"; 1542 | } else { 1543 | return current + "/following-sibling::*[1]/self::*"; 1544 | } 1545 | }, 1546 | previousSibling: function(current, elementNames) { 1547 | var self = this; 1548 | var names; 1549 | if (elementNames.length === 1) { 1550 | return current + "/preceding-sibling::*[1]/self::" + elementNames[0]; 1551 | } else if (elementNames.length > 1) { 1552 | names = elementNames.map(function(e) { 1553 | return "self::" + e; 1554 | }); 1555 | return current + "/preceding-sibling::*[1]/self::*[" + names.join(" | ") + "]"; 1556 | } else { 1557 | return current + "/preceding-sibling::*[1]/self::*"; 1558 | } 1559 | }, 1560 | inverse: function(current) { 1561 | var self = this; 1562 | return "not(" + current + ")"; 1563 | }, 1564 | stringFunction: function(current) { 1565 | var self = this; 1566 | return "string(" + current + ")"; 1567 | }, 1568 | substringFunction: function(current, args) { 1569 | var self = this; 1570 | return "substring(" + current + ", " + args.join(", ") + ")"; 1571 | }, 1572 | concatFunction: function(args) { 1573 | var self = this; 1574 | return "concat(" + args.join(", ") + ")"; 1575 | }, 1576 | stringLengthFunction: function(current) { 1577 | var self = this; 1578 | return "string-length(" + current + ")"; 1579 | }, 1580 | countFunction: function(current) { 1581 | var self = this; 1582 | return "count(" + current + ")"; 1583 | }, 1584 | nthOfType: function(n) { 1585 | var self = this; 1586 | return "position() = " + n; 1587 | }, 1588 | nthOfTypeMod: function(m, n) { 1589 | var self = this; 1590 | if (m === -1) { 1591 | return "(position() <= " + n + ") and (((position() - " + n + ") mod 1) = 0)"; 1592 | } else if (n > 0) { 1593 | return "(position() >= " + n + ") and (((position() - " + n + ") mod " + m + ") = 0)"; 1594 | } else { 1595 | return "(position() mod " + m + ") = 0"; 1596 | } 1597 | }, 1598 | nthOfTypeOdd: function() { 1599 | var self = this; 1600 | return "(position() mod 2) = 1"; 1601 | }, 1602 | nthOfTypeEven: function() { 1603 | var self = this; 1604 | return "(position() mod 2) = 0"; 1605 | }, 1606 | nthLastOfType: function(n) { 1607 | var self = this; 1608 | return "position() = last() - " + (n - 1); 1609 | }, 1610 | nthLastOfTypeMod: function(m, n) { 1611 | var self = this; 1612 | if (m === -1) { 1613 | return "((last() - position() + 1) <= " + n + ") and ((((last() - position() + 1) - " + n + ") mod 1) = 0)"; 1614 | } else if (n > 0) { 1615 | return "((last() - position() + 1) >= " + n + ") and ((((last() - position() + 1) - " + n + ") mod " + m + ") = 0)"; 1616 | } else { 1617 | return "((last() - position() + 1) mod " + m + ") = 0"; 1618 | } 1619 | }, 1620 | nthLastOfTypeOdd: function() { 1621 | var self = this; 1622 | return "((last() - position() + 1) >= 1) and ((((last() - position() + 1) - 1) mod 2) = 0)"; 1623 | }, 1624 | nthLastOfTypeEven: function() { 1625 | var self = this; 1626 | return "((last() - position() + 1) mod 2) = 0"; 1627 | }, 1628 | lastOfType: function() { 1629 | var self = this; 1630 | return "position() = last()"; 1631 | }, 1632 | nthChild: function(n) { 1633 | var self = this; 1634 | return "count(preceding-sibling::*) = " + (n - 1); 1635 | }, 1636 | nthLastChild: function(n) { 1637 | var self = this; 1638 | return "count(following-sibling::*) = " + (n - 1); 1639 | }, 1640 | firstChild: function() { 1641 | var self = this; 1642 | return "count(preceding-sibling::*) = 0"; 1643 | }, 1644 | lastChild: function() { 1645 | var self = this; 1646 | return "count(following-sibling::*) = 0"; 1647 | }, 1648 | onlyChild: function() { 1649 | var self = this; 1650 | return "count(preceding-sibling::*) = 0 and count(following-sibling::*) = 0"; 1651 | }, 1652 | onlyOfType: function() { 1653 | var self = this; 1654 | return "last() = 1"; 1655 | }, 1656 | empty: function() { 1657 | var self = this; 1658 | return "not(node())"; 1659 | } 1660 | }; 1661 | Renderer.render = function(node, type) { 1662 | var self = this; 1663 | if (typeof type === "undefined") { 1664 | type = "*"; 1665 | } 1666 | return new Renderer(type).render(node); 1667 | }; 1668 | exports.Renderer = Renderer; 1669 | }).call(this); 1670 | },{}],11:[function(require,module,exports){ 1671 | 1672 | },{}],12:[function(require,module,exports){ 1673 | (function (process){(function (){ 1674 | // 'path' module extracted from Node.js v8.11.1 (only the posix part) 1675 | // transplited with Babel 1676 | 1677 | // Copyright Joyent, Inc. and other Node contributors. 1678 | // 1679 | // Permission is hereby granted, free of charge, to any person obtaining a 1680 | // copy of this software and associated documentation files (the 1681 | // "Software"), to deal in the Software without restriction, including 1682 | // without limitation the rights to use, copy, modify, merge, publish, 1683 | // distribute, sublicense, and/or sell copies of the Software, and to permit 1684 | // persons to whom the Software is furnished to do so, subject to the 1685 | // following conditions: 1686 | // 1687 | // The above copyright notice and this permission notice shall be included 1688 | // in all copies or substantial portions of the Software. 1689 | // 1690 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1691 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1692 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 1693 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 1694 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 1695 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 1696 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 1697 | 1698 | 'use strict'; 1699 | 1700 | function assertPath(path) { 1701 | if (typeof path !== 'string') { 1702 | throw new TypeError('Path must be a string. Received ' + JSON.stringify(path)); 1703 | } 1704 | } 1705 | 1706 | // Resolves . and .. elements in a path with directory names 1707 | function normalizeStringPosix(path, allowAboveRoot) { 1708 | var res = ''; 1709 | var lastSegmentLength = 0; 1710 | var lastSlash = -1; 1711 | var dots = 0; 1712 | var code; 1713 | for (var i = 0; i <= path.length; ++i) { 1714 | if (i < path.length) 1715 | code = path.charCodeAt(i); 1716 | else if (code === 47 /*/*/) 1717 | break; 1718 | else 1719 | code = 47 /*/*/; 1720 | if (code === 47 /*/*/) { 1721 | if (lastSlash === i - 1 || dots === 1) { 1722 | // NOOP 1723 | } else if (lastSlash !== i - 1 && dots === 2) { 1724 | if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== 46 /*.*/ || res.charCodeAt(res.length - 2) !== 46 /*.*/) { 1725 | if (res.length > 2) { 1726 | var lastSlashIndex = res.lastIndexOf('/'); 1727 | if (lastSlashIndex !== res.length - 1) { 1728 | if (lastSlashIndex === -1) { 1729 | res = ''; 1730 | lastSegmentLength = 0; 1731 | } else { 1732 | res = res.slice(0, lastSlashIndex); 1733 | lastSegmentLength = res.length - 1 - res.lastIndexOf('/'); 1734 | } 1735 | lastSlash = i; 1736 | dots = 0; 1737 | continue; 1738 | } 1739 | } else if (res.length === 2 || res.length === 1) { 1740 | res = ''; 1741 | lastSegmentLength = 0; 1742 | lastSlash = i; 1743 | dots = 0; 1744 | continue; 1745 | } 1746 | } 1747 | if (allowAboveRoot) { 1748 | if (res.length > 0) 1749 | res += '/..'; 1750 | else 1751 | res = '..'; 1752 | lastSegmentLength = 2; 1753 | } 1754 | } else { 1755 | if (res.length > 0) 1756 | res += '/' + path.slice(lastSlash + 1, i); 1757 | else 1758 | res = path.slice(lastSlash + 1, i); 1759 | lastSegmentLength = i - lastSlash - 1; 1760 | } 1761 | lastSlash = i; 1762 | dots = 0; 1763 | } else if (code === 46 /*.*/ && dots !== -1) { 1764 | ++dots; 1765 | } else { 1766 | dots = -1; 1767 | } 1768 | } 1769 | return res; 1770 | } 1771 | 1772 | function _format(sep, pathObject) { 1773 | var dir = pathObject.dir || pathObject.root; 1774 | var base = pathObject.base || (pathObject.name || '') + (pathObject.ext || ''); 1775 | if (!dir) { 1776 | return base; 1777 | } 1778 | if (dir === pathObject.root) { 1779 | return dir + base; 1780 | } 1781 | return dir + sep + base; 1782 | } 1783 | 1784 | var posix = { 1785 | // path.resolve([from ...], to) 1786 | resolve: function resolve() { 1787 | var resolvedPath = ''; 1788 | var resolvedAbsolute = false; 1789 | var cwd; 1790 | 1791 | for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { 1792 | var path; 1793 | if (i >= 0) 1794 | path = arguments[i]; 1795 | else { 1796 | if (cwd === undefined) 1797 | cwd = process.cwd(); 1798 | path = cwd; 1799 | } 1800 | 1801 | assertPath(path); 1802 | 1803 | // Skip empty entries 1804 | if (path.length === 0) { 1805 | continue; 1806 | } 1807 | 1808 | resolvedPath = path + '/' + resolvedPath; 1809 | resolvedAbsolute = path.charCodeAt(0) === 47 /*/*/; 1810 | } 1811 | 1812 | // At this point the path should be resolved to a full absolute path, but 1813 | // handle relative paths to be safe (might happen when process.cwd() fails) 1814 | 1815 | // Normalize the path 1816 | resolvedPath = normalizeStringPosix(resolvedPath, !resolvedAbsolute); 1817 | 1818 | if (resolvedAbsolute) { 1819 | if (resolvedPath.length > 0) 1820 | return '/' + resolvedPath; 1821 | else 1822 | return '/'; 1823 | } else if (resolvedPath.length > 0) { 1824 | return resolvedPath; 1825 | } else { 1826 | return '.'; 1827 | } 1828 | }, 1829 | 1830 | normalize: function normalize(path) { 1831 | assertPath(path); 1832 | 1833 | if (path.length === 0) return '.'; 1834 | 1835 | var isAbsolute = path.charCodeAt(0) === 47 /*/*/; 1836 | var trailingSeparator = path.charCodeAt(path.length - 1) === 47 /*/*/; 1837 | 1838 | // Normalize the path 1839 | path = normalizeStringPosix(path, !isAbsolute); 1840 | 1841 | if (path.length === 0 && !isAbsolute) path = '.'; 1842 | if (path.length > 0 && trailingSeparator) path += '/'; 1843 | 1844 | if (isAbsolute) return '/' + path; 1845 | return path; 1846 | }, 1847 | 1848 | isAbsolute: function isAbsolute(path) { 1849 | assertPath(path); 1850 | return path.length > 0 && path.charCodeAt(0) === 47 /*/*/; 1851 | }, 1852 | 1853 | join: function join() { 1854 | if (arguments.length === 0) 1855 | return '.'; 1856 | var joined; 1857 | for (var i = 0; i < arguments.length; ++i) { 1858 | var arg = arguments[i]; 1859 | assertPath(arg); 1860 | if (arg.length > 0) { 1861 | if (joined === undefined) 1862 | joined = arg; 1863 | else 1864 | joined += '/' + arg; 1865 | } 1866 | } 1867 | if (joined === undefined) 1868 | return '.'; 1869 | return posix.normalize(joined); 1870 | }, 1871 | 1872 | relative: function relative(from, to) { 1873 | assertPath(from); 1874 | assertPath(to); 1875 | 1876 | if (from === to) return ''; 1877 | 1878 | from = posix.resolve(from); 1879 | to = posix.resolve(to); 1880 | 1881 | if (from === to) return ''; 1882 | 1883 | // Trim any leading backslashes 1884 | var fromStart = 1; 1885 | for (; fromStart < from.length; ++fromStart) { 1886 | if (from.charCodeAt(fromStart) !== 47 /*/*/) 1887 | break; 1888 | } 1889 | var fromEnd = from.length; 1890 | var fromLen = fromEnd - fromStart; 1891 | 1892 | // Trim any leading backslashes 1893 | var toStart = 1; 1894 | for (; toStart < to.length; ++toStart) { 1895 | if (to.charCodeAt(toStart) !== 47 /*/*/) 1896 | break; 1897 | } 1898 | var toEnd = to.length; 1899 | var toLen = toEnd - toStart; 1900 | 1901 | // Compare paths to find the longest common path from root 1902 | var length = fromLen < toLen ? fromLen : toLen; 1903 | var lastCommonSep = -1; 1904 | var i = 0; 1905 | for (; i <= length; ++i) { 1906 | if (i === length) { 1907 | if (toLen > length) { 1908 | if (to.charCodeAt(toStart + i) === 47 /*/*/) { 1909 | // We get here if `from` is the exact base path for `to`. 1910 | // For example: from='/foo/bar'; to='/foo/bar/baz' 1911 | return to.slice(toStart + i + 1); 1912 | } else if (i === 0) { 1913 | // We get here if `from` is the root 1914 | // For example: from='/'; to='/foo' 1915 | return to.slice(toStart + i); 1916 | } 1917 | } else if (fromLen > length) { 1918 | if (from.charCodeAt(fromStart + i) === 47 /*/*/) { 1919 | // We get here if `to` is the exact base path for `from`. 1920 | // For example: from='/foo/bar/baz'; to='/foo/bar' 1921 | lastCommonSep = i; 1922 | } else if (i === 0) { 1923 | // We get here if `to` is the root. 1924 | // For example: from='/foo'; to='/' 1925 | lastCommonSep = 0; 1926 | } 1927 | } 1928 | break; 1929 | } 1930 | var fromCode = from.charCodeAt(fromStart + i); 1931 | var toCode = to.charCodeAt(toStart + i); 1932 | if (fromCode !== toCode) 1933 | break; 1934 | else if (fromCode === 47 /*/*/) 1935 | lastCommonSep = i; 1936 | } 1937 | 1938 | var out = ''; 1939 | // Generate the relative path based on the path difference between `to` 1940 | // and `from` 1941 | for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) { 1942 | if (i === fromEnd || from.charCodeAt(i) === 47 /*/*/) { 1943 | if (out.length === 0) 1944 | out += '..'; 1945 | else 1946 | out += '/..'; 1947 | } 1948 | } 1949 | 1950 | // Lastly, append the rest of the destination (`to`) path that comes after 1951 | // the common path parts 1952 | if (out.length > 0) 1953 | return out + to.slice(toStart + lastCommonSep); 1954 | else { 1955 | toStart += lastCommonSep; 1956 | if (to.charCodeAt(toStart) === 47 /*/*/) 1957 | ++toStart; 1958 | return to.slice(toStart); 1959 | } 1960 | }, 1961 | 1962 | _makeLong: function _makeLong(path) { 1963 | return path; 1964 | }, 1965 | 1966 | dirname: function dirname(path) { 1967 | assertPath(path); 1968 | if (path.length === 0) return '.'; 1969 | var code = path.charCodeAt(0); 1970 | var hasRoot = code === 47 /*/*/; 1971 | var end = -1; 1972 | var matchedSlash = true; 1973 | for (var i = path.length - 1; i >= 1; --i) { 1974 | code = path.charCodeAt(i); 1975 | if (code === 47 /*/*/) { 1976 | if (!matchedSlash) { 1977 | end = i; 1978 | break; 1979 | } 1980 | } else { 1981 | // We saw the first non-path separator 1982 | matchedSlash = false; 1983 | } 1984 | } 1985 | 1986 | if (end === -1) return hasRoot ? '/' : '.'; 1987 | if (hasRoot && end === 1) return '//'; 1988 | return path.slice(0, end); 1989 | }, 1990 | 1991 | basename: function basename(path, ext) { 1992 | if (ext !== undefined && typeof ext !== 'string') throw new TypeError('"ext" argument must be a string'); 1993 | assertPath(path); 1994 | 1995 | var start = 0; 1996 | var end = -1; 1997 | var matchedSlash = true; 1998 | var i; 1999 | 2000 | if (ext !== undefined && ext.length > 0 && ext.length <= path.length) { 2001 | if (ext.length === path.length && ext === path) return ''; 2002 | var extIdx = ext.length - 1; 2003 | var firstNonSlashEnd = -1; 2004 | for (i = path.length - 1; i >= 0; --i) { 2005 | var code = path.charCodeAt(i); 2006 | if (code === 47 /*/*/) { 2007 | // If we reached a path separator that was not part of a set of path 2008 | // separators at the end of the string, stop now 2009 | if (!matchedSlash) { 2010 | start = i + 1; 2011 | break; 2012 | } 2013 | } else { 2014 | if (firstNonSlashEnd === -1) { 2015 | // We saw the first non-path separator, remember this index in case 2016 | // we need it if the extension ends up not matching 2017 | matchedSlash = false; 2018 | firstNonSlashEnd = i + 1; 2019 | } 2020 | if (extIdx >= 0) { 2021 | // Try to match the explicit extension 2022 | if (code === ext.charCodeAt(extIdx)) { 2023 | if (--extIdx === -1) { 2024 | // We matched the extension, so mark this as the end of our path 2025 | // component 2026 | end = i; 2027 | } 2028 | } else { 2029 | // Extension does not match, so our result is the entire path 2030 | // component 2031 | extIdx = -1; 2032 | end = firstNonSlashEnd; 2033 | } 2034 | } 2035 | } 2036 | } 2037 | 2038 | if (start === end) end = firstNonSlashEnd;else if (end === -1) end = path.length; 2039 | return path.slice(start, end); 2040 | } else { 2041 | for (i = path.length - 1; i >= 0; --i) { 2042 | if (path.charCodeAt(i) === 47 /*/*/) { 2043 | // If we reached a path separator that was not part of a set of path 2044 | // separators at the end of the string, stop now 2045 | if (!matchedSlash) { 2046 | start = i + 1; 2047 | break; 2048 | } 2049 | } else if (end === -1) { 2050 | // We saw the first non-path separator, mark this as the end of our 2051 | // path component 2052 | matchedSlash = false; 2053 | end = i + 1; 2054 | } 2055 | } 2056 | 2057 | if (end === -1) return ''; 2058 | return path.slice(start, end); 2059 | } 2060 | }, 2061 | 2062 | extname: function extname(path) { 2063 | assertPath(path); 2064 | var startDot = -1; 2065 | var startPart = 0; 2066 | var end = -1; 2067 | var matchedSlash = true; 2068 | // Track the state of characters (if any) we see before our first dot and 2069 | // after any path separator we find 2070 | var preDotState = 0; 2071 | for (var i = path.length - 1; i >= 0; --i) { 2072 | var code = path.charCodeAt(i); 2073 | if (code === 47 /*/*/) { 2074 | // If we reached a path separator that was not part of a set of path 2075 | // separators at the end of the string, stop now 2076 | if (!matchedSlash) { 2077 | startPart = i + 1; 2078 | break; 2079 | } 2080 | continue; 2081 | } 2082 | if (end === -1) { 2083 | // We saw the first non-path separator, mark this as the end of our 2084 | // extension 2085 | matchedSlash = false; 2086 | end = i + 1; 2087 | } 2088 | if (code === 46 /*.*/) { 2089 | // If this is our first dot, mark it as the start of our extension 2090 | if (startDot === -1) 2091 | startDot = i; 2092 | else if (preDotState !== 1) 2093 | preDotState = 1; 2094 | } else if (startDot !== -1) { 2095 | // We saw a non-dot and non-path separator before our dot, so we should 2096 | // have a good chance at having a non-empty extension 2097 | preDotState = -1; 2098 | } 2099 | } 2100 | 2101 | if (startDot === -1 || end === -1 || 2102 | // We saw a non-dot character immediately before the dot 2103 | preDotState === 0 || 2104 | // The (right-most) trimmed path component is exactly '..' 2105 | preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) { 2106 | return ''; 2107 | } 2108 | return path.slice(startDot, end); 2109 | }, 2110 | 2111 | format: function format(pathObject) { 2112 | if (pathObject === null || typeof pathObject !== 'object') { 2113 | throw new TypeError('The "pathObject" argument must be of type Object. Received type ' + typeof pathObject); 2114 | } 2115 | return _format('/', pathObject); 2116 | }, 2117 | 2118 | parse: function parse(path) { 2119 | assertPath(path); 2120 | 2121 | var ret = { root: '', dir: '', base: '', ext: '', name: '' }; 2122 | if (path.length === 0) return ret; 2123 | var code = path.charCodeAt(0); 2124 | var isAbsolute = code === 47 /*/*/; 2125 | var start; 2126 | if (isAbsolute) { 2127 | ret.root = '/'; 2128 | start = 1; 2129 | } else { 2130 | start = 0; 2131 | } 2132 | var startDot = -1; 2133 | var startPart = 0; 2134 | var end = -1; 2135 | var matchedSlash = true; 2136 | var i = path.length - 1; 2137 | 2138 | // Track the state of characters (if any) we see before our first dot and 2139 | // after any path separator we find 2140 | var preDotState = 0; 2141 | 2142 | // Get non-dir info 2143 | for (; i >= start; --i) { 2144 | code = path.charCodeAt(i); 2145 | if (code === 47 /*/*/) { 2146 | // If we reached a path separator that was not part of a set of path 2147 | // separators at the end of the string, stop now 2148 | if (!matchedSlash) { 2149 | startPart = i + 1; 2150 | break; 2151 | } 2152 | continue; 2153 | } 2154 | if (end === -1) { 2155 | // We saw the first non-path separator, mark this as the end of our 2156 | // extension 2157 | matchedSlash = false; 2158 | end = i + 1; 2159 | } 2160 | if (code === 46 /*.*/) { 2161 | // If this is our first dot, mark it as the start of our extension 2162 | if (startDot === -1) startDot = i;else if (preDotState !== 1) preDotState = 1; 2163 | } else if (startDot !== -1) { 2164 | // We saw a non-dot and non-path separator before our dot, so we should 2165 | // have a good chance at having a non-empty extension 2166 | preDotState = -1; 2167 | } 2168 | } 2169 | 2170 | if (startDot === -1 || end === -1 || 2171 | // We saw a non-dot character immediately before the dot 2172 | preDotState === 0 || 2173 | // The (right-most) trimmed path component is exactly '..' 2174 | preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) { 2175 | if (end !== -1) { 2176 | if (startPart === 0 && isAbsolute) ret.base = ret.name = path.slice(1, end);else ret.base = ret.name = path.slice(startPart, end); 2177 | } 2178 | } else { 2179 | if (startPart === 0 && isAbsolute) { 2180 | ret.name = path.slice(1, startDot); 2181 | ret.base = path.slice(1, end); 2182 | } else { 2183 | ret.name = path.slice(startPart, startDot); 2184 | ret.base = path.slice(startPart, end); 2185 | } 2186 | ret.ext = path.slice(startDot, end); 2187 | } 2188 | 2189 | if (startPart > 0) ret.dir = path.slice(0, startPart - 1);else if (isAbsolute) ret.dir = '/'; 2190 | 2191 | return ret; 2192 | }, 2193 | 2194 | sep: '/', 2195 | delimiter: ':', 2196 | win32: null, 2197 | posix: null 2198 | }; 2199 | 2200 | posix.posix = posix; 2201 | 2202 | module.exports = posix; 2203 | 2204 | }).call(this)}).call(this,require('_process')) 2205 | },{"_process":13}],13:[function(require,module,exports){ 2206 | // shim for using process in browser 2207 | var process = module.exports = {}; 2208 | 2209 | // cached from whatever global is present so that test runners that stub it 2210 | // don't break things. But we need to wrap it in a try catch in case it is 2211 | // wrapped in strict mode code which doesn't define any globals. It's inside a 2212 | // function because try/catches deoptimize in certain engines. 2213 | 2214 | var cachedSetTimeout; 2215 | var cachedClearTimeout; 2216 | 2217 | function defaultSetTimout() { 2218 | throw new Error('setTimeout has not been defined'); 2219 | } 2220 | function defaultClearTimeout () { 2221 | throw new Error('clearTimeout has not been defined'); 2222 | } 2223 | (function () { 2224 | try { 2225 | if (typeof setTimeout === 'function') { 2226 | cachedSetTimeout = setTimeout; 2227 | } else { 2228 | cachedSetTimeout = defaultSetTimout; 2229 | } 2230 | } catch (e) { 2231 | cachedSetTimeout = defaultSetTimout; 2232 | } 2233 | try { 2234 | if (typeof clearTimeout === 'function') { 2235 | cachedClearTimeout = clearTimeout; 2236 | } else { 2237 | cachedClearTimeout = defaultClearTimeout; 2238 | } 2239 | } catch (e) { 2240 | cachedClearTimeout = defaultClearTimeout; 2241 | } 2242 | } ()) 2243 | function runTimeout(fun) { 2244 | if (cachedSetTimeout === setTimeout) { 2245 | //normal enviroments in sane situations 2246 | return setTimeout(fun, 0); 2247 | } 2248 | // if setTimeout wasn't available but was latter defined 2249 | if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { 2250 | cachedSetTimeout = setTimeout; 2251 | return setTimeout(fun, 0); 2252 | } 2253 | try { 2254 | // when when somebody has screwed with setTimeout but no I.E. maddness 2255 | return cachedSetTimeout(fun, 0); 2256 | } catch(e){ 2257 | try { 2258 | // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally 2259 | return cachedSetTimeout.call(null, fun, 0); 2260 | } catch(e){ 2261 | // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error 2262 | return cachedSetTimeout.call(this, fun, 0); 2263 | } 2264 | } 2265 | 2266 | 2267 | } 2268 | function runClearTimeout(marker) { 2269 | if (cachedClearTimeout === clearTimeout) { 2270 | //normal enviroments in sane situations 2271 | return clearTimeout(marker); 2272 | } 2273 | // if clearTimeout wasn't available but was latter defined 2274 | if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { 2275 | cachedClearTimeout = clearTimeout; 2276 | return clearTimeout(marker); 2277 | } 2278 | try { 2279 | // when when somebody has screwed with setTimeout but no I.E. maddness 2280 | return cachedClearTimeout(marker); 2281 | } catch (e){ 2282 | try { 2283 | // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally 2284 | return cachedClearTimeout.call(null, marker); 2285 | } catch (e){ 2286 | // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. 2287 | // Some versions of I.E. have different rules for clearTimeout vs setTimeout 2288 | return cachedClearTimeout.call(this, marker); 2289 | } 2290 | } 2291 | 2292 | 2293 | 2294 | } 2295 | var queue = []; 2296 | var draining = false; 2297 | var currentQueue; 2298 | var queueIndex = -1; 2299 | 2300 | function cleanUpNextTick() { 2301 | if (!draining || !currentQueue) { 2302 | return; 2303 | } 2304 | draining = false; 2305 | if (currentQueue.length) { 2306 | queue = currentQueue.concat(queue); 2307 | } else { 2308 | queueIndex = -1; 2309 | } 2310 | if (queue.length) { 2311 | drainQueue(); 2312 | } 2313 | } 2314 | 2315 | function drainQueue() { 2316 | if (draining) { 2317 | return; 2318 | } 2319 | var timeout = runTimeout(cleanUpNextTick); 2320 | draining = true; 2321 | 2322 | var len = queue.length; 2323 | while(len) { 2324 | currentQueue = queue; 2325 | queue = []; 2326 | while (++queueIndex < len) { 2327 | if (currentQueue) { 2328 | currentQueue[queueIndex].run(); 2329 | } 2330 | } 2331 | queueIndex = -1; 2332 | len = queue.length; 2333 | } 2334 | currentQueue = null; 2335 | draining = false; 2336 | runClearTimeout(timeout); 2337 | } 2338 | 2339 | process.nextTick = function (fun) { 2340 | var args = new Array(arguments.length - 1); 2341 | if (arguments.length > 1) { 2342 | for (var i = 1; i < arguments.length; i++) { 2343 | args[i - 1] = arguments[i]; 2344 | } 2345 | } 2346 | queue.push(new Item(fun, args)); 2347 | if (queue.length === 1 && !draining) { 2348 | runTimeout(drainQueue); 2349 | } 2350 | }; 2351 | 2352 | // v8 likes predictible objects 2353 | function Item(fun, array) { 2354 | this.fun = fun; 2355 | this.array = array; 2356 | } 2357 | Item.prototype.run = function () { 2358 | this.fun.apply(null, this.array); 2359 | }; 2360 | process.title = 'browser'; 2361 | process.browser = true; 2362 | process.env = {}; 2363 | process.argv = []; 2364 | process.version = ''; // empty string to avoid regexp issues 2365 | process.versions = {}; 2366 | 2367 | function noop() {} 2368 | 2369 | process.on = noop; 2370 | process.addListener = noop; 2371 | process.once = noop; 2372 | process.off = noop; 2373 | process.removeListener = noop; 2374 | process.removeAllListeners = noop; 2375 | process.emit = noop; 2376 | process.prependListener = noop; 2377 | process.prependOnceListener = noop; 2378 | 2379 | process.listeners = function (name) { return [] } 2380 | 2381 | process.binding = function (name) { 2382 | throw new Error('process.binding is not supported'); 2383 | }; 2384 | 2385 | process.cwd = function () { return '/' }; 2386 | process.chdir = function (dir) { 2387 | throw new Error('process.chdir is not supported'); 2388 | }; 2389 | process.umask = function() { return 0; }; 2390 | 2391 | },{}]},{},[1]); 2392 | --------------------------------------------------------------------------------