zarro 1.92.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/LICENSE +10 -0
  2. package/README.md +260 -0
  3. package/gulp-tasks/.editorconfig +8 -0
  4. package/gulp-tasks/.git +1 -0
  5. package/gulp-tasks/.gitignore +9 -0
  6. package/gulp-tasks/.gitmodules +0 -0
  7. package/gulp-tasks/LICENSE +24 -0
  8. package/gulp-tasks/README.md +144 -0
  9. package/gulp-tasks/build.js +135 -0
  10. package/gulp-tasks/clean.js +37 -0
  11. package/gulp-tasks/cover-dotnet.js +56 -0
  12. package/gulp-tasks/default-report-generator.js +51 -0
  13. package/gulp-tasks/default-tools-installer.js +33 -0
  14. package/gulp-tasks/default.js +17 -0
  15. package/gulp-tasks/dotnet-publish.js +23 -0
  16. package/gulp-tasks/generate-reports.js +7 -0
  17. package/gulp-tasks/get-local-nuget.js +16 -0
  18. package/gulp-tasks/git-submodules.js +83 -0
  19. package/gulp-tasks/increment-package-json-version.js +12 -0
  20. package/gulp-tasks/increment-package-json-version.ts +17 -0
  21. package/gulp-tasks/install-tools.js +24 -0
  22. package/gulp-tasks/modules/add-stream-on-any-handler.js +31 -0
  23. package/gulp-tasks/modules/alter-package-json-version.js +64 -0
  24. package/gulp-tasks/modules/alter-package-json-version.ts +113 -0
  25. package/gulp-tasks/modules/are-all-dotnet-core.js +96 -0
  26. package/gulp-tasks/modules/ask.js +31 -0
  27. package/gulp-tasks/modules/ask.ts +41 -0
  28. package/gulp-tasks/modules/collect-files.js +15 -0
  29. package/gulp-tasks/modules/collect-files.ts +16 -0
  30. package/gulp-tasks/modules/config-generator.js +10 -0
  31. package/gulp-tasks/modules/defaults.js +9 -0
  32. package/gulp-tasks/modules/download-nuget.js +104 -0
  33. package/gulp-tasks/modules/ensure-folder-exists.js +21 -0
  34. package/gulp-tasks/modules/env-helpers.js +49 -0
  35. package/gulp-tasks/modules/env-helpers.ts +67 -0
  36. package/gulp-tasks/modules/env.js +364 -0
  37. package/gulp-tasks/modules/exec.js +257 -0
  38. package/gulp-tasks/modules/exec.ts +346 -0
  39. package/gulp-tasks/modules/fail-after.js +30 -0
  40. package/gulp-tasks/modules/fail-after.ts +34 -0
  41. package/gulp-tasks/modules/fallback.js +6 -0
  42. package/gulp-tasks/modules/find-dirs.js +39 -0
  43. package/gulp-tasks/modules/find-local-nuget.js +42 -0
  44. package/gulp-tasks/modules/find-npm-base.js +42 -0
  45. package/gulp-tasks/modules/fs.js +79 -0
  46. package/gulp-tasks/modules/gather-paths.js +23 -0
  47. package/gulp-tasks/modules/gather-paths.ts +29 -0
  48. package/gulp-tasks/modules/generate-env-help-for.js +30 -0
  49. package/gulp-tasks/modules/get-tools-folder.js +12 -0
  50. package/gulp-tasks/modules/git-push-tags.js +33 -0
  51. package/gulp-tasks/modules/git-push-tags.ts +42 -0
  52. package/gulp-tasks/modules/git-push.js +51 -0
  53. package/gulp-tasks/modules/git-tag.js +36 -0
  54. package/gulp-tasks/modules/gulp-dotnetcover.js +537 -0
  55. package/gulp-tasks/modules/gulp-git-tag-from-csproj.js +50 -0
  56. package/gulp-tasks/modules/gulp-git-tag-from-csproj.ts +71 -0
  57. package/gulp-tasks/modules/gulp-git-tag-from-package-nuspec.js +55 -0
  58. package/gulp-tasks/modules/gulp-increment-nuget-package-dependency-version.js +40 -0
  59. package/gulp-tasks/modules/gulp-increment-nuget-package-version.js +87 -0
  60. package/gulp-tasks/modules/gulp-increment-nuget-package-version.ts +122 -0
  61. package/gulp-tasks/modules/gulp-msbuild.js +1 -0
  62. package/gulp-tasks/modules/gulp-npm-run.js +40 -0
  63. package/gulp-tasks/modules/gulp-npm-run.ts +52 -0
  64. package/gulp-tasks/modules/gulp-nuget-pack.js +168 -0
  65. package/gulp-tasks/modules/gulp-nuget-restore.js +106 -0
  66. package/gulp-tasks/modules/gulp-nunit-runner/.jshintrc +5 -0
  67. package/gulp-tasks/modules/gulp-nunit-runner/.npmignore +16 -0
  68. package/gulp-tasks/modules/gulp-nunit-runner/LICENSE +21 -0
  69. package/gulp-tasks/modules/gulp-nunit-runner/README.md +300 -0
  70. package/gulp-tasks/modules/gulp-nunit-runner/index.js +1 -0
  71. package/gulp-tasks/modules/gulp-nunit-runner/lib/index.js +205 -0
  72. package/gulp-tasks/modules/gulp-nunit-runner/lib/teamcity.js +86 -0
  73. package/gulp-tasks/modules/gulp-purge.js +88 -0
  74. package/gulp-tasks/modules/gulp-util.js +5 -0
  75. package/gulp-tasks/modules/gulp-version.js +8 -0
  76. package/gulp-tasks/modules/gulp-with-help.js +1 -0
  77. package/gulp-tasks/modules/gulp-xbuild.js +62 -0
  78. package/gulp-tasks/modules/gulp.js +92 -0
  79. package/gulp-tasks/modules/http-downloader.js +113 -0
  80. package/gulp-tasks/modules/import-npm-tasks.js +33 -0
  81. package/gulp-tasks/modules/increment-version-string.js +18 -0
  82. package/gulp-tasks/modules/increment-version.js +30 -0
  83. package/gulp-tasks/modules/increment-version.ts +41 -0
  84. package/gulp-tasks/modules/install-local-tools.js +122 -0
  85. package/gulp-tasks/modules/load-xml-file.js +12 -0
  86. package/gulp-tasks/modules/load-xml-file.ts +15 -0
  87. package/gulp-tasks/modules/log-config.js +31 -0
  88. package/gulp-tasks/modules/log.js +142 -0
  89. package/gulp-tasks/modules/longest-string-length.js +13 -0
  90. package/gulp-tasks/modules/looks-like-a-promise.js +11 -0
  91. package/gulp-tasks/modules/ls-r.js +52 -0
  92. package/gulp-tasks/modules/multi-split.js +29 -0
  93. package/gulp-tasks/modules/net-framework-test-assembly-filter.js +45 -0
  94. package/gulp-tasks/modules/nuget-push.js +66 -0
  95. package/gulp-tasks/modules/nuget-update-self.js +9 -0
  96. package/gulp-tasks/modules/nuget.js +8 -0
  97. package/gulp-tasks/modules/nuget.ts +14 -0
  98. package/gulp-tasks/modules/pad-left.js +4 -0
  99. package/gulp-tasks/modules/pad-right.js +4 -0
  100. package/gulp-tasks/modules/pad.js +25 -0
  101. package/gulp-tasks/modules/parse-xml-string.js +5 -0
  102. package/gulp-tasks/modules/parse-xml-string.ts +6 -0
  103. package/gulp-tasks/modules/parse-xml.js +14 -0
  104. package/gulp-tasks/modules/parse-xml.ts +15 -0
  105. package/gulp-tasks/modules/path-unquote.js +6 -0
  106. package/gulp-tasks/modules/promisify-function.js +19 -0
  107. package/gulp-tasks/modules/promisify-function.ts +18 -0
  108. package/gulp-tasks/modules/promisify-stream.js +73 -0
  109. package/gulp-tasks/modules/promisify.js +1 -0
  110. package/gulp-tasks/modules/quote-if-required.js +14 -0
  111. package/gulp-tasks/modules/read-all-git-branches.js +10 -0
  112. package/gulp-tasks/modules/read-all-git-branches.ts +13 -0
  113. package/gulp-tasks/modules/read-all-git-remotes.js +36 -0
  114. package/gulp-tasks/modules/read-all-git-remotes.ts +44 -0
  115. package/gulp-tasks/modules/read-csproj-package-version.js +16 -0
  116. package/gulp-tasks/modules/read-csproj-package-version.ts +26 -0
  117. package/gulp-tasks/modules/read-csproj-version.js +16 -0
  118. package/gulp-tasks/modules/read-csproj-version.ts +26 -0
  119. package/gulp-tasks/modules/read-current-git-branch.js +12 -0
  120. package/gulp-tasks/modules/read-current-git-branch.ts +16 -0
  121. package/gulp-tasks/modules/read-git-commit-delta-count.js +21 -0
  122. package/gulp-tasks/modules/read-git-commit-delta-count.ts +33 -0
  123. package/gulp-tasks/modules/read-git-info.js +28 -0
  124. package/gulp-tasks/modules/read-git-info.ts +31 -0
  125. package/gulp-tasks/modules/read-git-remote.js +17 -0
  126. package/gulp-tasks/modules/read-git-remote.ts +23 -0
  127. package/gulp-tasks/modules/read-last-fetch-time.js +21 -0
  128. package/gulp-tasks/modules/read-last-fetch-time.ts +17 -0
  129. package/gulp-tasks/modules/read-main-branch-name.js +48 -0
  130. package/gulp-tasks/modules/read-main-branch-name.ts +76 -0
  131. package/gulp-tasks/modules/read-nuspec-version.js +14 -0
  132. package/gulp-tasks/modules/read-nuspec-version.ts +22 -0
  133. package/gulp-tasks/modules/read-package-json.js +16 -0
  134. package/gulp-tasks/modules/read-package-json.ts +22 -0
  135. package/gulp-tasks/modules/read-package-version.js +8 -0
  136. package/gulp-tasks/modules/read-package-version.ts +10 -0
  137. package/gulp-tasks/modules/read-text-file.js +14 -0
  138. package/gulp-tasks/modules/read-text-file.ts +14 -0
  139. package/gulp-tasks/modules/reduce-gulp-noise.js +34 -0
  140. package/gulp-tasks/modules/register-environment-variables.js +526 -0
  141. package/gulp-tasks/modules/require-module.js +28 -0
  142. package/gulp-tasks/modules/resolve-git-branch.js +11 -0
  143. package/gulp-tasks/modules/resolve-git-branch.ts +13 -0
  144. package/gulp-tasks/modules/resolve-git-remote.js +11 -0
  145. package/gulp-tasks/modules/resolve-git-remote.ts +13 -0
  146. package/gulp-tasks/modules/resolve-masks.js +47 -0
  147. package/gulp-tasks/modules/resolve-nuget.js +135 -0
  148. package/gulp-tasks/modules/resolve-test-masks.js +10 -0
  149. package/gulp-tasks/modules/rewrite-file.js +26 -0
  150. package/gulp-tasks/modules/rewrite-file.ts +34 -0
  151. package/gulp-tasks/modules/rimraf.js +21 -0
  152. package/gulp-tasks/modules/rimraf.ts +31 -0
  153. package/gulp-tasks/modules/run-sequence.js +16 -0
  154. package/gulp-tasks/modules/safe-git.js +23 -0
  155. package/gulp-tasks/modules/safe-git.ts +23 -0
  156. package/gulp-tasks/modules/seed.js +12 -0
  157. package/gulp-tasks/modules/set-task-name.js +9 -0
  158. package/gulp-tasks/modules/sleep.js +5 -0
  159. package/gulp-tasks/modules/spawn-nuget.js +13 -0
  160. package/gulp-tasks/modules/spawn.js +103 -0
  161. package/gulp-tasks/modules/split-path.js +3 -0
  162. package/gulp-tasks/modules/stat.js +8 -0
  163. package/gulp-tasks/modules/status.js +57 -0
  164. package/gulp-tasks/modules/status.ts +71 -0
  165. package/gulp-tasks/modules/test-path.js +3 -0
  166. package/gulp-tasks/modules/testutil-finder.js +176 -0
  167. package/gulp-tasks/modules/throw-if-no-files.js +15 -0
  168. package/gulp-tasks/modules/uniq.js +6 -0
  169. package/gulp-tasks/modules/uniq.ts +5 -0
  170. package/gulp-tasks/modules/verify-exe.js +17 -0
  171. package/gulp-tasks/modules/version-reading-shared.js +12 -0
  172. package/gulp-tasks/modules/version-reading-shared.ts +16 -0
  173. package/gulp-tasks/modules/write-text-file.js +10 -0
  174. package/gulp-tasks/modules/zarro-error.js +6 -0
  175. package/gulp-tasks/nuget-restore.js +57 -0
  176. package/gulp-tasks/pack.js +118 -0
  177. package/gulp-tasks/purge.js +94 -0
  178. package/gulp-tasks/release-npm.js +58 -0
  179. package/gulp-tasks/release-npm.ts +81 -0
  180. package/gulp-tasks/start/_package.json +39 -0
  181. package/gulp-tasks/start/gulpfile.js +204 -0
  182. package/gulp-tasks/start/update-starter-packages.js +63 -0
  183. package/gulp-tasks/test-dotnet.js +195 -0
  184. package/gulp-tasks/update-git-submodules.js +11 -0
  185. package/gulp-tasks/update-git-submodules.ts +29 -0
  186. package/gulp-tasks/update-self.js +65 -0
  187. package/gulp-tasks/update-self.ts +88 -0
  188. package/gulp-tasks/verify-up-to-date.js +77 -0
  189. package/gulp-tasks/verify-up-to-date.ts +119 -0
  190. package/index-modules/contains-any.js +31 -0
  191. package/index-modules/gather-args.js +21 -0
  192. package/index-modules/handlers/help.js +17 -0
  193. package/index-modules/handlers/init.js +57 -0
  194. package/index-modules/handlers/invoke-gulp.js +111 -0
  195. package/index-modules/handlers/show-env.js +46 -0
  196. package/index-modules/is-dir.js +6 -0
  197. package/index-modules/is-file.js +6 -0
  198. package/index.js +53 -0
  199. package/package.json +96 -0
  200. package/tsconfig.json +66 -0
  201. package/types.d.ts +753 -0
@@ -0,0 +1,16 @@
1
+ import * as vinyl from "vinyl";
2
+
3
+ (function() {
4
+ // collects the files from a gulp stream
5
+ const
6
+ es = require("event-stream");
7
+ module.exports = function collectFiles(target: vinyl.BufferFile[]) {
8
+ const stream = es.through(function data(file: vinyl.BufferFile) {
9
+ target.push(file);
10
+ stream.emit("data", file);
11
+ }, function end() {
12
+ stream.emit("end");
13
+ });
14
+ return stream;
15
+ }
16
+ })();
@@ -0,0 +1,10 @@
1
+ var env = requireModule("env"),
2
+ path = require("path");
3
+
4
+ module.exports = function configGenerator() {
5
+ return {
6
+ localNuget: path.join(env.resolve("BUILD_TOOLS_FOLDER"), "nuget.exe"),
7
+ nugetDownloadUrl:
8
+ "http://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
9
+ };
10
+ };
@@ -0,0 +1,9 @@
1
+ module.exports = function defaults(config, fallback) {
2
+ const result = { ...config };
3
+ Object.keys(fallback || {}).forEach(k => {
4
+ if (result[k] === undefined) {
5
+ result[k] = fallback[k];
6
+ }
7
+ });
8
+ return result;
9
+ }
@@ -0,0 +1,104 @@
1
+ const
2
+ { ZarroError } = requireModule("zarro-error"),
3
+ HttpDownloader = require("./http-downloader"),
4
+ nugetUpdateSelf = require("./nuget-update-self"),
5
+ logger = require("./log"),
6
+ path = require("path"),
7
+ url = 'http://dist.nuget.org/win-x86-commandline/latest/nuget.exe';
8
+
9
+ function downloadNugetTo(targetFolder) {
10
+ logger.debug(`Attempting to download nuget.exe to ${targetFolder}`);
11
+ const
12
+ downloader = new HttpDownloader(),
13
+ target = path.join(targetFolder, "nuget.exe");
14
+ return downloader
15
+ .download(url, path.join(targetFolder, "nuget.exe"))
16
+ .then(() => validateCanRunExe(target));
17
+ }
18
+
19
+ const
20
+ validators = {},
21
+ cached = {};
22
+
23
+ function validateCanRunExe(exePath) {
24
+ if (validators[exePath]) {
25
+ return validators[exePath];
26
+ }
27
+ const shouldLog = !validators[exePath];
28
+ if (shouldLog) {
29
+ logger.debug(`validating exe at: ${exePath}`);
30
+ }
31
+ return validators[exePath] = new Promise((resolve, reject) => {
32
+ let lastMessage = "unknown error",
33
+ attempts = 0;
34
+ setTimeout(function testExe() {
35
+ if (cached[exePath]) {
36
+ return resolve(exePath);
37
+ }
38
+ if (attempts === 10) {
39
+ return reject(`Unable to run executable at ${exePath}: ${lastMessage}`);
40
+ }
41
+ attempts++;
42
+ if (shouldLog) {
43
+ logger.debug(`attempt #${attempts} to run ${exePath}`);
44
+ }
45
+ const a = attempts;
46
+ nugetUpdateSelf(exePath).then(() => {
47
+ if (shouldLog) {
48
+ const sub = a > 1 ? ` (${a})` : "";
49
+ logger.info(`nuget.exe appears to be valid!${sub}`);
50
+ }
51
+ cached[exePath] = true;
52
+ return resolve(exePath);
53
+ }).catch(e => {
54
+ lastMessage = e.message || lastMessage;
55
+ if (shouldLog) {
56
+ logger.debug(`failed to run executable (${
57
+ e.message
58
+ }); ${
59
+ attempts < 9
60
+ ? "will try again"
61
+ : "giving up"
62
+ }`);
63
+ }
64
+ setTimeout(testExe, 1000);
65
+ });
66
+ }, 1000);
67
+ });
68
+ }
69
+
70
+ function retry(fn, attempt, maxAttempts, wait) {
71
+ attempt = attempt || 0;
72
+ maxAttempts = maxAttempts || 10;
73
+ wait = wait || 5000;
74
+ if (wait < 1000) {
75
+ wait *= 1000;
76
+ }
77
+ return fn().catch(e => {
78
+ if (attempt >= maxAttempts) {
79
+ throw new ZarroError(`${e} (giving up after ${attempt} attempts)`);
80
+ } else {
81
+ return new Promise((resolve, reject) => {
82
+ setTimeout(() => {
83
+ console.warn(e);
84
+ console.log(`trying again in ${wait / 1000}s (${++attempt} / ${maxAttempts})`);
85
+ retry(fn, attempt, maxAttempts).then(function () {
86
+ resolve(Array.from(arguments));
87
+ }).catch(function () {
88
+ reject(Array.from(arguments));
89
+ });
90
+ }, wait);
91
+ });
92
+ }
93
+ });
94
+ }
95
+
96
+ module.exports = function downloadNuget(targetFolder) {
97
+ return retry(() =>
98
+ downloadNugetTo(targetFolder)
99
+ ).then(downloaded => {
100
+ console.log(`nuget downloaded to: ${downloaded}`);
101
+ return downloaded;
102
+ });
103
+ };
104
+
@@ -0,0 +1,21 @@
1
+ const
2
+ fs = require("fs"),
3
+ debug = require("debug")("ensure-folder-exists")
4
+
5
+ module.exports = function ensureFolderExists(folder) {
6
+ debug(`Ensuring existence of tools folder "${folder}"`);
7
+ return new Promise((resolve, reject) => {
8
+ try {
9
+ if (!fs.existsSync(folder)) {
10
+ fs.mkdirSync(folder);
11
+ }
12
+ debug(`${folder} exists!`);
13
+ resolve();
14
+ } catch (e) {
15
+ debug(`${folder} doesn't exist and not creatable`);
16
+ debug(e);
17
+ reject(e);
18
+ }
19
+ });
20
+ }
21
+
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ (function () {
3
+ const { ZarroError } = requireModule("zarro-error");
4
+ function env(name, fallback) {
5
+ const value = process.env[name];
6
+ if (value !== undefined) {
7
+ return value;
8
+ }
9
+ const argCount = Array.from(arguments).length;
10
+ if (argCount > 1) {
11
+ return fallback;
12
+ }
13
+ throw new ZarroError(`environment variable '${name}' is not defined and no fallback provided`);
14
+ }
15
+ function envNumber(name, fallback) {
16
+ const haveFallback = fallback !== undefined, value = haveFallback ? env(name, fallback === null || fallback === void 0 ? void 0 : fallback.toString()) : env(name), parsed = parseInt(value, 10);
17
+ if (!isNaN(parsed)) {
18
+ return parsed;
19
+ }
20
+ throw new ZarroError(`environment variable '${name}' is invalid: expected numeric value but found '${value}'`);
21
+ }
22
+ function envFlag(name, fallback) {
23
+ const haveFallback = fallback !== undefined, value = haveFallback ? env(name, fallback === null || fallback === void 0 ? void 0 : fallback.toString()) : env(name);
24
+ return parseBool(name, value);
25
+ }
26
+ const truthy = [
27
+ "1",
28
+ "yes",
29
+ "true"
30
+ ], falsey = [
31
+ "0",
32
+ "no",
33
+ "false"
34
+ ];
35
+ function parseBool(name, value) {
36
+ if (truthy.indexOf(value === null || value === void 0 ? void 0 : value.toString()) > -1) {
37
+ return true;
38
+ }
39
+ if (falsey.indexOf(value === null || value === void 0 ? void 0 : value.toString()) > -1) {
40
+ return false;
41
+ }
42
+ throw new ZarroError(`environment variable '${name}' is invalid: could not parse '${value}' as a boolean value`);
43
+ }
44
+ module.exports = {
45
+ env,
46
+ envNumber,
47
+ envFlag
48
+ };
49
+ })();
@@ -0,0 +1,67 @@
1
+ (function() {
2
+ const { ZarroError } = requireModule("zarro-error");
3
+
4
+ function env(name: string, fallback?: string): string {
5
+ const value = process.env[name];
6
+ if (value !== undefined) {
7
+ return value;
8
+ }
9
+ const argCount = Array.from(arguments).length;
10
+ if (argCount > 1) {
11
+ return fallback as string;
12
+ }
13
+ throw new ZarroError(
14
+ `environment variable '${ name }' is not defined and no fallback provided`
15
+ );
16
+ }
17
+
18
+ function envNumber(name: string, fallback?: number): number {
19
+ const
20
+ haveFallback = fallback !== undefined,
21
+ value = haveFallback ? env(name, fallback?.toString()) : env(name),
22
+ parsed = parseInt(value, 10);
23
+ if (!isNaN(parsed)) {
24
+ return parsed;
25
+ }
26
+ throw new ZarroError(
27
+ `environment variable '${ name }' is invalid: expected numeric value but found '${ value }'`
28
+ );
29
+ }
30
+
31
+ function envFlag(name: string, fallback?: boolean): boolean {
32
+ const
33
+ haveFallback = fallback !== undefined,
34
+ value = haveFallback ? env(name, fallback?.toString()) : env(name);
35
+ return parseBool(name, value);
36
+ }
37
+
38
+ const truthy = [
39
+ "1",
40
+ "yes",
41
+ "true"
42
+ ],
43
+ falsey = [
44
+ "0",
45
+ "no",
46
+ "false"
47
+ ];
48
+
49
+ function parseBool(name: string, value: string): boolean {
50
+ if (truthy.indexOf(value?.toString()) > -1) {
51
+ return true;
52
+ }
53
+ if (falsey.indexOf(value?.toString()) > -1) {
54
+ return false;
55
+ }
56
+ throw new ZarroError(
57
+ `environment variable '${name}' is invalid: could not parse '${value}' as a boolean value`
58
+ );
59
+ }
60
+
61
+ module.exports = {
62
+ env,
63
+ envNumber,
64
+ envFlag
65
+ }
66
+
67
+ })();
@@ -0,0 +1,364 @@
1
+ if (!Array.prototype.flatMap) {
2
+ try {
3
+ const flatMap = require("array.prototype.flatmap");
4
+ flatMap.shim();
5
+ } catch (e) {
6
+ console.error(
7
+ "Array.prototype.flatmap is required -- either use a newer Node or install the npm package array.prototype.flatmap"
8
+ );
9
+ }
10
+ }
11
+ const
12
+ { ZarroError } = requireModule("zarro-error"),
13
+ chalk = require("ansi-colors"),
14
+ debug = require("debug")("env"),
15
+ registeredEnvironmentVariables = {},
16
+ longestStringLength = require("./longest-string-length"),
17
+ padRight = require("./pad-right"),
18
+ padLeft = require("./pad-left"),
19
+ toExport = {
20
+ flag,
21
+ fallback,
22
+ register,
23
+ printHelp,
24
+ taskHelp,
25
+ resolve,
26
+ associate,
27
+ resolveArray,
28
+ explode,
29
+ overrideDefault,
30
+ resolveNumber,
31
+ resolveFlag
32
+ };
33
+
34
+ const positives = [ "1", "yes", "true" ];
35
+ if (process.env.POSITIVE_FLAG) {
36
+ positives.push(process.env.POSITIVE_FLAG);
37
+ }
38
+
39
+ function flag(name, defaultValue) {
40
+ const envVar = fallback(name, defaultValue);
41
+
42
+ return (
43
+ envVar === true || positives.indexOf((envVar || "").toLowerCase()) > -1
44
+ );
45
+ }
46
+
47
+ function fallback(name, defaultValue) {
48
+ const envVar = process.env[name];
49
+ return envVar === undefined ? defaultValue : envVar;
50
+ }
51
+
52
+ function register(config) {
53
+ let { name, help, tasks, overriddenBy, when } = config;
54
+ if (toExport[name] !== undefined) {
55
+ throw new ZarroError(`env var already registered: ${name}`);
56
+ }
57
+ toExport[name] = name;
58
+ // 'default' seems like a more natural name, but we can't use it for a var name...
59
+ let fallback = config.default;
60
+ if (registeredEnvironmentVariables[name]) {
61
+ return update(name, fallback, help, tasks, overriddenBy, when);
62
+ }
63
+ tasks = normaliseArray(tasks);
64
+ help = trim(help);
65
+ fallback = trim(fallback);
66
+
67
+ registeredEnvironmentVariables[name] = {
68
+ help,
69
+ tasks,
70
+ default: fallback,
71
+ overriddenBy: overriddenBy || [],
72
+ when
73
+ };
74
+ if (pendingAssociations[name]) {
75
+ const otherTasks = pendingAssociations[name];
76
+ delete pendingAssociations[name];
77
+ tasks.push.apply(tasks, otherTasks);
78
+ }
79
+ if (pendingDefaultOverrides[name]) {
80
+ registeredEnvironmentVariables[name].default =
81
+ pendingDefaultOverrides[name];
82
+ delete pendingDefaultOverrides[name];
83
+ }
84
+ debug({
85
+ label: `register env var: ${name}`,
86
+ config: registeredEnvironmentVariables[name]
87
+ });
88
+ return toExport;
89
+ }
90
+
91
+ const pendingAssociations = {};
92
+
93
+ function associate(varName, tasks) {
94
+ if (Array.isArray(varName)) {
95
+ varName.forEach(v => associate(v, tasks));
96
+ return toExport;
97
+ }
98
+
99
+ if (!varName || !tasks || tasks.length === 0) {
100
+ return toExport;
101
+ }
102
+ if (!Array.isArray(tasks)) {
103
+ tasks = [ tasks ];
104
+ }
105
+
106
+ const target = registeredEnvironmentVariables[varName]
107
+ ? registeredEnvironmentVariables[varName].tasks
108
+ : (pendingAssociations[varName] = pendingAssociations[varName] || []);
109
+ tasks.forEach(task => {
110
+ if (target.indexOf(task) > -1) {
111
+ return;
112
+ }
113
+ target.push(task);
114
+ });
115
+ return toExport;
116
+ }
117
+
118
+ const pendingDefaultOverrides = {};
119
+
120
+ function overrideDefault(varName, newDefault) {
121
+ const target = registeredEnvironmentVariables[varName];
122
+ if (target) {
123
+ target.default = newDefault;
124
+ } else {
125
+ pendingDefaultOverrides[varName] = newDefault;
126
+ }
127
+ }
128
+
129
+ function normaliseArray(arr) {
130
+ if (!arr) {
131
+ return [];
132
+ }
133
+ return Array.isArray(arr) ? arr : [ arr ];
134
+ }
135
+
136
+ function update(varName, fallbackValue, help, tasks, overriddenBy, when) {
137
+ const target = registeredEnvironmentVariables[varName];
138
+ if (!target.help) {
139
+ target.help = trim(help);
140
+ }
141
+ if (!target.default) {
142
+ target.default = trim(fallbackValue);
143
+ }
144
+ tasks = normaliseArray(tasks);
145
+ target.tasks = target.tasks.concat(tasks);
146
+ target.overriddenBy = target.overriddenBy.concat(overriddenBy || []);
147
+ // TODO: composite when? this code is first-come-first-wins
148
+ target.when = target.when || when;
149
+ debug({
150
+ label: `update env var: ${varName}`,
151
+ config: target
152
+ });
153
+ return toExport;
154
+ }
155
+
156
+ function trim(str) {
157
+ if (str === null || str === undefined) {
158
+ return "";
159
+ }
160
+ if (Array.isArray(str)) {
161
+ return str.map(s => s.trim());
162
+ }
163
+ return str.toString().trim();
164
+ }
165
+
166
+ function printHelp() {
167
+ printHelpFor(listVars());
168
+ }
169
+
170
+ function printHelpFor(vars) {
171
+ const longest = longestStringLength(vars);
172
+ vars.forEach(k =>
173
+ createHelpFor(k, longest).forEach(line => console.log(line))
174
+ );
175
+ }
176
+
177
+ function indent(str, howMany) {
178
+ if (howMany === undefined || howMany < 1) {
179
+ howMany = 1;
180
+ }
181
+ return padLeft(str, howMany * 2 + str.length);
182
+ }
183
+
184
+ const tasksPre = chalk.greenBright("tasks"),
185
+ defaultPre = chalk.cyanBright("default");
186
+
187
+ function createHelpFor(k, longest) {
188
+ if (longest === undefined) {
189
+ // take a guess
190
+ longest = 16;
191
+ }
192
+ const result = [];
193
+ result.push(chalk.yellow(`${padRight(k, longest)}`));
194
+ const target = registeredEnvironmentVariables[k];
195
+ if (target.help) {
196
+ result.push(indent(chalk.gray(target.help)));
197
+ }
198
+ if (target.default) {
199
+ result.push(indent(`${defaultPre}: ${target.default}`, 2));
200
+ }
201
+ if (target.tasks && target.tasks.length) {
202
+ result.push(
203
+ indent(
204
+ `${tasksPre}: ${target.tasks
205
+ .map(t => t.trim())
206
+ .filter(t => t)
207
+ .sort()
208
+ .join(", ")}`,
209
+ 2
210
+ )
211
+ );
212
+ }
213
+ if (target.overriddenBy !== undefined) {
214
+ const overrides = Array.isArray(target.overriddenBy)
215
+ ? target.overriddenBy.join(",")
216
+ : target.overriddenBy;
217
+ if (overrides.trim()) {
218
+ result.push(indent(chalk.magenta(`overridden by: ${overrides}`)));
219
+ }
220
+ }
221
+ return result;
222
+ }
223
+
224
+ function listVars() {
225
+ return Object.keys(registeredEnvironmentVariables).sort();
226
+ }
227
+
228
+ function taskHelp(task) {
229
+ const keys = listVars(),
230
+ matchingRequest = keys.filter(cur => {
231
+ return registeredEnvironmentVariables[cur].tasks.indexOf(task) > -1;
232
+ });
233
+ printHelpFor(matchingRequest);
234
+ }
235
+
236
+ function resolve() {
237
+ const names = Array.from(arguments).flatMap(a => a);
238
+ const result = resolveInternal(names);
239
+ logResolved(names, result);
240
+ return result;
241
+ }
242
+
243
+ function resolveFirst(names, ignoreDefault) {
244
+ return names
245
+ .reduce((acc, cur) =>
246
+ acc === undefined
247
+ ? resolveInternal(cur, ignoreDefault)
248
+ : acc, undefined);
249
+ }
250
+
251
+ function resolveInternal(name, ignoreDefault) {
252
+ if (Array.isArray(name)) {
253
+ // attempt to resolve the first defined variable
254
+ const firstDefined = resolveFirst(name, true);
255
+ // if that doesn't work, get the first default value
256
+ return firstDefined === undefined
257
+ ? resolveFirst(name, false)
258
+ : firstDefined;
259
+ }
260
+
261
+ const target = registeredEnvironmentVariables[name] || {},
262
+ configuredOverrides = target.overriddenBy,
263
+ overrides = configuredOverrides
264
+ ? Array.isArray(configuredOverrides)
265
+ ? configuredOverrides
266
+ : [ configuredOverrides ]
267
+ : [],
268
+ overrideValues = overrides
269
+ .map(s => process.env[s])
270
+ .filter(s => s !== undefined),
271
+ initialValue =
272
+ (!ignoreDefault && process.env[name] === undefined) ? target.default : process.env[name];
273
+ if (overrideValues.length === 0) {
274
+ return initialValue;
275
+ }
276
+ if (target.when === undefined) {
277
+ if (overrideValues.length > 0) {
278
+ console.warn(
279
+ `multiple override values found for '${name}' and no strategy for discriminating set; selecting the first`
280
+ );
281
+ debug({
282
+ when: target.when,
283
+ overrides,
284
+ overrideValues,
285
+ initialValue
286
+ });
287
+ }
288
+ return overrideValues[0];
289
+ }
290
+
291
+ const result = overrideValues.reduce((acc, cur) => {
292
+ debug({
293
+ label: "invoke override discriminator",
294
+ when: target.when,
295
+ acc,
296
+ cur
297
+ });
298
+ return target.when(acc, cur) ? cur : acc;
299
+ }, initialValue);
300
+
301
+ debug({
302
+ when: target.when,
303
+ overrides,
304
+ overrideValues,
305
+ initialValue,
306
+ envVar: name,
307
+ envValue: process.env[name],
308
+ });
309
+
310
+ return result;
311
+ }
312
+
313
+ function logResolved(name, value) {
314
+ debug(`resolved: ${name} => ${quoteString(value)}`);
315
+ }
316
+
317
+ function quoteString(val) {
318
+ return typeof val === "string" ? `"${val}"` : val;
319
+ }
320
+
321
+ function resolveArray(name, delimiter) {
322
+ const value = resolveInternal(name) || "",
323
+ valueArray = Array.isArray(value) ? value : explode(value, delimiter);
324
+ logResolved(name, valueArray);
325
+ return valueArray;
326
+ }
327
+
328
+ function resolveNumber(name) {
329
+ const value = resolveInternal(name),
330
+ asNumber = parseInt(value, 10);
331
+ if (isNaN(asNumber)) {
332
+ throw new ZarroError(`${value} is not a valid numeric value for ${name}`);
333
+ }
334
+ logResolved(name, asNumber);
335
+ return asNumber;
336
+ }
337
+
338
+ const positiveFlags = [ "yes", "true", "1" ];
339
+ const negativeFlags = [ "no", "false", "0" ];
340
+
341
+ function resolveFlag(name) {
342
+ const value = (resolveInternal(name) || "").toLowerCase();
343
+ if (positiveFlags.indexOf(value) > -1) {
344
+ logResolved(name, true);
345
+ return true;
346
+ }
347
+ if (negativeFlags.indexOf(value) > -1) {
348
+ logResolved(name, false);
349
+ return false;
350
+ }
351
+ throw new ZarroError(`environmental flag not set and no default: ${name}`);
352
+ }
353
+
354
+ function explode(str, delimiter) {
355
+ return str
356
+ .split(delimiter || ",")
357
+ .map(p => p.trim())
358
+ .filter(p => !!p);
359
+ }
360
+
361
+ const registerEnvironmentVariables = require("./register-environment-variables");
362
+ registerEnvironmentVariables(toExport);
363
+
364
+ module.exports = toExport;