├── .editorconfig
├── .eslintrc.json
├── .gitattributes
├── .gitignore
├── .npmrc
├── .travis.yml
├── .verb.md
├── LICENSE
├── README.md
├── example.js
├── index.js
├── package.json
└── test
├── expected
└── _gitconfig.js
├── fixtures
├── _gitconfig
├── _gitconfig-branch
└── _gitconfig.local
└── test.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org/
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | end_of_line = lf
7 | indent_size = 2
8 | indent_style = space
9 | insert_final_newline = true
10 | trim_trailing_whitespace = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "eslint:recommended"
4 | ],
5 |
6 | "env": {
7 | "browser": false,
8 | "es6": true,
9 | "node": true,
10 | "mocha": true
11 | },
12 |
13 | "parserOptions":{
14 | "ecmaVersion": 9,
15 | "sourceType": "module",
16 | "ecmaFeatures": {
17 | "modules": true,
18 | "experimentalObjectRestSpread": true
19 | }
20 | },
21 |
22 | "globals": {
23 | "document": false,
24 | "navigator": false,
25 | "window": false
26 | },
27 |
28 | "rules": {
29 | "accessor-pairs": 2,
30 | "arrow-spacing": [2, { "before": true, "after": true }],
31 | "block-spacing": [2, "always"],
32 | "brace-style": [2, "1tbs", { "allowSingleLine": true }],
33 | "comma-dangle": [2, "never"],
34 | "comma-spacing": [2, { "before": false, "after": true }],
35 | "comma-style": [2, "last"],
36 | "constructor-super": 2,
37 | "curly": [2, "multi-line"],
38 | "dot-location": [2, "property"],
39 | "eol-last": 2,
40 | "eqeqeq": [2, "allow-null"],
41 | "generator-star-spacing": [2, { "before": true, "after": true }],
42 | "handle-callback-err": [2, "^(err|error)$" ],
43 | "indent": [2, 2, { "SwitchCase": 1 }],
44 | "key-spacing": [2, { "beforeColon": false, "afterColon": true }],
45 | "keyword-spacing": [2, { "before": true, "after": true }],
46 | "new-cap": [2, { "newIsCap": true, "capIsNew": false }],
47 | "new-parens": 2,
48 | "no-array-constructor": 2,
49 | "no-caller": 2,
50 | "no-class-assign": 2,
51 | "no-cond-assign": 2,
52 | "no-const-assign": 2,
53 | "no-control-regex": 2,
54 | "no-debugger": 2,
55 | "no-delete-var": 2,
56 | "no-dupe-args": 2,
57 | "no-dupe-class-members": 2,
58 | "no-dupe-keys": 2,
59 | "no-duplicate-case": 2,
60 | "no-empty-character-class": 2,
61 | "no-eval": 2,
62 | "no-ex-assign": 2,
63 | "no-extend-native": 2,
64 | "no-extra-bind": 2,
65 | "no-extra-boolean-cast": 2,
66 | "no-extra-parens": [2, "functions"],
67 | "no-fallthrough": 2,
68 | "no-floating-decimal": 2,
69 | "no-func-assign": 2,
70 | "no-implied-eval": 2,
71 | "no-inner-declarations": [2, "functions"],
72 | "no-invalid-regexp": 2,
73 | "no-irregular-whitespace": 2,
74 | "no-iterator": 2,
75 | "no-label-var": 2,
76 | "no-labels": 2,
77 | "no-lone-blocks": 2,
78 | "no-mixed-spaces-and-tabs": 2,
79 | "no-multi-spaces": 2,
80 | "no-multi-str": 2,
81 | "no-multiple-empty-lines": [2, { "max": 1 }],
82 | "no-native-reassign": 0,
83 | "no-negated-in-lhs": 2,
84 | "no-new": 2,
85 | "no-new-func": 2,
86 | "no-new-object": 2,
87 | "no-new-require": 2,
88 | "no-new-wrappers": 2,
89 | "no-obj-calls": 2,
90 | "no-octal": 2,
91 | "no-octal-escape": 2,
92 | "no-proto": 0,
93 | "no-redeclare": 2,
94 | "no-regex-spaces": 2,
95 | "no-return-assign": 2,
96 | "no-self-compare": 2,
97 | "no-sequences": 2,
98 | "no-shadow-restricted-names": 2,
99 | "no-spaced-func": 2,
100 | "no-sparse-arrays": 2,
101 | "no-this-before-super": 2,
102 | "no-throw-literal": 2,
103 | "no-trailing-spaces": 0,
104 | "no-undef": 2,
105 | "no-undef-init": 2,
106 | "no-unexpected-multiline": 2,
107 | "no-unneeded-ternary": [2, { "defaultAssignment": false }],
108 | "no-unreachable": 2,
109 | "no-unused-vars": [2, { "vars": "all", "args": "none" }],
110 | "no-useless-call": 0,
111 | "no-with": 2,
112 | "one-var": [0, { "initialized": "never" }],
113 | "operator-linebreak": [0, "after", { "overrides": { "?": "before", ":": "before" } }],
114 | "padded-blocks": [0, "never"],
115 | "quotes": [2, "single", "avoid-escape"],
116 | "radix": 2,
117 | "semi": [2, "always"],
118 | "semi-spacing": [2, { "before": false, "after": true }],
119 | "space-before-blocks": [2, "always"],
120 | "space-before-function-paren": [2, "never"],
121 | "space-in-parens": [2, "never"],
122 | "space-infix-ops": 2,
123 | "space-unary-ops": [2, { "words": true, "nonwords": false }],
124 | "spaced-comment": [0, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","] }],
125 | "use-isnan": 2,
126 | "valid-typeof": 2,
127 | "wrap-iife": [2, "any"],
128 | "yoda": [2, "never"]
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.* text eol=lf
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # always ignore files
2 | *.DS_Store
3 | .idea
4 | .vscode
5 | *.sublime-*
6 |
7 | # test related, or directories generated by tests
8 | test/actual
9 | actual
10 | coverage
11 | .nyc*
12 |
13 | # npm
14 | node_modules
15 | npm-debug.log
16 |
17 | # yarn
18 | yarn.lock
19 | yarn-error.log
20 |
21 | # misc
22 | _gh_pages
23 | _draft
24 | _drafts
25 | bower_components
26 | vendor
27 | temp
28 | tmp
29 | TODO.md
30 | package-lock.json
31 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | os:
3 | - linux
4 | - osx
5 | - windows
6 | language: node_js
7 | node_js:
8 | - node
9 | - '11'
10 | - '10'
11 | - '9'
12 | - '8'
13 |
--------------------------------------------------------------------------------
/.verb.md:
--------------------------------------------------------------------------------
1 | ## Usage
2 |
3 | ```js
4 | const parse = require('{%= name %}');
5 |
6 | // sync
7 | console.log(parse.sync());
8 |
9 | // using async/await
10 | (async () => console.log(await parse()))();
11 | ```
12 |
13 | ## Options
14 |
15 | ### cwd
16 |
17 | The starting directory to search from.
18 |
19 | **Type**: `string`
20 |
21 | **Default**: `process.cwd()` (current working directory)
22 |
23 |
24 | ### path
25 |
26 | Either the absolute path to .git `config`, or the path relative to the current working directory.
27 |
28 | **Type**: `string`
29 |
30 | **Default**: `.git/config`
31 |
32 |
33 | ### Examples config object
34 |
35 | Parsed config object will look something like:
36 |
37 | ```js
38 | { core:
39 | { repositoryformatversion: '0',
40 | filemode: true,
41 | bare: false,
42 | logallrefupdates: true,
43 | ignorecase: true,
44 | precomposeunicode: true },
45 | 'remote "origin"':
46 | { url: 'https://github.com/jonschlinkert/parse-git-config.git',
47 | fetch: '+refs/heads/*:refs/remotes/origin/*' },
48 | 'branch "master"': { remote: 'origin', merge: 'refs/heads/master', ... } }
49 | ```
50 |
51 | ## API
52 | {%= apidocs('index.js') %}
53 |
54 | ### .expandKeys examples
55 |
56 | Converts ini-style keys into objects:
57 |
58 | **Example 1**
59 |
60 | ```js
61 | const parse = require('parse-git-config');
62 | const config = {
63 | 'foo "bar"': { doStuff: true },
64 | 'foo "baz"': { doStuff: true }
65 | };
66 |
67 | console.log(parse.expandKeys(config));
68 | ```
69 |
70 | Results in:
71 |
72 | ```js
73 | {
74 | foo: {
75 | bar: { doStuff: true },
76 | baz: { doStuff: true }
77 | }
78 | }
79 | ```
80 |
81 | **Example 2**
82 |
83 | ```js
84 | const parse = require('parse-git-config');
85 | const config = {
86 | 'remote "origin"': {
87 | url: 'https://github.com/jonschlinkert/normalize-pkg.git',
88 | fetch: '+refs/heads/*:refs/remotes/origin/*'
89 | },
90 | 'branch "master"': {
91 | remote: 'origin',
92 | merge: 'refs/heads/master'
93 | },
94 | 'branch "dev"': {
95 | remote: 'origin',
96 | merge: 'refs/heads/dev',
97 | rebase: true
98 | }
99 | };
100 |
101 | console.log(parse.expandKeys(config));
102 | ```
103 |
104 | Results in:
105 |
106 | ```js
107 | {
108 | remote: {
109 | origin: {
110 | url: 'https://github.com/jonschlinkert/normalize-pkg.git',
111 | fetch: '+refs/heads/*:refs/remotes/origin/*'
112 | }
113 | },
114 | branch: {
115 | master: {
116 | remote: 'origin',
117 | merge: 'refs/heads/master'
118 | },
119 | dev: {
120 | remote: 'origin',
121 | merge: 'refs/heads/dev',
122 | rebase: true
123 | }
124 | }
125 | }
126 | ```
127 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015-present, Jon Schlinkert.
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # parse-git-config [](https://www.npmjs.com/package/parse-git-config) [](https://npmjs.org/package/parse-git-config) [](https://npmjs.org/package/parse-git-config) [](https://travis-ci.org/jonschlinkert/parse-git-config)
2 |
3 | > Parse `.git/config` into a JavaScript object. sync or async.
4 |
5 | Please consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support.
6 |
7 | ## Install
8 |
9 | Install with [npm](https://www.npmjs.com/):
10 |
11 | ```sh
12 | $ npm install --save parse-git-config
13 | ```
14 |
15 | ## Usage
16 |
17 | ```js
18 | const parse = require('parse-git-config');
19 |
20 | // sync
21 | console.log(parse.sync());
22 |
23 | // using async/await
24 | (async () => console.log(await parse()))();
25 | ```
26 |
27 | ## Options
28 |
29 | ### cwd
30 |
31 | The starting directory to search from.
32 |
33 | **Type**: `string`
34 |
35 | **Default**: `process.cwd()` (current working directory)
36 |
37 | ### path
38 |
39 | Either the absolute path to .git `config`, or the path relative to the current working directory.
40 |
41 | **Type**: `string`
42 |
43 | **Default**: `.git/config`
44 |
45 | ### Examples config object
46 |
47 | Parsed config object will look something like:
48 |
49 | ```js
50 | { core:
51 | { repositoryformatversion: '0',
52 | filemode: true,
53 | bare: false,
54 | logallrefupdates: true,
55 | ignorecase: true,
56 | precomposeunicode: true },
57 | 'remote "origin"':
58 | { url: 'https://github.com/jonschlinkert/parse-git-config.git',
59 | fetch: '+refs/heads/*:refs/remotes/origin/*' },
60 | 'branch "master"': { remote: 'origin', merge: 'refs/heads/master', ... } }
61 | ```
62 |
63 | ## API
64 |
65 | ### [parse](index.js#L42)
66 |
67 | Asynchronously parse a `.git/config` file. If only the callback is passed, the `.git/config` file relative to `process.cwd()` is used.
68 |
69 | **Params**
70 |
71 | * `options` **{Object|String|Function}**: Options with `cwd` or `path`, the cwd to use, or the callback function.
72 | * `callback` **{Function}**: callback function if the first argument is options or cwd.
73 | * `returns` **{Object}**
74 |
75 | **Example**
76 |
77 | ```js
78 | parse((err, config) => {
79 | if (err) throw err;
80 | // do stuff with config
81 | });
82 |
83 | // or, using async/await
84 | (async () => {
85 | console.log(await parse());
86 | console.log(await parse({ cwd: 'foo' }));
87 | console.log(await parse({ cwd: 'foo', path: 'some/.git/config' }));
88 | })();
89 | ```
90 |
91 | ### [.sync](index.js#L88)
92 |
93 | Synchronously parse a `.git/config` file. If no arguments are passed, the `.git/config` file relative to `process.cwd()` is used.
94 |
95 | **Params**
96 |
97 | * `options` **{Object|String}**: Options with `cwd` or `path`, or the cwd to use.
98 | * `returns` **{Object}**
99 |
100 | **Example**
101 |
102 | ```js
103 | console.log(parse.sync());
104 | console.log(parse.sync({ cwd: 'foo' }));
105 | console.log(parse.sync({ cwd: 'foo', path: 'some/.git/config' }));
106 | ```
107 |
108 | ### [.expandKeys](index.js#L134)
109 |
110 | Returns an object with only the properties that had ini-style keys converted to objects.
111 |
112 | **Params**
113 |
114 | * `config` **{Object}**: The parsed git config object.
115 | * `returns` **{Object}**
116 |
117 | **Example**
118 |
119 | ```js
120 | const config = parse.sync({ path: '/path/to/.gitconfig' });
121 | const obj = parse.expandKeys(config);
122 | ```
123 |
124 | ### .expandKeys examples
125 |
126 | Converts ini-style keys into objects:
127 |
128 | **Example 1**
129 |
130 | ```js
131 | const parse = require('parse-git-config');
132 | const config = {
133 | 'foo "bar"': { doStuff: true },
134 | 'foo "baz"': { doStuff: true }
135 | };
136 |
137 | console.log(parse.expandKeys(config));
138 | ```
139 |
140 | Results in:
141 |
142 | ```js
143 | {
144 | foo: {
145 | bar: { doStuff: true },
146 | baz: { doStuff: true }
147 | }
148 | }
149 | ```
150 |
151 | **Example 2**
152 |
153 | ```js
154 | const parse = require('parse-git-config');
155 | const config = {
156 | 'remote "origin"': {
157 | url: 'https://github.com/jonschlinkert/normalize-pkg.git',
158 | fetch: '+refs/heads/*:refs/remotes/origin/*'
159 | },
160 | 'branch "master"': {
161 | remote: 'origin',
162 | merge: 'refs/heads/master'
163 | },
164 | 'branch "dev"': {
165 | remote: 'origin',
166 | merge: 'refs/heads/dev',
167 | rebase: true
168 | }
169 | };
170 |
171 | console.log(parse.expandKeys(config));
172 | ```
173 |
174 | Results in:
175 |
176 | ```js
177 | {
178 | remote: {
179 | origin: {
180 | url: 'https://github.com/jonschlinkert/normalize-pkg.git',
181 | fetch: '+refs/heads/*:refs/remotes/origin/*'
182 | }
183 | },
184 | branch: {
185 | master: {
186 | remote: 'origin',
187 | merge: 'refs/heads/master'
188 | },
189 | dev: {
190 | remote: 'origin',
191 | merge: 'refs/heads/dev',
192 | rebase: true
193 | }
194 | }
195 | }
196 | ```
197 |
198 | ## About
199 |
200 |
201 | Contributing
202 |
203 | Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
204 |
205 |
206 |
207 |
208 | Running Tests
209 |
210 | Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:
211 |
212 | ```sh
213 | $ npm install && npm test
214 | ```
215 |
216 |
217 |
218 |
219 | Building docs
220 |
221 | _(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_
222 |
223 | To generate the readme, run the following command:
224 |
225 | ```sh
226 | $ npm install -g verbose/verb#dev verb-generate-readme && verb
227 | ```
228 |
229 |
230 |
231 | ### Related projects
232 |
233 | You might also be interested in these projects:
234 |
235 | * [git-user-name](https://www.npmjs.com/package/git-user-name): Get a user's name from git config at the project or global scope, depending on… [more](https://github.com/jonschlinkert/git-user-name) | [homepage](https://github.com/jonschlinkert/git-user-name "Get a user's name from git config at the project or global scope, depending on what git uses in the current context.")
236 | * [git-username](https://www.npmjs.com/package/git-username): Get the username (or 'owner' name) from a git/GitHub remote origin URL. | [homepage](https://github.com/jonschlinkert/git-username "Get the username (or 'owner' name) from a git/GitHub remote origin URL.")
237 | * [parse-author](https://www.npmjs.com/package/parse-author): Parse an author, contributor, maintainer or other 'person' string into an object with name, email… [more](https://github.com/jonschlinkert/parse-author) | [homepage](https://github.com/jonschlinkert/parse-author "Parse an author, contributor, maintainer or other 'person' string into an object with name, email and url properties following npm conventions.")
238 | * [parse-authors](https://www.npmjs.com/package/parse-authors): Parse a string into an array of objects with `name`, `email` and `url` properties following… [more](https://github.com/jonschlinkert/parse-authors) | [homepage](https://github.com/jonschlinkert/parse-authors "Parse a string into an array of objects with `name`, `email` and `url` properties following npm conventions. Useful for the `authors` property in package.json or for parsing an AUTHORS file into an array of authors objects.")
239 | * [parse-github-url](https://www.npmjs.com/package/parse-github-url): Parse a github URL into an object. | [homepage](https://github.com/jonschlinkert/parse-github-url "Parse a github URL into an object.")
240 | * [parse-gitignore](https://www.npmjs.com/package/parse-gitignore): Parse a .gitignore or .npmignore file into an array of patterns. | [homepage](https://github.com/jonschlinkert/parse-gitignore "Parse a .gitignore or .npmignore file into an array of patterns.")
241 |
242 | ### Contributors
243 |
244 | | **Commits** | **Contributor** |
245 | | --- | --- |
246 | | 66 | [jonschlinkert](https://github.com/jonschlinkert) |
247 | | 4 | [doowb](https://github.com/doowb) |
248 | | 1 | [daviwil](https://github.com/daviwil) |
249 | | 1 | [LexSwed](https://github.com/LexSwed) |
250 | | 1 | [sam3d](https://github.com/sam3d) |
251 | | 1 | [suarasaur](https://github.com/suarasaur) |
252 |
253 | ### Author
254 |
255 | **Jon Schlinkert**
256 |
257 | * [GitHub Profile](https://github.com/jonschlinkert)
258 | * [Twitter Profile](https://twitter.com/jonschlinkert)
259 | * [LinkedIn Profile](https://linkedin.com/in/jonschlinkert)
260 |
261 | ### License
262 |
263 | Copyright © 2018, [Jon Schlinkert](https://github.com/jonschlinkert).
264 | Released under the [MIT License](LICENSE).
265 |
266 | ***
267 |
268 | _This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on November 20, 2018._
--------------------------------------------------------------------------------
/example.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const parse = require('./');
4 | const gitconfig = {
5 | email: 'email',
6 | 'remote "origin"': {
7 | url: 'https://github.com/jonschlinkert/normalize-pkg.git',
8 | fetch: '+refs/heads/*:refs/remotes/origin/*'
9 | },
10 | 'branch "master"': {
11 | remote: 'origin', merge: 'refs/heads/master'
12 | },
13 | 'branch "dev"': {
14 | remote: 'origin', merge: 'refs/heads/dev', rebase: true
15 | }
16 | };
17 |
18 | const config = parse.expandKeys(gitconfig);
19 | console.log(config);
20 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * parse-git-config
3 | *
4 | * Copyright (c) 2015-present, Jon Schlinkert.
5 | * Released under the MIT License.
6 | */
7 |
8 | 'use strict';
9 |
10 | const fs = require('fs');
11 | const os = require('os');
12 | const path = require('path');
13 | const util = require('util');
14 | const ini = require('ini');
15 | const configPath = require('git-config-path');
16 | const expand = str => (str ? str.replace(/^~/, os.homedir()) : '');
17 |
18 | /**
19 | * Asynchronously parse a `.git/config` file. If only the callback is passed,
20 | * the `.git/config` file relative to `process.cwd()` is used.
21 | *
22 | * ```js
23 | * parse((err, config) => {
24 | * if (err) throw err;
25 | * // do stuff with config
26 | * });
27 | *
28 | * // or, using async/await
29 | * (async () => {
30 | * console.log(await parse());
31 | * console.log(await parse({ cwd: 'foo' }));
32 | * console.log(await parse({ cwd: 'foo', path: 'some/.git/config' }));
33 | * })();
34 | * ```
35 | * @name parse
36 | * @param {Object|String|Function} `options` Options with `cwd` or `path`, the cwd to use, or the callback function.
37 | * @param {Function} `callback` callback function if the first argument is options or cwd.
38 | * @return {Object}
39 | * @api public
40 | */
41 |
42 | const parse = (options, callback) => {
43 | if (typeof options === 'function') {
44 | callback = options;
45 | options = null;
46 | }
47 |
48 | if (typeof callback !== 'function') {
49 | return parse.promise(options);
50 | }
51 |
52 | return parse.promise(options)
53 | .then(config => callback(null, config))
54 | .catch(callback);
55 | };
56 |
57 | parse.promise = options => {
58 | let filepath = parse.resolveConfigPath(options);
59 | let read = util.promisify(fs.readFile);
60 | let stat = util.promisify(fs.stat);
61 | if (!filepath) return Promise.resolve(null);
62 |
63 | return stat(filepath)
64 | .then(() => read(filepath, 'utf8'))
65 | .then(str => {
66 | if (options && options.include === true) {
67 | str = injectInclude(str, path.resolve(path.dirname(filepath)));
68 | }
69 | return parseIni(str, options);
70 | });
71 | };
72 |
73 | /**
74 | * Synchronously parse a `.git/config` file. If no arguments are passed,
75 | * the `.git/config` file relative to `process.cwd()` is used.
76 | *
77 | * ```js
78 | * console.log(parse.sync());
79 | * console.log(parse.sync({ cwd: 'foo' }));
80 | * console.log(parse.sync({ cwd: 'foo', path: 'some/.git/config' }));
81 | * ```
82 | * @name .sync
83 | * @param {Object|String} `options` Options with `cwd` or `path`, or the cwd to use.
84 | * @return {Object}
85 | * @api public
86 | */
87 |
88 | parse.sync = options => {
89 | let filepath = parse.resolveConfigPath(options);
90 |
91 | if (filepath && fs.existsSync(filepath)) {
92 | let input = fs.readFileSync(filepath, 'utf8');
93 | if (options && options.include === true) {
94 | let cwd = path.resolve(path.dirname(filepath));
95 | input = injectInclude(input, cwd);
96 | }
97 | return parseIni(input, options);
98 | }
99 |
100 | return {};
101 | };
102 |
103 | /**
104 | * Resolve the git config path
105 | */
106 |
107 | parse.resolveConfigPath = options => {
108 | if (typeof options === 'string') options = { type: options };
109 | const opts = Object.assign({ cwd: process.cwd() }, options);
110 | const fp = opts.path ? expand(opts.path) : configPath(opts.type);
111 | return fp ? path.resolve(opts.cwd, fp) : null;
112 | };
113 |
114 | /**
115 | * Deprecated: use `.resolveConfigPath` instead
116 | */
117 |
118 | parse.resolve = options => parse.resolveConfigPath(options);
119 |
120 | /**
121 | * Returns an object with only the properties that had ini-style keys
122 | * converted to objects.
123 | *
124 | * ```js
125 | * const config = parse.sync({ path: '/path/to/.gitconfig' });
126 | * const obj = parse.expandKeys(config);
127 | * ```
128 | * @name .expandKeys
129 | * @param {Object} `config` The parsed git config object.
130 | * @return {Object}
131 | * @api public
132 | */
133 |
134 | parse.expandKeys = config => {
135 | for (let key of Object.keys(config)) {
136 | let m = /(\S+) "(.*)"/.exec(key);
137 | if (!m) continue;
138 | let prop = m[1];
139 | config[prop] = config[prop] || {};
140 | config[prop][m[2]] = config[key];
141 | delete config[key];
142 | }
143 | return config;
144 | };
145 |
146 | function parseIni(str, options) {
147 | let opts = Object.assign({}, options);
148 |
149 | str = str.replace(/\[(\S+) "(.*)"\]/g, (m, $1, $2) => {
150 | return $1 && $2 ? `[${$1} "${$2.split('.').join('\\.')}"]` : m;
151 | });
152 |
153 | let config = ini.parse(str);
154 | if (opts.expandKeys === true) {
155 | return parse.expandKeys(config);
156 | }
157 | return config;
158 | }
159 |
160 | function injectInclude(input, cwd) {
161 | let lines = input.split('\n').filter(line => line.trim() !== '');
162 | let len = lines.length;
163 | let res = [];
164 |
165 | for (let i = 0; i < len; i++) {
166 | let line = lines[i];
167 | if (line.indexOf('[include]') === 0) {
168 | let filepath = lines[i + 1].replace(/^\s*path\s*=\s*/, '');
169 | let fp = path.resolve(cwd, expand(filepath));
170 | res.push(fs.readFileSync(fp));
171 | } else {
172 | res.push(line);
173 | }
174 | }
175 | return res.join('\n');
176 | }
177 |
178 | /**
179 | * Expose `parse`
180 | */
181 |
182 | module.exports = parse;
183 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "parse-git-config",
3 | "description": "Parse `.git/config` into a JavaScript object. sync or async.",
4 | "version": "3.0.0",
5 | "homepage": "https://github.com/jonschlinkert/parse-git-config",
6 | "author": "Jon Schlinkert (https://github.com/jonschlinkert)",
7 | "contributors": [
8 | "j. suárez (http://suarez.systems)",
9 | "Jon Schlinkert (http://twitter.com/jonschlinkert)",
10 | "Sam Holmes (https://samholmes.net)"
11 | ],
12 | "repository": "jonschlinkert/parse-git-config",
13 | "bugs": {
14 | "url": "https://github.com/jonschlinkert/parse-git-config/issues"
15 | },
16 | "license": "MIT",
17 | "files": [
18 | "index.js"
19 | ],
20 | "main": "index.js",
21 | "engines": {
22 | "node": ">=8"
23 | },
24 | "scripts": {
25 | "test": "mocha"
26 | },
27 | "dependencies": {
28 | "git-config-path": "^2.0.0",
29 | "ini": "^1.3.5"
30 | },
31 | "devDependencies": {
32 | "gulp-format-md": "^2.0.0",
33 | "mocha": "^5.2.0"
34 | },
35 | "keywords": [
36 | "config",
37 | "git",
38 | "parse"
39 | ],
40 | "verb": {
41 | "run": true,
42 | "toc": false,
43 | "layout": "default",
44 | "tasks": [
45 | "readme"
46 | ],
47 | "plugins": [
48 | "gulp-format-md"
49 | ],
50 | "related": {
51 | "list": [
52 | "git-user-name",
53 | "git-username",
54 | "parse-author",
55 | "parse-authors",
56 | "parse-github-url",
57 | "parse-gitignore"
58 | ]
59 | },
60 | "lint": {
61 | "reflinks": true
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/test/expected/_gitconfig.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | user: {
3 | email: 'email',
4 | name: 'name',
5 | signingkey: 'https://help.github.com/articles/generating-a-new-gpg-key/'
6 | },
7 | github: {
8 | user: 'name',
9 | token: 'https://github.com/settings/tokens'
10 | },
11 | commit: {
12 | gpgsign: true
13 | },
14 | tag: {
15 | gpgsign: true,
16 | path: '_gitconfig.local',
17 | sort: 'version:refname'
18 | },
19 | core: {
20 | legacyheaders: false,
21 | quotepath: false,
22 | trustctime: false,
23 | precomposeunicode: false,
24 | pager: 'cat',
25 | logAllRefUpdates: true,
26 | excludesfile: '~/.gitignore'
27 | },
28 | repack: {
29 | usedeltabaseoffset: true
30 | },
31 | merge: {
32 | log: true,
33 | conflictstyle: 'diff3'
34 | },
35 | apply: {
36 | whitespace: 'fix'
37 | },
38 | help: {
39 | autocorrect: '1'
40 | },
41 | rerere: {
42 | enabled: true
43 | },
44 | color: {
45 | diff: 'auto',
46 | status: 'auto',
47 | branch: 'auto',
48 | interactive: 'auto',
49 | ui: 'always'
50 | },
51 | 'color "diff"': {
52 | meta: 'yellow bold',
53 | frag: 'magenta',
54 | plain: 'white bold',
55 | old: 'red bold',
56 | new: 'green bold',
57 | commit: 'yellow bold',
58 | func: 'green dim',
59 | whitespace: 'red reverse'
60 | },
61 | 'color "status"': {
62 | added: 'yellow',
63 | changed: 'green',
64 | untracked: 'cyan'
65 | },
66 | 'color "branch"': {
67 | current: 'yellow reverse',
68 | local: 'yellow',
69 | remote: 'green'
70 | },
71 | diff: {
72 | renames: 'copies',
73 | algorithm: 'patience',
74 | compactionHeuristic: true,
75 | wsErrorHighlight: 'all'
76 | },
77 | 'diff "bin"': {
78 | textconv: 'hexdump -v -C'
79 | },
80 | credential: {
81 | helper: 'store'
82 | },
83 | status: {
84 | relativePaths: true,
85 | showUntrackedFiles: 'no'
86 | },
87 | pull: {
88 | rebase: true
89 | },
90 | push: {
91 | default: 'current',
92 | followTags: true
93 | },
94 | alias: {
95 | a: 'commit --amend',
96 | c: 'commit -am',
97 | d: '!git diff --exit-code && git diff --cached',
98 | dif: 'diff',
99 | git: '!exec git',
100 | p: 'push -u',
101 | r: 'reset --soft HEAD~1',
102 | s: 'status',
103 | sc: 'clone --depth=1',
104 | l: 'log --graph --pretty=format:\'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset\' --abbrev-commit -n 15'
105 | },
106 | 'remote "origin"': {
107 | fetch: '+refs/tags/*:refs/tags/*'
108 | },
109 | branch: {
110 | autosetupmerge: 'always',
111 | autosetuprebase: 'always'
112 | },
113 | http: {
114 | sslverify: false
115 | },
116 | submodule: {
117 | fetchJobs: '0'
118 | },
119 | fetch: {
120 | prune: true
121 | }
122 | };
123 |
--------------------------------------------------------------------------------
/test/fixtures/_gitconfig:
--------------------------------------------------------------------------------
1 | [include]
2 | path = _gitconfig.local
3 | [core]
4 | legacyheaders = false
5 | quotepath = false
6 | trustctime = false
7 | precomposeunicode = false
8 | pager = cat
9 | logAllRefUpdates = true
10 | excludesfile = ~/.gitignore
11 | [repack]
12 | usedeltabaseoffset = true
13 | [merge]
14 | log = true
15 | conflictstyle = diff3
16 | [apply]
17 | whitespace = fix
18 | [help]
19 | autocorrect = 1
20 | [rerere]
21 | enabled = true
22 | [color]
23 | diff = auto
24 | status = auto
25 | branch = auto
26 | interactive = auto
27 | ui = always
28 | [color "diff"]
29 | meta = yellow bold
30 | frag = magenta
31 | plain = white bold
32 | old = red bold
33 | new = green bold
34 | commit = yellow bold
35 | func = green dim
36 | whitespace = red reverse
37 | [color "status"]
38 | added = yellow
39 | changed = green
40 | untracked = cyan
41 | [color "branch"]
42 | current = yellow reverse
43 | local = yellow
44 | remote = green
45 | [diff]
46 | renames = copies
47 | algorithm = patience
48 | compactionHeuristic = true
49 | wsErrorHighlight = all
50 | [diff "bin"]
51 | textconv = hexdump -v -C
52 | [credential]
53 | helper = store
54 | [status]
55 | relativePaths = true
56 | showUntrackedFiles = no
57 | [pull]
58 | rebase = true
59 | [push]
60 | default = current
61 | followTags = true
62 | [alias]
63 | a = commit --amend
64 | c = commit -am
65 | d = !git diff --exit-code && git diff --cached
66 | dif = diff
67 | git = !exec git
68 | p = push -u
69 | r = reset --soft HEAD~1
70 | s = status
71 | sc = clone --depth=1
72 | l = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit -n 15
73 | [remote "origin"]
74 | fetch = +refs/pr/*/head:refs/remotes/origin/pr/*
75 | fetch = +refs/tags/*:refs/tags/*
76 | [branch]
77 | autosetupmerge = always
78 | autosetuprebase = always
79 | [http]
80 | sslverify = false
81 | [submodule]
82 | fetchJobs = 0
83 | [fetch]
84 | prune = true
85 | [tag]
86 | sort = version:refname
87 |
--------------------------------------------------------------------------------
/test/fixtures/_gitconfig-branch:
--------------------------------------------------------------------------------
1 | [branch "2.0"]
2 | remote = origin
3 | merge = refs/heads/devel
4 |
5 | [branch "devel"]
6 | remote = origin
7 | merge = refs/heads/devel
8 |
9 | [branch "master"]
10 | remote = origin
11 | merge = refs/heads/devel
12 |
--------------------------------------------------------------------------------
/test/fixtures/_gitconfig.local:
--------------------------------------------------------------------------------
1 | [user]
2 | email = email
3 | name = name
4 | signingkey = https://help.github.com/articles/generating-a-new-gpg-key/
5 | [github]
6 | user = name
7 | token = https://github.com/settings/tokens
8 | [commit]
9 | gpgsign = true
10 | [tag]
11 | gpgsign = true
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('mocha');
4 | const isTravis = process.env.TRAVIS || process.env.CLI;
5 | const os = require('os');
6 | const assert = require('assert');
7 | const path = require('path');
8 | const parse = require('..');
9 |
10 | const cwd = (...args) => path.resolve(__dirname, ...args);
11 | const fixture = name => cwd('fixtures', name);
12 |
13 | describe('parse-git-config', function() {
14 | describe('async', function() {
15 | it('should return a promise when callback is not passed', function(cb) {
16 | parse({ path: fixture('_gitconfig') })
17 | .then(config => {
18 | assert(config.hasOwnProperty('core'));
19 | cb();
20 | })
21 | .catch(cb);
22 | });
23 |
24 | it('should parse .git/config', function(cb) {
25 | parse({ path: fixture('_gitconfig') }, function(err, config) {
26 | assert(!err);
27 | assert(config.hasOwnProperty('core'));
28 | cb();
29 | });
30 | });
31 |
32 | it('should expand keys in config', function(cb) {
33 | parse({ path: fixture('_gitconfig'), expandKeys: true })
34 | .then(config => {
35 | assert(config.hasOwnProperty('color'));
36 | assert(config.color.hasOwnProperty('diff'));
37 | cb();
38 | })
39 | .catch(cb);
40 | });
41 |
42 | it('should not expand dots in keys in config', function(cb) {
43 | parse({ path: fixture('_gitconfig-branch'), expandKeys: true })
44 | .then(config => {
45 | assert.deepEqual(Object.keys(config.branch), ['devel', 'master', '2.0']);
46 | cb();
47 | })
48 | .catch(cb);
49 | });
50 |
51 | it('should include other config sources', function(cb) {
52 | parse({ path: fixture('_gitconfig'), include: true }, function(err, config) {
53 | assert(!err);
54 | assert.deepEqual(config, require('./expected/_gitconfig.js'));
55 | cb();
56 | });
57 | });
58 |
59 | it('should throw an error when .git/config does not exist', function(cb) {
60 | parse({ path: 'foo' }, function(err, config) {
61 | assert(err instanceof Error);
62 | assert(/ENOENT.*parse-git-config/.test(err.message));
63 | cb();
64 | });
65 | });
66 | });
67 |
68 | describe('promise', function() {
69 | it('should return a promise', function(cb) {
70 | parse.promise({ path: fixture('_gitconfig') })
71 | .then(config => {
72 | assert(config.hasOwnProperty('core'));
73 | cb();
74 | });
75 | });
76 |
77 | it('should include other config sources', function() {
78 | return parse.promise({ path: fixture('_gitconfig'), include: true })
79 | .then(config => {
80 | assert.deepEqual(config, require('./expected/_gitconfig.js'));
81 | });
82 | });
83 | });
84 |
85 | describe('sync', function() {
86 | it('should return an object', function() {
87 | assert(parse.sync({path: fixture('_gitconfig') }).hasOwnProperty('core'));
88 | });
89 | });
90 |
91 | describe('.expandKeys', function() {
92 | it('should expand ini-style keys', function() {
93 | const config = {
94 | 'foo "bar"': { doStuff: true },
95 | 'foo "baz"': { doStuff: true }
96 | };
97 |
98 | assert.deepEqual(parse.expandKeys(config), {
99 | foo: {
100 | bar: { doStuff: true },
101 | baz: { doStuff: true }
102 | }
103 | });
104 | });
105 | });
106 |
107 | describe('resolve', function() {
108 | it('should resolve the git config in the cwd by default', function() {
109 | assert.equal(parse.resolve(), path.resolve(process.cwd(), '.git/config'));
110 | });
111 |
112 | it('should allow override path', function() {
113 | const fp = path.resolve(os.homedir(), '.gitconfig');
114 | assert.equal(parse.resolve({ path: fp }), fp);
115 | });
116 |
117 | it('should include other config sources', function() {
118 | const fp = path.join(__dirname, 'fixtures/_gitconfig');
119 | const actual = parse.sync({ path: fp, include: true });
120 | assert.deepEqual(actual, require('./expected/_gitconfig.js'));
121 | });
122 |
123 | it('should resolve relative path to cwd', function() {
124 | assert.equal(parse.resolve({ path: '.config' }), path.resolve(process.cwd(), '.config'));
125 | });
126 |
127 | it('should resolve relative path to the global git config when `global` is passed', function() {
128 | if (isTravis && os.platform() === 'darwin') return this.skip();
129 | assert.equal(parse.resolve('global'), path.resolve(os.homedir(), '.gitconfig'));
130 | });
131 |
132 | it('should allow override of cwd', function() {
133 | const actual = parse.resolve({ path: '.config', cwd: '/opt/config' });
134 | assert.equal(actual, path.resolve('/opt/config/.config'));
135 | });
136 | });
137 | });
138 |
--------------------------------------------------------------------------------