├── LICENSE ├── README.md ├── devtools.html ├── devtools.js ├── icon128.png ├── icon16.png ├── icon48.png ├── inject.js ├── manifest.json ├── panel.html ├── panel.js ├── prism.css └── prism.js /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 hanthomas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Protractor Recorder 2 | Chrome extension to record Protractor E2E test scripts 3 | 4 | ## How to Install 5 | 1. Download ZIP and unzip to folder on your local machine 6 | 2. Start Chrome browser and navigate to *chrome://extensions* 7 | 3. Click on **Load unpacked extension** and select location of unzipped folder 8 | 4. Enable the Protractor Recorder extension 9 | 10 | ## How to Use 11 | 1. Open your web site in Chrome 12 | 2. Launch **Developer Tools** by pressing F12 13 | 3. Select **Protractor** tab 14 | 4. Interact with your web site. Each action is recorded in the Protractor Recorder console. 15 | 5. When you're done, click **Copy to Clipboard** to copy the recorded script. 16 | 17 | ## Should I disable automatic synchronization? 18 | Check this box if the recorded scripts are timing out when run in Protractor. Protractor has known issues with AngularJS applications that use **$timeout**. See Protractor issues [#169](https://github.com/angular/protractor/issues/169) and [#2950](https://github.com/angular/protractor/issues/2950). 19 | -------------------------------------------------------------------------------- /devtools.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /devtools.js: -------------------------------------------------------------------------------- 1 | chrome.devtools.panels.create('Protractor', 'icon48.png', 'panel.html', function (panel) { 2 | var xhr = new XMLHttpRequest(); 3 | 4 | xhr.open('GET', chrome.runtime.getURL('/inject.js'), false); 5 | xhr.send(); 6 | 7 | var script = xhr.responseText; 8 | 9 | if (script) { 10 | chrome.devtools.inspectedWindow.eval(script.toString()); 11 | 12 | var interval; 13 | 14 | panel.onShown.addListener(function (o) { 15 | interval = window.setInterval(function () { 16 | chrome.devtools.inspectedWindow.eval('(function () { return window.protractor.logs; })()', function () { 17 | if (!arguments[1]) 18 | o.update(arguments[0]); 19 | else 20 | chrome.devtools.inspectedWindow.eval(script.toString()); 21 | }); 22 | }, 300); 23 | }); 24 | 25 | panel.onHidden.addListener(function () { 26 | if (interval) 27 | window.clearInterval(interval); 28 | }); 29 | } 30 | }); 31 | -------------------------------------------------------------------------------- /icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanthomas/protractor-recorder/308d6c24f3aada915836ba917ee1342a6c65c0ac/icon128.png -------------------------------------------------------------------------------- /icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanthomas/protractor-recorder/308d6c24f3aada915836ba917ee1342a6c65c0ac/icon16.png -------------------------------------------------------------------------------- /icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanthomas/protractor-recorder/308d6c24f3aada915836ba917ee1342a6c65c0ac/icon48.png -------------------------------------------------------------------------------- /inject.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | window.protractor = {}; 3 | window.protractor.logs = []; 4 | window.protractor.ignoreSynchronization = false; 5 | 6 | Event.prototype.stopPropagation = function () { }; 7 | 8 | var url = ''; 9 | var time = null; 10 | var mouse = []; 11 | 12 | document.addEventListener('click', function (e) { 13 | if (e.target.tagName.toLowerCase() != 'canvas') 14 | log('element(by.css(\'' + selector(e.target).replace(/\\\"/g, '\\\\\\"') + '\'))' + '.click();'); 15 | }); 16 | 17 | document.addEventListener('mousedown', function (e) { 18 | if (e.target.tagName.toLowerCase() == 'canvas') 19 | mouse = [e]; 20 | }); 21 | 22 | document.addEventListener('mousemove', function (e) { 23 | if (e.target.tagName.toLowerCase() == 'canvas' && mouse && mouse.length > 0) 24 | mouse.push(e); 25 | }); 26 | 27 | document.addEventListener('mouseup', function (e) { 28 | if (e.target.tagName.toLowerCase() == 'canvas' && mouse && mouse.length > 0 && mouse[0].target == e.target) { 29 | if (mouse.reduce(function (a, b) { return a.clientX - b.clientX; }, mouse[0]) <= 1 && mouse.reduce(function (a, b) { return a.clientY - b.clientY; }, mouse[0]) <= 1) 30 | log('browser.driver.actions().mouseMove(element(by.css(\'' + selector(mouse[0].target).replace(/\\\"/g, '\\\\\\"') + '\')), {x: ' + mouse[0].clientX.toString() + ', y:' + mouse[0].clientY.toString() + '}).click().perform();'); 31 | else 32 | log('browser.driver.actions().mouseMove(element(by.css(\'' + selector(mouse[0].target).replace(/\\\"/g, '\\\\\\"') + '\')), {x: ' + mouse[0].clientX.toString() + ', y:' + mouse[0].clientY.toString() + '}).mouseDown()' + mouse.reduce(function (a, b, i) { return i > 0 ? a + '.mouseMove({x: ' + (b.clientX - mouse[i - 1].clientX).toString() + ', y:' + (b.clientY - mouse[i - 1].clientY).toString() + '})' : ''; }, '') + '.mouseUp().perform();'); 33 | } 34 | }); 35 | 36 | document.addEventListener('touchstart', function (e) { 37 | if (e.target.tagName.toLowerCase() == 'canvas' && e.targetTouches && e.targetTouches.length > 0) 38 | mouse = [{ target: e.target, clientX: Math.floor(e.targetTouches[0].clientX), clientY: Math.floor(e.targetTouches[0].clientY) }]; 39 | }); 40 | 41 | document.addEventListener('touchmove', function (e) { 42 | if (e.target.tagName.toLowerCase() == 'canvas' && e.targetTouches && e.targetTouches.length > 0 && mouse && mouse.length > 0) 43 | mouse.push({ target: e.target, clientX: Math.floor(e.targetTouches[0].clientX), clientY: Math.floor(e.targetTouches[0].clientY) }); 44 | }); 45 | 46 | document.addEventListener('touchend', function (e) { 47 | if (e.target.tagName.toLowerCase() == 'canvas' && mouse && mouse.length > 0 && mouse[0].target == e.target) { 48 | if (mouse.reduce(function (a, b) { return a.clientX - b.clientX; }, mouse[0]) <= 1 && mouse.reduce(function (a, b) { return a.clientY - b.clientY; }, mouse[0]) <= 1) 49 | log('browser.driver.actions().mouseMove(element(by.css(\'' + selector(mouse[0].target).replace(/\\\"/g, '\\\\\\"') + '\')), {x: ' + mouse[0].clientX.toString() + ', y:' + mouse[0].clientY.toString() + '}).click().perform();'); 50 | else 51 | log('browser.driver.actions().mouseMove(element(by.css(\'' + selector(mouse[0].target).replace(/\\\"/g, '\\\\\\"') + '\')), {x: ' + mouse[0].clientX.toString() + ', y:' + mouse[0].clientY.toString() + '}).mouseDown()' + mouse.reduce(function (a, b, i) { return i > 0 ? a + '.mouseMove({x: ' + (b.clientX - mouse[i - 1].clientX).toString() + ', y:' + (b.clientY - mouse[i - 1].clientY).toString() + '})' : ''; }, '') + '.mouseUp().perform();'); 52 | } 53 | }); 54 | 55 | document.addEventListener('change', function (e) { 56 | if (e.target.tagName.toLowerCase() == 'input' && ['text', 'password', 'number'].indexOf(e.target.getAttribute('type').toLowerCase()) != -1) 57 | log('element(by.css(\'' + selector(e.target).replace(/\\\"/g, '\\\\\\"') + '\'))' + '.clear().sendKeys(\'' + e.target.value + '\');'); 58 | else if (e.target.tagName.toLowerCase() == 'textarea') 59 | log('element(by.css(\'' + selector(e.target).replace(/\\\"/g, '\\\\\\"') + '\'))' + '.clear().sendKeys(\'' + e.target.value + '\');'); 60 | }); 61 | 62 | var selector = function (target) { 63 | var query = ''; 64 | 65 | if (target == document) 66 | query = 'body'; 67 | else { 68 | var attr = ['ng-model', 'ng-href', 'name', 'aria-label'].reduce(function (a, b) { return a || (target.getAttribute(b) ? b : null); }, null); 69 | if (attr) 70 | query = target.tagName.toLowerCase() + '[' + attr + '="' + target.getAttribute(attr).replace(/\\/g, '\\\\').replace(/\'/g, '\\\'').replace(/\"/g, '\\"').replace(/\0/g, '\\0') + '"]'; 71 | else 72 | query = target.tagName.toLowerCase(); 73 | 74 | var nodes = target.parentNode.querySelectorAll(query); 75 | if (nodes && nodes.length > 1) 76 | query += ':nth-of-type(' + (Array.prototype.slice.call(nodes).indexOf(target) + 1).toString() + ')'; 77 | 78 | query = query.replace(/\s/g, ' '); 79 | } 80 | 81 | if (document.querySelectorAll(query).length > 1 && target.parentNode) 82 | query = selector(target.parentNode) + '>' + query; 83 | 84 | return query; 85 | }; 86 | 87 | var log = function (action) { 88 | if (window.protractor.logs.length == 0) 89 | window.protractor.logs.push('browser.driver.manage().window().setSize(' + window.outerWidth + ', ' + window.outerHeight + ');'); 90 | 91 | if (window.protractor.ignoreSynchronization && time) 92 | window.protractor.logs.push('browser.sleep(' + (new Date() - time).toString() + ');'); 93 | 94 | time = new Date(); 95 | 96 | if (!url || url != window.location.hash) 97 | window.protractor.logs.push('// URL: ' + window.location.hash); 98 | 99 | url = window.location.hash; 100 | 101 | window.protractor.logs.push(action); 102 | }; 103 | 104 | return window.protractor.logs; 105 | })(); 106 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Protractor Recorder", 3 | "version": "1.0.0", 4 | "description": "Records Protractor E2E test scripts", 5 | "devtools_page": "devtools.html", 6 | "icons": { 7 | "16": "icon16.png", 8 | "48": "icon48.png", 9 | "128": "icon128.png" 10 | }, 11 | "manifest_version": 2 12 | } -------------------------------------------------------------------------------- /panel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 51 | 52 | 53 | 54 |

55 | 56 | Protractor Recorder 57 |

58 | 59 |
60 |
61 | Record Protractor tests by interacting with the page via mouse or touch. 62 |
63 | 64 | 65 |
66 | 67 |
68 | 69 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /panel.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function () { 2 | document.querySelector('#copy').addEventListener('click', function () { 3 | var code = document.createRange(); 4 | code.selectNode(document.querySelector('code')); 5 | window.getSelection().addRange(code); 6 | 7 | try { 8 | if (document.execCommand('copy')) 9 | document.querySelector('#message').innerText = 'Copied to the clipboard on ' + (new Date()).toLocaleString(); 10 | else 11 | document.querySelector('#message').innerText = 'Problem copying test script to the clipboard.'; 12 | } 13 | catch (e) { 14 | document.querySelector('#message').innerText = 'Problem copying test script to the clipboard.'; 15 | } 16 | 17 | window.getSelection().removeAllRanges(); 18 | }, false); 19 | 20 | document.querySelector('#clear').addEventListener('click', function () { 21 | chrome.devtools.inspectedWindow.eval('(function () { window.protractor.logs = []; })()'); 22 | update([]); 23 | document.querySelector('#message').innerText = ''; 24 | }, false); 25 | 26 | document.querySelector('#nosync').addEventListener('change', function () { 27 | if (document.querySelector('#nosync').checked) 28 | chrome.devtools.inspectedWindow.eval('(function () { window.protractor.ignoreSynchronization = true; window.protractor.logs.push(\'browser.ignoreSynchronization = true;\'); })()'); 29 | else 30 | chrome.devtools.inspectedWindow.eval('(function () { window.protractor.ignoreSynchronization = false; window.protractor.logs.push(\'browser.ignoreSynchronization = false; })()'); 31 | }, false); 32 | 33 | document.querySelector('code').addEventListener('focus', function () { 34 | editing = true; 35 | }, false); 36 | 37 | document.querySelector('code').addEventListener('blur', function () { 38 | chrome.devtools.inspectedWindow.eval('(function () { window.protractor.logs = ' + JSON.stringify(document.querySelector('code').innerText.split('\n')) + '; })()'); 39 | editing = false; 40 | }, false); 41 | }, false); 42 | 43 | var editing = false; 44 | 45 | function update(logs) { 46 | if (!editing) { 47 | var code = document.querySelector('code'); 48 | if (code) 49 | code.innerText = logs.join('\n'); 50 | 51 | Prism.highlightAll(); 52 | 53 | if (logs && logs.length > 0) { 54 | document.querySelector('#copy').style.display = ''; 55 | document.querySelector('#clear').style.display = ''; 56 | } 57 | else { 58 | document.querySelector('#copy').style.display = 'none'; 59 | document.querySelector('#clear').style.display = 'none'; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /prism.css: -------------------------------------------------------------------------------- 1 | /* http://prismjs.com/download.html?themes=prism-okaidia&languages=markup+css+clike+javascript */ 2 | /** 3 | * okaidia theme for JavaScript, CSS and HTML 4 | * Loosely based on Monokai textmate theme by http://www.monokai.nl/ 5 | * @author ocodia 6 | */ 7 | 8 | code[class*="language-"], 9 | pre[class*="language-"] { 10 | color: #f8f8f2; 11 | background: none; 12 | text-shadow: 0 1px rgba(0, 0, 0, 0.3); 13 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 14 | text-align: left; 15 | white-space: pre; 16 | word-spacing: normal; 17 | word-break: normal; 18 | word-wrap: normal; 19 | line-height: 1.5; 20 | 21 | -moz-tab-size: 4; 22 | -o-tab-size: 4; 23 | tab-size: 4; 24 | 25 | -webkit-hyphens: none; 26 | -moz-hyphens: none; 27 | -ms-hyphens: none; 28 | hyphens: none; 29 | } 30 | 31 | /* Code blocks */ 32 | pre[class*="language-"] { 33 | padding: 1em; 34 | margin: .5em 0; 35 | overflow: auto; 36 | border-radius: 0.3em; 37 | } 38 | 39 | :not(pre) > code[class*="language-"], 40 | pre[class*="language-"] { 41 | background: #272822; 42 | } 43 | 44 | /* Inline code */ 45 | :not(pre) > code[class*="language-"] { 46 | padding: .1em; 47 | border-radius: .3em; 48 | white-space: normal; 49 | } 50 | 51 | .token.comment, 52 | .token.prolog, 53 | .token.doctype, 54 | .token.cdata { 55 | color: slategray; 56 | } 57 | 58 | .token.punctuation { 59 | color: #f8f8f2; 60 | } 61 | 62 | .namespace { 63 | opacity: .7; 64 | } 65 | 66 | .token.property, 67 | .token.tag, 68 | .token.constant, 69 | .token.symbol, 70 | .token.deleted { 71 | color: #f92672; 72 | } 73 | 74 | .token.boolean, 75 | .token.number { 76 | color: #ae81ff; 77 | } 78 | 79 | .token.selector, 80 | .token.attr-name, 81 | .token.string, 82 | .token.char, 83 | .token.builtin, 84 | .token.inserted { 85 | color: #a6e22e; 86 | } 87 | 88 | .token.operator, 89 | .token.entity, 90 | .token.url, 91 | .language-css .token.string, 92 | .style .token.string, 93 | .token.variable { 94 | color: #f8f8f2; 95 | } 96 | 97 | .token.atrule, 98 | .token.attr-value, 99 | .token.function { 100 | color: #e6db74; 101 | } 102 | 103 | .token.keyword { 104 | color: #66d9ef; 105 | } 106 | 107 | .token.regex, 108 | .token.important { 109 | color: #fd971f; 110 | } 111 | 112 | .token.important, 113 | .token.bold { 114 | font-weight: bold; 115 | } 116 | .token.italic { 117 | font-style: italic; 118 | } 119 | 120 | .token.entity { 121 | cursor: help; 122 | } 123 | 124 | -------------------------------------------------------------------------------- /prism.js: -------------------------------------------------------------------------------- 1 | /* http://prismjs.com/download.html?themes=prism-okaidia&languages=markup+css+clike+javascript */ 2 | var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-(\w+)\b/i,t=0,n=_self.Prism={util:{encode:function(e){return e instanceof a?new a(e.type,n.util.encode(e.content),e.alias):"Array"===n.util.type(e)?e.map(n.util.encode):e.replace(/&/g,"&").replace(/e.length)break e;if(!(m instanceof a)){u.lastIndex=0;var v=u.exec(m),y=1;if(!v&&h&&p!=r.length-1){var b=r[p+1].matchedStr||r[p+1],k=m+b;if(p=m.length)continue;var _=v.index+v[0].length,P=m.length+b.length;y=3,P>=_&&(y=2,k=k.slice(0,P)),m=k}if(v){g&&(f=v[1].length);var w=v.index+f,v=v[0].slice(f),_=w+v.length,S=m.slice(0,w),O=m.slice(_),j=[p,y];S&&j.push(S);var A=new a(i,c?n.tokenize(v,c):v,d,v);j.push(A),O&&j.push(O),Array.prototype.splice.apply(r,j)}}}}}return r},hooks:{all:{},add:function(e,t){var a=n.hooks.all;a[e]=a[e]||[],a[e].push(t)},run:function(e,t){var a=n.hooks.all[e];if(a&&a.length)for(var r,l=0;r=a[l++];)r(t)}}},a=n.Token=function(e,t,n,a){this.type=e,this.content=t,this.alias=n,this.matchedStr=a||null};if(a.stringify=function(e,t,r){if("string"==typeof e)return e;if("Array"===n.util.type(e))return e.map(function(n){return a.stringify(n,t,e)}).join("");var l={type:e.type,content:a.stringify(e.content,t,r),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:r};if("comment"==l.type&&(l.attributes.spellcheck="true"),e.alias){var i="Array"===n.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}n.hooks.run("wrap",l);var o="";for(var s in l.attributes)o+=(o?" ":"")+s+'="'+(l.attributes[s]||"")+'"';return"<"+l.tag+' class="'+l.classes.join(" ")+'" '+o+">"+l.content+""},!_self.document)return _self.addEventListener?(_self.addEventListener("message",function(e){var t=JSON.parse(e.data),a=t.language,r=t.code,l=t.immediateClose;_self.postMessage(n.highlight(r,n.languages[a],a)),l&&_self.close()},!1),_self.Prism):_self.Prism;var r=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return r&&(n.filename=r.src,document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",n.highlightAll)),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); 3 | Prism.languages.markup={comment://,prolog:/<\?[\w\W]+?\?>/,doctype://,cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=.$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup; 4 | Prism.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:/("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,"function":/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},Prism.languages.css.atrule.inside.rest=Prism.util.clone(Prism.languages.css),Prism.languages.markup&&(Prism.languages.insertBefore("markup","tag",{style:{pattern:/()[\w\W]*?(?=<\/style>)/i,lookbehind:!0,inside:Prism.languages.css,alias:"language-css"}}),Prism.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|').*?\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:Prism.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:Prism.languages.css}},alias:"language-css"}},Prism.languages.markup.tag)); 5 | Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:{pattern:/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(true|false)\b/,"function":/[a-z0-9_]+(?=\()/i,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/}; 6 | Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,"function":/[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*(?=\()/i}),Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^\/])\/(?!\/)(\[.+?]|\\.|[^\/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0,greedy:!0}}),Prism.languages.insertBefore("javascript","class-name",{"template-string":{pattern:/`(?:\\\\|\\?[^\\])*?`/,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/()[\w\W]*?(?=<\/script>)/i,lookbehind:!0,inside:Prism.languages.javascript,alias:"language-javascript"}}),Prism.languages.js=Prism.languages.javascript; 7 | --------------------------------------------------------------------------------