├── .prettierignore ├── .eslintrc.json ├── .gitignore ├── .editorconfig ├── jest.config.js ├── .prettierrc.json ├── .github └── workflows │ └── test.yml ├── LICENSE ├── package.json ├── index.js ├── __specs__ └── index.spec.js └── README.md /.prettierignore: -------------------------------------------------------------------------------- 1 | package.json 2 | package-lock.json 3 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": ["@wezom", "prettier"] 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | 4 | *.log* 5 | .DS_Store 6 | thumbs.db 7 | *.ipr 8 | *.iws 9 | 10 | node_modules/ 11 | coverage/ 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [{package.json, package-lock.json}] 4 | indent_style = space 5 | indent_size = 2 6 | 7 | [*.md] 8 | trim_trailing_whitespace = false 9 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | coverageReporters: ['json-summary', 'lcov'], 3 | coveragePathIgnorePatterns: ['/node_modules/'], 4 | testPathIgnorePatterns: ['/node_modules/'] 5 | }; 6 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "always", 3 | "bracketSpacing": true, 4 | "jsxBracketSameLine": false, 5 | "printWidth": 90, 6 | "semi": true, 7 | "singleQuote": true, 8 | "trailingComma": "none", 9 | "tabWidth": 4, 10 | "useTabs": true 11 | } 12 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | node-version: [12.x] 11 | steps: 12 | - uses: actions/checkout@v1 13 | - uses: actions/setup-node@v1 14 | with: 15 | node-version: ${{ matrix.node-version }} 16 | - name: Install 17 | run: npm ci 18 | - name: Test 19 | run: npm test 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 WezomAgency 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 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-loader-exclude-node-modules-except", 3 | "version": "1.2.1", 4 | "description": "Creating a regular expression for excluding node_modules from babel transpiling except for individual modules", 5 | "main": "index.js", 6 | "files": [ 7 | "index.js" 8 | ], 9 | "scripts": { 10 | "test": "npm run prettier && npm run eslint && npm run jest", 11 | "prettier": "prettier index.js --check", 12 | "eslint": "eslint index.js", 13 | "jest": "jest", 14 | "jest:coverage": "jest --coverage --collectCoverageFrom=\"index.js\" && istanbul-badges-readme" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/dutchenkoOleg/babel-loader-exclude-node-modules-except.git" 19 | }, 20 | "keywords": [ 21 | "webpack", 22 | "babel-loader", 23 | "exclude", 24 | "node_modules", 25 | "es6 modules" 26 | ], 27 | "author": "Oleg Dutchenko ", 28 | "contributors": [ 29 | "April Arcus (https://github.com/AprilArcus)" 30 | ], 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/dutchenkoOleg/babel-loader-exclude-node-modules-except/issues" 34 | }, 35 | "homepage": "https://github.com/dutchenkoOleg/babel-loader-exclude-node-modules-except#readme", 36 | "dependencies": { 37 | "escape-string-regexp": "2.0.0" 38 | }, 39 | "devDependencies": { 40 | "@wezom/eslint-config": "^2.1.0-beta.0", 41 | "eslint": "^7.19.0", 42 | "eslint-config-prettier": "^7.2.0", 43 | "istanbul-badges-readme": "^1.2.0", 44 | "jest": "^26.6.3", 45 | "prettier": "^2.2.1" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const escapeStringRegexp = require('escape-string-regexp'); 3 | const ESCAPED_NODE_MODULES = escapeStringRegexp('node_modules'); 4 | const ESCAPED_PATH_SEP = escapeStringRegexp(path.sep); 5 | 6 | /** 7 | * Creating a regular expression for excluding node modules 8 | * from babel transpiling except for individual modules 9 | * @param {string[]} [exceptionList] - exclude all modules except this list 10 | * @return {RegExp} 11 | */ 12 | function babelLoaderExcludeNodeModulesExcept(exceptionList) { 13 | if (Array.isArray(exceptionList) && exceptionList.length) { 14 | // Module names can contain path separators, e.g. "@types/react". 15 | // Assume POSIX input and normalize for the current platform. 16 | const normalizedExceptionList = exceptionList.map(function (moduleName) { 17 | // We'll handle trailing path separators when we build the 18 | // negative lookahead, so remove them if present. 19 | if (moduleName[moduleName.length - 1] === path.posix.sep) { 20 | moduleName = moduleName.slice(0, -1); 21 | } 22 | return moduleName.split(path.posix.sep).join(path.sep); 23 | }); 24 | 25 | const alternationGroup = 26 | '(' + 27 | normalizedExceptionList 28 | .map((item) => { 29 | // Breaking down string by wildcards. For every 30 | // occurrance between wildcards build the portion 31 | // with escapeStringRegexp. 32 | // For the wildcards, replace them by a non-capturing 33 | // group matching everything. 34 | const match = item.match(/([^*]*)/g); 35 | return match 36 | .map((m, i) => { 37 | if (m.length > 0) { 38 | return escapeStringRegexp(m); 39 | } else if (i !== match.length - 1 && m.length === 0) { 40 | return '(?:.*)'; 41 | } else { 42 | return ''; 43 | } 44 | }) 45 | .join(''); 46 | }) 47 | .join('|') + 48 | ')'; 49 | 50 | // If the exception list includes e.g. "react", we don't want to 51 | // accidentally make an exception for "react-dom", so make sure to 52 | // include a trailing path separator inside the negative lookahead. 53 | const negativeLookahead = '(?!' + alternationGroup + ESCAPED_PATH_SEP + ')'; 54 | 55 | return new RegExp( 56 | ESCAPED_NODE_MODULES + ESCAPED_PATH_SEP + negativeLookahead, 57 | 'i' 58 | ); 59 | } else { 60 | return new RegExp(ESCAPED_NODE_MODULES, 'i'); 61 | } 62 | } 63 | 64 | module.exports = babelLoaderExcludeNodeModulesExcept; 65 | -------------------------------------------------------------------------------- /__specs__/index.spec.js: -------------------------------------------------------------------------------- 1 | const babelLoaderExcludeNodeModulesExcept = require('../index'); 2 | const path = require('path'); 3 | const escapeStringRegexp = require('escape-string-regexp'); 4 | const ESCAPED_PATH_SEP = escapeStringRegexp(path.sep); 5 | 6 | const X = ESCAPED_PATH_SEP === '\\\\'; 7 | 8 | describe('Should create a correct regular expression for excluding node_modules', function () { 9 | /** 10 | * @type {TestCase[]} 11 | */ 12 | const testCases = [ 13 | { 14 | params: undefined, 15 | expected: /node_modules/i 16 | }, 17 | { 18 | params: [], 19 | expected: /node_modules/i 20 | }, 21 | { 22 | params: ['xxx'], 23 | expected: X ? /node_modules\\(?!(xxx)\\)/i : /node_modules\/(?!(xxx)\/)/i 24 | }, 25 | { 26 | params: ['xxx/'], 27 | expected: X ? /node_modules\\(?!(xxx)\\)/i : /node_modules\/(?!(xxx)\/)/i 28 | }, 29 | { 30 | params: ['zZz', 'yYy'], 31 | expected: X 32 | ? /node_modules\\(?!(zZz|yYy)\\)/i 33 | : /node_modules\/(?!(zZz|yYy)\/)/i 34 | } 35 | ]; 36 | 37 | testCases.forEach(function ({ params, expected }, i) { 38 | test(`Test case #${i + 1}`, function () { 39 | const result = babelLoaderExcludeNodeModulesExcept(params); 40 | expect(result).toEqual(expected); 41 | }); 42 | }); 43 | }); 44 | 45 | describe('Should be able to convert wildcards in parameters to matching pattern in the regular expression', () => { 46 | /** 47 | * @type {TestCase[]} 48 | */ 49 | const testCases = [ 50 | { 51 | description: 'Wildcard occurs in the only argument', 52 | params: ['react-*'], 53 | expected: X 54 | ? /node_modules\\(?!(react\-(?:.*))\\)/i 55 | : /node_modules\/(?!(react\-(?:.*))\/)/i 56 | }, 57 | { 58 | description: 'Wildcard occurs in the second argument out of three', 59 | params: ['abc', 'mno*', 'xvz'], 60 | expected: X 61 | ? /node_modules\\(?!(abc|mno(?:.*)|xvz)\\)/i 62 | : /node_modules\/(?!(abc|mno(?:.*)|xvz)\/)/i 63 | }, 64 | { 65 | description: 'Wildcard used for scoped packages', 66 | params: ['@awesomecorp/*'], 67 | expected: X 68 | ? /node_modules\\(?!(@awesomecorp\\(?:.*))\\)/i 69 | : /node_modules\/(?!(@awesomecorp\/(?:.*))\/)/i 70 | } 71 | ]; 72 | 73 | testCases.forEach(function ({ params, expected, description }, i) { 74 | test(`Test case #${i + 1}: ${description}`, function () { 75 | const result = babelLoaderExcludeNodeModulesExcept(params); 76 | expect(result).toEqual(expected); 77 | }); 78 | }); 79 | }); 80 | 81 | /** 82 | * @typedef {Object} TestCase 83 | * @property {string[]} params 84 | * @property {RegExp} expected 85 | * @property {string} [description] 86 | */ 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # babel-loader-exclude-node-modules-except 2 | 3 | [![license](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/WezomAgency/babel-loader-exclude-node-modules-except/blob/master/LICENSE) 4 | [![npm](https://img.shields.io/badge/js--tiny-module-yellow.svg)](https://github.com/topics/js-tiny-module) 5 | [![npm](https://img.shields.io/badge/npm-install-orange.svg)](https://www.npmjs.com/package/babel-loader-exclude-node-modules-except) 6 | ![Tests](https://github.com/dutchenkoOleg/babel-loader-exclude-node-modules-except/workflows/Tests/badge.svg) 7 | 8 | 9 | | Statements | Branches | Functions | Lines | 10 | | --------------------------- | ----------------------- | ------------------------- | -------------------- | 11 | | ![Statements](https://img.shields.io/badge/Coverage-100%25-brightgreen.svg) | ![Branches](https://img.shields.io/badge/Coverage-100%25-brightgreen.svg) | ![Functions](https://img.shields.io/badge/Coverage-100%25-brightgreen.svg) | ![Lines](https://img.shields.io/badge/Coverage-100%25-brightgreen.svg) | 12 | 13 | > Creating a regular expression for excluding node_modules 14 | > from babel transpiling except for individual modules 15 | 16 | 17 | ### Usage 18 | 19 | ```js 20 | // webpack.config.js 21 | 22 | const babelLoaderExcludeNodeModulesExcept = require('babel-loader-exclude-node-modules-except'); 23 | 24 | module.exports = { 25 | // config properties 26 | // ... 27 | module: { 28 | rules: [ 29 | { 30 | test: /\.js$/, 31 | exclude: babelLoaderExcludeNodeModulesExcept([ 32 | // es6 modules from node_modules/ 33 | 'custom-jquery-methods', 34 | 'swiper', 35 | 'dom7' 36 | ]), 37 | use: { 38 | loader: 'babel-loader' 39 | } 40 | } 41 | ] 42 | } 43 | }; 44 | 45 | ``` 46 | 47 | ### Also, wildcards for matching are allowed, except names 48 | 49 | _Since v1.2.0_ 50 | 51 | 52 | ```js 53 | // webpack.config.js 54 | 55 | const babelLoaderExcludeNodeModulesExcept = require('babel-loader-exclude-node-modules-except'); 56 | 57 | module.exports = { 58 | // config properties 59 | // ... 60 | module: { 61 | rules: [ 62 | { 63 | test: /\.js$/, 64 | exclude: babelLoaderExcludeNodeModulesExcept([ 65 | 'react-*', 66 | '@awesomecorp/*' 67 | ]), 68 | use: { 69 | loader: 'babel-loader' 70 | } 71 | } 72 | ] 73 | } 74 | }; 75 | 76 | ``` 77 | 78 | 79 | 80 | --- 81 | 82 | #### Contributors 💪 83 | 84 | - April Arcus [@AprilArcus](https://github.com/AprilArcus) 85 | - Thordur Thordarson [@earthslasthope](https://github.com/earthslasthope) 86 | 87 | --- 88 | 89 | #### License 90 | 91 | [MIT License](https://github.com/WezomAgency/babel-loader-exclude-node-modules-except/blob/master/LICENSE) 92 | 93 | --- 94 | --------------------------------------------------------------------------------