From 636874f2b912d5a118d6f9c0752512d694a272b9 Mon Sep 17 00:00:00 2001 From: andrei Date: Tue, 31 Oct 2023 21:28:57 +0300 Subject: [PATCH] feat(configLoader): added fully compatible cosmiconfig support Added fully compatible cosmiconfig support with BOM and encoding checks. Added json5 config format parser. Added tests. Some minor code style changes; Closes: #773 --- .gitignore | 3 +- package-lock.json | 257 ++++++----- package.json | 2 + src/commitizen/configLoader.js | 11 +- src/configLoader/cosmiconfigLoader.js | 81 ++++ src/configLoader/findContent.js | 50 +++ src/configLoader/findup.js | 12 +- src/configLoader/getContent.js | 102 ++--- src/configLoader/getNormalizedConfig.js | 11 +- src/configLoader/loader.js | 74 ++-- test/tests/configLoaderCosmiconfig.js | 562 ++++++++++++++++++++++++ test/tests/index.js | 1 + 12 files changed, 940 insertions(+), 226 deletions(-) create mode 100644 src/configLoader/cosmiconfigLoader.js create mode 100644 src/configLoader/findContent.js create mode 100644 test/tests/configLoaderCosmiconfig.js diff --git a/.gitignore b/.gitignore index 8673768e..d0bc5a27 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ artifacts/ npm-debug.log .nyc_output test/tools/trigger-appveyor-tests.sh -logo/*.png \ No newline at end of file +logo/*.png +.idea diff --git a/package-lock.json b/package-lock.json index df11f2d1..f14c61a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "cachedir": "2.3.0", + "cosmiconfig": "8.3.6", "cz-conventional-changelog": "3.3.0", "dedent": "0.7.0", "detect-indent": "6.1.0", @@ -19,6 +20,7 @@ "glob": "7.2.3", "inquirer": "8.2.5", "is-utf8": "^0.2.1", + "json5": "2.2.3", "lodash": "4.17.21", "minimist": "1.2.7", "strip-bom": "4.0.0", @@ -134,7 +136,6 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "devOptional": true, "dependencies": { "@babel/highlight": "^7.18.6" }, @@ -558,7 +559,6 @@ "version": "7.19.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "devOptional": true, "engines": { "node": ">=6.9.0" } @@ -605,7 +605,6 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "devOptional": true, "dependencies": { "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", @@ -2014,15 +2013,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@commitlint/load/node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "optional": true, - "engines": { - "node": ">=8" - } - }, "node_modules/@commitlint/load/node_modules/supports-color": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", @@ -3250,7 +3240,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "devOptional": true, "engines": { "node": ">=6" } @@ -4033,26 +4022,50 @@ "dev": true }, "node_modules/cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", - "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", - "dev": true, + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/cosmiconfig/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, "node_modules/cosmiconfig/node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -4066,15 +4079,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cosmiconfig/node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -4352,15 +4356,6 @@ "node": ">=8" } }, - "node_modules/dir-glob/node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", @@ -4478,7 +4473,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "devOptional": true, "dependencies": { "is-arrayish": "^0.2.1" } @@ -5458,7 +5452,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -5474,7 +5467,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "engines": { "node": ">=4" } @@ -5807,8 +5799,7 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "devOptional": true + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, "node_modules/is-buffer": { "version": "1.1.6", @@ -6266,8 +6257,7 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "devOptional": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { "version": "3.14.0", @@ -6303,8 +6293,7 @@ "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-stringify-safe": { "version": "5.0.1", @@ -6313,10 +6302,9 @@ "dev": true }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true, + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" }, @@ -6375,8 +6363,7 @@ "node_modules/lines-and-columns": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "devOptional": true + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "node_modules/load-json-file": { "version": "4.0.0", @@ -10683,7 +10670,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "devOptional": true, "dependencies": { "callsites": "^3.0.0" }, @@ -10759,6 +10745,14 @@ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, "node_modules/pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", @@ -11523,6 +11517,22 @@ "node": ">=14.17" } }, + "node_modules/semantic-release/node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/semantic-release/node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -11585,6 +11595,24 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/semantic-release/node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/semver": { "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", @@ -12881,7 +12909,6 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "devOptional": true, "requires": { "@babel/highlight": "^7.18.6" } @@ -13194,8 +13221,7 @@ "@babel/helper-validator-identifier": { "version": "7.19.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "devOptional": true + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" }, "@babel/helper-validator-option": { "version": "7.18.6", @@ -13230,7 +13256,6 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "devOptional": true, "requires": { "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", @@ -14202,12 +14227,6 @@ "lines-and-columns": "^1.1.6" } }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "optional": true - }, "supports-color": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", @@ -15166,8 +15185,7 @@ "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "devOptional": true + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, "camelcase": { "version": "5.3.1", @@ -15761,35 +15779,39 @@ "dev": true }, "cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", - "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", - "dev": true, + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" }, "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, "parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "requires": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true } } }, @@ -16005,14 +16027,6 @@ "dev": true, "requires": { "path-type": "^4.0.0" - }, - "dependencies": { - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - } } }, "duplexer2": { @@ -16107,7 +16121,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "devOptional": true, "requires": { "is-arrayish": "^0.2.1" } @@ -16866,7 +16879,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -16875,8 +16887,7 @@ "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" } } }, @@ -17113,8 +17124,7 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "devOptional": true + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, "is-buffer": { "version": "1.1.6", @@ -17459,8 +17469,7 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "devOptional": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { "version": "3.14.0", @@ -17487,8 +17496,7 @@ "json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "json-stringify-safe": { "version": "5.0.1", @@ -17497,10 +17505,9 @@ "dev": true }, "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" }, "jsonfile": { "version": "4.0.0", @@ -17541,8 +17548,7 @@ "lines-and-columns": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "devOptional": true + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "load-json-file": { "version": "4.0.0", @@ -20649,7 +20655,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "devOptional": true, "requires": { "callsites": "^3.0.0" } @@ -20709,6 +20714,11 @@ } } }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + }, "pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", @@ -21289,6 +21299,19 @@ "integrity": "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==", "dev": true }, + "cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -21327,6 +21350,18 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } } } }, diff --git a/package.json b/package.json index ee1778fb..f165ea54 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ }, "dependencies": { "cachedir": "2.3.0", + "cosmiconfig": "8.3.6", "cz-conventional-changelog": "3.3.0", "dedent": "0.7.0", "detect-indent": "6.1.0", @@ -83,6 +84,7 @@ "glob": "7.2.3", "inquirer": "8.2.5", "is-utf8": "^0.2.1", + "json5": "2.2.3", "lodash": "4.17.21", "minimist": "1.2.7", "strip-bom": "4.0.0", diff --git a/src/commitizen/configLoader.js b/src/commitizen/configLoader.js index 02355d78..c190cdee 100644 --- a/src/commitizen/configLoader.js +++ b/src/commitizen/configLoader.js @@ -2,9 +2,12 @@ import { loader } from '../configLoader'; export { load }; -// Configuration sources in priority order. -var configs = ['.czrc', '.cz.json', 'package.json']; - +/** + * Get content of the configuration file + * @param {string} [config] - partial path to configuration file + * @param {string} [cwd] - directory path which will be joined with config argument + * @return {Object|undefined} + */ function load (config, cwd) { - return loader(configs, config, cwd); + return loader(config, cwd); } diff --git a/src/configLoader/cosmiconfigLoader.js b/src/configLoader/cosmiconfigLoader.js new file mode 100644 index 00000000..80bf6cf6 --- /dev/null +++ b/src/configLoader/cosmiconfigLoader.js @@ -0,0 +1,81 @@ +import { cosmiconfigSync, defaultLoadersSync } from 'cosmiconfig'; +import JSON5 from 'json5'; +import stripBom from 'strip-bom'; +import isUTF8 from "is-utf8"; + +const moduleName = 'cz'; +const fullModuleName = 'commitizen'; + +const searchPlaces = [ + `.${moduleName}rc`, // .czrc + `.${moduleName}rc.json`, + `.${moduleName}rc.json5`, + `.${moduleName}rc.yaml`, + `.${moduleName}rc.yml`, + `.${moduleName}rc.js`, + `.${moduleName}rc.cjs`, + `.${moduleName}rc.ts`, + `.config/${moduleName}rc`, + `.config/${moduleName}rc.json`, + `.config/${moduleName}rc.json5`, + `.config/${moduleName}rc.yaml`, + `.config/${moduleName}rc.yml`, + `.config/${moduleName}rc.js`, + `.config/${moduleName}rc.ts`, + `.config/${moduleName}rc.cjs`, + `${moduleName}.config.js`, + `${moduleName}.config.ts`, + `${moduleName}.config.cjs`, + `.${moduleName}.json`, // .cz.json + `.${moduleName}.json5`, + 'package.json', +]; + +function withSafeContentLoader(loader) { + return function (filePath, content) { + if (!isUTF8(Buffer.from(content, 'utf8'))) { + throw new Error(`The config file at "${filePath}" contains invalid charset, expect utf8`); + } + return loader(filePath, stripBom(content)); + } +} + +function json5Loader(filePath, content) { + try { + return JSON5.parse(content) || null; + } catch (err) { + err.message = `Error parsing json at ${filePath}:\n${err.message}`; + throw err; + } +} + +// no '.ts': withSafeContentLoader(defaultLoadersSync['.ts']), +const loaders = { + '.cjs': withSafeContentLoader(defaultLoadersSync['.js']), + '.js': withSafeContentLoader(defaultLoadersSync['.js']), + '.yml': withSafeContentLoader(defaultLoadersSync['.yaml']), + '.json': withSafeContentLoader(json5Loader), + '.json5': withSafeContentLoader(json5Loader), + '.yaml': withSafeContentLoader(defaultLoadersSync['.yaml']), + '.ts': withSafeContentLoader(defaultLoadersSync['.ts']), + noExt: withSafeContentLoader(json5Loader) +} + +const defaultConfigExplorer = cosmiconfigSync(moduleName, { + packageProp: ['configs', fullModuleName], + searchPlaces: searchPlaces, + loaders: loaders, + cache: false, +}); + +/** + * @deprecated + */ +const deprecatedConfigExplorerFallback = cosmiconfigSync(moduleName, { + packageProp: ['czConfig'], + searchPlaces: ['package.json'], + loaders: loaders, + cache: false, +}); + +export { searchPlaces, moduleName, defaultConfigExplorer, deprecatedConfigExplorerFallback }; diff --git a/src/configLoader/findContent.js b/src/configLoader/findContent.js new file mode 100644 index 00000000..d7c95fd8 --- /dev/null +++ b/src/configLoader/findContent.js @@ -0,0 +1,50 @@ +import { defaultConfigExplorer, deprecatedConfigExplorerFallback } from "./cosmiconfigLoader"; +import { isInTest } from "../common/util"; + +export default findConfigContent; +/** + * Find content of the configuration file + * @param {String} cwd - partial path to configuration file + * @return {Object|undefined} + */ +function findConfigContent(cwd) { + const maybeConfig = defaultConfigExplorer.search(cwd); + if (maybeConfig) { + return maybeConfig.config + } else { + const deprecatedConfig = findOldCzConfig(cwd); + if (deprecatedConfig) { + return deprecatedConfig + } + } + + return undefined; +} + +/** + * find old czConfig + * + * @deprecated + * @param {string} [searchFrom] + * @return {Object|undefined} + */ +function findOldCzConfig(searchFrom) { + const maybeDeprecatedConfig = deprecatedConfigExplorerFallback.search(searchFrom); + if (maybeDeprecatedConfig) { + showOldCzConfigDeprecationWarning(); + return maybeDeprecatedConfig.config; + } + + return undefined; +} + +/** + * @deprecated + * @return void + */ +function showOldCzConfigDeprecationWarning() { + // Suppress during test + if (!isInTest()) { + console.error("\n********\nWARNING: This repository's package.json is using czConfig. czConfig will be deprecated in Commitizen 3. \nPlease use this instead:\n{\n \"config\": {\n \"commitizen\": {\n \"path\": \"./path/to/adapter\"\n }\n }\n}\nFor more information, see: http://commitizen.github.io/cz-cli/\n********\n"); + } +} diff --git a/src/configLoader/findup.js b/src/configLoader/findup.js index e79a61a2..ed20b47a 100644 --- a/src/configLoader/findup.js +++ b/src/configLoader/findup.js @@ -3,8 +3,16 @@ import glob from 'glob'; export default findup; -// Before, "findup-sync" package was used, -// but it does not provide filter callback +/** + * Before, "findup-sync" package was used, + * but it does not provide filter callback + * + * @param {string[]} patterns + * @param {Object} options + * @param {string} options.cwd + * @param {(baseName: string) => boolean} fn + * @return {string} + */ function findup (patterns, options, fn) { /* jshint -W083 */ diff --git a/src/configLoader/getContent.js b/src/configLoader/getContent.js index 08918031..385d2595 100644 --- a/src/configLoader/getContent.js +++ b/src/configLoader/getContent.js @@ -1,82 +1,60 @@ -import fs from 'fs'; import path from 'path'; -import stripJSONComments from 'strip-json-comments'; -import isUTF8 from 'is-utf8'; -import stripBom from 'strip-bom'; - -import { getNormalizedConfig } from '../configLoader'; +import { defaultConfigExplorer, deprecatedConfigExplorerFallback } from "./cosmiconfigLoader"; +import { isInTest } from "../common/util"; export default getConfigContent; -/** - * Read the content of a configuration file - * - if not js or json: strip any comments - * - if js or json: require it - * @param {String} configPath - full path to configuration file - * @return {Object} - */ -function readConfigContent (configPath) { - const parsedPath = path.parse(configPath) - const isRcFile = parsedPath.ext !== '.js' && parsedPath.ext !== '.json'; - const jsonString = readConfigFileContent(configPath); - const parse = isRcFile ? - (contents) => JSON.parse(stripJSONComments(contents)) : - (contents) => JSON.parse(contents); - - try { - const parsed = parse(jsonString); - - Object.defineProperty(parsed, 'configPath', { - value: configPath - }); - - return parsed; - } catch (error) { - error.message = [ - `Parsing JSON at ${configPath} for commitizen config failed:`, - error.mesasge - ].join('\n'); - - throw error; - } -} - /** * Get content of the configuration file - * @param {String} configPath - partial path to configuration file - * @param {String} directory - directory path which will be joined with config argument - * @return {Object} + * @param {String} [configPath] - partial path to configuration file + * @param {String} [baseDirectory] - directory path which will be joined with config argument + * @return {Object|undefined} */ function getConfigContent (configPath, baseDirectory) { - if (!configPath) { - return; - } + if (!configPath) { + return; + } - const resolvedPath = path.resolve(baseDirectory, configPath); - const configBasename = path.basename(resolvedPath); + const resolvedPath = path.resolve(baseDirectory, configPath); - if (!fs.existsSync(resolvedPath)) { - return getNormalizedConfig(resolvedPath); + const maybeConfig = defaultConfigExplorer.load(resolvedPath); + if (maybeConfig) { + return maybeConfig.config + } else { + const deprecatedConfig = loadOldCzConfig(resolvedPath); + if (deprecatedConfig) { + return deprecatedConfig } + } - const content = readConfigContent(resolvedPath); - return getNormalizedConfig(configBasename, content); -}; + return undefined; +} /** - * Read proper content from config file. - * If the chartset of the config file is not utf-8, one error will be thrown. - * @param {String} configPath - * @return {String} + * load old czConfig from known place + * + * @deprecated + * @param {string} [fullPath] + * @return {Object|undefined} */ -function readConfigFileContent (configPath) { +function loadOldCzConfig(fullPath) { + const maybeDeprecatedConfig = deprecatedConfigExplorerFallback.load(fullPath); + if (maybeDeprecatedConfig) { + showOldCzConfigDeprecationWarning(); + return maybeDeprecatedConfig.config; + } - let rawBufContent = fs.readFileSync(configPath); + return undefined; +} - if (!isUTF8(rawBufContent)) { - throw new Error(`The config file at "${configPath}" contains invalid charset, expect utf8`); +/** + * @deprecated + * @return void + */ +function showOldCzConfigDeprecationWarning() { + // Suppress during test + if (!isInTest()) { + console.error("\n********\nWARNING: This repository's package.json is using czConfig. czConfig will be deprecated in Commitizen 3. \nPlease use this instead:\n{\n \"config\": {\n \"commitizen\": {\n \"path\": \"./path/to/adapter\"\n }\n }\n}\nFor more information, see: http://commitizen.github.io/cz-cli/\n********\n"); } - - return stripBom(rawBufContent.toString("utf8")); } diff --git a/src/configLoader/getNormalizedConfig.js b/src/configLoader/getNormalizedConfig.js index e5588146..72663475 100644 --- a/src/configLoader/getNormalizedConfig.js +++ b/src/configLoader/getNormalizedConfig.js @@ -1,10 +1,13 @@ export default getNormalizedConfig; -// Given a config and content, plucks the actual -// settings that we're interested in -function getNormalizedConfig (config, content) { +/** + * @deprecated no need this function with cosmiconfig. + * + * Given a config and content, plucks the actual settings that we're interested in + */ +function getNormalizedConfig (baseName, content) { - if (content && (config === 'package.json')) { + if (content && (baseName === 'package.json')) { // PACKAGE.JSON diff --git a/src/configLoader/loader.js b/src/configLoader/loader.js index e4472d8e..996d51aa 100644 --- a/src/configLoader/loader.js +++ b/src/configLoader/loader.js @@ -1,7 +1,6 @@ -import path from 'path'; - -import { findup, getContent } from '../configLoader'; import { isInTest } from '../common/util.js'; +import getConfigContent from "./getContent"; +import findConfigContent from "./findContent"; export default loader; @@ -13,48 +12,39 @@ export default loader; /** * Get content of the configuration file - * @param {String} config - partial path to configuration file - * @param {String} [cwd = process.cwd()] - directory path which will be joined with config argument + * @param {string} [config] - partial path to configuration file + * @param {string} [cwd = process.cwd()] - directory path which will be joined with config argument * @return {Object|undefined} */ -function loader (configs, config, cwd) { - var content; - var directory = cwd || process.cwd(); - - // If config option is given, attempt to load it - if (config) { - return getContent(config, directory); - } - - content = getContent( - findup(configs, { nocase: true, cwd: directory }, function (configPath) { - if (path.basename(configPath) === 'package.json') { - // return !!this.getContent(configPath); - } - - return true; - }) - ); +function loader(config, cwd = process.cwd()) { + // If config option is given, attempt to load it + if (config) { + return getConfigContent(config, cwd); + } + + const content = findConfigContent(cwd) + + if (content) { + return content; + } + + /* istanbul ignore if */ + if (!isInTest()) { + // Try to load standard configs from home dir + const directoryArr = [process.env.USERPROFILE, process.env.HOMEPATH, process.env.HOME]; + for (let i = 0; i < directoryArr.length; i++) { + const currentDirectory = directoryArr[i]; + + if (!currentDirectory) { + continue; + } - if (content) { - return content; - } - /* istanbul ignore if */ - if (!isInTest()) { - // Try to load standard configs from home dir - var directoryArr = [process.env.USERPROFILE, process.env.HOMEPATH, process.env.HOME]; - for (var i = 0, dirLen = directoryArr.length; i < dirLen; i++) { - if (!directoryArr[i]) { - continue; - } - - for (var j = 0, len = configs.length; j < len; j++) { - content = getContent(configs[j], directoryArr[i]); - - if (content) { - return content; - } - } + const backupContent = findConfigContent(currentDirectory); + if (backupContent) { + return backupContent; } } + } + + return undefined; } diff --git a/test/tests/configLoaderCosmiconfig.js b/test/tests/configLoaderCosmiconfig.js new file mode 100644 index 00000000..acd089a0 --- /dev/null +++ b/test/tests/configLoaderCosmiconfig.js @@ -0,0 +1,562 @@ +import { expect } from 'chai'; +import { loader } from "../../src/configLoader"; +import fs from 'fs'; +import path from 'path'; + +// Bootstrap our tester +import { bootstrap } from '../tester'; + + +let { config, repo, clean, files } = bootstrap(); +let { writeFilesToPath } = files; + +const defaultConfigString = `{ + // this is json5 format + path: 'cz-conventional-changelog' +}` + +const defaultConfigObj = { + path: 'cz-conventional-changelog' +}; + +before(function () { + // Creates the temp path + clean.before(config.paths.tmp); +}); + +beforeEach(function () { + this.timeout(config.maxTimeout); // this could take a while + /* istanbul ignore next */ + repo.createEndUser(config.paths.endUserRepo); +}); + +afterEach(function () { + this.timeout(config.maxTimeout); // this could take a while + // All this should do is archive the tmp path to the artifacts + clean.afterEach(config.paths.tmp, config.preserve); +}); + +after(function () { + this.timeout(config.maxTimeout); // this could take a while + // Once everything is done, the artifacts should be cleaned up based on + // the preserve setting in the config + clean.after(config.paths.tmp, config.preserve); +}); + +describe('configLoader cosmiconfig', function () { + it('should load .czrc json5 format', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrc: { + contents: defaultConfigString, + filename: `.czrc`, + }, + } + }; + writeFilesToPath(repoConfig.files, repoConfig.path); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + it('should load .czrc.json json5 format', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrc: { + contents: defaultConfigString, + filename: `.czrc.json`, + }, + } + }; + writeFilesToPath(repoConfig.files, repoConfig.path); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + it('should load .czrc.json5 json5 format', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrc: { + contents: defaultConfigString, + filename: `.czrc.json5`, + }, + } + }; + writeFilesToPath(repoConfig.files, repoConfig.path); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + it('should load package.json format', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + packagejson: { + contents: `{ + "configs": { + "commitizen": { + "path": "cz-conventional-changelog" + } + } + }`, + filename: `package.json`, + }, + } + }; + writeFilesToPath(repoConfig.files, repoConfig.path); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + it('should load package.json format deprecated czConfig', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + packagejson: { + contents: `{ + "czConfig": { + "path": "cz-conventional-changelog" + } + }`, + filename: `package.json`, + }, + } + }; + writeFilesToPath(repoConfig.files, repoConfig.path); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + it('should load .cz.json config', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czjson: { + contents: defaultConfigString, + filename: `.cz.json`, + }, + } + }; + writeFilesToPath(repoConfig.files, repoConfig.path); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + it('should load .czrc.js config', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrcjs: { + contents: ` + module.exports = { + path: "cz-conventional-changelog", + }; + `, + filename: `.czrc.js`, + }, + } + }; + writeFilesToPath(repoConfig.files, repoConfig.path); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + it('should load .czrc.yaml config', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrcyaml: { + contents: ` + path: cz-conventional-changelog + `, + filename: `.czrc.yaml`, + }, + } + }; + writeFilesToPath(repoConfig.files, repoConfig.path); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + it('should load .czrc.yml config', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrcyml: { + contents: ` + path: 'cz-conventional-changelog' + `, + filename: `.czrc.yml`, + }, + } + }; + writeFilesToPath(repoConfig.files, repoConfig.path); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + // because haven't typescript + it.skip('should load .czrc.ts config', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrcts: { + contents: ` + type Config = { + path: string; + } + + const cfg: Config = { + path: 'cz-conventional-changelog', + }; + + module.exports = cfg; + `, + filename: `.czrc.ts`, + }, + } + }; + writeFilesToPath(repoConfig.files, repoConfig.path); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + it('should load .config/czrc json5 format', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrc: { + contents: defaultConfigString, + filename: `czrc`, + }, + } + }; + const dir = path.join(repoConfig.path, '.config'); + + fs.mkdirSync(dir); + writeFilesToPath(repoConfig.files, dir); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + it('should load .config/czrc.json json5 format', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrc: { + contents: defaultConfigString, + filename: `czrc.json`, + }, + } + }; + const dir = path.join(repoConfig.path, '.config'); + + fs.mkdirSync(dir); + writeFilesToPath(repoConfig.files, dir); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + it('should load .config/czrc.json5 json5 format', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrc: { + contents: defaultConfigString, + filename: `czrc.json5`, + }, + } + }; + const dir = path.join(repoConfig.path, '.config'); + + fs.mkdirSync(dir); + writeFilesToPath(repoConfig.files, dir); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + it('should load .config/czrc.yaml format', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrc: { + contents: ` + path: 'cz-conventional-changelog' + `, + filename: `czrc.yaml`, + }, + } + }; + const dir = path.join(repoConfig.path, '.config'); + + fs.mkdirSync(dir); + writeFilesToPath(repoConfig.files, dir); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + it('should load .config/czrc.yml format', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrc: { + contents: ` + path: 'cz-conventional-changelog' + `, + filename: `czrc.yml`, + }, + } + }; + const dir = path.join(repoConfig.path, '.config'); + + fs.mkdirSync(dir); + writeFilesToPath(repoConfig.files, dir); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + it('should load .config/czrc.js format', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrc: { + contents: ` + module.exports = { + path: "cz-conventional-changelog", + }; + `, + filename: `czrc.js`, + }, + } + }; + const dir = path.join(repoConfig.path, '.config'); + + fs.mkdirSync(dir); + writeFilesToPath(repoConfig.files, dir); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + // because haven't typescript + it.skip('should load .config/czrc.ts format', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrc: { + contents: ` + type Config = { + path: string; + } + + const cfg: Config = { + path: 'cz-conventional-changelog', + }; + + module.exports = cfg; + `, + filename: `czrc.ts`, + }, + } + }; + const dir = path.join(repoConfig.path, '.config'); + + fs.mkdirSync(dir); + writeFilesToPath(repoConfig.files, dir); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + it('should load any config by given name and path', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrcjs: { + contents: ` + module.exports = { + path: "cz-conventional-changelog", + }; + `, + filename: `.czrc.js`, + }, + } + }; + writeFilesToPath(repoConfig.files, repoConfig.path); + expect(loader(`.czrc.js`, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + describe('files with BOM', function () { + it('should load .czrc.json json5 format BOM', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrc: { + contents: `\ufeff{ + // this is json5 format + path: 'cz-conventional-changelog' +}`, + filename: `.czrc.json`, + }, + } + }; + writeFilesToPath(repoConfig.files, repoConfig.path); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + // can have BOM? + it.skip('should load package.json format BOM', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + packagejson: { + contents: `\ufeff{ + "configs": { + "commitizen": { + "path": "cz-conventional-changelog" + } + } + }`, + filename: `package.json`, + }, + } + }; + writeFilesToPath(repoConfig.files, repoConfig.path); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + it('should load .czrc.js config BOM', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrcjs: { + contents: `\ufeff + module.exports = { + path: "cz-conventional-changelog", + }; + `, + filename: `.czrc.js`, + }, + } + }; + writeFilesToPath(repoConfig.files, repoConfig.path); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + it('should load .czrc.yaml config BOM', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrcyaml: { + contents: `\ufeff + path: cz-conventional-changelog + `, + filename: `.czrc.yaml`, + }, + } + }; + writeFilesToPath(repoConfig.files, repoConfig.path); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + it('should load .czrc.yml config BOM', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrcyml: { + contents: `\ufeff + path: 'cz-conventional-changelog' + `, + filename: `.czrc.yml`, + }, + } + }; + writeFilesToPath(repoConfig.files, repoConfig.path); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + + // because haven't typescript + it.skip('should load .czrc.ts config BOM', function () { + const repoConfig = { + path: config.paths.endUserRepo, + files: { + czrcts: { + contents: `\ufeff + type Config = { + path: string; + } + + const cfg: Config = { + path: 'cz-conventional-changelog', + }; + + module.exports = cfg; + `, + filename: `.czrc.ts`, + }, + } + }; + writeFilesToPath(repoConfig.files, repoConfig.path); + expect(loader(undefined, repoConfig.path)).deep.equal(defaultConfigObj); + }); + }); + + describe('non utf8 files', function () { + it('should throw .czrc.json json5 non utf8', function () { + const repoConfig = { + path: config.paths.endUserRepo, + }; + + const file = { + contents: `{ + // this is json5 format + path: 'cz-conventional-changelog' + }`, + filename: `.czrc.json`, + }; + + fs.writeFileSync(path.resolve(repoConfig.path, file.filename), file.contents, { encoding: "utf16le" }) + expect(() => loader(undefined, repoConfig.path)).to.throw(/invalid charset/i); + }); + + it('should throw .czrc.js config non utf8', function () { + const repoConfig = { + path: config.paths.endUserRepo, + }; + const file = { + contents: `\ufeff + module.exports = { + path: "cz-conventional-changelog", + }; + `, + filename: `.czrc.js`, + } + fs.writeFileSync(path.resolve(repoConfig.path, file.filename), file.contents, { encoding: "utf16le" }) + expect(() => loader(undefined, repoConfig.path)).to.throw(/invalid charset/i); + }); + + it('should throw .czrc.yaml config non utf8', function () { + const repoConfig = { + path: config.paths.endUserRepo, + }; + + const file = { + contents: `\ufeff + path: cz-conventional-changelog + `, + filename: `.czrc.yaml`, + }; + + fs.writeFileSync(path.resolve(repoConfig.path, file.filename), file.contents, { encoding: "utf16le" }) + expect(() => loader(undefined, repoConfig.path)).to.throw(/invalid charset/i); + }); + + // because haven't typescript + it.skip('should throw .czrc.ts config non utf8', function () { + const repoConfig = { + path: config.paths.endUserRepo, + }; + + const file = { + contents: `\ufeff + type Config = { + path: string; + } + + const cfg: Config = { + path: 'cz-conventional-changelog', + }; + + module.exports = cfg; + `, + filename: `.czrc.ts`, + }; + + fs.writeFileSync(path.resolve(repoConfig.path, file.filename), file.contents, { encoding: "utf16le" }) + expect(() => loader(undefined, repoConfig.path)).to.throw(/invalid charset/i); + }); + }); +}); diff --git a/test/tests/index.js b/test/tests/index.js index 146478c4..2bd8c430 100644 --- a/test/tests/index.js +++ b/test/tests/index.js @@ -6,3 +6,4 @@ import './init'; import './parsers'; import './staging'; import './util'; +import './configLoaderCosmiconfig';