├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitattributes ├── .github └── workflows │ ├── dev.yml │ └── release.yml ├── .gitignore ├── .npmrc ├── .prettierignore ├── LICENSE ├── README.md ├── index.js ├── package.json └── test ├── .gitkeep └── main.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | end_of_line = lf 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "gulp" 3 | } 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | -------------------------------------------------------------------------------- /.github/workflows/dev.yml: -------------------------------------------------------------------------------- 1 | name: dev 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | - main 8 | env: 9 | CI: true 10 | 11 | jobs: 12 | prettier: 13 | name: Format code 14 | runs-on: ubuntu-latest 15 | if: ${{ github.event_name == 'push' }} 16 | 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v2 20 | 21 | - name: Prettier 22 | uses: gulpjs/prettier_action@v3.0 23 | with: 24 | commit_message: 'chore: Run prettier' 25 | prettier_options: '--write .' 26 | 27 | test: 28 | name: Tests for Node ${{ matrix.node }} on ${{ matrix.os }} 29 | runs-on: ${{ matrix.os }} 30 | 31 | strategy: 32 | fail-fast: false 33 | matrix: 34 | node: [10, 12, 14, 16] 35 | os: [ubuntu-latest, windows-latest, macos-latest] 36 | 37 | steps: 38 | - name: Clone repository 39 | uses: actions/checkout@v2 40 | 41 | - name: Set Node.js version 42 | uses: actions/setup-node@v2 43 | with: 44 | node-version: ${{ matrix.node }} 45 | 46 | - run: node --version 47 | - run: npm --version 48 | 49 | - name: Install npm dependencies 50 | run: npm install 51 | 52 | - name: Run lint 53 | run: npm run lint 54 | 55 | - name: Run tests 56 | run: npm test 57 | 58 | - name: Coveralls 59 | uses: coverallsapp/github-action@v1.1.2 60 | with: 61 | github-token: ${{ secrets.GITHUB_TOKEN }} 62 | flag-name: ${{matrix.os}}-node-${{ matrix.node }} 63 | parallel: true 64 | 65 | coveralls: 66 | needs: test 67 | name: Finish up 68 | 69 | runs-on: ubuntu-latest 70 | steps: 71 | - name: Coveralls Finished 72 | uses: coverallsapp/github-action@v1.1.2 73 | with: 74 | github-token: ${{ secrets.GITHUB_TOKEN }} 75 | parallel-finished: true 76 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | on: 3 | push: 4 | branches: 5 | - master 6 | - main 7 | 8 | jobs: 9 | release-please: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: GoogleCloudPlatform/release-please-action@v2 13 | with: 14 | token: ${{ secrets.GITHUB_TOKEN }} 15 | release-type: node 16 | package-name: release-please-action 17 | bump-minor-pre-major: true 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | # Garbage files 64 | .DS_Store 65 | 66 | # Test results 67 | test.xunit 68 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | .nyc_output/ 3 | CHANGELOG.md 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2020, 2021 Blaine Bublitz , Eric Schoffstall 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |

6 | 7 | # replace-ext 8 | 9 | [![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Coveralls Status][coveralls-image]][coveralls-url] 10 | 11 | Replaces a file extension with another one. 12 | 13 | ## Usage 14 | 15 | ```js 16 | var replaceExt = require('replace-ext'); 17 | 18 | var path = '/some/dir/file.js'; 19 | var newPath = replaceExt(path, '.coffee'); 20 | 21 | console.log(newPath); // /some/dir/file.coffee 22 | ``` 23 | 24 | ## API 25 | 26 | ### `replaceExt(path, extension)` 27 | 28 | Replaces the extension from `path` with `extension` and returns the updated path string. 29 | 30 | Does not replace the extension if `path` is not a string or is empty. 31 | 32 | ## License 33 | 34 | MIT 35 | 36 | 37 | [downloads-image]: https://img.shields.io/npm/dm/replace-ext.svg?style=flat-square 38 | [npm-url]: https://www.npmjs.com/package/replace-ext 39 | [npm-image]: https://img.shields.io/npm/v/replace-ext.svg?style=flat-square 40 | 41 | [ci-url]: https://github.com/gulpjs/replace-ext/actions?query=workflow:dev 42 | [ci-image]: https://img.shields.io/github/actions/workflow/status/gulpjs/replace-ext/dev.yml?branch=master&style=flat-square 43 | 44 | [coveralls-url]: https://coveralls.io/r/gulpjs/replace-ext 45 | [coveralls-image]: https://img.shields.io/coveralls/gulpjs/replace-ext/master.svg?style=flat-square 46 | 47 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | 5 | function replaceExt(npath, ext) { 6 | if (typeof npath !== 'string') { 7 | return npath; 8 | } 9 | 10 | if (npath.length === 0) { 11 | return npath; 12 | } 13 | 14 | var nFileName = path.basename(npath, path.extname(npath)) + ext; 15 | var nFilepath = path.join(path.dirname(npath), nFileName); 16 | 17 | // Because `path.join` removes the head './' from the given path. 18 | // This removal can cause a problem when passing the result to `require` or 19 | // `import`. 20 | if (startsWithSingleDot(npath)) { 21 | return '.' + path.sep + nFilepath; 22 | } 23 | 24 | return nFilepath; 25 | } 26 | 27 | function startsWithSingleDot(fpath) { 28 | var first2chars = fpath.slice(0, 2); 29 | return first2chars === '.' + path.sep || first2chars === './'; 30 | } 31 | 32 | module.exports = replaceExt; 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "replace-ext", 3 | "version": "2.0.0", 4 | "description": "Replaces a file extension with another one.", 5 | "author": "Gulp Team (http://gulpjs.com/)", 6 | "contributors": [ 7 | "Eric Schoffstall ", 8 | "Blaine Bublitz " 9 | ], 10 | "repository": "gulpjs/replace-ext", 11 | "license": "MIT", 12 | "engines": { 13 | "node": ">=10.13.0" 14 | }, 15 | "main": "index.js", 16 | "files": [ 17 | "LICENSE", 18 | "index.js" 19 | ], 20 | "scripts": { 21 | "lint": "eslint .", 22 | "pretest": "npm run lint", 23 | "test": "nyc mocha --async-only" 24 | }, 25 | "devDependencies": { 26 | "eslint": "^7.32.0", 27 | "eslint-config-gulp": "^5.0.1", 28 | "eslint-plugin-node": "^11.1.0", 29 | "expect": "^27.4.2", 30 | "mocha": "^8.4.0", 31 | "nyc": "^15.1.0" 32 | }, 33 | "nyc": { 34 | "reporter": [ 35 | "lcov", 36 | "text-summary" 37 | ] 38 | }, 39 | "prettier": { 40 | "singleQuote": true 41 | }, 42 | "keywords": [ 43 | "gulp", 44 | "extensions", 45 | "filepath", 46 | "basename" 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /test/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gulpjs/replace-ext/7ad3035eedc534504167bca1220b2e083bed3ed8/test/.gitkeep -------------------------------------------------------------------------------- /test/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var os = require('os'); 5 | 6 | var expect = require('expect'); 7 | 8 | var replaceExt = require('../'); 9 | 10 | describe('replace-ext', function () { 11 | it('returns a valid replaced extension on long path', function (done) { 12 | var fname = path.join(__dirname, './fixtures/test.coffee'); 13 | var expected = path.join(__dirname, './fixtures/test.js'); 14 | var result = replaceExt(fname, '.js'); 15 | expect(result).toEqual(expected); 16 | done(); 17 | }); 18 | 19 | it('returns a valid replaced extension on basename', function (done) { 20 | var fname = 'test.coffee'; 21 | var expected = 'test.js'; 22 | var result = replaceExt(fname, '.js'); 23 | expect(result).toEqual(expected); 24 | done(); 25 | }); 26 | 27 | it('should not return a valid replaced extension on empty string', function (done) { 28 | var fname = ''; 29 | var expected = ''; 30 | var result = replaceExt(fname, '.js'); 31 | expect(result).toEqual(expected); 32 | done(); 33 | }); 34 | 35 | it('returns a valid removed extension on long path', function (done) { 36 | var fname = path.join(__dirname, './fixtures/test.coffee'); 37 | var expected = path.join(__dirname, './fixtures/test'); 38 | var result = replaceExt(fname, ''); 39 | expect(result).toEqual(expected); 40 | done(); 41 | }); 42 | 43 | it('returns a valid added extension on long path', function (done) { 44 | var fname = path.join(__dirname, './fixtures/test'); 45 | var expected = path.join(__dirname, './fixtures/test.js'); 46 | var result = replaceExt(fname, '.js'); 47 | expect(result).toEqual(expected); 48 | done(); 49 | }); 50 | 51 | it('should not replace when 1st arg is not a string (null)', function (done) { 52 | var result = replaceExt(null, '.js'); 53 | expect(result).toEqual(null); 54 | done(); 55 | }); 56 | 57 | it('should not replace when 1st arg is not a string (object)', function (done) { 58 | var obj = {}; 59 | var result = replaceExt(obj, '.js'); 60 | expect(result).toEqual(obj); 61 | done(); 62 | }); 63 | 64 | it('Should preserve the first dot of relative dir name.', function (done) { 65 | if (os.platform() === 'win32') { 66 | expect(replaceExt('a/b/c.js', '.ts')).toEqual('a\\b\\c.ts'); 67 | expect(replaceExt('./a/b/c.js', '.ts')).toEqual('.\\a\\b\\c.ts'); 68 | expect(replaceExt('../a/b/c.js', '.ts')).toEqual('..\\a\\b\\c.ts'); 69 | expect(replaceExt('/a/b/c.js', '.ts')).toEqual('\\a\\b\\c.ts'); 70 | 71 | expect(replaceExt('C:/a/b/c.js', '.ts')).toEqual('C:\\a\\b\\c.ts'); 72 | 73 | expect(replaceExt('a\\b\\c.js', '.ts')).toEqual('a\\b\\c.ts'); 74 | expect(replaceExt('.\\a\\b\\c.js', '.ts')).toEqual('.\\a\\b\\c.ts'); 75 | expect(replaceExt('..\\a\\b\\c.js', '.ts')).toEqual('..\\a\\b\\c.ts'); 76 | expect(replaceExt('\\a\\b\\c.js', '.ts')).toEqual('\\a\\b\\c.ts'); 77 | 78 | expect(replaceExt('C:\\a\\b\\c.js', '.ts')).toEqual('C:\\a\\b\\c.ts'); 79 | } else { 80 | expect(replaceExt('a/b/c.js', '.ts')).toEqual('a/b/c.ts'); 81 | expect(replaceExt('./a/b/c.js', '.ts')).toEqual('./a/b/c.ts'); 82 | expect(replaceExt('../a/b/c.js', '.ts')).toEqual('../a/b/c.ts'); 83 | expect(replaceExt('/a/b/c.js', '.ts')).toEqual('/a/b/c.ts'); 84 | } 85 | done(); 86 | }); 87 | }); 88 | --------------------------------------------------------------------------------