├── .nvmrc ├── test ├── .eslintrc.json ├── fixtures │ └── bower-1.7.7.tgz ├── setup.js ├── npm │ ├── _load-spec.js │ ├── _config-spec.js │ ├── cache-spec.js │ └── versions-spec.js ├── is-npm-package-name-spec.js ├── extract-spec.js ├── mkdir-spec.js ├── npm-utils-spec.js ├── bower-utils-spec.js ├── resolver-spec.js └── matcher-utils-spec.js ├── .babelrc ├── .eslintrc ├── LICENSE ├── .eslintignore ├── .gitattributes ├── .gitignore ├── .npmignore ├── scripts ├── clean │ └── index.js ├── config.js ├── build │ └── index.js ├── log │ └── index.js ├── test │ └── index.js ├── lint │ └── index.js └── release │ └── index.js ├── src ├── is-npm-package-name.js ├── mkdirp.js ├── npm │ ├── _config.js │ ├── _load.js │ ├── versions.js │ └── cache.js ├── extract.js ├── bower-utils.js ├── npm-utils.js ├── matcher-utils.js └── resolver.js ├── package.json ├── .github └── workflows │ ├── rebase.yml │ └── build.yml ├── gulpfile.js └── README.md /.nvmrc: -------------------------------------------------------------------------------- 1 | 16.18.0 2 | -------------------------------------------------------------------------------- /test/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jasmine": true 4 | } 5 | } -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/bower-1.7.7.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjeanroy/bower-npm-resolver/HEAD/test/fixtures/bower-1.7.7.tgz -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint:recommended", 4 | "google" 5 | ], 6 | "parserOptions": { 7 | "ecmaVersion": 6 8 | }, 9 | "env": { 10 | "es6": true, 11 | "node": true 12 | }, 13 | "rules": { 14 | "max-len": [2, 180, 2], 15 | "new-cap": ["error", { "capIsNewExceptionPattern": "Q.Promise" }], 16 | "valid-jsdoc": [2, { 17 | "requireReturn": true, 18 | "requireParamDescription": true, 19 | "requireReturnDescription": true, 20 | "prefer": { 21 | "return": "return", 22 | "arg": "param", 23 | "argument": "param" 24 | }, 25 | "preferType": { 26 | "object": "object" 27 | } 28 | }] 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2020 Mickael Jeanroy 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 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | ## 2 | # The MIT License (MIT) 3 | # 4 | # Copyright (c) 2016-2020 Mickael Jeanroy 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | ## 24 | 25 | /dist 26 | -------------------------------------------------------------------------------- /test/setup.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | // Override default jasmine TIMEOUT 26 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 120000; 27 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ## 2 | # The MIT License (MIT) 3 | # 4 | # Copyright (c) 2016-2020 Mickael Jeanroy 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | ## 24 | 25 | * text=auto 26 | 27 | *.js eol=lf 28 | *.json eol=lf 29 | *.md eol=lf 30 | *.yml eol=lf 31 | 32 | *.tgz binary -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## 2 | # The MIT License (MIT) 3 | # 4 | # Copyright (c) 2016-2020 Mickael Jeanroy 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | ## 24 | 25 | # OS 26 | .DS_Store 27 | 28 | # NPM modules 29 | /node_modules 30 | /package-lock.json 31 | 32 | # IDE 33 | /.idea 34 | *.iml 35 | 36 | # Build 37 | /dist 38 | 39 | # Temporary directories 40 | /tmp-* 41 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | ## 2 | # The MIT License (MIT) 3 | # 4 | # Copyright (c) 2016-2020 Mickael Jeanroy 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | ## 24 | 25 | # NPM modules 26 | /node_modules 27 | 28 | # Do not dev files 29 | /test 30 | /src 31 | /scripts 32 | /gulpfile.js 33 | /.babelrc 34 | /.github 35 | /.eslintrc 36 | /.eslintrc.json 37 | /.eslintignore 38 | /.gitattributes 39 | -------------------------------------------------------------------------------- /scripts/clean/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | const rimraf = require('rimraf'); 26 | const config = require('../config'); 27 | 28 | module.exports = function clean(done) { 29 | return rimraf(config.dist, (err) => ( 30 | done(err) 31 | )); 32 | }; 33 | -------------------------------------------------------------------------------- /src/is-npm-package-name.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | const validatePackageName = require('validate-npm-package-name'); 26 | 27 | module.exports = function isNpmPackageName(name) { 28 | const validation = validatePackageName(name); 29 | return validation.validForOldPackages || validation.validForNewPackages; 30 | }; 31 | -------------------------------------------------------------------------------- /src/mkdirp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | const Q = require('q'); 26 | const mkdirp = require('mkdirp'); 27 | 28 | module.exports = (dir) => { 29 | return Q.promise((resolve, reject) => { 30 | mkdirp(dir, (err) => { 31 | if (err) { 32 | reject(err); 33 | } else { 34 | resolve(); 35 | } 36 | }); 37 | }); 38 | }; 39 | -------------------------------------------------------------------------------- /scripts/config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | const path = require('path'); 26 | const ROOT = path.join(__dirname, '..'); 27 | 28 | module.exports = { 29 | root: ROOT, 30 | src: path.join(ROOT, 'src'), 31 | test: path.join(ROOT, 'test'), 32 | scripts: path.join(ROOT, 'scripts'), 33 | dist: path.join(ROOT, 'dist'), 34 | pkg: path.join(ROOT, 'package.json'), 35 | }; 36 | -------------------------------------------------------------------------------- /scripts/build/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | /* eslint-disable require-jsdoc */ 26 | 27 | const path = require('path'); 28 | const gulp = require('gulp'); 29 | const babel = require('gulp-babel'); 30 | const config = require('../config'); 31 | 32 | module.exports = function build() { 33 | return gulp.src(path.join(config.src, '**', '*.js')) 34 | .pipe(babel()) 35 | .pipe(gulp.dest(config.dist)); 36 | }; 37 | -------------------------------------------------------------------------------- /test/npm/_load-spec.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | const load = require('../../src/npm/_load'); 28 | 29 | describe('load', () => { 30 | it('should load npm and get meta data', (done) => { 31 | load() 32 | .then((meta) => { 33 | expect(meta).toBeDefined(); 34 | expect(meta.version).toBeDefined(); 35 | done(); 36 | }) 37 | .catch((err) => { 38 | done.fail(err); 39 | }); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /test/npm/_config-spec.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | const requireg = require('requireg'); 28 | const npm = requireg('npm'); 29 | const npmConfig = require('../../src/npm/_config'); 30 | 31 | describe('config', () => { 32 | it('should load npm and get config', (done) => { 33 | npm.load((err) => { 34 | if (err) { 35 | done.fail(err); 36 | return; 37 | } 38 | 39 | expect(npmConfig()).toBeDefined(); 40 | done(); 41 | }); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /test/npm/cache-spec.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | const npmCache = require('../../src/npm/cache'); 28 | 29 | describe('npmCache', () => { 30 | it('should get cached package', (done) => { 31 | npmCache('bower@1.7.7') 32 | .then((result) => { 33 | expect(result.name).toBe('bower'); 34 | expect(result.version).toBe('1.7.7'); 35 | expect(result.inputStream).toBeDefined(); 36 | done(); 37 | }) 38 | .catch((err) => { 39 | done.fail(err); 40 | }); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /test/npm/versions-spec.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | const npmVersions = require('../../src/npm/versions'); 28 | 29 | describe('npmVersions', () => { 30 | it('should get versions of given package', (done) => { 31 | npmVersions('bower') 32 | .then((versions) => { 33 | expect(versions).toBeDefined(); 34 | expect(versions.length).toBeGreaterThan(0); 35 | expect(versions).toContain('1.7.7'); 36 | done(); 37 | }) 38 | .catch((err) => { 39 | done.fail(err); 40 | }); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /src/npm/_config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | const requireg = require('requireg'); 28 | const npm = requireg('npm'); 29 | 30 | /** 31 | * Get npm options as a flat object. 32 | * 33 | * @return {Object} NPM Options. 34 | */ 35 | module.exports = function npmConfig() { 36 | // Added with npm >= 7 37 | if (npm.flatOptions) { 38 | return npm.flatOptions; 39 | } 40 | 41 | const opts = { 42 | registry: npm.config.get('registry'), 43 | }; 44 | 45 | npm.config.keys.forEach((k) => { 46 | opts[k] = npm.config.get(k); 47 | }); 48 | 49 | return opts; 50 | }; 51 | -------------------------------------------------------------------------------- /scripts/log/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | const log = require('fancy-log'); 28 | const colors = require('ansi-colors'); 29 | 30 | /** 31 | * Log message to output using `DEBUG` level. 32 | * 33 | * @param {string} msg Message to log. 34 | * @return {void} 35 | */ 36 | function debug(msg) { 37 | log(colors.grey(msg)); 38 | } 39 | 40 | /** 41 | * Log message to output using `ERROR` level. 42 | * 43 | * @param {string} msg Message to log. 44 | * @return {void} 45 | */ 46 | function error(msg) { 47 | log(colors.red(msg)); 48 | } 49 | 50 | module.exports = { 51 | debug, 52 | error, 53 | }; 54 | -------------------------------------------------------------------------------- /src/npm/_load.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | const requireg = require('requireg'); 28 | const npm = requireg('npm'); 29 | const Q = require('q'); 30 | 31 | /** 32 | * Load NPM and returns a promise resolved with npm meta result. 33 | * 34 | * @return {Object} A promise, rejected if NPM cannot be loaded. 35 | */ 36 | module.exports = function load() { 37 | return Q.Promise((resolve, reject) => { 38 | npm.load((err, meta) => { 39 | if (err) { 40 | reject(err); 41 | } else { 42 | resolve(meta || { 43 | version: npm.version, 44 | }); 45 | } 46 | }); 47 | }); 48 | }; 49 | -------------------------------------------------------------------------------- /scripts/test/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | /* eslint-disable require-jsdoc */ 26 | 27 | const path = require('path'); 28 | const gulp = require('gulp'); 29 | const jasmine = require('gulp-jasmine'); 30 | const config = require('../config'); 31 | 32 | function test() { 33 | const testSources = [ 34 | path.join(config.test, 'setup.js'), 35 | path.join(config.test, '**', '*.js'), 36 | ]; 37 | 38 | return gulp.src(testSources).pipe(jasmine()); 39 | } 40 | 41 | function tdd() { 42 | gulp.watch(path.join(config.src, '**', '*.js'), test); 43 | gulp.watch(path.join(config.test, '**', '*.js'), test); 44 | } 45 | 46 | module.exports = { 47 | test, 48 | tdd, 49 | }; 50 | -------------------------------------------------------------------------------- /test/is-npm-package-name-spec.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | const isNpmPackageName = require('../src/is-npm-package-name'); 28 | 29 | describe('isNpmPackageName', () => { 30 | it('should return false with empty name', () => { 31 | expect(isNpmPackageName('')).toBe(false); 32 | }); 33 | 34 | it('should return true with "classic" name', () => { 35 | expect(isNpmPackageName('jquery')).toBe(true); 36 | }); 37 | 38 | it('should return true with scope package', () => { 39 | expect(isNpmPackageName('@angular/core')).toBe(true); 40 | }); 41 | 42 | it('should return false with URL', () => { 43 | expect(isNpmPackageName('https://github.com/clappr/clappr-level-selector-plugin.git')).toBe(false); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bower-npm-resolver", 3 | "version": "0.11.0", 4 | "description": "Use npm as a registry for your Bower Dependencies", 5 | "main": "dist/resolver.js", 6 | "scripts": { 7 | "clean": "gulp clean", 8 | "lint": "gulp lint", 9 | "test": "gulp test", 10 | "tdd": "gulp tdd", 11 | "build": "gulp build", 12 | "release": "gulp release:minor", 13 | "release:patch": "gulp release:patch", 14 | "release:minor": "gulp release:minor", 15 | "release:major": "gulp release:major" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/mjeanroy/bower-npm-resolver.git" 20 | }, 21 | "keywords": [ 22 | "bower-resolver" 23 | ], 24 | "author": { 25 | "name": "Mickael Jeanroy", 26 | "email": "mickael.jeanroy@gmail.com" 27 | }, 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/mjeanroy/bower-npm-resolver/issues" 31 | }, 32 | "homepage": "https://github.com/mjeanroy/bower-npm-resolver", 33 | "engines": { 34 | "npm": ">=1.0.0" 35 | }, 36 | "dependencies": { 37 | "cacache": "15.2.0", 38 | "escape-string-regexp": "4.0.0", 39 | "fs-write-stream-atomic": "1.0.10", 40 | "lodash": "4.17.21", 41 | "mkdirp": "0.5.1", 42 | "packument": "1.0.0", 43 | "pacote": "11.3.1", 44 | "q": "1.5.1", 45 | "requireg": "0.2.2", 46 | "semver": "7.3.5", 47 | "tar-fs": "2.1.1", 48 | "validate-npm-package-name": "3.0.0" 49 | }, 50 | "devDependencies": { 51 | "@babel/core": "7.14.8", 52 | "@babel/preset-env": "7.14.9", 53 | "@babel/register": "7.14.5", 54 | "eslint": "7.32.0", 55 | "eslint-config-google": "0.14.0", 56 | "fancy-log": "1.3.3", 57 | "gulp": "4.0.2", 58 | "gulp-babel": "8.0.0", 59 | "gulp-bump": "3.2.0", 60 | "gulp-eslint": "6.0.0", 61 | "gulp-git": "2.10.1", 62 | "gulp-jasmine": "4.0.0", 63 | "jasmine": "3.6.1", 64 | "jasmine-core": "3.8.0", 65 | "rimraf": "3.0.2", 66 | "tmp": "0.2.1" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/npm/versions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | const Q = require('q'); 28 | const packument = require('packument'); 29 | const npmLoad = require('./_load'); 30 | const npmConfig = require('./_config'); 31 | 32 | module.exports = function versions(pkg) { 33 | return npmLoad().then(() => ( 34 | getVersions(pkg) 35 | )); 36 | }; 37 | 38 | /** 39 | * Get all versions available for given package. 40 | * 41 | * @param {string} pkg The package. 42 | * @return {Promise>} An array containing all versions for given package. 43 | */ 44 | function getVersions(pkg) { 45 | return Q.promise((resolve, reject) => { 46 | packument(pkg, npmConfig(), (err, result) => { 47 | if (err) { 48 | reject(err); 49 | } else { 50 | resolve(Object.keys(result.versions)); 51 | } 52 | }); 53 | }); 54 | } 55 | -------------------------------------------------------------------------------- /.github/workflows/rebase.yml: -------------------------------------------------------------------------------- 1 | ## 2 | # The MIT License (MIT) 3 | # 4 | # Copyright (c) 2016-2020 Mickael Jeanroy 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | ## 24 | 25 | name: Automatic Rebase 26 | on: 27 | issue_comment: 28 | types: [created] 29 | jobs: 30 | rebase: 31 | name: Rebase 32 | if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') 33 | runs-on: ubuntu-latest 34 | steps: 35 | - uses: actions/checkout@master 36 | with: 37 | fetch-depth: 0 38 | - name: Automatic Rebase 39 | uses: cirrus-actions/rebase@1.2 40 | env: 41 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 42 | # https://github.community/t5/GitHub-Actions/Workflow-is-failing-if-no-job-can-be-ran-due-to-condition/m-p/38186#M3250 43 | always_job: 44 | name: Always run job 45 | runs-on: ubuntu-latest 46 | steps: 47 | - name: Always run 48 | run: echo "This job is used to prevent the workflow to fail when all other jobs are skipped." 49 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | require('@babel/register')({ 26 | ignore: [ 27 | /node_modules/, 28 | ], 29 | }); 30 | 31 | const gulp = require('gulp'); 32 | const clean = require('./scripts/clean'); 33 | const lint = require('./scripts/lint'); 34 | const build = require('./scripts/build'); 35 | const test = require('./scripts/test'); 36 | const release = require('./scripts/release'); 37 | 38 | const prebuild = gulp.series(clean, lint); 39 | const pretest = gulp.series(prebuild, build); 40 | const prerelease = gulp.series(pretest, test.test); 41 | 42 | module.exports = { 43 | 'clean': clean, 44 | 'lint': lint, 45 | 'build': gulp.series(prebuild, build), 46 | 'test': gulp.series(pretest, test.test), 47 | 'tdd': gulp.series(clean, build, test.tdd), 48 | 'release:patch': gulp.series(prerelease, release.patch), 49 | 'release:minor': gulp.series(prerelease, release.minor), 50 | 'release:major': gulp.series(prerelease, release.major), 51 | }; 52 | -------------------------------------------------------------------------------- /test/extract-spec.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | const path = require('path'); 28 | const fs = require('fs'); 29 | const extract = require('../src/extract'); 30 | const tmp = require('tmp'); 31 | 32 | describe('extract', () => { 33 | let tmpDir; 34 | 35 | beforeEach(() => { 36 | tmpDir = tmp.dirSync({ 37 | unsafeCleanup: true, 38 | }); 39 | }); 40 | 41 | afterEach(() => { 42 | tmpDir.removeCallback(); 43 | }); 44 | 45 | it('should extract tarball', (done) => { 46 | const src = path.join(__dirname, 'fixtures', 'bower-1.7.7.tgz'); 47 | const dst = tmpDir.name; 48 | const promise = extract.tgz(src, dst); 49 | expect(promise).toBeDefined(); 50 | 51 | promise 52 | .then((extracted) => { 53 | expect(extracted).toBeDefined(); 54 | expect(fs.statSync(extracted).isDirectory()).toBe(true); 55 | done(); 56 | }) 57 | .catch(() => { 58 | done.fail(); 59 | }); 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /scripts/lint/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | const path = require('path'); 26 | const gulp = require('gulp'); 27 | const log = require('../log'); 28 | const config = require('../config'); 29 | 30 | module.exports = function lint() { 31 | const nodeVersion = process.versions.node; 32 | const major = Number(nodeVersion.split('.')[0]); 33 | if (major < 8) { 34 | log.debug(`Skipping ESLint because of node version compatibility (currenly in used: ${nodeVersion})`); 35 | return Promise.resolve(); 36 | } 37 | 38 | const eslint = require('gulp-eslint'); 39 | const src = [ 40 | path.join(config.root, '*.js'), 41 | path.join(config.src, '**', '*.js'), 42 | path.join(config.test, '**', '*.js'), 43 | path.join(config.scripts, '**', '*.js'), 44 | ]; 45 | 46 | log.debug('Linting files: '); 47 | 48 | src.forEach((input) => ( 49 | log.debug(` ${input}`) 50 | )); 51 | 52 | return gulp.src(src) 53 | .pipe(eslint()) 54 | .pipe(eslint.format()) 55 | .pipe(eslint.failAfterError()); 56 | }; 57 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | ## 2 | # The MIT License (MIT) 3 | # 4 | # Copyright (c) 2016-2020 Mickael Jeanroy 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | ## 24 | 25 | name: CI 26 | on: [push] 27 | jobs: 28 | build: 29 | runs-on: ${{ matrix.os }} 30 | strategy: 31 | matrix: 32 | os: [ windows-latest, ubuntu-latest, macos-latest ] 33 | node: [ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ] 34 | steps: 35 | - uses: actions/checkout@v1 36 | - uses: actions/setup-node@v1 37 | name: Set up NodeJS 38 | with: 39 | node-version: ${{ matrix.node }} 40 | - name: Get npm cache directory 41 | id: npm-cache 42 | run: | 43 | echo "::set-output name=dir::$(npm config get cache)" 44 | - name: Get npm version 45 | id: npm-version 46 | run: | 47 | echo "::set-output name=version::$(npm -v)" 48 | - uses: actions/cache@v2 49 | with: 50 | path: ${{ steps.npm-cache.outputs.dir }} 51 | key: ${{ runner.os }}-npm-${{ steps.npm-version.outputs.version }} 52 | restore-keys: | 53 | ${{ runner.os }}-npm- 54 | - name: Install 55 | run: npm install 56 | - name: Dependencies 57 | run: npm list 58 | - name: Test 59 | run: npm test 60 | -------------------------------------------------------------------------------- /test/mkdir-spec.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | const path = require('path'); 28 | const fs = require('fs'); 29 | const mkdirp = require('../src/mkdirp'); 30 | const tmp = require('tmp'); 31 | 32 | describe('mkdirp', () => { 33 | let tmpDir; 34 | 35 | beforeEach(() => { 36 | tmpDir = tmp.dirSync({ 37 | unsafeCleanup: true, 38 | }); 39 | }); 40 | 41 | afterEach(() => { 42 | tmpDir.removeCallback(); 43 | }); 44 | 45 | it('should create directory', (done) => { 46 | const dst = tmpDir.name; 47 | const dir = path.join(dst, 'fixtures'); 48 | 49 | const promise = mkdirp(dir); 50 | expect(promise).toBeDefined(); 51 | 52 | promise 53 | .then(() => { 54 | expect(fs.statSync(dir).isDirectory()).toBe(true); 55 | done(); 56 | }) 57 | .catch(() => { 58 | done.fail(); 59 | }); 60 | }); 61 | 62 | it('should create directory and sub-directories', (done) => { 63 | const dst = tmpDir.name; 64 | const dir = path.join(dst, 'fixtures', 'bower'); 65 | 66 | const promise = mkdirp(dir); 67 | expect(promise).toBeDefined(); 68 | 69 | promise 70 | .then(() => { 71 | expect(fs.statSync(dir).isDirectory()).toBe(true); 72 | done(); 73 | }) 74 | .catch(() => { 75 | done.fail(); 76 | }); 77 | }); 78 | }); 79 | -------------------------------------------------------------------------------- /src/extract.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | /** 28 | * This module will extract an NPM package into 29 | * a destination directory. 30 | * NPM package are `tar.gz` files, so this module will: 31 | * - Unzip the package. 32 | * - Extract it. 33 | */ 34 | 35 | const fs = require('fs'); 36 | const zlib = require('zlib'); 37 | const tar = require('tar-fs'); 38 | const Q = require('q'); 39 | 40 | /** 41 | * Check that the given file is a symbolic link. 42 | * 43 | * @param {Object} file The file to check. 44 | * @return {boolean} `true` if the file is a symbolic link, `false` otherwise. 45 | */ 46 | function isSymlink(file) { 47 | return file.type === 'SymbolicLink'; 48 | } 49 | 50 | module.exports = { 51 | /** 52 | * Extract the package. 53 | * 54 | * This function return a promise resolved with the path 55 | * to the extracted file. 56 | * 57 | * If an error occurred (during unzip, or extraction), the promise 58 | * will be rejected with the error object. 59 | * 60 | * @param {String} src Source file to extract. 61 | * @param {String} dst Destination directory. 62 | * @return {Promise} The promise. 63 | */ 64 | tgz(src, dst) { 65 | const deferred = Q.defer(); 66 | 67 | fs.createReadStream(src) 68 | .on('error', deferred.reject) 69 | .pipe(zlib.createGunzip()) 70 | .on('error', deferred.reject) 71 | .pipe(tar.extract(dst, {ignore: isSymlink, dmode: '0555', fmode: '0444'})) 72 | .on('error', deferred.reject) 73 | .on('finish', deferred.resolve.bind(deferred, dst)); 74 | 75 | return deferred.promise; 76 | }, 77 | }; 78 | -------------------------------------------------------------------------------- /src/bower-utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | /** 28 | * This module is used as a wrapper for NPM commands. 29 | * Each functions will returned a promise: 30 | * - Resolved with the desired result. 31 | * - Rejected with the error returned from NPM. 32 | */ 33 | 34 | const path = require('path'); 35 | const fs = require('fs'); 36 | const Q = require('q'); 37 | const _ = require('lodash'); 38 | 39 | /** 40 | * Check that a given path is a valid file and returns a promise 41 | * that is resolved if the path is a file and rejected if not. 42 | * 43 | * @param {string} path The path to check. 44 | * @return {Promise} The promise. 45 | */ 46 | function isFile(path) { 47 | const deferred = Q.defer(); 48 | 49 | fs.stat(path, (err, stat) => { 50 | if (err || !stat.isFile()) { 51 | deferred.reject(); 52 | } else { 53 | deferred.resolve(); 54 | } 55 | }); 56 | 57 | return deferred.promise; 58 | } 59 | 60 | module.exports = { 61 | patchConfiguration(pkg) { 62 | const deferred = Q.defer(); 63 | const bowerJson = path.join(pkg, 'bower.json'); 64 | 65 | isFile(bowerJson) 66 | .then(deferred.resolve) 67 | .catch(() => { 68 | fs.readFile(path.join(pkg, 'package.json'), 'utf8', (err, data) => { 69 | if (err) { 70 | deferred.reject(`Could not read package.json from ${pkg}`); 71 | } else { 72 | const config = JSON.parse(data); 73 | const newConfig = _.pick(config, [ 74 | 'name', 75 | 'description', 76 | 'main', 77 | 'moduleType', 78 | 'keywords', 79 | 'authors', 80 | 'license', 81 | 'ignore', 82 | 'private', 83 | 'homepage', 84 | 'bugs', 85 | 'repository', 86 | ]); 87 | 88 | // scoped packages get special treatment 89 | // See https://github.com/npm/npm/blob/v3.9.1/lib/pack.js#L53 90 | if (newConfig.name[0] === '@') { 91 | newConfig.name = newConfig.name.substr(1).replace(/\//g, '-'); 92 | } 93 | 94 | // Do not try to translate dependencies. 95 | // Maybe be can try to deduce the dependencies ? 96 | newConfig.dependencies = {}; 97 | newConfig.devDependencies = {}; 98 | 99 | fs.writeFile(bowerJson, JSON.stringify(newConfig, null, 2), 'utf-8', (err) => { 100 | if (err) { 101 | deferred.reject(`Could not write bower.json file to ${pkg}`); 102 | } else { 103 | deferred.resolve(); 104 | } 105 | }); 106 | } 107 | }); 108 | }); 109 | 110 | return deferred.promise; 111 | }, 112 | }; 113 | -------------------------------------------------------------------------------- /scripts/release/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | const fs = require('fs'); 26 | const gulp = require('gulp'); 27 | const bump = require('gulp-bump'); 28 | const git = require('gulp-git'); 29 | const log = require('../log'); 30 | const config = require('../config'); 31 | 32 | /** 33 | * Update version in number in `package.json` file. 34 | * 35 | * @param {string} type The semver level identifier (`major`, `minor` or `patch`). 36 | * @return {WritableStream} The stream pipeline. 37 | */ 38 | function bumpVersion(type) { 39 | return gulp.src(config.pkg) 40 | .pipe(bump({type})) 41 | .on('error', (e) => log.error(e)) 42 | .pipe(gulp.dest(config.root)); 43 | } 44 | 45 | /** 46 | * Commit the current changes: 47 | * - The `dist` directory containing final bundle. 48 | * - The `package.json` containing the new version number. 49 | * 50 | * @return {WritableStream} The stream pipeline. 51 | */ 52 | function performRelease() { 53 | return gulp.src([config.pkg, config.dist]) 54 | .pipe(git.add({args: '-f'})) 55 | .pipe(git.commit('release: release version')); 56 | } 57 | 58 | /** 59 | * Tag current version: the tag name will be extracted from 60 | * the `version` field in the `package.json` file. 61 | * 62 | * @param {function} done The `done` callback. 63 | * @return {void} 64 | */ 65 | function tagRelease(done) { 66 | fs.readFile(config.pkg, 'utf-8', (err, content) => { 67 | if (err) { 68 | done(err); 69 | return; 70 | } 71 | 72 | const pkgJson = JSON.parse(content); 73 | const version = pkgJson.version; 74 | git.tag(`v${version}`, `release: tag version ${version}`, done); 75 | }); 76 | } 77 | 78 | /** 79 | * Prepare the next release cycle: 80 | * - Remove the `dist` directory containing bundle tagged on given version. 81 | * - Create a new commit preparing the next release. 82 | * 83 | * @return {WritableStream} The stream pipeline. 84 | */ 85 | function prepareNextRelease() { 86 | return gulp.src(config.dist) 87 | .pipe(git.rm({args: '-r'})) 88 | .pipe(git.commit('release: prepare next release')); 89 | } 90 | 91 | /** 92 | * Create the release task. 93 | * 94 | * @param {string} level The version level upgrade. 95 | * @return {function} The release task function. 96 | */ 97 | function createReleaseTask(level) { 98 | /** 99 | * Prepare the release: upgrade version number according to 100 | * the specified level. 101 | * 102 | * @return {WritableStream} The stream pipeline. 103 | */ 104 | function prepareRelease() { 105 | return bumpVersion(level); 106 | } 107 | 108 | return gulp.series( 109 | prepareRelease, 110 | performRelease, 111 | tagRelease, 112 | prepareNextRelease 113 | ); 114 | } 115 | 116 | module.exports = { 117 | patch: createReleaseTask('patch'), 118 | minor: createReleaseTask('minor'), 119 | major: createReleaseTask('major'), 120 | }; 121 | 122 | -------------------------------------------------------------------------------- /test/npm-utils-spec.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | const fs = require('fs'); 28 | const path = require('path'); 29 | const tmp = require('tmp'); 30 | const npmUtil = require('../src/npm-utils'); 31 | 32 | describe('npm-utils', () => { 33 | let tmpDir; 34 | 35 | beforeEach(() => { 36 | tmpDir = tmp.dirSync({ 37 | unsafeCleanup: true, 38 | }); 39 | }); 40 | 41 | afterEach(() => { 42 | tmpDir.removeCallback(); 43 | }); 44 | 45 | it('should get list of releases', (done) => { 46 | const promise = npmUtil.releases('bower', '1.7.7'); 47 | expect(promise).toBeDefined(); 48 | 49 | promise 50 | .then((releases) => { 51 | expect(releases.length).toBeGreaterThan(0); 52 | expect(releases).toContain('1.7.7'); 53 | done(); 54 | }) 55 | .catch((err) => { 56 | done.fail(err); 57 | }); 58 | }); 59 | 60 | it('should get tarball', (done) => { 61 | const promise = npmUtil.downloadTarball('bower', '1.7.7', tmpDir.name); 62 | 63 | expect(promise).toBeDefined(); 64 | 65 | promise 66 | .then((path) => { 67 | expect(path.length).toBeGreaterThan(0); 68 | expect(path).toContain('bower'); 69 | expect(path).toContain('1.7.7'); 70 | done(); 71 | }) 72 | .catch((err) => { 73 | done.fail(err); 74 | }); 75 | }); 76 | 77 | it('should not change current working directory', (done) => { 78 | const cwd = process.cwd(); 79 | const promise = npmUtil.downloadTarball('bower', '1.7.7', tmpDir.name); 80 | 81 | promise 82 | .then(() => { 83 | expect(process.cwd()).toBe(cwd); 84 | done(); 85 | }) 86 | .catch((err) => { 87 | done.fail(err); 88 | }); 89 | }); 90 | 91 | it('should get tarball with relative path', (done) => { 92 | const newTmpDir = tmp.dirSync({ 93 | unsafeCleanup: true, 94 | tmpdir: path.join(__dirname, '..'), 95 | }); 96 | 97 | const relativeToCwd = path.relative(process.cwd(), newTmpDir.name); 98 | const expected = path.join(newTmpDir.name, 'bower-1.7.7.tgz'); 99 | 100 | const promise = npmUtil.downloadTarball('bower', '1.7.7', relativeToCwd); 101 | 102 | promise 103 | .then((path) => { 104 | expect(path).toBe(expected); 105 | expect(fs.statSync(path).isFile()).toBe(true); 106 | done(); 107 | }) 108 | .catch((err) => { 109 | done.fail(err); 110 | }) 111 | .finally(() => { 112 | newTmpDir.removeCallback(); 113 | }); 114 | }); 115 | 116 | it('should get scoped package tarball', (done) => { 117 | const expected = path.join(tmpDir.name, 'angular-core-2.0.0.tgz'); 118 | const promise = npmUtil.downloadTarball('@angular/core', '2.0.0', tmpDir.name); 119 | 120 | promise 121 | .then((path) => { 122 | expect(path).toBe(expected); 123 | expect(fs.statSync(path).isFile()).toBe(true); 124 | done(); 125 | }) 126 | .catch((err) => { 127 | done.fail(err); 128 | }); 129 | }); 130 | }); 131 | -------------------------------------------------------------------------------- /src/npm-utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | /** 28 | * This module is used as a wrapper for NPM commands. 29 | * Each functions will returned a promise: 30 | * - Resolved with the desired result. 31 | * - Rejected with the error returned from NPM. 32 | */ 33 | 34 | const Q = require('q'); 35 | const path = require('path'); 36 | const writeStreamAtomic = require('fs-write-stream-atomic'); 37 | 38 | const npmVersions = require('./npm/versions'); 39 | const npmCache = require('./npm/cache'); 40 | 41 | /** 42 | * Executes `npm cache-add` command with passed arguments. 43 | * Arguments is the name of the cache to download. 44 | * So if cmd command was `npm cache-add bower@1.7.7 versions`, then argument 45 | * would be `['bower@1.7.7', 'versions']`. 46 | * 47 | * The returned promise will be resolved with the result of the cache command (i.e 48 | * object with all informations about the package). 49 | * 50 | * @param {Array} pkg THe package to download. 51 | * @return {Promise} The promise object 52 | */ 53 | function execCacheCommand(pkg) { 54 | return npmCache(pkg); 55 | } 56 | 57 | /** 58 | * Normalize NPM package name: 59 | * - For a scope package, remove the first `@` charachter and replace `/` with `-`. 60 | * - For a non scoped package, return the original name. 61 | * 62 | * @param {string} name The NPM package name. 63 | * @return {string} The normalized package name. 64 | */ 65 | function normalizePkgName(name) { 66 | return name[0] === '@' ? name.substr(1).replace(/\//g, '-') : name; 67 | } 68 | 69 | module.exports = { 70 | 71 | /** 72 | * Return the versions defined on NPM for a given package. 73 | * The promise will be resolved with the array of versions (i.e `['1.0.0', '1.1.0' ]`). 74 | * 75 | * @param {String} pkg The package name. 76 | * @return {Promise} The promise object. 77 | */ 78 | releases(pkg) { 79 | return npmVersions(pkg); 80 | }, 81 | 82 | /** 83 | * Download tarball using `npm pack pkg@version`, move to temporary folder and return 84 | * the location of the tarball in the temporary folder. 85 | * 86 | * The promise will be resolved with the tarball 87 | * path (i.e. `'/home/user/.cache/bower-1.7.7.tgz'`). 88 | * 89 | * @param {String} pkg The package name. 90 | * @param {String} version The package version. 91 | * @param {String} [dir] Tarball download location. 92 | * @return {Promise} The promise object. 93 | */ 94 | downloadTarball(pkg, version, dir) { 95 | const deferred = Q.defer(); 96 | 97 | execCacheCommand(`${pkg}@${version}`) 98 | .then((result) => { 99 | // The original `pack` command does not support custom directory output. 100 | // So, to avoid to change the current working directory pointed by `process.cwd()` (i.e 101 | // to avoid side-effect), we just copy the file manually. 102 | // This is basically what is done by `npm pack` command. 103 | // See: https://github.com/npm/npm/issues/4074 104 | // See: https://github.com/npm/npm/blob/v3.10.8/lib/pack.js#L49 105 | const inputStream = result.inputStream; 106 | 107 | const targetDir = path.resolve(dir); 108 | const name = normalizePkgName(result.name); 109 | const fileName = `${name}-${result.version}.tgz`; 110 | const outputFile = path.join(targetDir, fileName); 111 | const outputStream = writeStreamAtomic(outputFile); 112 | 113 | // Handle errors. 114 | inputStream.on('error', (err) => { 115 | deferred.reject(err); 116 | }); 117 | 118 | outputStream.on('error', (err) => { 119 | deferred.reject(err); 120 | }); 121 | 122 | // Handle success. 123 | outputStream.on('close', () => { 124 | deferred.resolve(outputFile); 125 | }); 126 | 127 | inputStream.pipe(outputStream); 128 | }) 129 | .catch((err) => { 130 | deferred.reject(err); 131 | }); 132 | 133 | return deferred.promise; 134 | }, 135 | }; 136 | -------------------------------------------------------------------------------- /test/bower-utils-spec.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | const path = require('path'); 28 | const tmp = require('tmp'); 29 | const fs = require('fs'); 30 | const bowerUtil = require('../src/bower-utils'); 31 | 32 | describe('bower-utils', () => { 33 | let tmpDir; 34 | 35 | beforeEach(() => { 36 | tmpDir = tmp.dirSync({ 37 | unsafeCleanup: true, 38 | }); 39 | }); 40 | 41 | afterEach(() => { 42 | tmpDir.removeCallback(); 43 | }); 44 | 45 | it('should create json file from package json', (done) => { 46 | const config = { 47 | name: 'bower-npm-resolver', 48 | description: 'This is a fake module', 49 | main: 'src/resolver.js', 50 | moduleType: ['amd', 'globals', 'node'], 51 | keywords: ['test'], 52 | authors: ['mickael.jeanroy@gmail.com'], 53 | license: 'MIT', 54 | ignore: ['test'], 55 | bugs: 'https://github.com/mjeanroy/bower-npm-resolver/issues', 56 | homepage: 'https://github.com/mjeanroy/bower-npm-resolver', 57 | repository: { 58 | type: 'git', 59 | url: 'https://github.com/mjeanroy/bower-npm-resolver.git', 60 | }, 61 | private: false, 62 | }; 63 | 64 | fs.writeFileSync(path.join(tmpDir.name, 'package.json'), JSON.stringify(config, null, 2), 'utf-8'); 65 | 66 | const p = bowerUtil.patchConfiguration(tmpDir.name); 67 | expect(p).toBeDefined(); 68 | 69 | p.then(() => { 70 | expect(fs.statSync(path.join(tmpDir.name, 'bower.json')).isFile()).toBe(true); 71 | 72 | const bowerJson = JSON.parse(fs.readFileSync(path.join(tmpDir.name, 'bower.json'), 'utf-8')); 73 | expect(bowerJson).toEqual(jasmine.objectContaining(config)); 74 | expect(bowerJson.dependencies).toEqual({}); 75 | expect(bowerJson.devDependencies).toEqual({}); 76 | done(); 77 | }); 78 | 79 | p.catch(() => { 80 | done.fail(); 81 | }); 82 | }); 83 | 84 | it('should not create json file if bower.json already exist', (done) => { 85 | const packageConfig = { 86 | name: 'foo', 87 | description: 'This is a fake module', 88 | main: 'foo.js', 89 | moduleType: ['amd', 'globals', 'node'], 90 | keywords: ['test'], 91 | authors: ['mickael.jeanroy@gmail.com'], 92 | license: 'MIT', 93 | ignore: ['test'], 94 | private: false, 95 | }; 96 | 97 | const bowerConfig = { 98 | name: 'foo', 99 | description: 'This is a fake module', 100 | main: 'foo.js', 101 | moduleType: ['amd', 'globals', 'node'], 102 | keywords: ['test'], 103 | authors: ['mickael.jeanroy@gmail.com'], 104 | license: 'MIT', 105 | ignore: ['test'], 106 | private: false, 107 | dependencies: { 108 | jquery: '1.11.0', 109 | }, 110 | }; 111 | 112 | fs.writeFileSync(path.join(tmpDir.name, 'package.json'), JSON.stringify(packageConfig, null, 2), 'utf-8'); 113 | fs.writeFileSync(path.join(tmpDir.name, 'bower.json'), JSON.stringify(bowerConfig, null, 2), 'utf-8'); 114 | 115 | const p = bowerUtil.patchConfiguration(tmpDir.name); 116 | expect(p).toBeDefined(); 117 | 118 | p.then(() => { 119 | expect(fs.statSync(path.join(tmpDir.name, 'bower.json')).isFile()).toBe(true); 120 | expect(JSON.parse(fs.readFileSync(path.join(tmpDir.name, 'bower.json'), 'utf-8'))).toEqual(bowerConfig); 121 | done(); 122 | }); 123 | 124 | p.catch(() => { 125 | done.fail(); 126 | }); 127 | }); 128 | 129 | it('should normalize scoped package names', (done) => { 130 | const config = { 131 | name: '@scope/my-package', 132 | description: 'This is a fake scoped package', 133 | }; 134 | 135 | const normalizedName = 'scope-my-package'; 136 | 137 | fs.writeFileSync(path.join(tmpDir.name, 'package.json'), JSON.stringify(config, null, 2), 'utf-8'); 138 | 139 | const p = bowerUtil.patchConfiguration(tmpDir.name); 140 | expect(p).toBeDefined(); 141 | 142 | p.then(() => { 143 | expect(fs.statSync(path.join(tmpDir.name, 'bower.json')).isFile()).toBe(true); 144 | 145 | const bowerJson = JSON.parse(fs.readFileSync(path.join(tmpDir.name, 'bower.json'), 'utf-8')); 146 | expect(bowerJson.name).toEqual(normalizedName); 147 | done(); 148 | }); 149 | 150 | p.catch(() => { 151 | done.fail(); 152 | }); 153 | }); 154 | }); 155 | -------------------------------------------------------------------------------- /src/matcher-utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mathieu Hofman, Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | /** 28 | * This module is used to parse the config and generate matchers. 29 | */ 30 | 31 | const escapeStringRegexp = require('escape-string-regexp'); 32 | 33 | /** 34 | * Matcher that tests a source against a regexp 35 | * and replaces the match to produce a clean source 36 | * @constructor 37 | */ 38 | class Matcher { 39 | /** 40 | * Create the matcher. 41 | * @param {RegExp} regexp A regular expression to match against 42 | * @param {string?} replace A string to replace the match with if necessary 43 | * @constructor 44 | */ 45 | constructor(regexp, replace) { 46 | this.regexp = regexp; 47 | this.replace = replace; 48 | } 49 | 50 | /** 51 | * Test the matcher against the source 52 | * @param {string} source Source 53 | * @return {boolean} Match result 54 | */ 55 | test(source) { 56 | return this.regexp.test(source); 57 | } 58 | 59 | /** 60 | * Executes the matcher against the source 61 | * @param {string} source Source 62 | * @return {string} Cleaned up result 63 | */ 64 | exec(source) { 65 | return this.replace === undefined ? source : source.replace(this.regexp, this.replace); 66 | } 67 | } 68 | 69 | /** 70 | * Test if any matcher in the list matches against the source 71 | * @this {Array} 72 | * @param {string} source Source 73 | * @return {boolean} Match result 74 | */ 75 | function matchersTest(source) { 76 | return this.some((matcher) => matcher.test(source)); 77 | } 78 | 79 | /** 80 | * Executes the first macther in the list that matches against the source 81 | * @this {Array} 82 | * @param {string} source Source 83 | * @return {string} Cleaned up result 84 | */ 85 | function matchersExec(source) { 86 | const matcher = this.reduce((matcher, newMatcher) => matcher || (newMatcher.test(source) ? newMatcher : null), null); 87 | return matcher.exec(source); 88 | } 89 | 90 | const NPM_SCHEME_PATTERN = '^npm:/{0,3}(?!/)'; 91 | // const NPM_SCHEME_PATTERN_VALID_ONLY = '^npm:(?:/?|///)(?!\\/)'; 92 | const NPM_PREFIX = 'npm+'; 93 | 94 | /** 95 | * Creates a list of matchers from the config, providing default matchers if necessary 96 | * 97 | * @param {object} config The user config from the `.bowerrc` file. 98 | * @return {Array.} List of matchers. 99 | */ 100 | exports.getFromConfig = function getFromConfig(config) { 101 | config = config || {}; 102 | 103 | let patterns = config.match || []; 104 | 105 | if (typeof patterns !== 'object' || !Array.isArray(patterns)) { 106 | patterns = [patterns]; 107 | } 108 | 109 | // Handle v0.2.0 style config 110 | if (config.matchPrefix) { 111 | if (typeof config.ignoreMatchDefaults === 'undefined') { 112 | config.ignoreMatchDefaults = true; 113 | } 114 | patterns.unshift({ 115 | pattern: `^${escapeStringRegexp(config.matchPrefix)}`, 116 | replace: ('stripPrefix' in config) ? Boolean(config.stripPrefix) : true, 117 | }); 118 | } 119 | 120 | if (!config.ignoreMatchDefaults) { 121 | patterns.push({ 122 | pattern: NPM_SCHEME_PATTERN, 123 | flags: 'i', 124 | replace: true, 125 | }); 126 | patterns.push({ 127 | prefix: NPM_PREFIX, 128 | replace: true, 129 | }); 130 | } 131 | 132 | const matchers = patterns.map((pattern) => { 133 | if (typeof pattern === 'string') { 134 | pattern = { 135 | pattern, 136 | }; 137 | } 138 | 139 | if (pattern instanceof RegExp) { 140 | pattern = { 141 | regexp: pattern, 142 | }; 143 | } 144 | 145 | if (typeof pattern !== 'object' || !pattern) { 146 | throw new Error('Invalid match value: ' + pattern); 147 | } 148 | 149 | const patternString = pattern.pattern || (pattern.prefix ? `^${escapeStringRegexp(pattern.prefix)}` : null); 150 | 151 | const regexp = pattern.regexp || new RegExp(patternString, pattern.flags); 152 | let replace; 153 | 154 | if (pattern.replace === true) { 155 | replace = ''; 156 | } else if (pattern.replace === false || pattern.replace === undefined) { 157 | replace = undefined; 158 | } else { 159 | replace = pattern.replace; 160 | } 161 | 162 | return new Matcher(regexp, replace); 163 | }); 164 | 165 | matchers.test = matchersTest; 166 | matchers.exec = matchersExec; 167 | 168 | return matchers; 169 | }; 170 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bower-npm-resolver 2 | 3 | [![Greenkeeper badge](https://badges.greenkeeper.io/mjeanroy/bower-npm-resolver.svg)](https://greenkeeper.io/) 4 | 5 | [![Build Status](https://travis-ci.org/mjeanroy/bower-npm-resolver.svg?branch=master)](https://travis-ci.org/mjeanroy/bower-npm-resolver) 6 | 7 | [![Get it on npm](https://nodei.co/npm/bower-npm-resolver.png?compact=true)](https://www.npmjs.org/package/bower-npm-resolver) 8 | 9 | A [custom Bower resolver](http://bower.io/docs/pluggable-resolvers/) supporting installation of NPM packages. 10 | This resolver should be used if the package (or the version of the package you want to use) is not available on default 11 | resolvers (bower registry, github, etc.). 12 | 13 | ## Installation 14 | 15 | ```bash 16 | npm install -g bower-npm-resolver 17 | ``` 18 | 19 | Or, if you use bower locally: 20 | 21 | ```bash 22 | npm install bower-npm-resolver 23 | ``` 24 | 25 | ## Configuration and usage 26 | 27 | ### .bowerrc 28 | 29 | Add the resolver in your `.bowerrc` file: 30 | 31 | ```json 32 | { 33 | "resolvers": [ 34 | "bower-npm-resolver" 35 | ] 36 | } 37 | ``` 38 | 39 | ### Usage 40 | 41 | Once configured, your bower.json files may reference packages using `npm:` prefix: 42 | 43 | ```json 44 | { 45 | "dependencies": { 46 | "jquery": "npm:jquery#1.0.0", 47 | "lodash": "4.0.0" 48 | } 49 | } 50 | ``` 51 | 52 | The resolver will match packages with `npm:` prefix. 53 | In the example above, `jquery` will be fetched from npm. `lodash` will not be matched by this resolver. 54 | 55 | Note that you can also specify scope package: 56 | 57 | ```json 58 | { 59 | "dependencies": { 60 | "angular-core": "npm:@angular/core#~2.0.0" 61 | } 62 | } 63 | ``` 64 | 65 | The resolver will download the scope package on npm and extract the tarball in the `bower_components` directory named `[scope]-[name]` (in the example above, scope is `angular`, name is `core`). 66 | 67 | ### Alternative usage 68 | 69 | As of v0.2.0, matching were made using `npm+` prefix, such as: 70 | 71 | 72 | ```json 73 | { 74 | "dependencies": { 75 | "npm+jquery": "jquery", 76 | "lodash": "4.0.0" 77 | } 78 | } 79 | ``` 80 | 81 | The resolver will match packages with npm+ prefix, and strip the prefix prior to fetching from npm repo. 82 | In the example above, `jquery` will be fetched from npm, `lodash` will not be matched by this resolver. 83 | 84 | If this is not what you want, you can pass configuration parameters in `.bowerrc`. 85 | 86 | If you use a private npm repository for all your company's packages, and they all start with a shared prefix, 87 | you can change the prefix: 88 | 89 | ```json 90 | { 91 | "resolvers": [ 92 | "bower-npm-resolver" 93 | ], 94 | "bowerNpmResolver": { 95 | "matchPrefix": "mycompanynpmpackages-", 96 | "stripPrefix": false 97 | } 98 | } 99 | ``` 100 | 101 | Then in your `bower.json`: 102 | 103 | ```json 104 | { 105 | "dependencies": { 106 | "mycompanynpmpackages-foobar": "1.0.0", 107 | "other": "1.0.0" 108 | } 109 | } 110 | ``` 111 | 112 | In the example above, `mycompanynpmpackages-foobar` will be fetched from npm. `other` will not be matched by this resolver. 113 | 114 | 115 | ## Features 116 | 117 | This resolver will: 118 | - Use NPM commands to get the version (and the list of available versions) to download. 119 | - Download the tarball associated with the package and the version (you can see the tarball URL that will be used by typing: `npm view pkg@version dist.tarball`). 120 | - Use NPM proxy configuration to download the tarball. 121 | - Extract the tarball, this directory will be used by bower. 122 | 123 | ## Notes 124 | 125 | If the package you download on NPM does not contains `bower.json`, you will not get the 126 | transitive dependencies (and you will have to explicitly add then to your `bower.json` file). 127 | 128 | ## License 129 | 130 | MIT License (MIT) 131 | 132 | ## Changelogs 133 | 134 | - 0.10.0 135 | - Fix a compatibility issue with npm >= 6.6.0 (see [#183](https://github.com/mjeanroy/bower-npm-resolver/issues/183)). 136 | - Various dependency updates. 137 | - 0.9.1 138 | - Fix a bug ([#35](https://github.com/mjeanroy/bower-npm-resolver/issues/35)) that prevent using custom npm registry (thanks [@madbonez](https://github.com/madbonez)). 139 | - 0.9.0 140 | - Update dependencies (`cacache`, `pacote`, etc.). 141 | - Fail if npm package name is not valid ([#93](https://github.com/mjeanroy/bower-npm-resolver/issues/93)). 142 | - Print package version when running bower with verbose option. 143 | - 0.8.2 144 | - Fix an incompatibility with NPM >= 5.6.0 145 | - Various dependency updates 146 | - 0.8.1 147 | - Fix NPM 5 compatibility 148 | - 0.8.0 149 | - Fix an incompatibility with NPM >= 5.0.0 150 | - 0.7.0 151 | - Fix a bug with `requireg` module. 152 | - Remove `cwd` update side effect. 153 | - 0.6.0 154 | - Use global npm instead of local module. 155 | - 0.5.0 156 | - Fix a bug with temporary directory being removed between two downloads. 157 | - 0.4.0 158 | - Use `npm pack` command to download packages (using npm proxy settings). 159 | - 0.3.0 160 | - Use `npm:` prefix. 161 | - Support scope packages. 162 | - 0.2.0 163 | - Allow custom prefixes (instead of default `npm+`). 164 | - 0.1.0 - Initial release 165 | - Use `npm+` prefix to match packages. 166 | 167 | ## Contributing 168 | 169 | If you find a bug or think about enhancement, feel free to contribute and submit an issue or a pull request. 170 | 171 | To work in TDD mode, just run: `npm run tdd`. 172 | 173 | ## Credits 174 | 175 | Special thanks to @mhofman & @jakub-g for their [contributions](https://github.com/mjeanroy/bower-npm-resolver/pulls?q=is%3Apr+is%3Aclosed)! 176 | -------------------------------------------------------------------------------- /src/npm/cache.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | const path = require('path'); 28 | const fs = require('fs'); 29 | const semver = require('semver'); 30 | const Q = require('q'); 31 | const requireg = require('requireg'); 32 | const npm = requireg('npm'); 33 | 34 | const npmLoad = require('./_load'); 35 | const npmConfig = require('./_config'); 36 | 37 | module.exports = function cache(args) { 38 | return cacheAdd(args).then((result) => ( 39 | readCacheQueryResult(result) 40 | )); 41 | }; 42 | 43 | /** 44 | * Executes `npm cache-add` command with passed arguments. 45 | * Arguments is the name of the cache to download. 46 | * So if cmd command was `npm cache-add bower@1.7.7 versions`, then argument 47 | * would be `['bower@1.7.7', 'versions']`. 48 | * 49 | * The returned promise will be resolved with the result of the cache command (i.e 50 | * object with all informations about the package). 51 | * 52 | * @param {Array} pkg THe package to download. 53 | * @return {Promise} The promise object 54 | */ 55 | function cacheAdd(pkg) { 56 | return npmLoad().then((meta) => { 57 | if (semver.lt(meta.version, '5.0.0')) { 58 | return npmCacheAddLegacy(pkg); 59 | } else { 60 | return npmCacheAdd(pkg); 61 | } 62 | }); 63 | } 64 | 65 | /** 66 | * Run npm cache command and resolve the deferred object with the returned 67 | * metadata. 68 | * 69 | * @param {string} pkg NPM Package id (i.e `bower@1.8.0`). 70 | * @return {void} 71 | */ 72 | function npmCacheAddLegacy(pkg) { 73 | return Q.Promise((resolve, reject) => { 74 | npm.commands.cache(['add', pkg], (err, data) => { 75 | if (err) { 76 | reject(err); 77 | } else { 78 | resolve({ 79 | cache: npm.cache, 80 | name: data.name, 81 | version: data.version, 82 | path: path.resolve(npm.cache, data.name, data.version, 'package.tgz'), 83 | integrity: null, 84 | }); 85 | } 86 | }); 87 | }); 88 | } 89 | 90 | /** 91 | * Run npm cache command and resolve the deferred object with the returned 92 | * metadata. 93 | * 94 | * @param {string} pkg NPM Package id (i.e `bower@1.8.0`). 95 | * @return {void} 96 | */ 97 | function npmCacheAdd(pkg) { 98 | const promise = Q.promise((resolve, reject) => { 99 | npm.commands.cache(['add', pkg], (err, result) => { 100 | if (err) { 101 | reject(err); 102 | } else { 103 | resolve(result); 104 | } 105 | }); 106 | }); 107 | 108 | return promise 109 | .then((info) => info ? info : manifest(pkg)) 110 | .then((info) => ({ 111 | cache: path.join(npm.cache, '_cacache'), 112 | name: info.manifest.name, 113 | version: info.manifest.version, 114 | integrity: info.integrity, 115 | path: null, 116 | })); 117 | } 118 | 119 | /** 120 | * Fetch package manifest using `pacote` dependency. 121 | * With npm < 5.6.0, the manifest object was automatically returned by 122 | * the `cache.add` command. This function is here to deal with npm >= 5.6.0 123 | * to get the `integrity` checksum used to download the tarball using `cacache`. 124 | * 125 | * @param {string} pkg Package identifier. 126 | * @return {Promise} The manifest object. 127 | */ 128 | function manifest(pkg) { 129 | return require('pacote').manifest(pkg, npmConfig()).then((pkgJson) => ({ 130 | integrity: pkgJson._integrity, 131 | manifest: { 132 | name: pkgJson.name, 133 | version: pkgJson.version, 134 | }, 135 | })); 136 | } 137 | 138 | /** 139 | * Read cache query result and transform cache entry result to a readable stream. 140 | * 141 | * @param {Object} result The cache query result. 142 | * @return {Object} The result. 143 | */ 144 | function readCacheQueryResult(result) { 145 | const name = result.name; 146 | const version = result.version; 147 | const inputStream = result.path ? createReadStream(result) : getStreamByDigest(result); 148 | return { 149 | name, 150 | version, 151 | inputStream, 152 | }; 153 | } 154 | 155 | /** 156 | * Create stream from given `path` property of result object. 157 | * 158 | * @param {Object} result The result object. 159 | * @return {ReadStream} The result stream. 160 | */ 161 | function createReadStream(result) { 162 | return fs.createReadStream(result.path); 163 | } 164 | 165 | /** 166 | * Get stream from npm cache. 167 | * 168 | * @param {Object} result The result object. 169 | * @return {ReadStream} The result stream. 170 | */ 171 | function getStreamByDigest(result) { 172 | return require('cacache').get.stream.byDigest(result.cache, result.integrity); 173 | } 174 | -------------------------------------------------------------------------------- /test/resolver-spec.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | const path = require('path'); 28 | const Q = require('q'); 29 | const factory = require('../src/resolver'); 30 | const npmUtils = require('../src/npm-utils'); 31 | const extract = require('../src/extract'); 32 | const bowerUtils = require('../src/bower-utils'); 33 | const tmp = require('tmp'); 34 | 35 | describe('resolver', () => { 36 | let resolver; 37 | let tmpDir; 38 | let logger; 39 | 40 | beforeEach(() => { 41 | tmpDir = tmp.dirSync({ 42 | unsafeCleanup: true, 43 | }); 44 | 45 | logger = jasmine.createSpyObj('logger', [ 46 | 'debug', 47 | 'error', 48 | ]); 49 | 50 | resolver = factory({ 51 | config: { 52 | storage: { 53 | packages: tmpDir.name, 54 | }, 55 | }, 56 | version: '1.7.7', 57 | logger, 58 | }); 59 | }); 60 | 61 | afterEach(() => { 62 | tmpDir.removeCallback(); 63 | }); 64 | 65 | it('should not fail to match valid npm package', () => { 66 | const source = 'npm:jquery'; 67 | const result = resolver.match(source); 68 | expect(result).toBe(true); 69 | expect(logger.error).not.toHaveBeenCalled(); 70 | }); 71 | 72 | it('should not fail to match valid npm package with version', () => { 73 | const source = 'npm:jquery#1.12.4'; 74 | const result = resolver.match(source); 75 | expect(result).toBe(true); 76 | expect(logger.error).not.toHaveBeenCalled(); 77 | }); 78 | 79 | it('should not fail to match valid npm scope package', () => { 80 | const source = 'npm:@angular/core'; 81 | const result = resolver.match(source); 82 | expect(result).toBe(true); 83 | expect(logger.error).not.toHaveBeenCalled(); 84 | }); 85 | 86 | it('should not fail to match valid npm scope package with version', () => { 87 | const source = 'npm:@angular/core#2.0.0'; 88 | const result = resolver.match(source); 89 | expect(result).toBe(true); 90 | expect(logger.error).not.toHaveBeenCalled(); 91 | }); 92 | 93 | it('should fail to match npm package URL', () => { 94 | const source = 'npm:https://github.com/clappr/clappr-level-selector-plugin.git'; 95 | const result = resolver.match(source); 96 | expect(result).toBe(false); 97 | expect(logger.error).toHaveBeenCalled(); 98 | }); 99 | 100 | it('should get list of releases', (done) => { 101 | const source = 'npm:bower'; 102 | const defer = Q.defer(); 103 | const promise = defer.promise; 104 | spyOn(npmUtils, 'releases').and.returnValue(promise); 105 | 106 | const result = resolver.releases(source); 107 | 108 | expect(npmUtils.releases).toHaveBeenCalledWith('bower'); 109 | expect(result).toBeDefined(); 110 | expect(result).not.toBe(promise); 111 | 112 | const success = jasmine.createSpy('success').and.callFake((data) => { 113 | expect(data).toEqual([ 114 | {target: '1.0.0', version: '1.0.0'}, 115 | {target: '2.0.0', version: '2.0.0'}, 116 | ]); 117 | 118 | done(); 119 | }); 120 | 121 | const error = jasmine.createSpy('error').and.callFake(() => { 122 | done.fail(); 123 | }); 124 | 125 | result.then(success, error); 126 | defer.resolve(['1.0.0', '2.0.0']); 127 | }); 128 | 129 | it('should fetch release', (done) => { 130 | const pkgName = 'bower'; 131 | const pkgVersion = '1.7.7'; 132 | 133 | const tarballPath = '/tmp/bower.tgz'; 134 | const pkgPath = '/tmp/bower'; 135 | const bowerPkgPath = path.normalize(pkgPath + '/package'); 136 | 137 | spyOn(npmUtils, 'downloadTarball').and.callFake((pkg, version, dir) => { 138 | expect(pkg).toBe('bower'); 139 | expect(version).toBe('1.7.7'); 140 | expect(dir).toBe(path.join(tmpDir.name, 'npm-resolver', 'compressed')); 141 | return Q.resolve(tarballPath); 142 | }); 143 | 144 | spyOn(extract, 'tgz').and.callFake((file, dir) => { 145 | expect(file).toBe(tarballPath); 146 | expect(dir).toBe(path.join(tmpDir.name, 'npm-resolver', 'uncompressed', pkgName, pkgVersion)); 147 | return Q.resolve(pkgPath); 148 | }); 149 | 150 | spyOn(bowerUtils, 'patchConfiguration').and.callFake((dir) => { 151 | expect(dir).toBe(bowerPkgPath); 152 | return Q.resolve(); 153 | }); 154 | 155 | const source = `npm:${pkgName}#~1.7.0`; 156 | const target = `${pkgVersion}`; 157 | const result = resolver.fetch({ 158 | source: source, 159 | target: target, 160 | }); 161 | 162 | // Fail if something bad happen. 163 | result.catch((err) => { 164 | done.fail(err); 165 | }); 166 | 167 | result.then((r) => { 168 | expect(npmUtils.downloadTarball).toHaveBeenCalled(); 169 | expect(extract.tgz).toHaveBeenCalled(); 170 | expect(bowerUtils.patchConfiguration).toHaveBeenCalled(); 171 | 172 | expect(r).toBeDefined(); 173 | expect(r).toEqual({ 174 | tempPath: bowerPkgPath, 175 | removeIgnores: true, 176 | }); 177 | 178 | done(); 179 | }); 180 | }); 181 | }); 182 | -------------------------------------------------------------------------------- /test/matcher-utils-spec.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mathieu Hofman, Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | const matcherUtils = require('../src/matcher-utils'); 28 | 29 | /** 30 | * Iterate over object keys and trigger callback for each entry. 31 | * @param {object} obj Object to iterate. 32 | * @param {function} callback Iteration callback. 33 | * @return {void} 34 | */ 35 | function forEachObjectAsMap(obj, callback) { 36 | Object.keys(obj).forEach((key) => { 37 | callback(obj[key], key, obj); 38 | }); 39 | } 40 | 41 | describe('matcher-utils', () => { 42 | it('should match npm source by default', () => { 43 | const matchers = matcherUtils.getFromConfig(); 44 | 45 | expect(matchers.test('npm+test')).toBe(true); 46 | expect(matchers.test('npm:test')).toBe(true); 47 | expect(matchers.test('npm:test#~1.0.0')).toBe(true); 48 | expect(matchers.test('npm:@scope/test#~1.0.0')).toBe(true); 49 | expect(matchers.test('test')).toBe(false); 50 | }); 51 | 52 | describe('should match only valid variations of npm scheme.', () => { 53 | const matchers = matcherUtils.getFromConfig(); 54 | 55 | it('accepts valid URIs', () => { 56 | // a urn type URI (no authority) where package name is the whole path 57 | expect(matchers.test('npm:test')).toBe(true); 58 | 59 | // a urn type URI (no authority) where package name is prefixed by a / (i.e. absolute path) 60 | expect(matchers.test('npm:/test')).toBe(true); 61 | 62 | // URI with empty authority (package name is prefixed by a /) 63 | expect(matchers.test('npm:///test')).toBe(true); 64 | 65 | // URI with empty authority (full package name is prefixed by a /, @scope is considered a directory) 66 | expect(matchers.test('npm:///@scope/test')).toBe(true); 67 | 68 | // URIs are case insensitive 69 | expect(matchers.test('NPM:test')).toBe(true); 70 | }); 71 | 72 | it('accepts invalid, yet common URIs', () => { 73 | // URI where the package name is the authority 74 | expect(matchers.test('npm://test')).toBe(true); 75 | 76 | // URI where the scope is the authority and scoped name is the path 77 | expect(matchers.test('npm://@scope/test')).toBe(true); 78 | }); 79 | 80 | it('rejects invalid URIs', () => { 81 | // Path has too many slashes 82 | expect(matchers.test('npm:////test')).toBe(false); 83 | }); 84 | }); 85 | 86 | forEachObjectAsMap({ 87 | 'string': { 88 | match: '^mycompany', 89 | }, 90 | 'RegExp': { 91 | match: /^mycompany/, 92 | }, 93 | 'object': { 94 | match: { 95 | pattern: '^mycompany', 96 | }, 97 | }, 98 | 'object with prefix': { 99 | match: { 100 | prefix: 'mycompany', 101 | }, 102 | }, 103 | 'object with replace=false': { 104 | match: { 105 | pattern: '^mycompany', 106 | replace: false, 107 | }, 108 | }, 109 | 'array': { 110 | match: [ 111 | '^myothercompany', 112 | '^mycompany', 113 | ], 114 | }, 115 | 'matchPrefix': { 116 | matchPrefix: 'mycompany', 117 | stripPrefix: false, 118 | }, 119 | }, (config, type) => { 120 | describe(`when pattern passed as a ${type}`, () => { 121 | let matchers; 122 | 123 | beforeEach(() => { 124 | matchers = matcherUtils.getFromConfig(config); 125 | }); 126 | 127 | it(`should parse config when pattern passed as a ${type}`, () => { 128 | expect(matchers).toBeDefined(); 129 | }); 130 | 131 | it(`should match a custom pattern passed as a ${type}`, () => { 132 | expect(matchers.test('mycompany-test')).toBe(true); 133 | expect(matchers.test('test')).toBe(false); 134 | }); 135 | 136 | if (type !== 'matchPrefix') { 137 | it(`should keep matching defaults when custom pattern passed as a ${type}`, () => { 138 | expect(matchers.test('npm:test')).toBe(true); 139 | expect(matchers.test('npm+test')).toBe(true); 140 | }); 141 | } 142 | 143 | it(`should not replace from custom pattern passed as a ${type}`, () => { 144 | expect(matchers.exec('mycompany-test')).toEqual('mycompany-test'); 145 | }); 146 | }); 147 | }); 148 | 149 | forEachObjectAsMap({ 150 | 'replace=true': { 151 | match: { 152 | prefix: 'mycompany-', 153 | replace: true, 154 | }, 155 | }, 156 | 'replace with empty string': { 157 | match: { 158 | pattern: '^mycompany-', 159 | replace: '', 160 | }, 161 | }, 162 | 'replace with string': { 163 | match: { 164 | pattern: '^mycompany-te', 165 | replace: 'te', 166 | }, 167 | }, 168 | 'replace with regexp result': { 169 | match: { 170 | pattern: '^mycompany-(test)', 171 | replace: '$1', 172 | }, 173 | }, 174 | 'matchPrefix': { 175 | matchPrefix: 'mycompany-', 176 | }, 177 | 'matchPrefix with stripPrefix=true': { 178 | matchPrefix: 'mycompany-', 179 | stripPrefix: true, 180 | }, 181 | }, (config, type) => { 182 | it(`should strip/replace when ${type}`, () => { 183 | const matchers = matcherUtils.getFromConfig(config); 184 | 185 | expect(matchers.exec('mycompany-test')).toEqual('test'); 186 | }); 187 | }); 188 | 189 | forEachObjectAsMap({ 190 | 'ignoreMatchDefaults=true': { 191 | match: '^mycompany', 192 | ignoreMatchDefaults: true, 193 | }, 194 | 'matchPrefix': { 195 | matchPrefix: 'mycompany', 196 | }, 197 | }, (config, type) => { 198 | it(`should ignore the defaults when ${type}`, () => { 199 | const matchers = matcherUtils.getFromConfig(config); 200 | 201 | expect(matchers.test('npm:test')).toBe(false); 202 | expect(matchers.test('npm+test')).toBe(false); 203 | }); 204 | }); 205 | 206 | it('should not match anything with an empty match list', () => { 207 | const matchers = matcherUtils.getFromConfig({ 208 | match: [], 209 | ignoreMatchDefaults: true, 210 | }); 211 | 212 | expect(matchers.test('test')).toBe(false); 213 | expect(matchers.test('')).toBe(false); 214 | }); 215 | }); 216 | -------------------------------------------------------------------------------- /src/resolver.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016-2020 Mickael Jeanroy 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | /** 28 | * Factory function for the resolver. 29 | * Will be called only one time by Bower, to instantiate resolver. 30 | */ 31 | 32 | const path = require('path'); 33 | const pkg = require('../package.json'); 34 | const mkdirp = require('./mkdirp'); 35 | const npmUtils = require('./npm-utils'); 36 | const extract = require('./extract'); 37 | const bowerUtils = require('./bower-utils'); 38 | const isNpmPackageName = require('./is-npm-package-name'); 39 | const matcherUtils = require('./matcher-utils'); 40 | 41 | module.exports = function resolver(bower) { 42 | const logger = bower.logger; 43 | 44 | // Read configuration passed via .bowerrc 45 | const matchers = matcherUtils.getFromConfig(bower.config.bowerNpmResolver); 46 | logger.debug('npm-resolver', `initializing bower-npm-resolver ${pkg.version}`); 47 | logger.debug('npm-resolver', `found matchers: ${JSON.stringify(matchers)}`); 48 | 49 | /** 50 | * Extract package name from package source. 51 | * The source is formatted such as: 52 | * npm:[package]#[version] 53 | * 54 | * @param {string} source Source read from `bower.json` file. 55 | * @return {string} Package name extracted from given source. 56 | */ 57 | function extractPackageName(source) { 58 | const matchedSource = matchers.exec(source); 59 | const withoutVersion = matchedSource.split('#')[0]; 60 | return withoutVersion; 61 | } 62 | 63 | // Resolver factory returns an instance of resolver 64 | return { 65 | /** 66 | * Match method tells whether resolver supports given source. 67 | * The resolver matches entries whose package value in `bower.json` starts with `npm:` string. 68 | * 69 | * @param {string} source Source from `bower.json`. 70 | * @return {boolean} `true` if source match this resolver, `false` otherwise. 71 | */ 72 | match(source) { 73 | logger.debug('npm-resolver', `checking for: ${source}`); 74 | 75 | const matchResolver = matchers.test(source); 76 | const pkgName = matchResolver ? extractPackageName(source) : source; 77 | const matchPackageName = matchResolver && isNpmPackageName(pkgName); 78 | 79 | if (matchResolver && !matchPackageName) { 80 | logger.error('npm-resolver', `it seems that you try to fetch a package that is a not a valid npm package: ${source} (parsed as: ${pkgName}).`); 81 | logger.error('npm-resolver', `if you want to fetch a GIT endpoint or an URL, bower can do it natively.`); 82 | logger.error('npm-resolver', `otherwise, if your are sure that your package exist, please submit an issue.`); 83 | } 84 | 85 | return matchResolver && matchPackageName; 86 | }, 87 | 88 | /** 89 | * List available versions of given package. 90 | * The list of version is automatically fetched from NPM. 91 | * Bower chooses matching release and passes it to "fetch". 92 | * 93 | * @param {string} source Source from `bower.json`. 94 | * @return {Promise} Promise resolved with available releases versions. 95 | */ 96 | releases(source) { 97 | logger.debug('npm-resolver', `extracting package name from: ${source}`); 98 | const pkg = extractPackageName(source); 99 | 100 | logger.debug('npm-resolver', `fetching releases information from: ${pkg}`); 101 | return npmUtils.releases(pkg).then((versions) => { 102 | logger.debug('npm-resolver', `found releases: ${versions}`); 103 | return versions.map((v) => ({ 104 | target: v, 105 | version: v, 106 | })); 107 | }); 108 | }, 109 | 110 | /** 111 | * Downloads package and extracts it to temporary directory. 112 | * If an error occurred, the temporary directory will be deleted. 113 | * 114 | * The endpoint parameter is an object, containing following keys: 115 | * - `name`: the name of resource (like jquery). 116 | * - `source`: Where to download resource. 117 | * - `target`: the version or release of resource to download (like v1.0.0). 118 | * 119 | * The `cached` paramter contains information about cached resource. It 120 | * contains following keys: 121 | * - `endpoint`: endpoint of cached resource (the same format as above). 122 | * - `release`: release of cached resource. 123 | * - `releases`: the result of releases method. 124 | * - `version`: present cached resource has been resolved as version (like 1.0.0). 125 | * - `resolution`: the “resolution” returned from previous fetch call for same resource. 126 | * 127 | * @param {object} endpoint Endpoint source. 128 | * @param {object} cached The cached object (describe above). 129 | * @return {Promise} Promise object. 130 | * @see http://bower.io/docs/pluggable-resolvers/#resolverfetch 131 | */ 132 | fetch(endpoint, cached) { 133 | logger.debug('npm-resolver', `fetching: ${JSON.stringify(endpoint)}`); 134 | 135 | // If cached version of package exists, re-use it 136 | if (cached && cached.version) { 137 | return undefined; 138 | } 139 | 140 | logger.debug('npm-resolver', `extracting package name from: ${endpoint.source}`); 141 | const pkg = extractPackageName(endpoint.source); 142 | const storage = bower.config.storage.packages; 143 | 144 | // Directory where the tgz will be stored. 145 | const compressedDir = path.join(storage, 'npm-resolver/compressed'); 146 | const uncompressedDir = path.join(storage, 'npm-resolver/uncompressed', pkg, endpoint.target); 147 | 148 | logger.debug('npm-resolver', `creating directory for compressed resources: ${compressedDir}`); 149 | return mkdirp(compressedDir) 150 | .then(() => { 151 | logger.debug('npm-resolver', `creating directory for uncompressed resources: ${uncompressedDir}`); 152 | return mkdirp(uncompressedDir); 153 | }) 154 | 155 | // Download tarball. 156 | .then(() => { 157 | logger.debug('npm-resolver', `downloading tarball for: ${pkg}#${endpoint.target}`); 158 | return npmUtils.downloadTarball(pkg, endpoint.target, compressedDir); 159 | }) 160 | 161 | // Download ok, extract tarball. 162 | .then((tarballPath) => { 163 | logger.debug('npm-resolver', `extracting tarball from: "${tarballPath}" to "${uncompressedDir}`); 164 | return extract.tgz(tarballPath, uncompressedDir); 165 | }) 166 | 167 | // Patch configuration with `package.json` file if `bower.json` does not exist. 168 | .then((dir) => { 169 | const pkgPath = path.join(dir, 'package'); 170 | logger.debug('npm-resolver', `extracting and patching bower.json from: ${pkgPath}`); 171 | return bowerUtils.patchConfiguration(pkgPath).then(() => ({ 172 | tempPath: pkgPath, 173 | removeIgnores: true, 174 | })); 175 | }); 176 | }, 177 | }; 178 | }; 179 | --------------------------------------------------------------------------------