UNPKG

@gerhobbelt/gitignore-parser

Version:
1 lines 21.6 kB
{"version":3,"file":"gitignoreParser.mjs","sources":["../lib/index.js"],"sourcesContent":["\n// force to false and smart code compressors can remove the resulting 'dead code':\nconst DEBUG = true;\n\n/**\n * Compile the given `.gitignore` content (not filename!)\n * and return an object with `accepts`, `denies` and `inspects` methods.\n * These methods each accepts a single filename or path and determines whether\n * they are acceptable or unacceptable according to the `.gitignore` definition.\n *\n * @param {String} content The `.gitignore` content to compile.\n * @return {Object} The helper object with methods that operate on the compiled content.\n */\nexport function compile(content) {\n let parsed = parse(content),\n positives = parsed[0],\n negatives = parsed[1];\n\n return {\n /// Helper (which can be overridden by userland code) invoked when\n /// any `accepts()`, `denies()` or `inspects()` fail to help\n /// the developer analyze what is going on inside: some gitignore spec\n /// bits are non-intuitive / non-trivial, after all.\n diagnose: function (query) {\n if (DEBUG) {\n console.log(`${query.query}:`, query);\n }\n },\n /// Return TRUE when the given `input` path PASSES the gitignore filters,\n /// i.e. when the given input path is DENIED.\n ///\n /// Notes:\n /// - you MUST postfix a input directory with '/' to ensure the gitignore\n /// rules can be applied conform spec.\n /// - you MAY prefix a input directory with '/' when that directory is\n /// 'rooted' in the same directory as the compiled .gitignore spec file.\n accepts: function (input, expected) {\n if (input[0] === '/') input = input.slice(1);\n input = '/' + input;\n\n let acceptRe = negatives[0];\n let acceptTest = acceptRe.test(input);\n let denyRe = positives[0];\n let denyTest = denyRe.test(input);\n let returnVal = (acceptTest || !denyTest);\n // See the test/fixtures/gitignore.manpage.txt near line 680 (grep for \"uber-nasty\"):\n // to resolve chained rules which reject, then accept, we need to establish\n // the precedence of both accept and reject parts of the compiled gitignore by\n // comparing match lengths.\n // Since the generated consolidated regexes are lazy, we must loop through all lines' regexes instead:\n let acceptMatch, denyMatch;\n if (acceptTest && denyTest) {\n for (let re of negatives[1]) {\n let m = re.exec(input);\n if (m) {\n if (!acceptMatch) {\n acceptMatch = m;\n } else if (acceptMatch[0].length < m[0].length) {\n acceptMatch = m;\n }\n }\n }\n for (let re of positives[1]) {\n let m = re.exec(input);\n if (m) {\n if (!denyMatch) {\n denyMatch = m;\n } else if (denyMatch[0].length < m[0].length) {\n denyMatch = m;\n }\n }\n }\n // acceptMatch = acceptRe.exec(input);\n // denyMatch = denyRe.exec(input);\n\n returnVal = (acceptMatch[0].length >= denyMatch[0].length);\n }\n\n if (expected != null && expected !== returnVal) {\n this.diagnose({ query: 'accepts', input, expected, acceptRe, acceptTest, acceptMatch, denyRe, denyTest, denyMatch, combine: '(Accept || !Deny)', returnVal });\n }\n return returnVal;\n },\n /// Return TRUE when the given `input` path FAILS the gitignore filters,\n /// i.e. when the given input path is ACCEPTED.\n ///\n /// Notes:\n /// - you MUST postfix a input directory with '/' to ensure the gitignore\n /// rules can be applied conform spec.\n /// - you MAY prefix a input directory with '/' when that directory is\n /// 'rooted' in the same directory as the compiled .gitignore spec file.\n denies: function (input, expected) {\n if (input[0] === '/') input = input.slice(1);\n input = '/' + input;\n\n let acceptRe = negatives[0];\n let acceptTest = acceptRe.test(input);\n let denyRe = positives[0];\n let denyTest = denyRe.test(input);\n // boolean logic:\n //\n // denies = !accepts =>\n // = !(Accept || !Deny) =>\n // = (!Accept && !!Deny) =>\n // = (!Accept && Deny)\n let returnVal = (!acceptTest && denyTest);\n // See the test/fixtures/gitignore.manpage.txt near line 680 (grep for \"uber-nasty\"):\n // to resolve chained rules which reject, then accept, we need to establish\n // the precedence of both accept and reject parts of the compiled gitignore by\n // comparing match lengths.\n // Since the generated regexes are all set up to be GREEDY, we can use the\n // consolidated regex for this, instead of having to loop through all lines' regexes:\n let acceptMatch, denyMatch;\n if (acceptTest && denyTest) {\n for (let re of negatives[1]) {\n let m = re.exec(input);\n if (m) {\n if (!acceptMatch) {\n acceptMatch = m;\n } else if (acceptMatch[0].length < m[0].length) {\n acceptMatch = m;\n }\n }\n }\n for (let re of positives[1]) {\n let m = re.exec(input);\n if (m) {\n if (!denyMatch) {\n denyMatch = m;\n } else if (denyMatch[0].length < m[0].length) {\n denyMatch = m;\n }\n }\n }\n // acceptMatch = acceptRe.exec(input);\n // denyMatch = denyRe.exec(input);\n\n // boolean logic: !(A>=B) ==> A<B\n returnVal = (acceptMatch[0].length < denyMatch[0].length);\n }\n\n if (expected != null && expected !== returnVal) {\n this.diagnose({ query: 'denies', input, expected, acceptRe, acceptTest, acceptMatch, denyRe, denyTest, denyMatch, combine: '(!Accept && Deny)', returnVal });\n }\n return returnVal;\n },\n /// Return TRUE when the given `input` path is inspected by any .gitignore\n /// filter line.\n ///\n /// You can use this method to help construct the decision path when you\n /// process nested .gitignore files: .gitignore filters in subdirectories\n /// MAY override parent .gitignore filters only when there's actually ANY\n /// filter in the child .gitignore after all.\n ///\n /// Notes:\n /// - you MUST postfix a input directory with '/' to ensure the gitignore\n /// rules can be applied conform spec.\n /// - you MAY prefix a input directory with '/' when that directory is\n /// 'rooted' in the same directory as the compiled .gitignore spec file.\n inspects: function (input, expected) {\n if (input[0] === '/') input = input.slice(1);\n input = '/' + input;\n\n let acceptRe = negatives[0];\n let acceptTest = acceptRe.test(input);\n let denyRe = positives[0];\n let denyTest = denyRe.test(input);\n // when any filter 'touches' the input path, it must match,\n // no matter whether it's a deny or accept filter line:\n let returnVal = (acceptTest || denyTest);\n\n if (expected != null && expected !== returnVal) {\n this.diagnose({ query: 'inspects', input, expected, acceptRe, acceptTest, denyRe, denyTest, combine: '(Accept || Deny)', returnVal });\n }\n return returnVal;\n }\n };\n}\n\n/**\n * Parse the given `.gitignore` content and return an array\n * containing positives and negatives.\n * Each of these in turn contains a regexp which will be\n * applied to the 'rooted' paths to test for *deny* or *accept*\n * respectively.\n *\n * @param {String} content The content to parse,\n * @return {Array[]} The parsed positive and negatives definitions.\n */\nexport function parse(content) {\n return content.split('\\n')\n .map(function (line) {\n line = line.trim();\n return line;\n })\n .filter(function (line) {\n return line && line[0] !== '#';\n })\n .reduce(function (lists, line) {\n let isNegative = line[0] === '!';\n if (isNegative) {\n line = line.slice(1);\n }\n if (isNegative) {\n lists[1].push(line);\n } else {\n lists[0].push(line);\n }\n return lists;\n }, [ [], [] ])\n .map(function (list) {\n list = list\n .sort()\n .map(prepareRegexPattern);\n\n // don't need submatches, hence we use should use non-capturing `(?:...)` grouping regexes:\n // those are generally faster than their submatch-capturing brothers:\n if (list.length > 0) {\n return [ new RegExp('(?:' + list.join(')|(?:') + ')'), list.map((re) => new RegExp(re)) ];\n }\n // this regex *won't match a thing*:\n return [ new RegExp('$^'), [] ];\n });\n}\n\nfunction prepareRegexPattern(pattern) {\n // https://git-scm.com/docs/gitignore#_pattern_format\n //\n // * ...\n //\n // * If there is a separator at the beginning or middle (or both) of the pattern,\n // then the pattern is relative to the directory level of the particular\n // .gitignore file itself.\n // Otherwise the pattern may also match at any level below the .gitignore level.\n //\n // * ...\n //\n // * For example, a pattern `doc/frotz/` matches `doc/frotz` directory, but\n // not `a/doc/frotz` directory; however `frotz/` matches `frotz` and `a/frotz`\n // that is a directory (all paths are relative from the .gitignore file).\n //\n let input = pattern;\n let re = '';\n let rooted = false;\n let directory = false;\n if (pattern[0] === '/') {\n rooted = true;\n pattern = pattern.slice(1);\n }\n if (pattern[pattern.length - 1] === '/') {\n directory = true;\n pattern = pattern.slice(0, pattern.length - 1);\n }\n // keep character ranges intact:\n const rangeRe = /^((?:[^\\[\\\\]|(?:\\\\.))*)\\[((?:[^\\]\\\\]|(?:\\\\.))*)\\]/;\n // ^ could have used the 'y' sticky flag, but there's some trouble with infine loops inside\n // the matcher below then...\n let match;\n\n while ((match = rangeRe.exec(pattern)) !== null) {\n if (match[1].includes('/')) {\n rooted = true;\n // ^ cf. man page:\n //\n // If there is a separator at the beginning or middle (or both)\n // of the pattern, then the pattern is relative to the directory\n // level of the particular .gitignore file itself. Otherwise\n // the pattern may also match at any level below the .gitignore level.\n }\n re += transpileRegexPart(match[1]);\n re += '[' + match[2] + ']';\n\n pattern = pattern.slice(match[0].length);\n }\n if (pattern) {\n if (pattern.includes('/')) {\n rooted = true;\n // ^ cf. man page:\n //\n // If there is a separator at the beginning or middle (or both)\n // of the pattern, then the pattern is relative to the directory\n // level of the particular .gitignore file itself. Otherwise\n // the pattern may also match at any level below the .gitignore level.\n }\n re += transpileRegexPart(pattern);\n }\n\n // prep regexes assuming we'll always prefix the check string with a '/':\n if (rooted) {\n re = '^\\\\/' + re;\n } else {\n re = '\\\\/' + re;\n }\n // cf spec:\n //\n // If there is a separator at the end of the pattern then the pattern\n // will only match directories, otherwise the pattern can match\n // **both files and directories**. (emphasis mine)\n if (directory) {\n // match the directory itself and anything within:\n re += '\\\\/';\n } else {\n // match the file itself, or, when it is a directory, match the directory and anything within:\n re += '(?:$|\\\\/)';\n }\n\n // regex validation diagnostics: better to check if the part is valid\n // then to discover it's gone haywire in the big conglomerate at the end.\n if (DEBUG) {\n try {\n /* eslint no-new:1 */\n new RegExp('(?:' + re + ')');\n } catch (ex) {\n console.log('failed regex:', { input, re, ex });\n }\n }\n return re;\n\n function transpileRegexPart(re) {\n return re\n // unescape for these will be escaped again in the subsequent `.replace(...)`,\n // whether they were escaped before or not:\n .replace(/\\\\(.)/g, '$1')\n // escape special regex characters:\n .replace(/[\\-\\[\\]\\{\\}\\(\\)\\+\\.\\\\\\^\\$\\|]/g, '\\\\$&')\n .replace(/\\?/g, '[^/]')\n .replace(/\\/\\*\\*\\//g, '(?:/|(?:/.+/))')\n .replace(/^\\*\\*\\//g, '(?:|(?:.+/))')\n .replace(/\\/\\*\\*$/g, () => {\n directory = true; // `a/**` should match `a/`, `a/b/` and `a/b`, the latter by implication of matching directory `a/`\n return '(?:|(?:/.+))'; // `a/**` also accepts `a/` itself\n })\n .replace(/\\*\\*/g, '.*')\n // `a/*` should match `a/b` and `a/b/` but NOT `a` or `a/`\n // meanwhile, `a/*/` should match `a/b/` and `a/b/c` but NOT `a` or `a/` or `a/b`\n .replace(/\\/\\*(\\/|$)/g, '/[^/]+$1')\n .replace(/\\*/g, '[^/]*')\n .replace(/\\//g, '\\\\/');\n }\n}\n"],"names":["compile","content","parsed","parse","positives","negatives","diagnose","query","console","log","accepts","input","expected","slice","acceptRe","acceptTest","test","denyRe","denyTest","returnVal","acceptMatch","denyMatch","re","m","exec","length","combine","denies","inspects","split","map","line","trim","filter","reduce","lists","isNegative","push","list","sort","prepareRegexPattern","RegExp","join","pattern","rooted","directory","rangeRe","match","includes","transpileRegexPart","ex","replace"],"mappings":"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"}