Socket
Socket
Sign inDemoInstall

parse-gitignore

Package Overview
Dependencies
0
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.1 to 2.0.0

244

index.js
/*!
* parse-gitignore <https://github.com/jonschlinkert/parse-gitignore>
*
* Copyright (c) 2015-present, Jon Schlinkert.

@@ -10,43 +9,238 @@ * Released under the MIT License.

const gitignore = input => {
return input.toString()
.split(/\r?\n/)
.filter(l => l.trim() !== '' && l.charAt(0) !== '#');
const fs = require('fs');
const isObject = v => v !== null && typeof v === 'object' && !Array.isArray(v);
// eslint-disable-next-line no-control-regex
const INVALID_PATH_CHARS_REGEX = /[<>:"|?*\n\r\t\f\x00-\x1F]/;
const GLOBSTAR_REGEX = /(?:^|\/)[*]{2}($|\/)/;
const MAX_PATH_LENGTH = 260 - 12;
const isValidPath = input => {
if (typeof input === 'string') {
return input.length <= MAX_PATH_LENGTH && !INVALID_PATH_CHARS_REGEX.test(input);
}
return false;
};
gitignore.parse = (input, fn = line => line) => {
let lines = input.toString().split(/\r?\n/);
let state = { patterns: [], sections: [] };
const split = str => String(str).split(/\r\n?|\n/);
const isComment = str => str.startsWith('#');
const isParsed = input => isObject(input) && input.patterns && input.sections;
const patterns = input => {
return split(input).map(l => l.trim()).filter(line => line !== '' && !isComment(line));
};
const parse = (input, options = {}) => {
let filepath = options.path;
if (isParsed(input)) return input;
if (isValidPath(input) && fs.existsSync(input)) {
filepath = input;
input = fs.readFileSync(input);
}
const lines = split(input);
const names = new Map();
let parsed = { sections: [], patterns: [] };
let section = { name: 'default', patterns: [] };
let prev;
for (let line of lines) {
if (line.charAt(0) === '#') {
section = { name: line.slice(1).trim(), patterns: []};
state.sections.push(section);
for (const line of lines) {
const value = line.trim();
if (value.startsWith('#')) {
const [, name] = /^#+\s*(.*)\s*$/.exec(value);
if (prev) {
names.delete(prev.name);
prev.comment += value ? `\n${value}` : '';
prev.name = name ? `${prev.name.trim()}\n${name.trim()}` : prev.name.trim();
names.set(prev.name.toLowerCase().trim(), prev);
continue;
}
section = { name: name.trim(), comment: value, patterns: [] };
names.set(section.name.toLowerCase(), section);
parsed.sections.push(section);
prev = section;
continue;
}
if (line.trim() !== '') {
let pattern = fn(line, section, state);
section.patterns.push(pattern);
state.patterns.push(pattern);
if (value !== '') {
section.patterns.push(value);
parsed.patterns.push(value);
}
prev = null;
}
return state;
if (options.dedupe === true || options.unique === true) {
parsed = dedupe(parsed, { ...options, format: false });
}
parsed.path = filepath;
parsed.input = Buffer.from(input);
parsed.format = opts => format(parsed, { ...options, ...opts });
parsed.dedupe = opts => dedupe(parsed, { ...options, ...opts });
parsed.globs = opts => globs(parsed, { path: filepath, ...options, ...opts });
return parsed;
};
gitignore.format = (section) => {
return `# ${section.name}\n${section.patterns.join('\n')}\n\n`;
const parseFile = (filepath, options) => {
return parse(fs.readFileSync(filepath, 'utf8'), options);
};
gitignore.stringify = (sections, fn = gitignore.format) => {
let result = '';
for (let section of [].concat(sections)) result += fn(section);
return result.trim();
const dedupe = (input, options) => {
const parsed = parse(input, { ...options, dedupe: false });
const names = new Map();
const res = { sections: [], patterns: new Set() };
let current;
// first, combine duplicate sections
for (const section of parsed.sections) {
const { name = '', comment, patterns } = section;
const key = name.trim().toLowerCase();
for (const pattern of patterns) {
res.patterns.add(pattern);
}
if (name && names.has(key)) {
current = names.get(key);
current.patterns = [...current.patterns, ...patterns];
} else {
current = { name, comment, patterns };
res.sections.push(current);
names.set(key, current);
}
}
// next, de-dupe patterns in each section
for (const section of res.sections) {
section.patterns = [...new Set(section.patterns)];
}
res.patterns = [...res.patterns];
return res;
};
const glob = (pattern, options) => {
// Return if a glob pattern has already been specified for sub-directories
if (GLOBSTAR_REGEX.test(pattern)) {
return pattern;
}
// 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. Otherwise the pattern may also match at any level below the
// .gitignore level. relative paths only
let relative = false;
if (pattern.startsWith('/')) {
pattern = pattern.slice(1);
relative = true;
} else if (pattern.slice(1, pattern.length - 1).includes('/')) {
relative = true;
}
// If there is a separator at the end of the pattern then the pattern will only match directories.
pattern += pattern.endsWith('/') ? '**/' : '/**';
// If not relative, the pattern can match any files and directories.
return relative ? pattern : `**/${pattern}`;
};
const globs = (input, options = {}) => {
const parsed = parse(input, options);
const result = [];
let index = 0;
const patterns = parsed.patterns
.concat(options.ignore || [])
.concat((options.unignore || []).map(p => !p.startsWith('!') ? '!' + p : p));
const push = (prefix, pattern) => {
const prev = result[result.length - 1];
const type = prefix ? 'unignore' : 'ignore';
if (prev && prev.type === type) {
if (!prev.patterns.includes(pattern)) {
prev.patterns.push(pattern);
}
} else {
result.push({ type, path: options.path || null, patterns: [pattern], index });
index++;
}
};
for (let pattern of patterns) {
let prefix = '';
// An optional prefix "!" which negates the pattern; any matching file excluded by
// a previous pattern will become included again
if (pattern.startsWith('!')) {
pattern = pattern.slice(1);
prefix = '!';
}
// add the raw pattern to the results
push(prefix, (pattern.startsWith('/') ? pattern.slice(1) : pattern));
// add the glob pattern to the results
push(prefix, glob(pattern));
}
return result;
};
/**
* Expose `gitignore`
* Formats a .gitignore section
*/
module.exports = gitignore;
const formatSection = (section = {}) => {
const output = [section.comment || ''];
if (section.patterns?.length) {
output.push(section.patterns.join('\n'));
output.push('');
}
return output.join('\n');
};
/**
* Format a .gitignore file from the given input or object from `.parse()`.
* @param {String} input File path or contents.
* @param {Object} options
* @return {String} Returns formatted string.
* @api public
*/
const format = (input, options = {}) => {
const parsed = parse(input, options);
const fn = options.formatSection || formatSection;
const sections = parsed.sections || parsed;
const output = [];
for (const section of [].concat(sections)) {
output.push(fn(section));
}
return output.join('\n');
};
parse.file = parseFile;
parse.parse = parse;
parse.dedupe = dedupe;
parse.format = format;
parse.globs = globs;
parse.formatSection = formatSection;
parse.patterns = patterns;
/**
* Expose `parse`
*/
module.exports = parse;

9

package.json
{
"name": "parse-gitignore",
"description": "Parse a .gitignore or .npmignore file into an array of patterns.",
"version": "1.0.1",
"version": "2.0.0",
"homepage": "https://github.com/jonschlinkert/parse-gitignore",

@@ -21,3 +21,3 @@ "author": "Jon Schlinkert (https://github.com/jonschlinkert)",

"engines": {
"node": ">=6"
"node": ">=14"
},

@@ -28,4 +28,5 @@ "scripts": {

"devDependencies": {
"gulp-format-md": "^1.0.0",
"mocha": "^5.2.0"
"gulp-format-md": "^2.0.0",
"matched": "^5.0.1",
"mocha": "^9.0.3"
},

@@ -32,0 +33,0 @@ "keywords": [

@@ -29,3 +29,3 @@ # parse-gitignore [![NPM version](https://img.shields.io/npm/v/parse-gitignore.svg?style=flat)](https://www.npmjs.com/package/parse-gitignore) [![NPM monthly downloads](https://img.shields.io/npm/dm/parse-gitignore.svg?style=flat)](https://npmjs.org/package/parse-gitignore) [![NPM total downloads](https://img.shields.io/npm/dt/parse-gitignore.svg?style=flat)](https://npmjs.org/package/parse-gitignore) [![Linux Build Status](https://img.shields.io/travis/jonschlinkert/parse-gitignore.svg?style=flat&label=Travis)](https://travis-ci.org/jonschlinkert/parse-gitignore)

// pass the contents of a .gitignore file as a string or buffer
// pass the contents of a .gitignore file as a string or buffer
console.log(parse(fs.readFileSync('foo/bar/.gitignore')));

@@ -111,3 +111,3 @@ //=> ['*.DS_Store', 'node_modules', ...];

| **Commits** | **Contributor** |
| **Commits** | **Contributor** |
| --- | --- |

@@ -133,2 +133,2 @@ | 33 | [jonschlinkert](https://github.com/jonschlinkert) |

_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on July 26, 2018._
_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on July 26, 2018._
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc