├── .github └── workflows │ └── nodejs.yml ├── .gitignore ├── .jshintignore ├── .jshintrc ├── History.md ├── LICENSE.txt ├── README.md ├── index.js ├── lib └── giturl.js ├── logo.png ├── package.json └── test └── giturl.test.js /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | pull_request: 8 | branches: [ master ] 9 | 10 | jobs: 11 | Job: 12 | name: Node.js 13 | uses: node-modules/github-actions/.github/workflows/node-test.yml@master 14 | with: 15 | os: 'ubuntu-latest' 16 | version: '14, 16, 18, 20' 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | coverage.html 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | node_modules 15 | npm-debug.log 16 | coverage 17 | -------------------------------------------------------------------------------- /.jshintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ 3 | .tmp/ 4 | .git/ 5 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | // JSHint Default Configuration File (as on JSHint website) 3 | // See http://jshint.com/docs/ for more details 4 | 5 | "maxerr" : 50, // {int} Maximum error before stopping 6 | 7 | // Enforcing 8 | "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.) 9 | "camelcase" : false, // true: Identifiers must be in camelCase 10 | "curly" : true, // true: Require {} for every new block or scope 11 | "eqeqeq" : true, // true: Require triple equals (===) for comparison 12 | "forin" : false, // true: Require filtering for..in loops with obj.hasOwnProperty() 13 | "immed" : false, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());` 14 | "indent" : false, // {int} Number of spaces to use for indentation 15 | "latedef" : false, // true: Require variables/functions to be defined before being used 16 | "newcap" : false, // true: Require capitalization of all constructor functions e.g. `new F()` 17 | "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` 18 | "noempty" : true, // true: Prohibit use of empty blocks 19 | "nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment) 20 | "plusplus" : false, // true: Prohibit use of `++` & `--` 21 | "quotmark" : false, // Quotation mark consistency: 22 | // false : do nothing (default) 23 | // true : ensure whatever is used is consistent 24 | // "single" : require single quotes 25 | // "double" : require double quotes 26 | "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks) 27 | "unused" : false, // true: Require all defined variables be used 28 | "strict" : true, // true: Requires all functions run in ES5 Strict Mode 29 | "trailing" : false, // true: Prohibit trailing whitespaces 30 | "maxparams" : false, // {int} Max number of formal params allowed per function 31 | "maxdepth" : false, // {int} Max depth of nested blocks (within functions) 32 | "maxstatements" : false, // {int} Max number statements per function 33 | "maxcomplexity" : false, // {int} Max cyclomatic complexity per function 34 | "maxlen" : false, // {int} Max number of characters per line 35 | 36 | // Relaxing 37 | "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) 38 | "boss" : true, // true: Tolerate assignments where comparisons would be expected 39 | "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. 40 | "eqnull" : false, // true: Tolerate use of `== null` 41 | "es5" : false, // true: Allow ES5 syntax (ex: getters and setters) 42 | "esnext" : true, // true: Allow ES.next (ES6) syntax (ex: `const`) 43 | "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features) 44 | // (ex: `for each`, multiple try/catch, function expression…) 45 | "evil" : false, // true: Tolerate use of `eval` and `new Function()` 46 | "expr" : true, // true: Tolerate `ExpressionStatement` as Programs 47 | "funcscope" : false, // true: Tolerate defining variables inside control statements" 48 | "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict') 49 | "iterator" : false, // true: Tolerate using the `__iterator__` property 50 | "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block 51 | "laxbreak" : true, // true: Tolerate possibly unsafe line breakings 52 | "laxcomma" : false, // true: Tolerate comma-first style coding 53 | "loopfunc" : false, // true: Tolerate functions being defined in loops 54 | "multistr" : true, // true: Tolerate multi-line strings 55 | "proto" : false, // true: Tolerate using the `__proto__` property 56 | "scripturl" : false, // true: Tolerate script-targeted URLs 57 | "smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment 58 | "shadow" : true, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` 59 | "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation 60 | "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` 61 | "validthis" : true, // true: Tolerate using this in a non-constructor function 62 | 63 | // Environments 64 | "browser" : true, // Web Browser (window, document, etc) 65 | "couch" : false, // CouchDB 66 | "devel" : true, // Development/debugging (alert, confirm, etc) 67 | "dojo" : false, // Dojo Toolkit 68 | "jquery" : false, // jQuery 69 | "mootools" : false, // MooTools 70 | "node" : true, // Node.js 71 | "nonstandard" : false, // Widely adopted globals (escape, unescape, etc) 72 | "prototypejs" : false, // Prototype and Scriptaculous 73 | "rhino" : false, // Rhino 74 | "worker" : false, // Web Workers 75 | "wsh" : false, // Windows Scripting Host 76 | "yui" : false, // Yahoo User Interface 77 | "noyield" : true, // allow generators without a yield 78 | 79 | // Legacy 80 | "nomen" : false, // true: Prohibit dangling `_` in variables 81 | "onevar" : false, // true: Allow only one `var` statement per function 82 | "passfail" : false, // true: Stop on first error 83 | "white" : false, // true: Check against strict whitespace and indentation rules 84 | 85 | // Custom Globals 86 | "globals" : { // additional predefined global variables 87 | // mocha 88 | "describe": true, 89 | "it": true, 90 | "before": true, 91 | "afterEach": true, 92 | "beforeEach": true, 93 | "after": true 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 2.0.0 / 2023-06-17 3 | ================== 4 | 5 | **features** 6 | * [[`df78450`](http://github.com/repo-utils/giturl/commit/df784508c213ff7caccf3c6ea99c8ea979e3dcc3)] - feat: drop Node.js < 14 support (fengmk2 <>) 7 | 8 | 1.0.2 / 2023-06-15 9 | ================== 10 | 11 | **fixes** 12 | * [[`3ba325d`](http://github.com/repo-utils/giturl/commit/3ba325d7cd56ab0a3e037edf2e91398ccbfc996b)] - fix: use origin http protocol (#16) (Haoliang Gao <>) 13 | 14 | **others** 15 | * [[`89c8cba`](http://github.com/repo-utils/giturl/commit/89c8cba9fbd98e73d9d889700a5e5e4c5ae56b78)] - test: run test on github ci (#17) (fengmk2 <>) 16 | * [[`be30f17`](http://github.com/repo-utils/giturl/commit/be30f17bf780492b75502d470f440d1de2a9e28f)] - update https://registry.npm.taobao.org to https://registry.npmmirror.com (#15) (NPM Mirror Bot <<99484857+npmmirror@users.noreply.github.com>>) 17 | 18 | 1.0.1 / 2018-12-12 19 | ================== 20 | 21 | **fixes** 22 | * [[`17a90af`](http://github.com/repo-utils/giturl/commit/17a90af15e48b585ef503467d4a4f80c3e003ebf)] - fix: support multiple directory (#11) (Haoliang Gao <>) 23 | 24 | 1.0.0 / 2015-10-15 25 | ================== 26 | 27 | * chore: update travis config 28 | * fix: parse url that start with git+https:// 29 | * ignore 0.8 on travis ci 30 | 31 | 0.0.3 / 2014-04-24 32 | ================== 33 | 34 | * support parse github tarballs url. close #2 35 | 36 | 0.0.2 / 2014-02-27 37 | ================== 38 | 39 | * fix #1 TypeError on not git url bug 40 | 41 | 0.0.1 / 2014-01-20 42 | ================== 43 | 44 | * first commit 45 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | This software is licensed under the MIT License. 2 | 3 | Copyright (C) 2014 fengmk2 and other contributors 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # giturl 2 | 3 | [![CI](https://github.com/repo-utils/giturl/actions/workflows/nodejs.yml/badge.svg)](https://github.com/repo-utils/giturl/actions/workflows/nodejs.yml) 4 | 5 | [![NPM](https://nodei.co/npm/giturl.png?downloads=true&stars=true)](https://nodei.co/npm/giturl/) 6 | 7 | ![logo](https://raw.github.com/repo-utils/giturl/master/logo.png) 8 | 9 | Transfer git url to web url. 10 | 11 | ## Install 12 | 13 | ```bash 14 | npm install giturl 15 | ``` 16 | 17 | ## Usage 18 | 19 | ```js 20 | var giturl = require('giturl'); 21 | 22 | giturl.parse('git://gitlab.com/edp/logger.git'); 23 | // => http://gitlab.com/edp/logger 24 | 25 | giturl.parse('git@gitlab.com:edp/logger.git'); 26 | // => http://gitlab.com/edp/logger 27 | 28 | giturl.parse('git://github.com/treygriffith/cellar.git'); 29 | // => https://github.com/treygriffith/cellar 30 | 31 | giturl.parse('https://jpillora@github.com/banchee/tranquil.git'); 32 | // => https://github.com/banchee/tranquil 33 | 34 | giturl.parse('https://jpillora@github.com/banchee/tranquil.git'); 35 | // => https://github.com/banchee/tranquil 36 | 37 | giturl.parse('git@github.com:cnpm/cnpm.git'); 38 | // => https://github.com/cnpm/cnpm 39 | 40 | giturl.parse('git@gitcafe.com:fengmk2/cnpm.git'); 41 | // => http://gitcafe.com/fengmk2/cnpm 42 | 43 | giturl.parse('http://github.com/component/emitter/archive/1.0.1.tar.gz') 44 | // => https://github.com/component/emitter 45 | ``` 46 | 47 | ## License 48 | 49 | (The MIT License) 50 | 51 | Copyright (c) 2014 fengmk2 <> and other contributors 52 | 53 | Permission is hereby granted, free of charge, to any person obtaining 54 | a copy of this software and associated documentation files (the 55 | 'Software'), to deal in the Software without restriction, including 56 | without limitation the rights to use, copy, modify, merge, publish, 57 | distribute, sublicense, and/or sell copies of the Software, and to 58 | permit persons to whom the Software is furnished to do so, subject to 59 | the following conditions: 60 | 61 | The above copyright notice and this permission notice shall be 62 | included in all copies or substantial portions of the Software. 63 | 64 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 65 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 66 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 67 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 68 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 69 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 70 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 71 | 72 | 73 | 74 | ## Contributors 75 | 76 | |[
fengmk2](https://github.com/fengmk2)
|[
popomore](https://github.com/popomore)
|[
npmmirror](https://github.com/npmmirror)
| 77 | | :---: | :---: | :---: | 78 | 79 | 80 | This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Thu Jun 15 2023 08:58:20 GMT+0800`. 81 | 82 | 83 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/giturl'); -------------------------------------------------------------------------------- /lib/giturl.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // host[:/]n1/n2 4 | var RE = /^([^:\/]+)[:\/](.+)$/i; 5 | 6 | var HTTPS_HOSTS = { 7 | 'github.com': 1, 8 | 'gitcafe.com': 1, 9 | 'gist.github.com': 1, 10 | }; 11 | 12 | exports.parse = function parse(sourceURL) { 13 | if (!sourceURL || typeof sourceURL !== 'string') { 14 | return ''; 15 | } 16 | 17 | var url = sourceURL; 18 | 19 | var originProtocol; 20 | try { 21 | var uo = new URL(url); 22 | originProtocol = uo.protocol; 23 | } catch (_) {} 24 | 25 | if (url.indexOf('@') >= 0) { 26 | url = url.replace(/^[^@]+@/, ''); // `git@`` || `https://jpillora@` => "" 27 | } 28 | url = url.replace(/^[\w+]+:\/\//, '') // `git://` || `git+https://` => "" 29 | .replace(/\.git$/, ''); // .git => "" 30 | var item = RE.exec(url); 31 | if (!item) { 32 | return sourceURL; 33 | } 34 | 35 | var host = item[1]; 36 | 37 | var protocol; 38 | if (HTTPS_HOSTS[host]) { 39 | protocol = 'https:'; 40 | } else if ([ 'https:', 'http:' ].includes(originProtocol)) { 41 | protocol = originProtocol; 42 | } else { 43 | protocol = 'http:'; 44 | } 45 | 46 | // p1/p2/.../pn[.xxx] 47 | var isContainGit = /\.git$/.test(sourceURL); 48 | var url = isContainGit ? item[2] : item[2].split('/', 2).join('/'); 49 | return protocol + '//' + host + '/' + url; 50 | }; 51 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repo-utils/giturl/5ca499a0f70b75106ec52c66684d769ad2c1b5d0/logo.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "giturl", 3 | "version": "2.0.0", 4 | "description": "Transfer git url to web url", 5 | "main": "index.js", 6 | "files": [ 7 | "lib", 8 | "index.js" 9 | ], 10 | "scripts": { 11 | "test": "mocha test/*.test.js", 12 | "ci": "c8 -r text -r lcov npm test", 13 | "contributor": "git-contributor" 14 | }, 15 | "dependencies": {}, 16 | "devDependencies": { 17 | "c8": "^8.0.0", 18 | "git-contributor": "^2.1.5", 19 | "jshint": "*", 20 | "mocha": "^10.2.0", 21 | "should": "3.3.1" 22 | }, 23 | "homepage": "https://github.com/repo-utils/giturl", 24 | "repository": { 25 | "type": "git", 26 | "url": "git://github.com/repo-utils/giturl.git" 27 | }, 28 | "bugs": { 29 | "url": "https://github.com/repo-utils/giturl/issues" 30 | }, 31 | "keywords": [ 32 | "giturl", 33 | "git", 34 | "github", 35 | "gitlab", 36 | "url" 37 | ], 38 | "engines": { 39 | "node": ">= 14.17.0" 40 | }, 41 | "author": "fengmk2 (http://github.com/fengmk2)", 42 | "license": "MIT" 43 | } 44 | -------------------------------------------------------------------------------- /test/giturl.test.js: -------------------------------------------------------------------------------- 1 | /**! 2 | * giturl - test/giturl.test.js 3 | * 4 | * Copyright(c) 2014 5 | * MIT Licensed 6 | * 7 | * Authors: 8 | * fengmk2 (http://fengmk2.github.com) 9 | */ 10 | 11 | "use strict"; 12 | 13 | /** 14 | * Module dependencies. 15 | */ 16 | 17 | var should = require('should'); 18 | var giturl = require('../'); 19 | 20 | describe('giturl.test.js', function () { 21 | describe('parse()', function () { 22 | it('should parse project web url from giturl', function () { 23 | giturl.parse('git://gitlab.com/edp/logger.git').should.equal('http://gitlab.com/edp/logger'); 24 | giturl.parse('git@gitlab.com:edp/logger.git').should.equal('http://gitlab.com/edp/logger'); 25 | giturl.parse('git://github.com/treygriffith/cellar.git').should.equal('https://github.com/treygriffith/cellar'); 26 | giturl.parse('git@gitlab.xxx.com:frontend/arch/xxx.git').should.equal('http://gitlab.xxx.com/frontend/arch/xxx'); 27 | giturl.parse('https://github.com/banchee/tranquil.git').should.equal('https://github.com/banchee/tranquil'); 28 | giturl.parse('https://github.com/banchee/tranquil').should.equal('https://github.com/banchee/tranquil'); 29 | giturl.parse('http://github.com/banchee/tranquil.git').should.equal('https://github.com/banchee/tranquil'); 30 | giturl.parse('git+https://github.com/banchee/tranquil.git').should.equal('https://github.com/banchee/tranquil'); 31 | giturl.parse('github.com/banchee/tranquil.git').should.equal('https://github.com/banchee/tranquil'); 32 | giturl.parse('https://jpillora@github.com/banchee/tranquil.git').should.equal('https://github.com/banchee/tranquil'); 33 | giturl.parse('git@github.com:cnpm/cnpm.git').should.equal('https://github.com/cnpm/cnpm'); 34 | giturl.parse('github.com:cnpm/cnpm.git').should.equal('https://github.com/cnpm/cnpm'); 35 | giturl.parse('git@github.com:cnpm/cnpm').should.equal('https://github.com/cnpm/cnpm'); 36 | giturl.parse('git@gitcafe.com:fengmk2/cnpm.git').should.equal('https://gitcafe.com/fengmk2/cnpm'); 37 | giturl.parse('git@gist.github.com:3135914.git').should.equal('https://gist.github.com/3135914'); 38 | }); 39 | 40 | it('should parse not git url', function () { 41 | giturl.parse('http://bauer-information-technology.com/').should.eql('http://bauer-information-technology.com/'); 42 | giturl.parse('').should.eql(''); 43 | }); 44 | 45 | it('should parse github archive url', function () { 46 | giturl.parse('http://github.com/component/emitter/archive/1.0.1.tar.gz') 47 | .should.equal('https://github.com/component/emitter'); 48 | giturl.parse('http://github.com/emitter/archive/1.0.1.tar.gz') 49 | .should.equal('https://github.com/emitter/archive'); 50 | giturl.parse('http://github.com/emitter/') 51 | .should.equal('https://github.com/emitter/'); 52 | }); 53 | 54 | it('should parse gist url', function () { 55 | giturl.parse('https://gist.github.com/fengmk2/10453258') 56 | .should.equal('https://gist.github.com/fengmk2/10453258'); 57 | giturl.parse('http://gist.github.com/fengmk2/10453258') 58 | .should.equal('https://gist.github.com/fengmk2/10453258'); 59 | giturl.parse('http://gist.github.com/10453258.git') 60 | .should.equal('https://gist.github.com/10453258'); 61 | }); 62 | 63 | it('should parse protocol', function () { 64 | giturl.parse('http://git.foo.com/foo/bar').should.equal('http://git.foo.com/foo/bar'); 65 | giturl.parse('https://git.foo.com/foo/bar').should.equal('https://git.foo.com/foo/bar'); 66 | giturl.parse('git://git.foo.com/foo/bar.git').should.equal('http://git.foo.com/foo/bar'); 67 | }); 68 | }); 69 | }); 70 | --------------------------------------------------------------------------------