├── .eslintignore ├── .eslintrc.json ├── .gitattributes ├── .gitignore ├── .mailmap ├── .prettierignore ├── .prettierrc.js ├── .travis.yml ├── Gruntfile.js ├── LICENSE ├── README.md ├── appveyor.yml ├── lib └── gitignore-to-glob.js ├── package.json └── test ├── .eslintrc.json ├── fixtures ├── gitignore-comment ├── gitignore-dirs ├── gitignore-emptyline ├── gitignore-ignore ├── gitignore-noslash └── gitignore-slash └── spec.js /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/** 2 | test/*/**/*.js 3 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | 4 | "extends": "mgol", 5 | 6 | "env": { 7 | "node": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /package-lock.json 2 | /yarn.lock 3 | /node_modules/ 4 | *.log 5 | /test/*/not-ok-install-copy 6 | -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | Michał Gołębiowski-Owczarek 2 | Michał Gołębiowski-Owczarek 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EE/gitignore-to-glob/2cc548f1def882e135d7708593fba1e4a5adc126/.prettierignore -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // See https://prettier.io/docs/en/options.html 4 | module.exports = { 5 | singleQuote: true, 6 | 7 | // JS files are not compiled to ES5 so trailing commas in function 8 | // parameters would break in older browsers. 9 | trailingComma: 'all', 10 | 11 | tabWidth: 4, 12 | }; 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: false 3 | node_js: 4 | - '10' 5 | - '12' 6 | - '13' 7 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * gitignore-to-glob 3 | * https://github.com/EE/gitignore-to-glob 4 | * 5 | * Author Michał Gołębiowski-Owczarek 6 | * Licensed under the MIT license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | module.exports = function (grunt) { 12 | require('time-grunt')(grunt); 13 | 14 | grunt.initConfig({ 15 | clean: { 16 | all: { 17 | src: ['*.log', 'test/*/*-copy'], 18 | }, 19 | }, 20 | 21 | eslint: { 22 | all: { 23 | src: ['*.js', 'lib', 'test'], 24 | }, 25 | }, 26 | 27 | mochaTest: { 28 | all: { 29 | options: { 30 | reporter: 'spec', 31 | }, 32 | src: ['test/spec.js'], 33 | }, 34 | }, 35 | }); 36 | 37 | // Load all grunt tasks matching the `grunt-*` pattern. 38 | require('load-grunt-tasks')(grunt); 39 | 40 | grunt.registerTask('lint', ['eslint']); 41 | 42 | grunt.registerTask('test', ['mochaTest']); 43 | 44 | grunt.registerTask('default', ['clean', 'lint', 'test']); 45 | }; 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gitignore-to-glob 2 | 3 | > Transforms .gitignore patterns to ones compatible with the glob package (used by Grunt & others) 4 | 5 | [![Build Status](https://travis-ci.org/EE/gitignore-to-glob.svg?branch=master)](https://travis-ci.org/EE/gitignore-to-glob) 6 | [![Build status](https://ci.appveyor.com/api/projects/status/oi2hv39087wp6c00/branch/master?svg=true)](https://ci.appveyor.com/project/mgol/gitignore-to-glob/branch/master) 7 | 8 | ## Installation 9 | 10 | To install the package and add it to your `package.json`, invoke: 11 | 12 | ```shell 13 | npm install gitignore-to-glob --save-dev 14 | ``` 15 | 16 | ## Rationale 17 | 18 | `.gitignore` uses a different format than the `glob` package used, among others, by Grunt. Sometimes it's desirable 19 | to exclude files excluded by `.gitignore` in a glob pattern so a transformation function is needed. 20 | 21 | ## Usage 22 | 23 | Once the package has been installed, it may be used via: 24 | 25 | ```js 26 | require('gitignore-to-glob')(pathToGitignore, dirsToCheck); 27 | ``` 28 | 29 | where `pathToGitignore` is `'.gitignore'` by default and `dirsToCheck` is an optional array of directories where we 30 | assume all files matched by the glob pattern exist. The parameter is optional but may be passed for performance reasons. 31 | The rationale is that `.gitignore` patterns not starting with `/` are treated as if a glob pattern started with `**/` 32 | and that would be expensive as some directories like `node_modules` usually contain a lot of files so excluding them 33 | all manually would be slow. 34 | 35 | ## Usage Examples 36 | 37 | The most basic usage: 38 | 39 | ```js 40 | require('gitignore-to-glob')(); 41 | ``` 42 | 43 | This will convert files from the main `'.gitignore'`. 44 | 45 | ```js 46 | require('gitignore-to-glob')('app/.gitignore', ['app', 'test']); 47 | ``` 48 | 49 | This will convert the `'app/.gitignore'` file but will omit patterns outside directories `app` and `test`. 50 | 51 | ## Supported Node.js versions 52 | 53 | This project aims to support all Node.js versions supported upstream (see [Release README](https://github.com/nodejs/Release/blob/master/README.md) for more details). 54 | 55 | ## Contributing 56 | 57 | In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using `npm test`. 58 | 59 | ## License 60 | 61 | Copyright (c) 2014 Laboratorium EE. Licensed under the MIT license. 62 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # http://www.appveyor.com/docs/appveyor-yml 2 | 3 | clone_depth: 10 4 | 5 | # Fix line endings in Windows. (runs before repo cloning) 6 | init: 7 | - git config --global core.autocrlf input 8 | 9 | # Test against these versions of Node.js. 10 | environment: 11 | matrix: 12 | - nodejs_version: '10' 13 | - nodejs_version: '13' 14 | 15 | # Install scripts. (runs after repo cloning) 16 | install: 17 | # Get the Node version with matching major & minor numbers 18 | - ps: Install-Product node $env:nodejs_version 19 | # Typical npm stuff. 20 | - npm install 21 | 22 | # Post-install test scripts. 23 | test_script: 24 | # Output useful info for debugging. 25 | - node --version 26 | - npm --version 27 | - npm test 28 | 29 | # Don't actually build. 30 | build: off 31 | 32 | # Finish immediately if one of the jobs fails. 33 | matrix: 34 | fast_finish: true 35 | 36 | # Set up cache, clear it on package.json changes. 37 | cache: 38 | # npm cache. 39 | - C:\Users\appveyor\AppData\Roaming\npm-cache -> package.json 40 | # Local npm packages. 41 | - node_modules -> package.json 42 | 43 | # Set build version format here instead of in the admin panel. 44 | version: '{build}' 45 | -------------------------------------------------------------------------------- /lib/gitignore-to-glob.js: -------------------------------------------------------------------------------- 1 | /** 2 | * gitignore-to-glob 3 | * https://github.com/EE/gitignore-to-glob 4 | * 5 | * Author Michał Gołębiowski-Owczarek 6 | * Licensed under the MIT license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | const fs = require('fs'); 12 | const path = require('path'); 13 | 14 | module.exports = (gitignorePath, dirsToCheck) => { 15 | gitignorePath = path.resolve(gitignorePath || '.gitignore'); 16 | 17 | return ( 18 | fs 19 | .readFileSync(gitignorePath, { encoding: 'utf8' }) 20 | .split('\n') 21 | 22 | // Filter out empty lines and comments. 23 | .filter((pattern) => !!pattern && pattern[0] !== '#') 24 | 25 | // '!' in .gitignore and glob mean opposite things so we need to swap it. 26 | // Return pairt [ignoreFlag, pattern], we'll concatenate it later. 27 | .map((pattern) => 28 | pattern[0] === '!' 29 | ? ['', pattern.substring(1)] 30 | : ['!', pattern], 31 | ) 32 | 33 | // Filter out hidden files/directories (i.e. starting with a dot). 34 | .filter((patternPair) => { 35 | const pattern = patternPair[1]; 36 | return ( 37 | pattern.indexOf('/.') === -1 && pattern.indexOf('.') !== 0 38 | ); 39 | }) 40 | 41 | // There may be a lot of files outside of directories from `dirsToCheck`, don't ignore 42 | // them wasting time. 43 | .filter((patternPair) => { 44 | const pattern = patternPair[1]; 45 | return ( 46 | pattern[0] !== '/' || 47 | !dirsToCheck || 48 | new RegExp(`^/(?:${dirsToCheck.join('|')})(?:/|$)`).test( 49 | pattern, 50 | ) 51 | ); 52 | }) 53 | 54 | // Patterns not starting with '/' are in fact "starting" with '**/'. Since that would 55 | // catch a lot of files, restrict it to directories we check. 56 | // Patterns starting with '/' are relative to the project directory and glob would 57 | // treat them as relative to the OS root directory so strip the slash then. 58 | .map((patternPair) => { 59 | const pattern = patternPair[1]; 60 | if (pattern[0] !== '/') { 61 | return [ 62 | patternPair[0], 63 | `${ 64 | dirsToCheck ? `{${dirsToCheck}}/` : '' 65 | }**/${pattern}`, 66 | ]; 67 | } 68 | return [patternPair[0], pattern.substring(1)]; 69 | }) 70 | 71 | // We don't know whether a pattern points to a directory or a file and we need files. 72 | // Therefore, include both `pattern` and `pattern/**` for every pattern in the array. 73 | .reduce((result, patternPair) => { 74 | const pattern = patternPair.join(''); 75 | result.push(pattern); 76 | result.push(`${pattern}/**`); 77 | return result; 78 | }, []) 79 | ); 80 | }; 81 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gitignore-to-glob", 3 | "version": "0.3.1-pre", 4 | "description": "Transforms .gitignore patterns to ones compatible with the glob package (used by Grunt & others)", 5 | "homepage": "https://github.com/EE/gitignore-to-glob", 6 | "author": { 7 | "name": "Michał Gołębiowski-Owczarek", 8 | "email": "m.goleb@gmail.com" 9 | }, 10 | "keywords": [ 11 | "gitignore", 12 | "glob" 13 | ], 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/EE/gitignore-to-glob.git" 17 | }, 18 | "bugs": "https://github.com/EE/gitignore-to-glob/issues", 19 | "license": "MIT", 20 | "main": "lib/gitignore-to-glob.js", 21 | "files": [ 22 | "index.js", 23 | "lib" 24 | ], 25 | "devDependencies": { 26 | "eslint": "6.8.0", 27 | "eslint-config-mgol": "0.0.47", 28 | "grunt": "1.1.0", 29 | "grunt-cli": "1.3.2", 30 | "grunt-contrib-clean": "2.0.0", 31 | "grunt-eslint": "22.0.0", 32 | "grunt-mocha-test": "0.13.3", 33 | "husky": "4.2.3", 34 | "lint-staged": "10.1.1", 35 | "load-grunt-tasks": "5.1.0", 36 | "mocha": "7.1.1", 37 | "prettier": "2.0.2", 38 | "time-grunt": "2.0.0" 39 | }, 40 | "scripts": { 41 | "prettier-check": "prettier --check \"**/*.{json,js,yml,yaml,md}\"", 42 | "prettier-format": "prettier --write \"**/*.{json,js,yml,yaml,md}\"", 43 | "test": "npm run prettier-check && grunt" 44 | }, 45 | "engines": { 46 | "node": ">=10" 47 | }, 48 | "husky": { 49 | "hooks": { 50 | "pre-commit": "lint-staged" 51 | } 52 | }, 53 | "lint-staged": { 54 | "*.{json,yml,yaml,md}": [ 55 | "prettier --write", 56 | "git add" 57 | ], 58 | "*.js": [ 59 | "eslint --fix", 60 | "prettier --write", 61 | "git add" 62 | ] 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /test/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/gitignore-comment: -------------------------------------------------------------------------------- 1 | /pattern1 2 | # Comment 1 3 | /pattern2 4 | # Comment 2 5 | -------------------------------------------------------------------------------- /test/fixtures/gitignore-dirs: -------------------------------------------------------------------------------- 1 | /pattern1 2 | /pattern2 3 | /pattern3 4 | -------------------------------------------------------------------------------- /test/fixtures/gitignore-emptyline: -------------------------------------------------------------------------------- 1 | /pattern1 2 | 3 | /pattern2 4 | -------------------------------------------------------------------------------- /test/fixtures/gitignore-ignore: -------------------------------------------------------------------------------- 1 | !pattern1 2 | !/pattern2 3 | -------------------------------------------------------------------------------- /test/fixtures/gitignore-noslash: -------------------------------------------------------------------------------- 1 | pattern 2 | -------------------------------------------------------------------------------- /test/fixtures/gitignore-slash: -------------------------------------------------------------------------------- 1 | /pattern 2 | -------------------------------------------------------------------------------- /test/spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const gitignoreToGlob = require('../lib/gitignore-to-glob'); 5 | 6 | const getProcessedArray = (gitignoreSuffixOrArray, dirsToCheck) => 7 | Array.isArray(gitignoreSuffixOrArray) 8 | ? gitignoreSuffixOrArray 9 | : gitignoreToGlob( 10 | `${__dirname}/fixtures/gitignore-${gitignoreSuffixOrArray}`, 11 | dirsToCheck, 12 | ); 13 | 14 | const assertContain = (gitignoreSuffixOrArray, elem) => { 15 | const processedArray = getProcessedArray(gitignoreSuffixOrArray); 16 | return assert.notEqual( 17 | processedArray.indexOf(elem), 18 | -1, 19 | `Expected ${JSON.stringify(processedArray)} to contain ${elem}`, 20 | ); 21 | }; 22 | 23 | const assertNotContain = (gitignoreSuffixOrArray, elem) => { 24 | const processedArray = getProcessedArray(gitignoreSuffixOrArray); 25 | return assert.equal( 26 | processedArray.indexOf(elem), 27 | -1, 28 | `Expected ${JSON.stringify(processedArray)} to not contain ${elem}`, 29 | ); 30 | }; 31 | 32 | const assertDeep = (gitignoreSuffixOrArray, expectedArray) => { 33 | const processedArray = getProcessedArray(gitignoreSuffixOrArray); 34 | return assert.deepEqual(processedArray, expectedArray); 35 | }; 36 | 37 | describe('gitignoreToGlob', () => { 38 | it('should treat paths starting with "/" as relative to the main directory', () => { 39 | assertContain('slash', '!pattern'); 40 | }); 41 | 42 | it('should treat paths not starting with "/" as relative to all directories', () => { 43 | assertContain('noslash', '!**/pattern'); 44 | }); 45 | 46 | it('should not ignore files ignored in .gitignore', () => { 47 | assertContain('ignore', '**/pattern1'); 48 | assertContain('ignore', 'pattern2'); 49 | }); 50 | 51 | it('should omit empty lines', () => { 52 | assertDeep('emptyline', [ 53 | '!pattern1', 54 | '!pattern1/**', 55 | '!pattern2', 56 | '!pattern2/**', 57 | ]); 58 | }); 59 | 60 | it('should omit comments', () => { 61 | assertDeep('comment', [ 62 | '!pattern1', 63 | '!pattern1/**', 64 | '!pattern2', 65 | '!pattern2/**', 66 | ]); 67 | }); 68 | 69 | it('should take `dirsToCheck` into account', () => { 70 | const processedArray = getProcessedArray('dirs', [ 71 | 'pattern1', 72 | 'pattern3', 73 | ]); 74 | assertContain(processedArray, '!pattern1'); 75 | assertNotContain(processedArray, '!pattern2'); 76 | assertContain(processedArray, '!pattern3'); 77 | }); 78 | }); 79 | --------------------------------------------------------------------------------