Skip to content

Commit

Permalink
feat: git ignore to glob converter
Browse files Browse the repository at this point in the history
  • Loading branch information
aminya committed Mar 3, 2021
1 parent a5a9dba commit 9873705
Showing 1 changed file with 69 additions and 0 deletions.
69 changes: 69 additions & 0 deletions lib/path-utils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import path from "path"
import { promises } from "fs"
const { readFile } = promises

import { unique } from "./utils"

/** Converts given path to Posix (replacing \\ with /)
* @param {string} givenPath Path to convert
* @returns {string} Converted filepath
Expand All @@ -15,6 +20,70 @@ export function posixifyPathNormalized(givenPath) {
return posixifyPath(givenPath).replace(/[/\\]$/, "")
}

/**
* @param {string} gitIgnoreEntry one git ignore entry (it expects a valid non-comment gitignore entry with no surrounding whitespace)
* @param {string | undefined} gitIgnoreDirectory the directory of gitignore
* @returns {string | [string, string]} the equivilant glob
*/
function globifyGitIgnoreEntry(gitIgnoreEntry, gitIgnoreDirectory) {
// output glob entry
let entry = gitIgnoreEntry

// Process the entry beginning

// '!' in .gitignore means to force include the pattern
// remove "!" to allow the processing of the pattern and swap ! in the end of the loop
let forceInclude = false
if (entry[0] === "!") {
entry = entry.substring(1)
forceInclude = true
}

// If there is a separator at the beginning or middle (or both) of the pattern,
// then the pattern is relative to the directory level of the particular .gitignore file itself

if (entry[0] === "/") {
// Patterns starting with '/' in gitignore are considred relative to the project directory while glob
// treats them as relative to the OS root directory.
// So we trim the slash to make it relative to project folder from glob perspective.
entry = entry.substring(1)
} else {
// Process the middle

if (entry.indexOf("/") === -1) {
if (!entry.startsWith("**/")) {
// Patterns that don't have `/` are '**/' from glob perspective (can match at any level)
entry = `**/${entry}`
}
}
}

// prepend the absolute root directory
if (gitIgnoreDirectory) {
entry = `${posixifyPath(gitIgnoreDirectory)}/${entry}`
}

// swap !
entry = forceInclude ? entry : `!${entry}`

// Process the entry ending

if (entry.endsWith("/")) {
// If there is a separator at the end of the pattern then it only matches directories
// in glob this is equal to `directry/**`
entry = `${entry}**`
} else {
// unless already ends with /**
if (!entry.endsWith("/**")) {
// the pattern can match both files and directories
// so we should include both `entry` and `entry/**`
return [entry, `${entry}/**`]
}
}

return entry
}

function isWhitespace(str) {
return /^\s*$/.test(str)
}
Expand Down

0 comments on commit 9873705

Please sign in to comment.