zarro 1.173.0 โ†’ 1.173.4

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.
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ (function () {
3
+ class CacheItem {
4
+ constructor(value, expires) {
5
+ this.value = value;
6
+ this.expires = expires;
7
+ }
8
+ }
9
+ class Cache {
10
+ constructor() {
11
+ this._store = {};
12
+ }
13
+ /**
14
+ * reads a value from the cache
15
+ * if the value is not found, the fallback, if supplied
16
+ * is returned, otherwise undefined is returned
17
+ * @param key
18
+ * @param fallback
19
+ */
20
+ read(key, fallback) {
21
+ const cached = this._findCacheItem(key);
22
+ return cached === undefined
23
+ ? fallback
24
+ : cached.value;
25
+ }
26
+ /**
27
+ * clears all cached values
28
+ */
29
+ clear() {
30
+ this._store = {};
31
+ }
32
+ /**
33
+ * stores a value in the cache
34
+ * @param key
35
+ * @param value
36
+ * @param ttlSeconds
37
+ */
38
+ write(key, value, ttlSeconds) {
39
+ this._store[key] = new CacheItem(value, Date.now() + ttlSeconds);
40
+ }
41
+ /**
42
+ * Runs the generator if there is no cache item with
43
+ * the provided key and stores the result. Subsequent
44
+ * calls will skip the generator function to retrieve
45
+ * from cache until the item expires.
46
+ * @param key
47
+ * @param generator
48
+ * @param ttlSeconds
49
+ */
50
+ async through(key, generator, ttlSeconds) {
51
+ const cached = this._findCacheItem(key);
52
+ if (cached) {
53
+ return cached.value;
54
+ }
55
+ const result = await generator();
56
+ this.write(key, result, ttlSeconds);
57
+ return result;
58
+ }
59
+ /**
60
+ * Runs the generator if there is no cache item with
61
+ * the provided key and stores the result. Subsequent
62
+ * calls will skip the generator function to retrieve
63
+ * from cache until the item expires.
64
+ * @param key
65
+ * @param generator
66
+ * @param ttlSeconds
67
+ */
68
+ throughSync(key, generator, ttlSeconds) {
69
+ const cached = this._findCacheItem(key);
70
+ if (cached) {
71
+ return cached.value;
72
+ }
73
+ const result = generator();
74
+ this.write(key, result, ttlSeconds);
75
+ return result;
76
+ }
77
+ _findCacheItem(key) {
78
+ const result = this._store[key];
79
+ if (result === undefined) {
80
+ return undefined;
81
+ }
82
+ if (result.expires < Date.now()) {
83
+ this.forget(key);
84
+ return undefined;
85
+ }
86
+ return result;
87
+ }
88
+ /**
89
+ * creates a new empty cache
90
+ */
91
+ create() {
92
+ return new Cache();
93
+ }
94
+ /**
95
+ * trims expired items from the cache
96
+ */
97
+ trim() {
98
+ for (const key of Object.keys(this._store)) {
99
+ const item = this._store[key];
100
+ if (item.expires < Date.now()) {
101
+ this.forget(key);
102
+ }
103
+ }
104
+ }
105
+ /**
106
+ * forgets the cached item by key
107
+ * @param key
108
+ */
109
+ forget(key) {
110
+ delete this._store[key];
111
+ }
112
+ }
113
+ module.exports = new Cache();
114
+ })();
@@ -5,7 +5,7 @@
5
5
  const { isRegExp } = types;
6
6
  const ZarroError = requireModule("zarro-error");
7
7
  const path = require("path");
8
- const { fileExists, readTextFile } = require("yafs");
8
+ const { fileExists, readTextFile, ls, FsEntities } = require("yafs");
9
9
  const { yellow } = requireModule("ansi-colors");
10
10
  const q = requireModule("quote-if-required");
11
11
  const { pushIfSet, pushFlag } = requireModule("cli-support");
@@ -18,6 +18,7 @@
18
18
  const env = requireModule("env");
19
19
  const Version = requireModule("version");
20
20
  const SystemError = requireModule("system-error");
21
+ const cache = requireModule("cache");
21
22
  const emojiLabels = {
22
23
  testing: `๐Ÿงช Testing`,
23
24
  packing: `๐Ÿ“ฆ Packing`,
@@ -264,7 +265,7 @@
264
265
  async function enableNugetSource(source) {
265
266
  const toEnable = await tryFindConfiguredNugetSource(source);
266
267
  if (!toEnable) {
267
- throw new Error(`unable to find source matching: ${JSON.stringify(source)}`);
268
+ throw new ZarroError(`unable to find source matching: ${JSON.stringify(source)}`);
268
269
  }
269
270
  await runDotNetWith(["dotnet", "nuget", "enable", "source", toEnable.name], {
270
271
  suppressOutput: true
@@ -273,7 +274,7 @@
273
274
  async function disableNugetSource(source) {
274
275
  const toDisable = await tryFindConfiguredNugetSource(source);
275
276
  if (!toDisable) {
276
- throw new Error(`unable to find source matching: ${JSON.stringify(source)}`);
277
+ throw new ZarroError(`unable to find source matching: ${JSON.stringify(source)}`);
277
278
  }
278
279
  await runDotNetWith(["dotnet", "nuget", "disable", "source", toDisable.name], {
279
280
  suppressOutput: true
@@ -334,7 +335,7 @@
334
335
  }
335
336
  function single(results) {
336
337
  if (results.length > 1) {
337
- throw new Error(`multiple matches for nuget source by name / url / host: ${JSON.stringify(find)}\nfound:\n${JSON.stringify(allSources, null, 2)}`);
338
+ throw new ZarroError(`multiple matches for nuget source by name / url / host: ${JSON.stringify(find)}\nfound:\n${JSON.stringify(allSources, null, 2)}`);
338
339
  }
339
340
  return results[0];
340
341
  }
@@ -356,7 +357,7 @@
356
357
  async function removeNugetSourceByName(find) {
357
358
  const source = await tryFindConfiguredNugetSource(find);
358
359
  if (!source) {
359
- throw new Error(`Can't find source with '${find}'`);
360
+ throw new ZarroError(`Can't find source with '${find}'`);
360
361
  }
361
362
  const result = await runDotNetWith(["nuget", "remove", "source", source.name], { suppressOutput: true });
362
363
  if (system.isError(result)) {
@@ -469,7 +470,7 @@ WARNING: 'dotnet pack' ignores --version-suffix when a nuspec file is provided.
469
470
  if (await fileExists(test)) {
470
471
  return test;
471
472
  }
472
- throw new Error(`Unable to resolve '${resolvedPath}' relative to '${containerDir}'`);
473
+ throw new ZarroError(`Unable to resolve '${resolvedPath}' relative to '${containerDir}'`);
473
474
  }
474
475
  }
475
476
  async function shouldIncludeNuspec(opts) {
@@ -495,7 +496,7 @@ WARNING: 'dotnet pack' ignores --version-suffix when a nuspec file is provided.
495
496
  async function nugetPush(opts) {
496
497
  validateCommonBuildOptions(opts);
497
498
  if (!opts.apiKey) {
498
- throw new Error("apiKey was not specified");
499
+ throw new ZarroError("apiKey was not specified");
499
500
  }
500
501
  const args = [
501
502
  "nuget",
@@ -554,7 +555,7 @@ WARNING: 'dotnet pack' ignores --version-suffix when a nuspec file is provided.
554
555
  // for simplicity: return the last system result (at least for now, until there's a reason to get clever)
555
556
  if (lastResult === undefined) {
556
557
  // this is really here for TS
557
- throw new Error(`No build configurations could be determined, which is odd, because there's even a fallback.`);
558
+ throw new ZarroError(`No build configurations could be determined, which is odd, because there's even a fallback.`);
558
559
  }
559
560
  return lastResult;
560
561
  }
@@ -601,7 +602,7 @@ WARNING: 'dotnet pack' ignores --version-suffix when a nuspec file is provided.
601
602
  });
602
603
  const result = enabledSources[0];
603
604
  if (!result) {
604
- throw new Error(`Unable to determine default nuget source. Please specify 'source' on your options.`);
605
+ throw new ZarroError(`Unable to determine default nuget source. Please specify 'source' on your options.`);
605
606
  }
606
607
  return result;
607
608
  }
@@ -670,6 +671,10 @@ WARNING: 'dotnet pack' ignores --version-suffix when a nuspec file is provided.
670
671
  }
671
672
  }
672
673
  async function runDotNetWith(args, opts) {
674
+ opts = opts || {};
675
+ if (opts.suppressOutput === undefined) {
676
+ opts.suppressOutput = true;
677
+ }
673
678
  let result;
674
679
  try {
675
680
  result = await system("dotnet", args, {
@@ -677,7 +682,8 @@ WARNING: 'dotnet pack' ignores --version-suffix when a nuspec file is provided.
677
682
  stderr: opts.stderr,
678
683
  suppressOutput: opts.suppressOutput,
679
684
  suppressStdIoInErrors: opts.suppressStdIoInErrors,
680
- env: opts.env
685
+ env: opts.env,
686
+ cwd: opts.cwd
681
687
  });
682
688
  }
683
689
  catch (e) {
@@ -761,13 +767,34 @@ WARNING: 'dotnet pack' ignores --version-suffix when a nuspec file is provided.
761
767
  usingFallback
762
768
  });
763
769
  }
770
+ function parsePackageSearchResult(stdout) {
771
+ const allText = stdout.join(" ");
772
+ let parsed;
773
+ try {
774
+ parsed = JSON.parse(allText);
775
+ }
776
+ catch (e) {
777
+ throw new ZarroError(`Unable to parse json from:\n${allText}`);
778
+ }
779
+ if (parsed.problems && parsed.problems.length) {
780
+ throw new ZarroError(`unable to perform package search (check your access token):\n${parsed.problems.join("\n")}`);
781
+ }
782
+ return parsed;
783
+ }
764
784
  async function searchPackages(options) {
765
785
  if (!options) {
766
- throw new Error(`No options or search string provided`);
786
+ throw new ZarroError(`No options or search string provided`);
767
787
  }
768
788
  const opts = typeof options === "string"
769
789
  ? { search: options }
770
790
  : options;
791
+ if (opts.skipCache) {
792
+ return await searchPackages(opts);
793
+ }
794
+ return await cache.through(JSON.stringify(opts), async () => await searchPackagesUncached(opts), 60 // cache for a minute
795
+ );
796
+ }
797
+ async function searchPackagesUncached(opts) {
771
798
  const args = ["package", "search"];
772
799
  pushIfSet(args, opts.source, "--source");
773
800
  pushFlag(args, opts.exactMatch, "--exact-match");
@@ -798,7 +825,7 @@ WARNING: 'dotnet pack' ignores --version-suffix when a nuspec file is provided.
798
825
  const systemError = rawResult;
799
826
  throw wrapSearchError(systemError);
800
827
  }
801
- const allText = stdout.join(" "), parsed = JSON.parse(allText);
828
+ const parsed = parsePackageSearchResult(stdout);
802
829
  const finalResult = [];
803
830
  for (const sourceResult of parsed.searchResult) {
804
831
  for (const pkg of sourceResult.packages) {
@@ -828,35 +855,21 @@ WARNING: 'dotnet pack' ignores --version-suffix when a nuspec file is provided.
828
855
  function wrapSearchError(e) {
829
856
  return new Error(`Unable to perform package search (check your access token if necessary): ${e}`);
830
857
  }
831
- function parsePackageSearchResult(stdout) {
832
- const allText = stdout.join(" ");
833
- let parsed;
834
- try {
835
- parsed = JSON.parse(allText);
836
- }
837
- catch (e) {
838
- throw new Error(`Unable to parse json from:\n${allText}`);
839
- }
840
- if (parsed.problems && parsed.problems.length) {
841
- throw new Error(`unable to perform package search (check your access token):\n${parsed.problems.join("\n")}`);
842
- }
843
- return parsed;
844
- }
845
858
  async function installPackage(opts) {
846
859
  if (!opts) {
847
- throw new Error(`no options passed to 'installPackage' - target project and package name not specified`);
860
+ throw new ZarroError(`no options passed to 'installPackage' - target project and package name not specified`);
848
861
  }
849
862
  if (!`${opts.projectFile}`.trim()) {
850
- throw new Error(`projectFile not specified`);
863
+ throw new ZarroError(`projectFile not specified`);
851
864
  }
852
865
  if (!`${opts.id}`.trim()) {
853
- throw new Error(`package id not specified`);
866
+ throw new ZarroError(`package id not specified`);
854
867
  }
855
868
  const args = ["add", opts.projectFile, "package", opts.id];
856
869
  pushIfSet(args, opts.version, "--version");
857
870
  pushIfSet(args, opts.framework, "--framework");
858
871
  pushFlag(args, opts.noRestore, "--no-restore");
859
- pushIfSet(args, opts.source, "--source");
872
+ pushIfSet(args, await resolveSourceUrlFor(opts.source), "--source");
860
873
  pushIfSet(args, opts.packageDirectory, "--package-directory");
861
874
  pushFlag(args, opts.preRelease, "--prerelease");
862
875
  if (opts.suppressOutput === undefined) {
@@ -864,6 +877,178 @@ WARNING: 'dotnet pack' ignores --version-suffix when a nuspec file is provided.
864
877
  }
865
878
  await runDotNetWith(args, opts);
866
879
  }
880
+ const defaultCreateOptions = {
881
+ skipTemplateUpdateCheck: true
882
+ };
883
+ const solutionRegex = /.*\.sln$/i;
884
+ function isSolution(filePath) {
885
+ return solutionRegex.test(filePath);
886
+ }
887
+ const projectRegex = /.*\.csproj$/i;
888
+ function isProject(filePath) {
889
+ return projectRegex.test(filePath);
890
+ }
891
+ async function create(opts) {
892
+ verifyExists(opts, `no options passed to create`);
893
+ opts = Object.assign(Object.assign({}, defaultCreateOptions), opts);
894
+ verifyNonEmptyString(opts.template, `template was not specified and is required`);
895
+ const args = ["new", opts.template];
896
+ pushIfSet(args, opts.output, "--output");
897
+ pushIfSet(args, opts.name, "--name");
898
+ pushFlag(args, opts.skipTemplateUpdateCheck, "--no-update-check");
899
+ pushIfSet(args, opts.projectFile, "--project");
900
+ pushIfSet(args, opts.verbosity, "--verbosity");
901
+ pushFlag(args, opts.enableDiagnostics, "--diagnostics");
902
+ if (opts.suppressOutput === undefined) {
903
+ opts.suppressOutput = true;
904
+ }
905
+ const newFiles = await runAndReportNewFiles(opts.cwd, () => runDotNetWith(args, opts));
906
+ return newFiles.find(isSolution)
907
+ || newFiles.find(isProject)
908
+ || newFiles[0];
909
+ }
910
+ async function runAndReportNewFiles(where, toRun) {
911
+ const before = new Set(await listDotNetFilesUnder(where));
912
+ await toRun();
913
+ const after = await listDotNetFilesUnder(where);
914
+ const added = [];
915
+ for (const item of after) {
916
+ if (!before.has(item)) {
917
+ added.push(item);
918
+ }
919
+ }
920
+ return added;
921
+ }
922
+ async function listDotNetFilesUnder(folder) {
923
+ return await ls(folder || ".", {
924
+ entities: FsEntities.files,
925
+ fullPaths: true,
926
+ recurse: true,
927
+ doNotTraverse: [
928
+ /node_modules/,
929
+ /[\\/]obj[\\/]/,
930
+ /[\\/]bin[\\/]/
931
+ ]
932
+ });
933
+ }
934
+ async function addProjectToSolution(opts) {
935
+ verifyExists(opts, "no options were passed to 'addProjectToSolution'");
936
+ verifyNonEmptyString(opts.projectFile, "path to project file is required");
937
+ verifyNonEmptyString(opts.solutionFile, "path to solution file is required");
938
+ if (!await fileExists(opts.solutionFile)) {
939
+ throw new ZarroError(`file not found: ${opts.solutionFile}`);
940
+ }
941
+ if (!await fileExists(opts.projectFile)) {
942
+ throw new ZarroError(`file not found: ${opts.projectFile}`);
943
+ }
944
+ const args = ["sln", opts.solutionFile, "add", opts.projectFile];
945
+ await runDotNetWith(args, opts);
946
+ }
947
+ async function listProjects(solutionFile) {
948
+ const args = ["sln", solutionFile, "list"], basePath = path.dirname(solutionFile), rawResult = await runDotNetWith(args), result = [];
949
+ for (const line of rawResult.stdout) {
950
+ const trimmed = line.trim(), test = path.join(basePath, trimmed);
951
+ if (await fileExists(test)) {
952
+ result.push(test);
953
+ }
954
+ }
955
+ return result;
956
+ }
957
+ async function resolveSourceUrlFor(source) {
958
+ if (!source) {
959
+ return undefined;
960
+ }
961
+ const lowered = source.toLowerCase();
962
+ const sources = await listNugetSources();
963
+ for (const source of sources) {
964
+ if (source.name.toLowerCase() == lowered) {
965
+ return source.url;
966
+ }
967
+ }
968
+ // hopefully this is a valid source that dotnet understands
969
+ // - in my testing, dotnet doesn't understand source names,
970
+ // unlike nuget.exe
971
+ return source;
972
+ }
973
+ async function upgradePackages(opts) {
974
+ verifyExists(opts, "no options provided to upgradePackages");
975
+ verifyNonEmptyString(opts.pathToProjectOrSolution, "no path to a project or solution was supplied");
976
+ if (!opts.packages || opts.packages.length === 0) {
977
+ throw new ZarroError(`no packages were specified`);
978
+ }
979
+ if (opts.showProgress === undefined) {
980
+ opts.showProgress = true;
981
+ }
982
+ const { ExecStepContext, Labelers } = require("exec-step"), ctx = new ExecStepContext({
983
+ labeler: opts.showProgress
984
+ ? Labelers.interactive
985
+ : Labelers.none
986
+ });
987
+ const projects = isProject(opts.pathToProjectOrSolution)
988
+ ? [opts.pathToProjectOrSolution]
989
+ : await listProjects(opts.pathToProjectOrSolution);
990
+ for (const project of projects) {
991
+ const projectPackages = await listPackages(project);
992
+ const toUpgrade = [];
993
+ for (const pkg of opts.packages) {
994
+ const test = isRegex(pkg)
995
+ ? (s) => pkg.test(s)
996
+ : (s) => projectPackages.find(pp => pp.id.toLowerCase() === s.toLowerCase());
997
+ for (const projectPackage of projectPackages) {
998
+ if (test(projectPackage.id)) {
999
+ toUpgrade.push(projectPackage.id);
1000
+ }
1001
+ }
1002
+ }
1003
+ if (toUpgrade.length === 0) {
1004
+ }
1005
+ const message = `searching for ${toUpgrade.length} packages to upgrade in ${project}`;
1006
+ const upstream = await ctx.exec(message, async () => {
1007
+ var _a;
1008
+ return await searchForMultiplePackages(toUpgrade, opts.source, (_a = opts.preRelease) !== null && _a !== void 0 ? _a : false);
1009
+ });
1010
+ for (const pkg of upstream) {
1011
+ await ctx.exec(`installing '${pkg.id}' at version '${pkg.version}' into '${project}'`, async () => await installPackage({
1012
+ projectFile: project,
1013
+ id: pkg.id,
1014
+ version: pkg.version.toString(),
1015
+ source: opts.source,
1016
+ noRestore: opts.noRestore,
1017
+ preRelease: opts.preRelease
1018
+ }));
1019
+ }
1020
+ }
1021
+ }
1022
+ async function searchForMultiplePackages(packageIds, source, preRelease) {
1023
+ // TODO: optimise
1024
+ const promises = packageIds.map(id => searchPackages({
1025
+ search: id,
1026
+ exactMatch: true,
1027
+ preRelease,
1028
+ source,
1029
+ take: 1
1030
+ }));
1031
+ const allResults = await Promise.all(promises), finalResult = [];
1032
+ for (const resultArray of allResults) {
1033
+ for (const result of resultArray) {
1034
+ finalResult.push(result);
1035
+ }
1036
+ }
1037
+ return finalResult;
1038
+ }
1039
+ function isRegex(value) {
1040
+ return value instanceof RegExp;
1041
+ }
1042
+ function verifyExists(value, failMessage) {
1043
+ if (value === undefined || value === null) {
1044
+ throw new ZarroError(failMessage);
1045
+ }
1046
+ }
1047
+ function verifyNonEmptyString(value, failMessage) {
1048
+ if (!`${value}`.trim()) {
1049
+ throw new ZarroError(failMessage);
1050
+ }
1051
+ }
867
1052
  module.exports = {
868
1053
  test,
869
1054
  build,
@@ -881,6 +1066,10 @@ WARNING: 'dotnet pack' ignores --version-suffix when a nuspec file is provided.
881
1066
  tryFindConfiguredNugetSource,
882
1067
  incrementTempDbPortHintIfFound,
883
1068
  searchPackages,
884
- installPackage
1069
+ installPackage,
1070
+ upgradePackages,
1071
+ create,
1072
+ listProjects,
1073
+ addProjectToSolution
885
1074
  };
886
1075
  })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zarro",
3
- "version": "1.173.0",
3
+ "version": "1.173.4",
4
4
  "description": "Some glue to make gulp easier, perhaps even zero- or close-to-zero-conf",
5
5
  "bin": {
6
6
  "zarro": "./index.js"
@@ -61,7 +61,7 @@
61
61
  "decompress": "^4.2.1",
62
62
  "del": "^5.1.0",
63
63
  "event-stream": "^4.0.1",
64
- "exec-step": "^0.11.0",
64
+ "exec-step": "^0.14.0",
65
65
  "fancy-log": "^1.3.3",
66
66
  "gulp": "^4.0.0",
67
67
  "gulp-debug": "^4.0.0",
package/types.d.ts CHANGED
@@ -22,6 +22,7 @@ interface RequireModule<T>
22
22
  }
23
23
 
24
24
  declare global {
25
+
25
26
  function requireModule<T>(module: string): T;
26
27
 
27
28
  // copied out of @types/fancy-log because imports are being stupid
@@ -82,7 +83,7 @@ declare global {
82
83
  }
83
84
 
84
85
  interface Log {
85
- setThreshold(level: number): void;
86
+ setThreshold(level: number | string): void;
86
87
 
87
88
  debug(...args: any[]): void;
88
89
 
@@ -115,7 +116,9 @@ declare global {
115
116
  threshold: LogThreshold;
116
117
 
117
118
  outputDisabled: boolean;
119
+
118
120
  enableOutput(): void;
121
+
119
122
  disableOutput(): void;
120
123
 
121
124
  }
@@ -1202,15 +1205,21 @@ declare global {
1202
1205
  stdout: string[];
1203
1206
 
1204
1207
  isResult(): this is SystemResult;
1208
+
1205
1209
  isError(): this is SystemError;
1206
1210
  }
1207
1211
 
1208
1212
  interface SystemResultBuilder {
1209
1213
  withExe(exe: string): SystemResultBuilder;
1214
+
1210
1215
  withArgs(args: string[]): SystemResultBuilder;
1216
+
1211
1217
  withExitCode(code: number): SystemResultBuilder;
1218
+
1212
1219
  withStdErr(lines: string[] | string): SystemResultBuilder;
1220
+
1213
1221
  withStdOut(lines: string[] | string): SystemResultBuilder;
1222
+
1214
1223
  build(): SystemResult;
1215
1224
  }
1216
1225
 
@@ -1244,11 +1253,13 @@ declare global {
1244
1253
  interface System
1245
1254
  extends SystemFunction {
1246
1255
  isError(o: any): o is SystemError;
1256
+
1247
1257
  isResult(o: any): o is SystemResult;
1248
1258
  }
1249
1259
 
1250
1260
  interface TempFile {
1251
1261
  path: string;
1262
+
1252
1263
  destroy(): void;
1253
1264
  }
1254
1265
 
@@ -1262,11 +1273,13 @@ declare global {
1262
1273
  }
1263
1274
 
1264
1275
  type ZarroTestPackage = "local" | "beta" | "latest" | string;
1276
+
1265
1277
  interface TestZarroOptions {
1266
1278
  packageVersion: ZarroTestPackage;
1267
1279
  tasks: string | string[];
1268
1280
  rollback?: boolean;
1269
1281
  }
1282
+
1270
1283
  type TestZarro = (opts: TestZarroOptions) => Promise<void>;
1271
1284
 
1272
1285
  type GulpNugetRestore = (opts: NugetRestoreOptions) => Stream;
@@ -1288,11 +1301,12 @@ declare global {
1288
1301
  gulpNpmRun: (gulp: Gulp) => void;
1289
1302
  isNpmScript: (name: string) => boolean;
1290
1303
  }
1304
+
1291
1305
  type Nuget = (args: string[], opts?: SystemOptions) => Promise<void>;
1292
1306
 
1293
1307
  interface CliSupport {
1294
- pushIfSet: (args: string[], value: Optional<string | number>, cliSwitch: string) => void;
1295
- pushFlag: (args: string[], value: Optional<boolean>, cliSwitch: string) => void;
1308
+ pushIfSet: (args: string[], value: Nullable<Optional<string | number>>, cliSwitch: string) => void;
1309
+ pushFlag: (args: string[], value: Nullable<Optional<boolean>>, cliSwitch: string) => void;
1296
1310
  }
1297
1311
 
1298
1312
  interface NugetInstallOptions {
@@ -1324,11 +1338,17 @@ declare global {
1324
1338
 
1325
1339
  interface NugetCli {
1326
1340
  install: (opts: NugetInstallOptions) => Promise<void>;
1341
+
1327
1342
  clearAllCache(): Promise<void>;
1343
+
1328
1344
  clearHttpCache(): Promise<void>;
1345
+
1329
1346
  listSources(): Promise<NugetSource[]>;
1347
+
1330
1348
  addSource(src: NugetAddSourceOptions): Promise<void>;
1349
+
1331
1350
  enableSource(name: string): Promise<void>;
1351
+
1332
1352
  disableSource(name: string): Promise<void>;
1333
1353
  }
1334
1354
 
@@ -1349,6 +1369,7 @@ declare global {
1349
1369
  outputStream?: NodeJS.WriteStream,
1350
1370
  validator?: (s: string) => boolean;
1351
1371
  }
1372
+
1352
1373
  type AskFunction = (message: string, options?: AskOptions) => Promise<string>;
1353
1374
  type Ask = {
1354
1375
  ask: AskFunction
@@ -1373,13 +1394,17 @@ declare global {
1373
1394
 
1374
1395
  interface DotNetBaseOptions
1375
1396
  extends IoConsumers {
1376
- msbuildProperties?: Dictionary<string>;
1377
- additionalArguments?: string[];
1378
1397
  verbosity?: DotNetVerbosity | string;
1379
1398
  // when set, errors are returned instead of thrown
1380
1399
  suppressErrors?: boolean;
1381
1400
  suppressStdIoInErrors?: boolean;
1382
1401
  suppressOutput?: boolean;
1402
+ }
1403
+
1404
+ interface DotNetMsBuildOptions
1405
+ extends DotNetBaseOptions {
1406
+ msbuildProperties?: Dictionary<string>;
1407
+ additionalArguments?: string[];
1383
1408
 
1384
1409
  env?: Dictionary<string>;
1385
1410
  }
@@ -1426,7 +1451,7 @@ declare global {
1426
1451
  type GulpDotNetCover = (opts?: GulpDotNetCoverOptions) => Transform;
1427
1452
 
1428
1453
  interface DotNetCommonBuildOptions
1429
- extends DotNetBaseOptions {
1454
+ extends DotNetMsBuildOptions {
1430
1455
  target: string;
1431
1456
  configuration?: string | string[];
1432
1457
  framework?: string;
@@ -1456,7 +1481,7 @@ declare global {
1456
1481
  }
1457
1482
 
1458
1483
  interface DotNetPackOptions
1459
- extends DotNetBaseOptions {
1484
+ extends DotNetMsBuildOptions {
1460
1485
  target: string;
1461
1486
  output?: string;
1462
1487
  configuration?: string | string[];
@@ -1485,7 +1510,7 @@ declare global {
1485
1510
  }
1486
1511
 
1487
1512
  interface DotNetCleanOptions
1488
- extends DotNetBaseOptions {
1513
+ extends DotNetMsBuildOptions {
1489
1514
  target: string;
1490
1515
  framework?: string;
1491
1516
  runtime?: string;
@@ -1494,7 +1519,7 @@ declare global {
1494
1519
  }
1495
1520
 
1496
1521
  interface DotNetNugetPushOptions
1497
- extends DotNetBaseOptions {
1522
+ extends DotNetMsBuildOptions {
1498
1523
  target: string;
1499
1524
  apiKey?: string;
1500
1525
  symbolApiKey?: string;
@@ -1508,8 +1533,9 @@ declare global {
1508
1533
  timeout?: number;
1509
1534
  }
1510
1535
 
1511
- interface DotNetSearchPackagesOptions extends DotNetBaseOptions {
1512
- source?: string;
1536
+ interface DotNetSearchPackagesOptions
1537
+ extends DotNetMsBuildOptions {
1538
+ source?: string | null | undefined;
1513
1539
  search?: string;
1514
1540
  take?: number;
1515
1541
  skip?: number;
@@ -1517,9 +1543,16 @@ declare global {
1517
1543
  preRelease?: boolean;
1518
1544
  configFile?: string;
1519
1545
  latestOnly?: boolean;
1546
+ /**
1547
+ * search results are typically cached in memory
1548
+ * for 1 minute. If you absolutely _must_ have
1549
+ * fresh data, set this to false
1550
+ */
1551
+ skipCache?: boolean;
1520
1552
  }
1521
1553
 
1522
- interface DotNetInstallNugetPackageOption extends DotNetBaseOptions {
1554
+ interface DotNetInstallNugetPackageOption
1555
+ extends DotNetMsBuildOptions {
1523
1556
  id: string;
1524
1557
  projectFile: string;
1525
1558
  version?: string;
@@ -1533,6 +1566,8 @@ declare global {
1533
1566
  interface IoConsumers {
1534
1567
  stdout?: IoConsumer;
1535
1568
  stderr?: IoConsumer;
1569
+ cwd?: string;
1570
+ env?: NodeJS.ProcessEnv
1536
1571
  }
1537
1572
 
1538
1573
  interface DotNetTestOptions
@@ -1576,6 +1611,42 @@ declare global {
1576
1611
  usingFallback: boolean;
1577
1612
  }
1578
1613
 
1614
+ interface DotNetCreateBaseOptions
1615
+ extends DotNetBaseOptions {
1616
+ output?: string;
1617
+ name: string;
1618
+ dryRun?: boolean;
1619
+ force?: boolean;
1620
+ skipTemplateUpdateCheck?: boolean;
1621
+ enableDiagnostics?: boolean;
1622
+ }
1623
+
1624
+ interface DotNetCreateOptions
1625
+ extends DotNetCreateBaseOptions {
1626
+ template: string;
1627
+ projectFile?: string;
1628
+ }
1629
+
1630
+ interface DotNetAddProjectToSolutionOptions
1631
+ extends DotNetBaseOptions {
1632
+ solutionFile: string;
1633
+ projectFile: string;
1634
+ }
1635
+
1636
+ type StringOrRegex = string | RegExp;
1637
+
1638
+ interface DotNetUpgradePackagesOptions {
1639
+ pathToProjectOrSolution: string;
1640
+ packages: StringOrRegex[],
1641
+ preRelease?: boolean;
1642
+ noRestore?: boolean;
1643
+ source?: string;
1644
+ /**
1645
+ * defaults to true
1646
+ */
1647
+ showProgress?: boolean;
1648
+ }
1649
+
1579
1650
  type DotNetTestFunction = (opts: DotNetTestOptions) => Promise<SystemResult | SystemError>;
1580
1651
  type DotNetBuildFunction = (opts: DotNetBuildOptions) => Promise<SystemResult | SystemError>;
1581
1652
  type DotNetPackFunction = (opts: DotNetPackOptions) => Promise<SystemResult | SystemError>;
@@ -1592,6 +1663,10 @@ declare global {
1592
1663
  type DotNetTryMatchNugetSourceFunction = (nameOrUrlOrHostOrSpec: string | Partial<NugetSource> | RegExp) => Promise<Optional<NugetSource>>;
1593
1664
  type DotNetSearchNugetPackagesFunction = (opts: DotNetSearchPackagesOptions | string) => Promise<PackageInfo[]>;
1594
1665
  type DotNetInstallNugetPackageFunction = (opts: DotNetInstallNugetPackageOption | string) => Promise<void>;
1666
+ type DotNetUpgradePackagesFunction = (opts: DotNetUpgradePackagesOptions) => Promise<void>;
1667
+ type DotNetCreateFunction = (opts: DotNetCreateOptions) => Promise<string>;
1668
+ type DotNetListProjectsFunction = (solutionFile: string) => Promise<string[]>;
1669
+ type DotNetAddProjectToSolutionFunction = (opts: DotNetAddProjectToSolutionOptions) => Promise<void>;
1595
1670
 
1596
1671
  interface DotNetCli {
1597
1672
  clean: DotNetCleanFunction;
@@ -1611,6 +1686,10 @@ declare global {
1611
1686
  incrementTempDbPortHintIfFound: (env: Dictionary<string>) => void;
1612
1687
  searchPackages: DotNetSearchNugetPackagesFunction;
1613
1688
  installPackage: DotNetInstallNugetPackageFunction;
1689
+ upgradePackages: DotNetUpgradePackagesFunction;
1690
+ create: DotNetCreateFunction;
1691
+ listProjects: DotNetListProjectsFunction;
1692
+ addProjectToSolution: DotNetAddProjectToSolutionFunction;
1614
1693
  }
1615
1694
 
1616
1695
  type ReadCsProjNode = (csproj: string) => Promise<string>;
@@ -2066,5 +2145,24 @@ declare global {
2066
2145
  "ZPL-1.1" |
2067
2146
  "ZPL-2.0" |
2068
2147
  "ZPL-2.1"
2148
+
2149
+ interface Cache {
2150
+ read<T>(key: string, fallback?: T): Optional<T>;
2151
+ write<T>(key: string, value: T, ttlSeconds: number): void;
2152
+ through<T>(
2153
+ key: string,
2154
+ generator: Func<Promise<T>>,
2155
+ ttlSeconds: number
2156
+ ): Promise<T>;
2157
+ throughSync<T>(
2158
+ key: string,
2159
+ generator: Func<T>,
2160
+ ttlSeconds: number
2161
+ ): T;
2162
+ create(): Cache;
2163
+ trim(): void;
2164
+ forget(key: string): void;
2165
+ clear(): void;
2166
+ }
2069
2167
  }
2070
2168