Repository: jhawthorn/curl-to-ruby Branch: gh-pages Commit: 24abdb538dd2 Files: 19 Total size: 66.2 KB Directory structure: gitextract_7qxwwb6z/ ├── .github/ │ └── workflows/ │ └── test.yml ├── .gitignore ├── Gemfile ├── LICENSE.txt ├── README.md ├── index.html ├── package.json ├── resources/ │ ├── css/ │ │ ├── color-brewer.css │ │ └── common.css │ └── js/ │ ├── curl-to-ruby.js │ └── default.js ├── src/ │ ├── curl-to-ruby.js │ ├── curlToRuby.js │ ├── default.js │ ├── highlight.pack.js │ ├── jsonToRuby.js │ └── parseCommand.js ├── test.rb └── webpack.config.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/test.yml ================================================ name: Test on: push: branches: - gh-pages pull_request: branches: - gh-pages jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - name: Set up Ruby 2.6 uses: actions/setup-ruby@v1 with: ruby-version: 2.6.x - name: Set up Node.js 8.x uses: actions/setup-node@v1 with: node-version: 8.x - name: Install dependencies run: | gem install bundler bundle install --jobs 4 --retry 3 yarn - name: Build and run tests run: | yarn run compile bundle exec ruby test.rb ================================================ FILE: .gitignore ================================================ .DS_Store Thumbs.db _gitignore node_modules ================================================ FILE: Gemfile ================================================ source 'https://rubygems.org' gem 'execjs' gem 'execjs-fastnode' gem 'minitest' gem 'pry' ================================================ FILE: LICENSE.txt ================================================ The MIT License (MIT) Copyright (c) 2016 Matthew Holt Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ curl-to-ruby ============ curl-to-ruby is a tool to instantly convert [curl](http://curl.haxx.se) commands to ruby code using [net/http](http://ruby-doc.org/stdlib-2.1.1/libdoc/net/http/rdoc/Net/HTTP.html) in the browser. It does *not* guarantee high-fidelity conversions, but it's good enough for most API docs that have curl samples. ### Try it **[Check it out!](https://jhawthorn.github.io/curl-to-ruby)** It works inside your browser. ### FAQ #### Does any curl command work? Any curl command should work, but only certain flags are understood and converted into ruby code. The rest of the flags will be ignored. #### Which kinds of curl commands are understood? Mostly simple HTTP commands (headers, basic auth, body, etc). #### Will you consider supporting *this-or-that* flag? curl has like a bajillion options, so don't expect all of them to be implemented; just the most common/important ones to stub out code from API samples and docs, etc. But feel free to open an issue or submit a pull request! ### Credits Updated to ruby by John Hawthorn ([jhawthorn](https://twitter.com/jhawthorn)) Based on [curl-to-Go](https://github.com/mholt/curl-to-go) by Matt Holt ([mholt6](https://twitter.com/mholt6)). ================================================ FILE: index.html ================================================ curl-to-ruby: Convert curl commands to ruby's net/http

curl-to-ruby

Instantly convert curl commands to Ruby's net/http

Ruby's net/http is notorious for not having the friendliest API, but it isn't all that bad. Ruby has great gems like faraday, but in libraries and small utilities it's better to kill your dependencies and use what the stdlib provides.

This tool turns a curl command into ruby (2.0+) code using net/http. Currently, it knows the following options: -d/--data, -H/--header, -I/--head, -u/--user, -k/--insecure, --url, and -X/--request.

There's probably bugs; please contribute on GitHub. Based on curl-to-go.

Simple · Basic Auth · JSON · Complex JSON · Form Data

================================================ FILE: package.json ================================================ { "name": "curl-to-ruby", "version": "1.0.0", "private": true, "description": "curl-to-ruby ============", "scripts": { "watch": "webpack --watch --colors --progress --display-error-details", "compile": "webpack --no-colors -p --display-error-details", "eslint": "eslint src" }, "repository": { "type": "git", "url": "git+https://github.com/jhawthorn/curl-to-ruby.git" }, "author": "John Hawthorn", "license": "MIT", "bugs": { "url": "https://github.com/jhawthorn/curl-to-ruby/issues" }, "homepage": "https://github.com/jhawthorn/curl-to-ruby#readme", "dependencies": { "@babel/core": "^7.5.5", "@babel/preset-env": "^7.5.5", "babel-loader": "^8.0.6", "highlight.js": "^9.4.0", "query-string": "^6.8.2", "shell-quote": "^1.6.0", "webpack": "^4.39.2" }, "devDependencies": { "babel-eslint": "^10.0.2", "expose-loader": "^0.7.1", "webpack-cli": "^3.3.6" } } ================================================ FILE: resources/css/color-brewer.css ================================================ /* Colorbrewer theme Original: https://github.com/mbostock/colorbrewer-theme (c) Mike Bostock Ported by Fabrício Tavares de Oliveira */ .hljs { display: block; overflow-x: auto; padding: 0.5em; background: #fff; } .hljs, .hljs-subst { color: #000; } .hljs-string, .hljs-meta, .hljs-symbol, .hljs-template-tag, .hljs-template-variable, .hljs-addition { color: #756bb1; } .hljs-comment, .hljs-quote { color: #636363; } .hljs-number, .hljs-regexp, .hljs-literal, .hljs-bullet, .hljs-link { color: #31a354; } .hljs-deletion, .hljs-variable { color: #88f; } .hljs-keyword, .hljs-selector-tag, .hljs-title, .hljs-section, .hljs-built_in, .hljs-doctag, .hljs-type, .hljs-tag, .hljs-name, .hljs-selector-id, .hljs-selector-class, .hljs-strong { color: #3182bd; } .hljs-emphasis { font-style: italic; } .hljs-attribute { color: #e6550d; } ================================================ FILE: resources/css/common.css ================================================ /* Eric Meyer's Reset CSS v2.0 NOTICE: This copy of the CSS reset has been modified to make main tag "display: block" because the default in even IE 11 is "display: inline", which is not correct. */ html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{border:0;font-size:100%;font:inherit;vertical-align:baseline;margin:0;padding:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:none}table{border-collapse:collapse;border-spacing:0} * { box-sizing: border-box; } body { font: 14px/1.5em sans-serif; } header, main, footer { width: 85%; max-width: 900px; margin: 0 auto; } header { margin-bottom: 50px; } h1 { font-size: 48px; font-weight: bold; line-height: 1.5em; text-align: center; } h2 { font-size: 18px; line-height: 1.3em; text-align: center; margin-bottom: 25px; } p { max-width: 625px; margin: 10px auto; } code { font-family: 'Consolas', 'Menlo', 'Monaco', 'Courier New', monospace; padding: 1px 3px; background-color: #EEE; font-size: 12px; } .examples { max-width: none; text-align: center; } .examples a { margin: 0 3px; } .clr-red { color: #CC0000; } #input, #output { border: 1px solid #CCC; padding: 10px; outline: none; font: 16px/1.5em Consolas, Menlo, Monaco, 'Courier New', monospace; white-space: pre; tab-size: 4; } #input { width: 100%; margin-bottom: 50px; overflow-y: auto; resize: vertical; } #output { background-color: #F0F8FF; /* "aliceblue" - happened on that by chance choosing a color in chrome inspector tools */ word-wrap: break-word; font-size: 14px; } footer { margin: 50px auto; text-align: center; } ================================================ FILE: resources/js/curl-to-ruby.js ================================================ !function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=8)}([function(e,t,r){"use strict";const n=r(3),o=r(4),s=r(5);function i(e,t){return t.encode?t.strict?n(e):encodeURIComponent(e):e}function a(e,t){return t.decode?o(e):e}function u(e){const t=e.indexOf("#");return-1!==t&&(e=e.slice(0,t)),e}function c(e){const t=(e=u(e)).indexOf("?");return-1===t?"":e.slice(t+1)}function l(e,t){const r=function(e){let t;switch(e.arrayFormat){case"index":return(e,r,n)=>{t=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),t?(void 0===n[e]&&(n[e]={}),n[e][t[1]]=r):n[e]=r};case"bracket":return(e,r,n)=>{t=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),t?void 0!==n[e]?n[e]=[].concat(n[e],r):n[e]=[r]:n[e]=r};case"comma":return(e,t,r)=>{const n="string"==typeof t&&t.split("").indexOf(",")>-1?t.split(","):t;r[e]=n};default:return(e,t,r)=>{void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=t}}}(t=Object.assign({decode:!0,sort:!0,arrayFormat:"none",parseNumbers:!1,parseBooleans:!1},t)),n=Object.create(null);if("string"!=typeof e)return n;if(!(e=e.trim().replace(/^[?#&]/,"")))return n;for(const o of e.split("&")){let[e,i]=s(o.replace(/\+/g," "),"=");i=void 0===i?null:a(i,t),t.parseNumbers&&!Number.isNaN(Number(i))&&"string"==typeof i&&""!==i.trim()?i=Number(i):!t.parseBooleans||null===i||"true"!==i.toLowerCase()&&"false"!==i.toLowerCase()||(i="true"===i.toLowerCase()),r(a(e,t),i,n)}return!1===t.sort?n:(!0===t.sort?Object.keys(n).sort():Object.keys(n).sort(t.sort)).reduce((e,t)=>{const r=n[t];return Boolean(r)&&"object"==typeof r&&!Array.isArray(r)?e[t]=function e(t){return Array.isArray(t)?t.sort():"object"==typeof t?e(Object.keys(t)).sort((e,t)=>Number(e)-Number(t)).map(e=>t[e]):t}(r):e[t]=r,e},Object.create(null))}t.extract=c,t.parse=l,t.stringify=(e,t)=>{if(!e)return"";const r=function(e){switch(e.arrayFormat){case"index":return t=>(r,n)=>{const o=r.length;return void 0===n?r:null===n?[...r,[i(t,e),"[",o,"]"].join("")]:[...r,[i(t,e),"[",i(o,e),"]=",i(n,e)].join("")]};case"bracket":return t=>(r,n)=>void 0===n?r:null===n?[...r,[i(t,e),"[]"].join("")]:[...r,[i(t,e),"[]=",i(n,e)].join("")];case"comma":return t=>(r,n,o)=>null==n||0===n.length?r:0===o?[[i(t,e),"=",i(n,e)].join("")]:[[r,i(n,e)].join(",")];default:return t=>(r,n)=>void 0===n?r:null===n?[...r,i(t,e)]:[...r,[i(t,e),"=",i(n,e)].join("")]}}(t=Object.assign({encode:!0,strict:!0,arrayFormat:"none"},t)),n=Object.keys(e);return!1!==t.sort&&n.sort(t.sort),n.map(n=>{const o=e[n];return void 0===o?"":null===o?i(n,t):Array.isArray(o)?o.reduce(r(n),[]).join("&"):i(n,t)+"="+i(o,t)}).filter(e=>e.length>0).join("&")},t.parseUrl=(e,t)=>({url:u(e).split("?")[0]||"",query:l(c(e),t)})},function(e,t){t.quote=function(e){return e.map(function(e){return e&&"object"==typeof e?e.op.replace(/(.)/g,"\\$1"):/["\s]/.test(e)&&!/'/.test(e)?"'"+e.replace(/(['\\])/g,"\\$1")+"'":/["'\s]/.test(e)?'"'+e.replace(/(["\\$`!])/g,"\\$1")+'"':e=(e=String(e).replace(/([A-z]:)?([#!"$&'()*,:;<=>?@\[\\\]^`{|}])/g,"$1\\$2")).replace(/\\\\/g,"\\")}).join(" ")};for(var r="(?:"+["\\|\\|","\\&\\&",";;","\\|\\&","\\<\\(",">>",">\\&","[&;()|<>]"].join("|")+")",n="(\\\\['\"|&;()<> \\t]|[^\\s'\"|&;()<> \\t])+",o='"((\\\\"|[^"])*?)"',s="'((\\\\'|[^'])*?)'",i="",a=0;a<4;a++)i+=(Math.pow(16,8)*Math.random()).toString(16);t.parse=function(e,t,a){var u=function(e,t,a){var u=new RegExp(["("+r+")","("+n+"|"+o+"|"+s+")*"].join("|"),"g"),c=e.match(u).filter(Boolean),l=!1;if(!c)return[];t||(t={});a||(a={});return c.map(function(e,n){if(!l){if(RegExp("^"+r+"$").test(e))return{op:e};for(var o=a.escape||"\\",s=!1,u=!1,f="",p=!1,d=0,h=e.length;d0?t.url=e.url[0]:e._.length>1&&(t.url=e._[1]);t.url=function(e){return e&&!new RegExp("^https?://","i").test(e)?"http://"+e:e}(t.url),e.H&&(t.headers=t.headers.concat(e.H));e.header&&(t.headers=t.headers.concat(e.header));(e.I||e.head)&&(t.method="HEAD");e.request&&e.request.length>0?t.method=e.request[e.request.length-1].toUpperCase():e.X&&e.X.length>0&&(t.method=e.X[e.X.length-1].toUpperCase());var r=[],n=[],o=function(e){t.method||(t.method="POST");for(var o=0;o0&&"@"==e[o][0]?n.push(e[o].substr(1)):r.push(e[o])};e.d&&o(e.d);e.data&&o(e.data);e["data-binary"]&&o(e["data-binary"]);r.length>0&&(t.data.ascii=r.join("&"));n.length>0&&(t.data.files=n);var s="";e.user&&e.user.length>0?s=e.user[e.user.length-1]:e.u&&e.u.length>0&&(s=e.u[e.u.length-1]);var i=s.indexOf(":");i>-1?t.basicauth={user:s.substr(0,i),pass:s.substr(i+1)}:t.basicAuth={user:s,pass:""};(e.k||e.insecure)&&(t.insecure=!0);t.method||(t.method="GET");return t}(u);return 0!=c.headers.length||"GET"!=c.method||c.data.ascii||c.data.files||c.basicauth||c.insecure?function(e){for(var i={},u=0;u1&&void 0!==arguments[1]?arguments[1]:"",n=s(t);if(null==t)return"nil";if("boolean"==n)return t.toString();if("number"==n)return t.toString();if("string"==n)return'"'+t.toString()+'"';if(Array.isArray(t)){var o="[\n";return t.forEach(function(t){o+=r+" ",o+=e(t,r+" "),o+=",\n"}),o=o.slice(0,-2),o+="\n"+r+"]"}if("object"==n){var i="{\n";for(var a in t)i+=r+" ",i+=e(a),i+=" => ",i+=e(t[a],r+" "),i+=",\n";return i=i.slice(0,-2),i+="\n"+r+"}"}throw"Invalid JSON object"}(g)+")\n"}else if(a.test(e.data.ascii)){var b=o.a.parse(e.data.ascii);for(var f in h+="request.set_form_data(\n",b){var y=b[f];h+=' "'.concat(l(f),'" => "').concat(l(y),'",\n')}h+=")\n"}else h+='request.body = "'+l(e.data.ascii)+'"\n';if(e.data.files&&e.data.files.length>0){e.data.ascii||(h+='request.body = ""\n');for(u=0;uencodeURIComponent(e).replace(/[!'()*]/g,e=>`%${e.charCodeAt(0).toString(16).toUpperCase()}`)},function(e,t,r){"use strict";var n=new RegExp("%[a-f0-9]{2}","gi"),o=new RegExp("(%[a-f0-9]{2})+","gi");function s(e,t){try{return decodeURIComponent(e.join(""))}catch(e){}if(1===e.length)return e;t=t||1;var r=e.slice(0,t),n=e.slice(t);return Array.prototype.concat.call([],s(r),s(n))}function i(e){try{return decodeURIComponent(e)}catch(o){for(var t=e.match(n),r=1;r{if("string"!=typeof e||"string"!=typeof t)throw new TypeError("Expected the arguments to be of type `string`");if(""===t)return[e];const r=e.indexOf(t);return-1===r?[e]:[e.slice(0,r),e.slice(r+t.length)]}},,,function(e,t,r){r(9)},function(e,t,r){(function(t){e.exports=t.curlToRuby=r(2)}).call(this,r(10))},function(e,t){var r;r=function(){return this}();try{r=r||new Function("return this")()}catch(e){"object"==typeof window&&(r=window)}e.exports=r}]); ================================================ FILE: resources/js/default.js ================================================ !function(e){var n={};function t(r){if(n[r])return n[r].exports;var a=n[r]={i:r,l:!1,exports:{}};return e[r].call(a.exports,a,a.exports,t),a.l=!0,a.exports}t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:r})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var a in e)t.d(r,a,function(n){return e[n]}.bind(null,a));return r},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=11)}([function(e,n,t){"use strict";const r=t(3),a=t(4),s=t(5);function i(e,n){return n.encode?n.strict?r(e):encodeURIComponent(e):e}function o(e,n){return n.decode?a(e):e}function c(e){const n=e.indexOf("#");return-1!==n&&(e=e.slice(0,n)),e}function u(e){const n=(e=c(e)).indexOf("?");return-1===n?"":e.slice(n+1)}function l(e,n){const t=function(e){let n;switch(e.arrayFormat){case"index":return(e,t,r)=>{n=/\[(\d*)\]$/.exec(e),e=e.replace(/\[\d*\]$/,""),n?(void 0===r[e]&&(r[e]={}),r[e][n[1]]=t):r[e]=t};case"bracket":return(e,t,r)=>{n=/(\[\])$/.exec(e),e=e.replace(/\[\]$/,""),n?void 0!==r[e]?r[e]=[].concat(r[e],t):r[e]=[t]:r[e]=t};case"comma":return(e,n,t)=>{const r="string"==typeof n&&n.split("").indexOf(",")>-1?n.split(","):n;t[e]=r};default:return(e,n,t)=>{void 0!==t[e]?t[e]=[].concat(t[e],n):t[e]=n}}}(n=Object.assign({decode:!0,sort:!0,arrayFormat:"none",parseNumbers:!1,parseBooleans:!1},n)),r=Object.create(null);if("string"!=typeof e)return r;if(!(e=e.trim().replace(/^[?#&]/,"")))return r;for(const a of e.split("&")){let[e,i]=s(a.replace(/\+/g," "),"=");i=void 0===i?null:o(i,n),n.parseNumbers&&!Number.isNaN(Number(i))&&"string"==typeof i&&""!==i.trim()?i=Number(i):!n.parseBooleans||null===i||"true"!==i.toLowerCase()&&"false"!==i.toLowerCase()||(i="true"===i.toLowerCase()),t(o(e,n),i,r)}return!1===n.sort?r:(!0===n.sort?Object.keys(r).sort():Object.keys(r).sort(n.sort)).reduce((e,n)=>{const t=r[n];return Boolean(t)&&"object"==typeof t&&!Array.isArray(t)?e[n]=function e(n){return Array.isArray(n)?n.sort():"object"==typeof n?e(Object.keys(n)).sort((e,n)=>Number(e)-Number(n)).map(e=>n[e]):n}(t):e[n]=t,e},Object.create(null))}n.extract=u,n.parse=l,n.stringify=(e,n)=>{if(!e)return"";const t=function(e){switch(e.arrayFormat){case"index":return n=>(t,r)=>{const a=t.length;return void 0===r?t:null===r?[...t,[i(n,e),"[",a,"]"].join("")]:[...t,[i(n,e),"[",i(a,e),"]=",i(r,e)].join("")]};case"bracket":return n=>(t,r)=>void 0===r?t:null===r?[...t,[i(n,e),"[]"].join("")]:[...t,[i(n,e),"[]=",i(r,e)].join("")];case"comma":return n=>(t,r,a)=>null==r||0===r.length?t:0===a?[[i(n,e),"=",i(r,e)].join("")]:[[t,i(r,e)].join(",")];default:return n=>(t,r)=>void 0===r?t:null===r?[...t,i(n,e)]:[...t,[i(n,e),"=",i(r,e)].join("")]}}(n=Object.assign({encode:!0,strict:!0,arrayFormat:"none"},n)),r=Object.keys(e);return!1!==n.sort&&r.sort(n.sort),r.map(r=>{const a=e[r];return void 0===a?"":null===a?i(r,n):Array.isArray(a)?a.reduce(t(r),[]).join("&"):i(r,n)+"="+i(a,n)}).filter(e=>e.length>0).join("&")},n.parseUrl=(e,n)=>({url:c(e).split("?")[0]||"",query:l(u(e),n)})},function(e,n){n.quote=function(e){return e.map(function(e){return e&&"object"==typeof e?e.op.replace(/(.)/g,"\\$1"):/["\s]/.test(e)&&!/'/.test(e)?"'"+e.replace(/(['\\])/g,"\\$1")+"'":/["'\s]/.test(e)?'"'+e.replace(/(["\\$`!])/g,"\\$1")+'"':e=(e=String(e).replace(/([A-z]:)?([#!"$&'()*,:;<=>?@\[\\\]^`{|}])/g,"$1\\$2")).replace(/\\\\/g,"\\")}).join(" ")};for(var t="(?:"+["\\|\\|","\\&\\&",";;","\\|\\&","\\<\\(",">>",">\\&","[&;()|<>]"].join("|")+")",r="(\\\\['\"|&;()<> \\t]|[^\\s'\"|&;()<> \\t])+",a='"((\\\\"|[^"])*?)"',s="'((\\\\'|[^'])*?)'",i="",o=0;o<4;o++)i+=(Math.pow(16,8)*Math.random()).toString(16);n.parse=function(e,n,o){var c=function(e,n,o){var c=new RegExp(["("+t+")","("+r+"|"+a+"|"+s+")*"].join("|"),"g"),u=e.match(c).filter(Boolean),l=!1;if(!u)return[];n||(n={});o||(o={});return u.map(function(e,r){if(!l){if(RegExp("^"+t+"$").test(e))return{op:e};for(var a=o.escape||"\\",s=!1,c=!1,d="",f=!1,g=0,p=e.length;g0?n.url=e.url[0]:e._.length>1&&(n.url=e._[1]);n.url=function(e){return e&&!new RegExp("^https?://","i").test(e)?"http://"+e:e}(n.url),e.H&&(n.headers=n.headers.concat(e.H));e.header&&(n.headers=n.headers.concat(e.header));(e.I||e.head)&&(n.method="HEAD");e.request&&e.request.length>0?n.method=e.request[e.request.length-1].toUpperCase():e.X&&e.X.length>0&&(n.method=e.X[e.X.length-1].toUpperCase());var t=[],r=[],a=function(e){n.method||(n.method="POST");for(var a=0;a0&&"@"==e[a][0]?r.push(e[a].substr(1)):t.push(e[a])};e.d&&a(e.d);e.data&&a(e.data);e["data-binary"]&&a(e["data-binary"]);t.length>0&&(n.data.ascii=t.join("&"));r.length>0&&(n.data.files=r);var s="";e.user&&e.user.length>0?s=e.user[e.user.length-1]:e.u&&e.u.length>0&&(s=e.u[e.u.length-1]);var i=s.indexOf(":");i>-1?n.basicauth={user:s.substr(0,i),pass:s.substr(i+1)}:n.basicAuth={user:s,pass:""};(e.k||e.insecure)&&(n.insecure=!0);n.method||(n.method="GET");return n}(c);return 0!=u.headers.length||"GET"!=u.method||u.data.ascii||u.data.files||u.basicauth||u.insecure?function(e){for(var i={},c=0;c1&&void 0!==arguments[1]?arguments[1]:"",r=s(n);if(null==n)return"nil";if("boolean"==r)return n.toString();if("number"==r)return n.toString();if("string"==r)return'"'+n.toString()+'"';if(Array.isArray(n)){var a="[\n";return n.forEach(function(n){a+=t+" ",a+=e(n,t+" "),a+=",\n"}),a=a.slice(0,-2),a+="\n"+t+"]"}if("object"==r){var i="{\n";for(var o in n)i+=t+" ",i+=e(o),i+=" => ",i+=e(n[o],t+" "),i+=",\n";return i=i.slice(0,-2),i+="\n"+t+"}"}throw"Invalid JSON object"}(b)+")\n"}else if(o.test(e.data.ascii)){var h=a.a.parse(e.data.ascii);for(var d in p+="request.set_form_data(\n",h){var m=h[d];p+=' "'.concat(l(d),'" => "').concat(l(m),'",\n')}p+=")\n"}else p+='request.body = "'+l(e.data.ascii)+'"\n';if(e.data.files&&e.data.files.length>0){e.data.ascii||(p+='request.body = ""\n');for(c=0;cencodeURIComponent(e).replace(/[!'()*]/g,e=>`%${e.charCodeAt(0).toString(16).toUpperCase()}`)},function(e,n,t){"use strict";var r=new RegExp("%[a-f0-9]{2}","gi"),a=new RegExp("(%[a-f0-9]{2})+","gi");function s(e,n){try{return decodeURIComponent(e.join(""))}catch(e){}if(1===e.length)return e;n=n||1;var t=e.slice(0,n),r=e.slice(n);return Array.prototype.concat.call([],s(t),s(r))}function i(e){try{return decodeURIComponent(e)}catch(a){for(var n=e.match(r),t=1;t{if("string"!=typeof e||"string"!=typeof n)throw new TypeError("Expected the arguments to be of type `string`");if(""===n)return[e];const t=e.indexOf(n);return-1===t?[e]:[e.slice(0,t),e.slice(t+n.length)]}},function(e,n,t){var r,a,s;a=function(e){var n,t=[],r=Object.keys,a={},s={},i=/^(no-?highlight|plain|text)$/i,o=/\blang(?:uage)?-([\w-]+)\b/i,c=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,u="",l={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0};function d(e){return e.replace(/&/g,"&").replace(//g,">")}function f(e){return e.nodeName.toLowerCase()}function g(e,n){var t=e&&e.exec(n);return t&&0===t.index}function p(e){return i.test(e)}function b(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach(function(e){for(n in e)t[n]=e[n]}),t}function h(e){var n=[];return function e(t,r){for(var a=t.firstChild;a;a=a.nextSibling)3===a.nodeType?r+=a.nodeValue.length:1===a.nodeType&&(n.push({event:"start",offset:r,node:a}),r=e(a,r),f(a).match(/br|hr|img|input/)||n.push({event:"stop",offset:r,node:a}));return r}(e,0),n}function m(e){if(n&&!e.langApiRestored){for(var t in e.langApiRestored=!0,n)e[t]&&(e[n[t]]=e[t]);(e.contains||[]).concat(e.variants||[]).forEach(m)}}function v(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.case_insensitive?"i":"")+(r?"g":""))}!function a(s,i){if(!s.compiled){if(s.compiled=!0,s.keywords=s.keywords||s.beginKeywords,s.keywords){var o={},c=function(n,t){e.case_insensitive&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");o[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof s.keywords?c("keyword",s.keywords):r(s.keywords).forEach(function(e){c(e,s.keywords[e])}),s.keywords=o}s.lexemesRe=t(s.lexemes||/\w+/,!0),i&&(s.beginKeywords&&(s.begin="\\b("+s.beginKeywords.split(" ").join("|")+")\\b"),s.begin||(s.begin=/\B|\b/),s.beginRe=t(s.begin),s.endSameAsBegin&&(s.end=s.begin),s.end||s.endsWithParent||(s.end=/\B|\b/),s.end&&(s.endRe=t(s.end)),s.terminator_end=n(s.end)||"",s.endsWithParent&&i.terminator_end&&(s.terminator_end+=(s.end?"|":"")+i.terminator_end)),s.illegal&&(s.illegalRe=t(s.illegal)),null==s.relevance&&(s.relevance=1),s.contains||(s.contains=[]),s.contains=Array.prototype.concat.apply([],s.contains.map(function(e){return function(e){return e.variants&&!e.cached_variants&&(e.cached_variants=e.variants.map(function(n){return b(e,{variants:null},n)})),e.cached_variants||e.endsWithParent&&[b(e)]||[e]}("self"===e?s:e)})),s.contains.forEach(function(e){a(e,s)}),s.starts&&a(s.starts,i);var u=s.contains.map(function(e){return e.beginKeywords?"\\.?(?:"+e.begin+")\\.?":e.begin}).concat([s.terminator_end,s.illegal]).map(n).filter(Boolean);s.terminators=u.length?t(function(e,t){for(var r=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./,a=0,s="",i=0;i0&&(s+=t);c.length>0;){var u=r.exec(c);if(null==u){s+=c;break}s+=c.substring(0,u.index),c=c.substring(u.index+u[0].length),"\\"==u[0][0]&&u[1]?s+="\\"+String(Number(u[1])+o):(s+=u[0],"("==u[0]&&a++)}}return s}(u,"|"),!0):{exec:function(){return null}}}}(e)}function E(e,n,t,r){function s(e){return new RegExp(e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")}function i(e,n){var t=b.case_insensitive?n[0].toLowerCase():n[0];return e.keywords.hasOwnProperty(t)&&e.keywords[t]}function o(e,n,t,r){var a='')+n+(t?"":u):n}function c(){w+=null!=m.subLanguage?function(){var e="string"==typeof m.subLanguage;if(e&&!a[m.subLanguage])return d(N);var n=e?E(m.subLanguage,N,!0,_[m.subLanguage]):y(N,m.subLanguage.length?m.subLanguage:void 0);return m.relevance>0&&(x+=n.relevance),e&&(_[m.subLanguage]=n.top),o(n.language,n.value,!1,!0)}():function(){var e,n,t,r;if(!m.keywords)return d(N);for(r="",n=0,m.lexemesRe.lastIndex=0,t=m.lexemesRe.exec(N);t;)r+=d(N.substring(n,t.index)),(e=i(m,t))?(x+=e[1],r+=o(e[0],d(t[0]))):r+=d(t[0]),n=m.lexemesRe.lastIndex,t=m.lexemesRe.exec(N);return r+d(N.substr(n))}(),N=""}function f(e){w+=e.className?o(e.className,"",!0):"",m=Object.create(e,{parent:{value:m}})}function p(e,n){if(N+=e,null==n)return c(),0;var r=function(e,n){var t,r;for(t=0,r=n.contains.length;t")+'"');return N+=n,n.length||1}var b=R(e);if(!b)throw new Error('Unknown language: "'+e+'"');v(b);var h,m=r||b,_={},w="";for(h=m;h!==b;h=h.parent)h.className&&(w=o(h.className,"",!0)+w);var N="",x=0;try{for(var O,S,A=0;m.terminators.lastIndex=A,O=m.terminators.exec(n);)S=p(n.substring(A,O.index),O[0]),A=O.index+S;for(p(n.substr(A)),h=m;h.parent;h=h.parent)h.className&&(w+=u);return{relevance:x,value:w,language:e,top:m}}catch(e){if(e.message&&-1!==e.message.indexOf("Illegal"))return{relevance:0,value:d(n)};throw e}}function y(e,n){n=n||l.languages||r(a);var t={relevance:0,value:d(e)},s=t;return n.filter(R).filter(x).forEach(function(n){var r=E(n,e,!1);r.language=n,r.relevance>s.relevance&&(s=r),r.relevance>t.relevance&&(s=t,t=r)}),s.language&&(t.second_best=s),t}function _(e){return l.tabReplace||l.useBR?e.replace(c,function(e,n){return l.useBR&&"\n"===e?"
":l.tabReplace?n.replace(/\t/g,l.tabReplace):""}):e}function w(e){var n,r,a,i,c,u=function(e){var n,t,r,a,s=e.className+" ";if(s+=e.parentNode?e.parentNode.className:"",t=o.exec(s))return R(t[1])?t[1]:"no-highlight";for(n=0,r=(s=s.split(/\s+/)).length;n/g,"\n"):n=e,c=n.textContent,a=u?E(u,c,!0):y(c),(r=h(n)).length&&((i=document.createElementNS("http://www.w3.org/1999/xhtml","div")).innerHTML=a.value,a.value=function(e,n,r){var a=0,s="",i=[];function o(){return e.length&&n.length?e[0].offset!==n[0].offset?e[0].offset"}function u(e){s+=""}function l(e){("start"===e.event?c:u)(e.node)}for(;e.length||n.length;){var g=o();if(s+=d(r.substring(a,g[0].offset)),a=g[0].offset,g===e){i.reverse().forEach(u);do{l(g.splice(0,1)[0]),g=o()}while(g===e&&g.length&&g[0].offset===a);i.reverse().forEach(c)}else"start"===g[0].event?i.push(g[0].node):i.pop(),l(g.splice(0,1)[0])}return s+d(r.substr(a))}(r,h(i),c)),a.value=_(a.value),e.innerHTML=a.value,e.className=function(e,n,t){var r=n?s[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}(e.className,u,a.language),e.result={language:a.language,re:a.relevance},a.second_best&&(e.second_best={language:a.second_best.language,re:a.second_best.relevance}))}function N(){if(!N.called){N.called=!0;var e=document.querySelectorAll("pre code");t.forEach.call(e,w)}}function R(e){return e=(e||"").toLowerCase(),a[e]||a[s[e]]}function x(e){var n=R(e);return n&&!n.disableAutodetect}return e.highlight=E,e.highlightAuto=y,e.fixMarkup=_,e.highlightBlock=w,e.configure=function(e){l=b(l,e)},e.initHighlighting=N,e.initHighlightingOnLoad=function(){addEventListener("DOMContentLoaded",N,!1),addEventListener("load",N,!1)},e.registerLanguage=function(n,t){var r=a[n]=t(e);m(r),r.aliases&&r.aliases.forEach(function(e){s[e]=n})},e.listLanguages=function(){return r(a)},e.getLanguage=R,e.autoDetection=x,e.inherit=b,e.IDENT_RE="[a-zA-Z]\\w*",e.UNDERSCORE_IDENT_RE="[a-zA-Z_]\\w*",e.NUMBER_RE="\\b\\d+(\\.\\d+)?",e.C_NUMBER_RE="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BINARY_NUMBER_RE="\\b(0b[01]+)",e.RE_STARTERS_RE="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BACKSLASH_ESCAPE={begin:"\\\\[\\s\\S]",relevance:0},e.APOS_STRING_MODE={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},e.QUOTE_STRING_MODE={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},e.PHRASAL_WORDS_MODE={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},e.COMMENT=function(n,t,r){var a=e.inherit({className:"comment",begin:n,end:t,contains:[]},r||{});return a.contains.push(e.PHRASAL_WORDS_MODE),a.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|XXX):",relevance:0}),a},e.C_LINE_COMMENT_MODE=e.COMMENT("//","$"),e.C_BLOCK_COMMENT_MODE=e.COMMENT("/\\*","\\*/"),e.HASH_COMMENT_MODE=e.COMMENT("#","$"),e.NUMBER_MODE={className:"number",begin:e.NUMBER_RE,relevance:0},e.C_NUMBER_MODE={className:"number",begin:e.C_NUMBER_RE,relevance:0},e.BINARY_NUMBER_MODE={className:"number",begin:e.BINARY_NUMBER_RE,relevance:0},e.CSS_NUMBER_MODE={className:"number",begin:e.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},e.REGEXP_MODE={className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[e.BACKSLASH_ESCAPE,{begin:/\[/,end:/\]/,relevance:0,contains:[e.BACKSLASH_ESCAPE]}]},e.TITLE_MODE={className:"title",begin:e.IDENT_RE,relevance:0},e.UNDERSCORE_TITLE_MODE={className:"title",begin:e.UNDERSCORE_IDENT_RE,relevance:0},e.METHOD_GUARD={begin:"\\.\\s*"+e.UNDERSCORE_IDENT_RE,relevance:0},e},s="object"==typeof window&&window||"object"==typeof self&&self,n.nodeType?s&&(s.hljs=a({}),void 0===(r=function(){return s.hljs}.apply(n,[]))||(e.exports=r)):a(n)},function(e,n){e.exports=function(e){var n="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",t={keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor",literal:"true false nil"},r={className:"doctag",begin:"@[A-Za-z]+"},a={begin:"#<",end:">"},s=[e.COMMENT("#","$",{contains:[r]}),e.COMMENT("^\\=begin","^\\=end",{contains:[r],relevance:10}),e.COMMENT("^__END__","\\n$")],i={className:"subst",begin:"#\\{",end:"}",keywords:t},o={className:"string",contains:[e.BACKSLASH_ESCAPE,i],variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:"%[qQwWx]?\\(",end:"\\)"},{begin:"%[qQwWx]?\\[",end:"\\]"},{begin:"%[qQwWx]?{",end:"}"},{begin:"%[qQwWx]?<",end:">"},{begin:"%[qQwWx]?/",end:"/"},{begin:"%[qQwWx]?%",end:"%"},{begin:"%[qQwWx]?-",end:"-"},{begin:"%[qQwWx]?\\|",end:"\\|"},{begin:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/},{begin:/<<(-?)\w+$/,end:/^\s*\w+$/}]},c={className:"params",begin:"\\(",end:"\\)",endsParent:!0,keywords:t},u=[o,a,{className:"class",beginKeywords:"class module",end:"$|;",illegal:/=/,contains:[e.inherit(e.TITLE_MODE,{begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{begin:"<\\s*",contains:[{begin:"("+e.IDENT_RE+"::)?"+e.IDENT_RE}]}].concat(s)},{className:"function",beginKeywords:"def",end:"$|;",contains:[e.inherit(e.TITLE_MODE,{begin:n}),c].concat(s)},{begin:e.IDENT_RE+"::"},{className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"(\\!|\\?)?:",relevance:0},{className:"symbol",begin:":(?!\\s)",contains:[o,{begin:n}],relevance:0},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",relevance:0},{begin:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{className:"params",begin:/\|/,end:/\|/,keywords:t},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[a,{className:"regexp",contains:[e.BACKSLASH_ESCAPE,i],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:"%r{",end:"}[a-z]*"},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(s),relevance:0}].concat(s);i.contains=u,c.contains=u;var l=[{begin:/^\s*=>/,starts:{end:"$",contains:u}},{className:"meta",begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+>|(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>)",starts:{end:"$",contains:u}}];return{aliases:["rb","gemspec","podspec","thor","irb"],keywords:t,illegal:/\/\*/,contains:s.concat(l).concat(u)}}},,,,function(e,n,t){"use strict";t.r(n);var r=t(2),a=t(6),s=t.n(a),i=t(7),o=t.n(i);s.a.registerLanguage("ruby",o.a);var c=s.a;function u(){var e='Ruby code will appear here';function n(){var n=document.getElementById("input").value;document.getElementById("output").innerHTML=function(n){if(!n)return e;try{var t=Object(r.default)(n);if(t)return c.highlight("ruby",t).value}catch(e){return console.log(e),''+e+""}}(n)}["focus","blur","keyup"].forEach(function(e){document.getElementById("input").addEventListener(e,n)}),n(),document.getElementById("output").addEventListener("click",function(){if(document.selection){var e=document.body.createTextRange();e.moveToElementText(this),e.select()}else if(window.getSelection){var n=document.createRange();n.selectNode(this),window.getSelection().addRange(n)}}),window.useExample=function(e){var t=document.getElementById(e).innerHTML.trim();document.getElementById("input").value=t,n()}}"loading"!=document.readyState?u():document.addEventListener("DOMContentLoaded",u)}]); ================================================ FILE: src/curl-to-ruby.js ================================================ require("expose-loader?curlToRuby!./curlToRuby"); ================================================ FILE: src/curlToRuby.js ================================================ /* curl-to-ruby A simple utility to convert curl commands into ruby code. Based on curl-to-go by Matt Holt https://github.com/mholt/curl-to-go */ import queryString from 'query-string'; import jsonToRuby from './jsonToRuby'; import parseCommand from "./parseCommand"; export default function curlToRuby(curl) { var prelude = "require 'net/http'\nrequire 'uri'\n"; var coda = "\n" + "# response.code\n" + "# response.body\n"; // List of curl flags that are boolean typed; this helps with parsing // a command like `curl -abc value` to know whether 'value' belongs to '-c' // or is just a positional argument instead. var boolOptions = ['#', 'progress-bar', '-', 'next', '0', 'http1.0', 'http1.1', 'http2', 'no-npn', 'no-alpn', '1', 'tlsv1', '2', 'sslv2', '3', 'sslv3', '4', 'ipv4', '6', 'ipv6', 'a', 'append', 'anyauth', 'B', 'use-ascii', 'basic', 'compressed', 'create-dirs', 'crlf', 'digest', 'disable-eprt', 'disable-epsv', 'environment', 'cert-status', 'false-start', 'f', 'fail', 'ftp-create-dirs', 'ftp-pasv', 'ftp-skip-pasv-ip', 'ftp-pret', 'ftp-ssl-ccc', 'ftp-ssl-control', 'g', 'globoff', 'G', 'get', 'ignore-content-length', 'i', 'include', 'I', 'head', 'j', 'junk-session-cookies', 'J', 'remote-header-name', 'k', 'insecure', 'l', 'list-only', 'L', 'location', 'location-trusted', 'metalink', 'n', 'netrc', 'N', 'no-buffer', 'netrc-file', 'netrc-optional', 'negotiate', 'no-keepalive', 'no-sessionid', 'ntlm', 'O', 'remote-name', 'oauth2-bearer', 'p', 'proxy-tunnel', 'path-as-is', 'post301', 'post302', 'post303', 'proxy-anyauth', 'proxy-basic', 'proxy-digest', 'proxy-negotiate', 'proxy-ntlm', 'q', 'raw', 'remote-name-all', 's', 'silent', 'sasl-ir', 'S', 'show-error', 'ssl', 'ssl-reqd', 'ssl-allow-beast', 'ssl-no-revoke', 'socks5-gssapi-nec', 'tcp-nodelay', 'tlsv1.0', 'tlsv1.1', 'tlsv1.2', 'tr-encoding', 'trace-time', 'v', 'verbose', 'xattr', 'h', 'help', 'M', 'manual', 'V', 'version']; var httpMethods = { 'COPY': 'Copy', 'DELETE': 'Delete', 'GET': 'Get', 'HEAD': 'Head', 'LOCK': 'Lock', 'MKCOL': 'Mkcol', 'MoVE': 'Move', 'OPTIONS': 'Options', 'PATCH': 'Patch', 'POST': 'Post', 'PROPFIND': 'Propfind', 'PROPPATCH': 'Proppatch', 'PUT': 'Put', 'TRACE': 'Trace', 'UNLOCK': 'Unlock' }; let formUrlEncodedRegex = /^([^\s]+=[^\s]+)(&[^\s]+=[^\s]+)*$/; if (!curl.trim()) return; var cmd = parseCommand(curl, { boolFlags: boolOptions }); if (cmd._[0] != "curl") throw "Not a curl command"; var req = extractRelevantPieces(cmd); if (isSimple(req)) { return renderSimple(req); } else { return renderComplex(req); } // renderSimple renders a simple HTTP request using net/http convenience methods function renderSimple(req) { var ruby = ""; ruby += 'uri = URI.parse("' + rubyEsc(req.url) + '")\n'; ruby += 'response = Net::HTTP.get_response(uri)\n'; return prelude + "\n" + ruby + coda; } // renderComplex renders Go code that requires making a http.Request. function renderComplex(req) { // First, figure out the headers var headers = {}; for (var i = 0; i < req.headers.length; i++) { var split = req.headers[i].indexOf(":"); if (split == -1) continue; var name = req.headers[i].substr(0, split).trim(); var value = req.headers[i].substr(split+1).trim(); headers[toTitleCase(name)] = value; } delete headers["Accept-Encoding"]; var ruby = ""; ruby += 'uri = URI.parse("' + rubyEsc(req.url) + '")\n'; if (httpMethods[req.method]) { ruby += 'request = Net::HTTP::'+httpMethods[req.method]+'.new(uri)\n'; } else { ruby += 'request = Net::HTTPGenericRequest.new("' + rubyEsc(req.method) + '", false, false, uri)\n'; } // set basic auth if (req.basicauth) { ruby += 'request.basic_auth("'+rubyEsc(req.basicauth.user)+'", "'+rubyEsc(req.basicauth.pass)+'")\n'; } if (headers["Content-Type"]) { ruby += 'request.content_type = "' + rubyEsc(headers["Content-Type"]) + '"\n'; delete(headers["Content-Type"]); } // set headers for (var name in headers) { ruby += 'request["'+rubyEsc(name)+'"] = "'+rubyEsc(headers[name])+'"\n'; } function isJson(json) { try { JSON.parse(json); return true; } catch (e) { return false; } } if (req.data.ascii) { if (isJson(req.data.ascii)) { let json = JSON.parse(req.data.ascii); prelude += "require 'json'\n"; ruby += "request.body = JSON.dump(" + jsonToRuby(json) + ")\n"; } else if (formUrlEncodedRegex.test(req.data.ascii)) { let formData = queryString.parse(req.data.ascii); ruby += "request.set_form_data(\n"; for(var name in formData) { let value = formData[name]; ruby += ` "${rubyEsc(name)}" => "${rubyEsc(value)}",\n` } ruby += ")\n"; } else { ruby += 'request.body = "' + rubyEsc(req.data.ascii) + '"\n'; } } if (req.data.files && req.data.files.length > 0) { if (!req.data.ascii) { ruby += 'request.body = ""\n'; } for (var i = 0; i < req.data.files.length; i++) { ruby += 'request.body << File.read("'+rubyEsc(req.data.files[i])+'").delete("\\r\\n")\n'; } } ruby += '\n' ruby += 'req_options = {\n' ruby += ' use_ssl: uri.scheme == "https",\n' if (req.insecure) { prelude += "require 'openssl'\n" ruby += ' verify_mode: OpenSSL::SSL::VERIFY_NONE,\n' } ruby += '}\n' ruby += '\n' ruby += 'response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|\n' ruby += ' http.request(request)\n' ruby += 'end\n' return prelude + "\n" + ruby + coda; } // extractRelevantPieces returns an object with relevant pieces // extracted from cmd, the parsed command. This accounts for // multiple flags that do the same thing and return structured // data that makes it easy to spit out Go code. function extractRelevantPieces(cmd) { var relevant = { url: "", method: "", headers: [], data: {} }; // prefer --url over unnamed parameter, if it exists; keep first one only if (cmd.url && cmd.url.length > 0) relevant.url = cmd.url[0]; else if (cmd._.length > 1) relevant.url = cmd._[1]; // position 1 because index 0 is the curl command itself relevant.url = fixUrl(relevant.url); // gather the headers together if (cmd.H) relevant.headers = relevant.headers.concat(cmd.H); if (cmd.header) relevant.headers = relevant.headers.concat(cmd.header); // set method to HEAD? if (cmd.I || cmd.head) relevant.method = "HEAD"; // between -X and --request, prefer the long form I guess if (cmd.request && cmd.request.length > 0) relevant.method = cmd.request[cmd.request.length-1].toUpperCase(); else if (cmd.X && cmd.X.length > 0) relevant.method = cmd.X[cmd.X.length-1].toUpperCase(); // if multiple, use last (according to curl docs) // join multiple request body data, if any var dataAscii = []; var dataFiles = []; var loadData = function(d) { if (!relevant.method) relevant.method = "POST"; for (var i = 0; i < d.length; i++) { if (d[i].length > 0 && d[i][0] == "@") dataFiles.push(d[i].substr(1)); else dataAscii.push(d[i]); } }; if (cmd.d) loadData(cmd.d); if (cmd.data) loadData(cmd.data); if (cmd['data-binary']) loadData(cmd['data-binary']); if (dataAscii.length > 0) relevant.data.ascii = dataAscii.join("&"); if (dataFiles.length > 0) relevant.data.files = dataFiles; // between -u and --user, choose the long form... var basicAuthString = ""; if (cmd.user && cmd.user.length > 0) basicAuthString = cmd.user[cmd.user.length-1]; else if (cmd.u && cmd.u.length > 0) basicAuthString = cmd.u[cmd.u.length-1]; var basicAuthSplit = basicAuthString.indexOf(":"); if (basicAuthSplit > -1) { relevant.basicauth = { user: basicAuthString.substr(0, basicAuthSplit), pass: basicAuthString.substr(basicAuthSplit+1) }; } else { relevant.basicAuth = { user: basicAuthString, pass: "" }; } if (cmd.k || cmd.insecure) { relevant.insecure = true; } // default to GET if nothing else specified if (!relevant.method) relevant.method = "GET"; return relevant; } function fixUrl(url) { if(url && !(new RegExp("^https?://", "i")).test(url)) { return "http://" + url; } else { return url; } } function toTitleCase(str) { return str.replace(/\w*/g, function(txt) { return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); }); } function rubyEsc(s) { return s.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); } function isSimple() { return req.headers.length == 0 && req.method == "GET" && !req.data.ascii && !req.data.files && !req.basicauth && !req.insecure; } } ================================================ FILE: src/default.js ================================================ import curlToRuby from "./curlToRuby"; import hljs from "./highlight.pack.js"; function init() { const emptyOutputMsg = "Ruby code will appear here"; const formattedEmptyOutputMsg = ''+emptyOutputMsg+''; function getOutputHTML(input) { if (!input) { return formattedEmptyOutputMsg; } try { const output = curlToRuby(input); if (output) { const coloredOutput = hljs.highlight("ruby", output); return coloredOutput.value; } } catch (e) { console.log(e); return ''+e+''; } } function updateOutput() { const input = document.getElementById('input').value; const output = document.getElementById('output'); output.innerHTML = getOutputHTML(input); } // Update placeholder text ['focus', 'blur', 'keyup'].forEach((ev) => { document.getElementById('input').addEventListener(ev, updateOutput); }); updateOutput(); // Highlights the output for the user document.getElementById('output').addEventListener('click', function() { if (document.selection) { const range = document.body.createTextRange(); range.moveToElementText(this); range.select(); } else if (window.getSelection) { const range = document.createRange(); range.selectNode(this); window.getSelection().addRange(range); } }); window.useExample = function(name) { const example = document.getElementById(name).innerHTML.trim(); const input = document.getElementById('input'); input.value = example; updateOutput(); } } if (document.readyState != 'loading'){ init(); } else { document.addEventListener('DOMContentLoaded', init); } ================================================ FILE: src/highlight.pack.js ================================================ import hljs from "highlight.js/lib/highlight"; import ruby from "highlight.js/lib/languages/ruby"; hljs.registerLanguage('ruby', ruby); export default hljs; ================================================ FILE: src/jsonToRuby.js ================================================ export default function jsonToRuby(json, indent = "") { let type = typeof(json); if (json == null) { return "nil"; } else if (type == "boolean") { return json.toString(); } else if (type == "number") { return json.toString(); } else if (type == "string") { return '"' + json.toString() + '"'; } else if (Array.isArray(json)) { let ret = "[\n"; json.forEach((element) => { ret += indent + " "; ret += jsonToRuby(element, indent + " "); ret += ",\n"; }); ret = ret.slice(0, -2); ret += "\n" + indent + "]"; return ret; } else if (type == "object") { let ret = "{\n"; for (var key in json) { ret += indent + " "; ret += jsonToRuby(key); ret += " => "; ret += jsonToRuby(json[key], indent + " "); ret += ",\n"; } ret = ret.slice(0, -2); ret += "\n" + indent + "}"; return ret; } else { throw "Invalid JSON object"; } } ================================================ FILE: src/parseCommand.js ================================================ import {parse} from "shell-quote"; export default function parseCommand(input, options) { if (typeof options === 'undefined') { options = {}; } // trim \ at and of line input = input.replace(/\\\n/g, ''); input = input.trim(); let argv = parse(input); let argObj = {_: []}; function setFlag(name, value) { argObj[name] || (argObj[name] = []); argObj[name].push(value); } while(argv.length) { let flag = argv.shift(); /* Assume globs are typos/missing qutotes/shell-quote sillyness w */ if (flag.op == 'glob') { flag = flag.pattern; } if (flag[0] == '-'){ flag = flag.substring(1, flag.length); if (flag[0] == '-') { /* long argument */ flag = flag.substring(1, flag.length); if (boolFlag(flag)) { argObj[flag] = true; } else { if (flag.indexOf('=') > 0) { let flagName = flag.substring(0, flag.indexOf('=')); setFlag(flagName, flag.substring(flag.indexOf('=')+1, flag.length)); } else { setFlag(flag, argv.shift()); } } } else { if (boolFlag(flag)) { argObj[flag] = true; } else if(flag.length > 1) { setFlag(flag[0], flag.substring(1, flag.length)); } else { setFlag(flag[0], argv.shift()); } } if (boolFlag(flag)) { argObj[flag] = true; } } else { setFlag('_', flag); } } return argObj; // boolFlag returns whether a flag is known to be boolean type function boolFlag(flag) { if (Array.isArray(options.boolFlags)) { for (var i = 0; i < options.boolFlags.length; i++) { if (options.boolFlags[i] == flag) return true; } } return false; } } ================================================ FILE: test.rb ================================================ require 'minitest' require 'minitest/autorun' require 'execjs' require 'webrick' class TestCurlToGo < Minitest::Test JS_CONTEXT = ExecJS.compile(File.read("resources/js/curl-to-ruby.js")) def test_simple_get assert_curl_eq "/" assert_curl_eq "/foo.txt" end def test_post assert_curl_eq "/", '-X POST -d "foo"' assert_curl_eq "/", '-X POST -d "foobar"' end def test_headers assert_curl_eq "/", '-XPOST -H MyCrazyHeader:foo -d "foo"' end def test_basic_auth assert_curl_eq "/", "-u banana:coconuts" end def test_complex_post assert_curl_eq "/", <<-CURL -X POST \ -u API_KEY: \ -d 'shipment[to_address][id]=adr_HrBKVA85' \ -d 'shipment[from_address][id]=adr_VtuTOj7o' \ -d 'shipment[parcel][id]=prcl_WDv2VzHp' \ -d 'shipment[is_return]=true' \ -d 'shipment[customs_info][id]=cstinfo_bl5sE20Y' CURL end def test_simple_data assert_curl_eq "/", "-d foo=bar" end def test_data_file_reference assert_curl_eq "/", "-d @README.md" end def test_query_string assert_curl_eq "/curl-to-ruby/?foo=bar", "-d @README.md" end private def assert_curl_eq(path, curl_args="") curl_req = normalize_request capture_http { |url| system "curl -s -o /dev/null #{url}#{path} #{curl_args}" } ruby_req = normalize_request capture_http { |url| ruby = curl_to_ruby("curl #{url}#{path} #{curl_args}") eval(ruby) } assert_equal curl_req.verb, ruby_req.verb assert_equal curl_req.path, ruby_req.path if curl_req.body.nil? assert_nil ruby_req.body else assert_equal curl_req.body, ruby_req.body end assert_equal curl_req.headers, ruby_req.headers end Request = Struct.new(:verb, :path, :headers, :body) def curl_to_ruby(cmd) JS_CONTEXT.call("curlToRuby.default", cmd) end def normalize_request(original) headers = original.headers.dup headers.delete("accept-encoding") headers.delete("user-agent") headers.delete("host") headers.delete("expect") if original.body body = original.body if headers['content-type'] == ['application/x-www-form-urlencoded'] # May encode slightly differently begin body = URI.decode_www_form(body).sort headers.delete("content-length") rescue ArgumentError end end end Request.new( original.verb, original.path, headers, body ) end def capture_http server = WEBrick::HTTPServer.new( Port: 0, Logger: WEBrick::Log.new("/dev/null"), AccessLog: [] ) port = server[:Port] request = nil thread = Thread.new do server.mount_proc('/') do |req, res| request = Request.new( req.request_method, req.path, req.header, req.body ) res.body = "hello, world" server.shutdown end server.start request end url = "http://127.0.0.1:#{port}" yield url, port thread.join thread.value end end ================================================ FILE: webpack.config.js ================================================ "use strict"; var path = require('path'); var webpack = require('webpack'); module.exports = { entry: { default: './src/default.js', "curl-to-ruby": './src/curl-to-ruby.js' }, output: { path: path.join(__dirname, "resources/js/"), filename: "[name].js" }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } } ] } }