@salesforce/source-tracking 0.5.0 → 1.0.1

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,38 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [1.0.1](https://github.com/forcedotcom/source-tracking/compare/v1.0.0...v1.0.1) (2022-01-25)
6
+
7
+ ### Bug Fixes
8
+
9
+ - emailTempalteFolder via aliased types ([f4c88f9](https://github.com/forcedotcom/source-tracking/commit/f4c88f9b59ad6d061933bfd3f6827e44a59b0e80))
10
+
11
+ ## [1.0.0](https://github.com/forcedotcom/source-tracking/compare/v0.5.2...v1.0.0) (2022-01-20)
12
+
13
+ ### Bug Fixes
14
+
15
+ - handle element count errors ([8817329](https://github.com/forcedotcom/source-tracking/commit/8817329f8198ce701aba22c7a4476ef31a4d73a4))
16
+ - lightning EmailTemplateFolder ([554c766](https://github.com/forcedotcom/source-tracking/commit/554c76676a85c7a4b673879116912cde51dd1498))
17
+ - remove emailtf attempt ([262839d](https://github.com/forcedotcom/source-tracking/commit/262839dc025c7094d8868d3ae9d769dd39ad5324))
18
+ - sourceMember excepton for nondecomposed children ([05db59e](https://github.com/forcedotcom/source-tracking/commit/05db59e7a6e070224a45f5fbf08013565c9f2131))
19
+
20
+ ### [0.5.2](https://github.com/forcedotcom/source-tracking/compare/v0.5.1...v0.5.2) (2022-01-05)
21
+
22
+ ### Features
23
+
24
+ - path-scoped singleton ([de46db4](https://github.com/forcedotcom/source-tracking/commit/de46db4b08a3fe087a2931936655c75b3b7cc32c))
25
+
26
+ ### Bug Fixes
27
+
28
+ - distributed .gitignore and loose pkgDir matching ([a148a36](https://github.com/forcedotcom/source-tracking/commit/a148a366739b6941f3f479b375147897103316bb))
29
+ - remove singleton behavior for localShadowRepo ([887bb68](https://github.com/forcedotcom/source-tracking/commit/887bb684528df8df07fe9b4edf1bd2f4165fe3e2))
30
+
31
+ ### [0.5.1](https://github.com/forcedotcom/source-tracking/compare/v0.5.0...v0.5.1) (2021-12-03)
32
+
33
+ ### Bug Fixes
34
+
35
+ - support addressable child types ([8251095](https://github.com/forcedotcom/source-tracking/commit/82510955ba8ffe4a2e7e5411973795da3671d01e))
36
+
5
37
  ## [0.5.0](https://github.com/forcedotcom/source-tracking/compare/v0.4.4...v0.5.0) (2021-12-02)
6
38
 
7
39
  ### ⚠ BREAKING CHANGES
package/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2021, Salesforce.com, Inc.
1
+ Copyright (c) 2022, Salesforce.com, Inc.
2
2
  All rights reserved.
3
3
 
4
4
  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
@@ -3,3 +3,8 @@ import { RemoteChangeElement, ChangeResult } from './types';
3
3
  export declare const getMetadataKey: (metadataType: string, metadataName: string) => string;
4
4
  export declare const getKeyFromObject: (element: RemoteChangeElement | ChangeResult) => string;
5
5
  export declare const isBundle: (cmp: SourceComponent) => boolean;
6
+ /**
7
+ * Verify that a filepath starts exactly with a complete parent path
8
+ * ex: '/foo/bar-extra/baz'.startsWith('foo/bar') would be true, but this function understands that they are not in the same folder
9
+ */
10
+ export declare const pathIsInFolder: (filePath: string, folder: string) => boolean;
@@ -6,7 +6,9 @@
6
6
  * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.isBundle = exports.getKeyFromObject = exports.getMetadataKey = void 0;
9
+ exports.pathIsInFolder = exports.isBundle = exports.getKeyFromObject = exports.getMetadataKey = void 0;
10
+ const path_1 = require("path");
11
+ const ts_types_1 = require("@salesforce/ts-types");
10
12
  const getMetadataKey = (metadataType, metadataName) => {
11
13
  return `${metadataType}__${metadataName}`;
12
14
  };
@@ -20,4 +22,19 @@ const getKeyFromObject = (element) => {
20
22
  exports.getKeyFromObject = getKeyFromObject;
21
23
  const isBundle = (cmp) => { var _a; return ((_a = cmp.type.strategies) === null || _a === void 0 ? void 0 : _a.adapter) === 'bundle'; };
22
24
  exports.isBundle = isBundle;
25
+ /**
26
+ * Verify that a filepath starts exactly with a complete parent path
27
+ * ex: '/foo/bar-extra/baz'.startsWith('foo/bar') would be true, but this function understands that they are not in the same folder
28
+ */
29
+ const pathIsInFolder = (filePath, folder) => {
30
+ const biggerStringParts = (0, path_1.normalize)(filePath).split(path_1.sep).filter(nonEmptyStringFilter);
31
+ return (0, path_1.normalize)(folder)
32
+ .split(path_1.sep)
33
+ .filter(nonEmptyStringFilter)
34
+ .every((part, index) => part === biggerStringParts[index]);
35
+ };
36
+ exports.pathIsInFolder = pathIsInFolder;
37
+ const nonEmptyStringFilter = (value) => {
38
+ return (0, ts_types_1.isString)(value) && value.length > 0;
39
+ };
23
40
  //# sourceMappingURL=functions.js.map
@@ -11,12 +11,13 @@ interface CommitRequest {
11
11
  message?: string;
12
12
  }
13
13
  export declare class ShadowRepo {
14
- private static instance;
14
+ private static instanceMap;
15
15
  gitDir: string;
16
16
  projectPath: string;
17
17
  private packageDirs;
18
18
  private status;
19
19
  private logger;
20
+ private gitIgnoreLocations;
20
21
  private constructor();
21
22
  static getInstance(options: ShadowRepoOptions): Promise<ShadowRepo>;
22
23
  init(): Promise<void>;
@@ -74,6 +75,7 @@ export declare class ShadowRepo {
74
75
  * @returns sha (string)
75
76
  */
76
77
  commitChanges({ deployedFiles, deletedFiles, message, }?: CommitRequest): Promise<string>;
78
+ private locateIgnoreFiles;
77
79
  private stashIgnoreFile;
78
80
  private unStashIgnoreFile;
79
81
  }
@@ -12,6 +12,7 @@ const path = require("path");
12
12
  const os = require("os");
13
13
  const core_1 = require("@salesforce/core");
14
14
  const git = require("isomorphic-git");
15
+ const functions_1 = require("./functions");
15
16
  const gitIgnoreFileName = '.gitignore';
16
17
  const stashedGitIgnoreFileName = '.BAK.gitignore';
17
18
  /**
@@ -28,16 +29,19 @@ const HEAD = 1;
28
29
  const WORKDIR = 2;
29
30
  class ShadowRepo {
30
31
  constructor(options) {
32
+ this.gitIgnoreLocations = [];
31
33
  this.gitDir = getGitDir(options.orgId, options.projectPath);
32
34
  this.projectPath = options.projectPath;
33
35
  this.packageDirs = options.packageDirs;
34
36
  }
37
+ // think of singleton behavior but unique to the projectPath
35
38
  static async getInstance(options) {
36
- if (!ShadowRepo.instance) {
37
- ShadowRepo.instance = new ShadowRepo(options);
38
- await ShadowRepo.instance.init();
39
+ if (!ShadowRepo.instanceMap.has(options.projectPath)) {
40
+ const newInstance = new ShadowRepo(options);
41
+ await newInstance.init();
42
+ ShadowRepo.instanceMap.set(options.projectPath, newInstance);
39
43
  }
40
- return ShadowRepo.instance;
44
+ return ShadowRepo.instanceMap.get(options.projectPath);
41
45
  }
42
46
  async init() {
43
47
  this.logger = await core_1.Logger.child('ShadowRepo');
@@ -54,6 +58,7 @@ class ShadowRepo {
54
58
  async gitInit() {
55
59
  await core_1.fs.promises.mkdir(this.gitDir, { recursive: true });
56
60
  await git.init({ fs: core_1.fs, dir: this.projectPath, gitdir: this.gitDir, defaultBranch: 'main' });
61
+ await this.locateIgnoreFiles();
57
62
  }
58
63
  /**
59
64
  * Delete the local tracking files
@@ -94,8 +99,15 @@ class ShadowRepo {
94
99
  dir: this.projectPath,
95
100
  gitdir: this.gitDir,
96
101
  filepaths,
97
- // filter out hidden files and __tests__ patterns, regardless of gitignore
98
- filter: (f) => !f.includes(`${path.sep}.`) && !f.includes('__tests__'),
102
+ filter: (f) =>
103
+ // no hidden files
104
+ !f.includes(`${path.sep}.`) &&
105
+ // no lwc tests
106
+ !f.includes('__tests__') &&
107
+ // no gitignore files
108
+ ![gitIgnoreFileName, stashedGitIgnoreFileName].includes(path.basename(f)) &&
109
+ // isogit uses `startsWith` for filepaths so it's possible to get a false positive
110
+ filepaths.some((pkgDir) => (0, functions_1.pathIsInFolder)(f, pkgDir)),
99
111
  });
100
112
  // isomorphic-git stores things in unix-style tree. Convert to windows-style if necessary
101
113
  if (isWindows) {
@@ -196,20 +208,31 @@ class ShadowRepo {
196
208
  await this.unStashIgnoreFile();
197
209
  }
198
210
  }
211
+ async locateIgnoreFiles() {
212
+ // set the gitIgnoreLocations so we only have to do it once
213
+ this.gitIgnoreLocations = (await git.walk({
214
+ fs: core_1.fs,
215
+ dir: this.projectPath,
216
+ gitdir: this.gitDir,
217
+ trees: [git.WORKDIR()],
218
+ // TODO: this can be marginally faster if we limit it to pkgDirs and toplevel project files
219
+ // eslint-disable-next-line @typescript-eslint/require-await
220
+ map: async (filepath) => filepath,
221
+ }))
222
+ .filter((filepath) => filepath.includes(gitIgnoreFileName) &&
223
+ // can be top-level like '.' (no sep) OR must be in one of the package dirs
224
+ (!filepath.includes(path.sep) || this.packageDirs.some((dir) => (0, functions_1.pathIsInFolder)(filepath, dir.name))))
225
+ .map((ignoreFile) => path.join(this.projectPath, ignoreFile));
226
+ }
199
227
  async stashIgnoreFile() {
200
- const originalLocation = path.join(this.projectPath, gitIgnoreFileName);
201
- // another process may have already stashed the file
202
- if (core_1.fs.existsSync(originalLocation)) {
203
- await core_1.fs.promises.rename(originalLocation, path.join(this.projectPath, stashedGitIgnoreFileName));
204
- }
228
+ // allSettled allows them to fail (example, the file wasn't where it was expected).
229
+ await Promise.allSettled(this.gitIgnoreLocations.map((originalLocation) => core_1.fs.promises.rename(originalLocation, originalLocation.replace(gitIgnoreFileName, stashedGitIgnoreFileName))));
205
230
  }
206
231
  async unStashIgnoreFile() {
207
- const stashedLocation = path.join(this.projectPath, stashedGitIgnoreFileName);
208
- // another process may have already un-stashed the file
209
- if (core_1.fs.existsSync(stashedLocation)) {
210
- await core_1.fs.promises.rename(stashedLocation, path.join(this.projectPath, gitIgnoreFileName));
211
- }
232
+ // allSettled allows them to fail (example, the file wasn't where it was expected).
233
+ await Promise.allSettled(this.gitIgnoreLocations.map((originalLocation) => core_1.fs.promises.rename(originalLocation.replace(gitIgnoreFileName, stashedGitIgnoreFileName), originalLocation)));
212
234
  }
213
235
  }
214
236
  exports.ShadowRepo = ShadowRepo;
237
+ ShadowRepo.instanceMap = new Map();
215
238
  //# sourceMappingURL=localShadowRepo.js.map
@@ -1,2 +1,3 @@
1
1
  import { RemoteSyncInput } from './types';
2
2
  export declare const getMetadataKeyFromFileResponse: (fileResponse: RemoteSyncInput) => string[];
3
+ export declare const mappingsForSourceMemberTypesToMetadataType: Map<string, string>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getMetadataKeyFromFileResponse = void 0;
3
+ exports.mappingsForSourceMemberTypesToMetadataType = exports.getMetadataKeyFromFileResponse = void 0;
4
4
  /*
5
5
  * Copyright (c) 2020, salesforce.com, inc.
6
6
  * All rights reserved.
@@ -8,11 +8,18 @@ exports.getMetadataKeyFromFileResponse = void 0;
8
8
  * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
9
9
  */
10
10
  const path = require("path");
11
+ const source_deploy_retrieve_1 = require("@salesforce/source-deploy-retrieve");
11
12
  const functions_1 = require("./functions");
12
13
  // LWC can have child folders (ex: dynamic templates like /templates/noDataIllustration.html
13
14
  const pathAfterFullName = (fileResponse) => fileResponse && fileResponse.filePath
14
15
  ? fileResponse.filePath.substr(fileResponse.filePath.indexOf(fileResponse.fullName)).replace(/\\/gi, '/')
15
16
  : '';
17
+ const registry = new source_deploy_retrieve_1.RegistryAccess();
18
+ // only compute once
19
+ const aliasTypes = registry
20
+ .getAliasTypes()
21
+ .map((aliasType) => [aliasType.name, registry.getTypeByName(aliasType.aliasFor).name]);
22
+ const reverseAliasTypes = new Map(aliasTypes.map(([alias, type]) => [type, alias]));
16
23
  // handle all "weird" type/name translation between SourceMember and SDR FileResponse
17
24
  // These get de-duplicated in a set later, so it's ok to have one per file
18
25
  const getMetadataKeyFromFileResponse = (fileResponse) => {
@@ -38,8 +45,27 @@ const getMetadataKeyFromFileResponse = (fileResponse) => {
38
45
  (0, functions_1.getMetadataKey)(fileResponse.type, fileResponse.fullName),
39
46
  ];
40
47
  }
41
- // standard key
48
+ // CustomLabels (file) => CustomLabel[] (how they're storedin SourceMembers)
49
+ if (fileResponse.type === 'CustomLabels' && fileResponse.filePath) {
50
+ return source_deploy_retrieve_1.ComponentSet.fromSource(fileResponse.filePath)
51
+ .getSourceComponents()
52
+ .toArray()
53
+ .flatMap((component) => component.getChildren().map((child) => (0, functions_1.getMetadataKey)('CustomLabel', child.fullName)));
54
+ }
55
+ // if we've aliased a type, we'll have to possibly sync both types--you can't tell from the sourceComponent retrieved which way it was stored on the server
56
+ if (reverseAliasTypes.has(fileResponse.type)) {
57
+ return [
58
+ (0, functions_1.getMetadataKey)(fileResponse.type, fileResponse.fullName),
59
+ (0, functions_1.getMetadataKey)(reverseAliasTypes.get(fileResponse.type), fileResponse.fullName),
60
+ ];
61
+ }
62
+ // standard key for everything else
42
63
  return [(0, functions_1.getMetadataKey)(fileResponse.type, fileResponse.fullName)];
43
64
  };
44
65
  exports.getMetadataKeyFromFileResponse = getMetadataKeyFromFileResponse;
66
+ exports.mappingsForSourceMemberTypesToMetadataType = new Map([
67
+ ...aliasTypes,
68
+ ['AuraDefinition', 'AuraDefinitionBundle'],
69
+ ['LightningComponentResource', 'LightningComponentBundle'],
70
+ ]);
45
71
  //# sourceMappingURL=metadataKeys.js.map
@@ -477,18 +477,14 @@ RemoteSourceTrackingService.remoteSourceTrackingServiceDictionary = {};
477
477
  const remoteChangeElementToChangeResult = (rce) => {
478
478
  return {
479
479
  ...rce,
480
- ...(mappingsForSourceMemberTypesToMetadataType.has(rce.type)
480
+ ...(metadataKeys_1.mappingsForSourceMemberTypesToMetadataType.has(rce.type)
481
481
  ? {
482
482
  name: rce.name.split('/')[0],
483
- type: mappingsForSourceMemberTypesToMetadataType.get(rce.type),
483
+ type: metadataKeys_1.mappingsForSourceMemberTypesToMetadataType.get(rce.type),
484
484
  }
485
485
  : {}),
486
486
  origin: 'remote', // we know they're remote
487
487
  };
488
488
  };
489
489
  exports.remoteChangeElementToChangeResult = remoteChangeElementToChangeResult;
490
- const mappingsForSourceMemberTypesToMetadataType = new Map([
491
- ['AuraDefinition', 'AuraDefinitionBundle'],
492
- ['LightningComponentResource', 'LightningComponentBundle'],
493
- ]);
494
490
  //# sourceMappingURL=remoteSourceTrackingService.js.map
@@ -18,6 +18,7 @@ const remoteSourceTrackingService_1 = require("./shared/remoteSourceTrackingServ
18
18
  const localShadowRepo_1 = require("./shared/localShadowRepo");
19
19
  const guards_1 = require("./shared/guards");
20
20
  const functions_1 = require("./shared/functions");
21
+ const metadataKeys_1 = require("./shared/metadataKeys");
21
22
  /**
22
23
  * Manages source tracking files (remote and local)
23
24
  *
@@ -59,8 +60,8 @@ class SourceTracking extends kit_1.AsyncCreatable {
59
60
  const groupings = (byPackageDir
60
61
  ? this.packagesDirs.map((pkgDir) => ({
61
62
  path: pkgDir.name,
62
- nonDeletes: allNonDeletes.filter((f) => f.startsWith(pkgDir.name)),
63
- deletes: allDeletes.filter((f) => f.startsWith(pkgDir.name)),
63
+ nonDeletes: allNonDeletes.filter((f) => (0, functions_1.pathIsInFolder)(f, pkgDir.name)),
64
+ deletes: allDeletes.filter((f) => (0, functions_1.pathIsInFolder)(f, pkgDir.name)),
64
65
  }))
65
66
  : [
66
67
  {
@@ -282,7 +283,7 @@ class SourceTracking extends kit_1.AsyncCreatable {
282
283
  .filter(ts_types_1.isString);
283
284
  await this.localRepo.commitChanges({
284
285
  deployedFiles: relativeOptions.files,
285
- deletedFiles: relativeOptions.deletedFiles.concat((await this.localRepo.getDeleteFilenames()).filter((deployedFile) => bundlesWithDeletedFiles.some((bundlePath) => deployedFile.startsWith(bundlePath)) &&
286
+ deletedFiles: relativeOptions.deletedFiles.concat((await this.localRepo.getDeleteFilenames()).filter((deployedFile) => bundlesWithDeletedFiles.some((bundlePath) => (0, functions_1.pathIsInFolder)(deployedFile, bundlePath)) &&
286
287
  !relativeOptions.files.includes(deployedFile))),
287
288
  });
288
289
  }
@@ -518,11 +519,18 @@ class SourceTracking extends kit_1.AsyncCreatable {
518
519
  return results;
519
520
  }
520
521
  registrySupportsType(type) {
521
- if (this.registry.findType((metadataType) => metadataType.name === type)) {
522
+ try {
523
+ if (metadataKeys_1.mappingsForSourceMemberTypesToMetadataType.has(type)) {
524
+ return true;
525
+ }
526
+ // this must use getTypeByName because findType doesn't support addressable child types (ex: customField!)
527
+ this.registry.getTypeByName(type);
522
528
  return true;
523
529
  }
524
- process.emitWarning(`Unable to find type ${type} in registry`);
525
- return false;
530
+ catch (e) {
531
+ process.emitWarning(`Unable to find type ${type} in registry`);
532
+ return false;
533
+ }
526
534
  }
527
535
  /**
528
536
  * uses SDR to translate remote metadata records into local file paths
@@ -547,11 +555,16 @@ class SourceTracking extends kit_1.AsyncCreatable {
547
555
  const remoteChangesAsComponentSet = new source_deploy_retrieve_1.ComponentSet(remoteChangesAsMetadataMember);
548
556
  this.logger.debug(` the generated component set has ${remoteChangesAsComponentSet.size.toString()} items`);
549
557
  if (remoteChangesAsComponentSet.size < elements.length) {
558
+ // there *could* be something missing
559
+ // some types (ex: LWC) show up as multiple files in the remote changes, but only one in the component set
550
560
  // iterate the elements to see which ones didn't make it into the component set
551
- throw new Error(`unable to generate complete component set for ${elements
552
- .filter((element) => !remoteChangesAsComponentSet.has({ type: element === null || element === void 0 ? void 0 : element.type, fullName: element === null || element === void 0 ? void 0 : element.name }))
553
- .map((element) => `${element.name} (${element.type})`)
554
- .join(os_1.EOL)}`);
561
+ const missingComponents = elements.filter((element) => !remoteChangesAsComponentSet.has({ type: element === null || element === void 0 ? void 0 : element.type, fullName: element === null || element === void 0 ? void 0 : element.name }));
562
+ // Throw if anything was actually missing
563
+ if (missingComponents.length > 0) {
564
+ throw new Error(`unable to generate complete component set for ${elements
565
+ .map((element) => `${element.name} (${element.type})`)
566
+ .join(os_1.EOL)}`);
567
+ }
555
568
  }
556
569
  const matchingLocalSourceComponentsSet = source_deploy_retrieve_1.ComponentSet.fromSource({
557
570
  fsPaths: this.packagesDirs.map((dir) => dir.path),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@salesforce/source-tracking",
3
3
  "description": "API for tracking local and remote Salesforce metadata changes",
4
- "version": "0.5.0",
4
+ "version": "1.0.1",
5
5
  "author": "Salesforce",
6
6
  "license": "BSD-3-Clause",
7
7
  "main": "lib/index.js",
@@ -24,7 +24,8 @@
24
24
  "pretest": "sf-compile-test",
25
25
  "prune:dead": "ts-prune | grep -v 'source-deploy-retrieve' | grep -v 'index.ts'",
26
26
  "test": "sf-test",
27
- "test:nuts": "nyc mocha \"**/*.nut.ts\" --slow 4500 --timeout 600000 --parallel"
27
+ "test:nuts": "nyc mocha \"**/*.nut.ts\" --slow 4500 --timeout 600000 --parallel",
28
+ "test:nuts:local": "mocha \"**/local/*.nut.ts\" --slow 4500 --timeout 600000 --parallel"
28
29
  },
29
30
  "keywords": [
30
31
  "force",
@@ -42,16 +43,16 @@
42
43
  "/oclif.manifest.json"
43
44
  ],
44
45
  "dependencies": {
45
- "@salesforce/core": "^2.31.0",
46
+ "@salesforce/core": "^2.33.1",
46
47
  "@salesforce/kit": "^1.5.17",
47
- "@salesforce/source-deploy-retrieve": "^5.8.0",
48
+ "@salesforce/source-deploy-retrieve": "^5.9.4",
48
49
  "isomorphic-git": "^1.9.2",
49
50
  "ts-retry-promise": "^0.6.0"
50
51
  },
51
52
  "devDependencies": {
52
53
  "@salesforce/cli-plugins-testkit": "^1.3.7",
53
- "@salesforce/dev-config": "^2.1.2",
54
- "@salesforce/dev-scripts": "^1.0.2",
54
+ "@salesforce/dev-config": "^3.0.0",
55
+ "@salesforce/dev-scripts": "^2.0.0",
55
56
  "@salesforce/prettier-config": "^0.0.2",
56
57
  "@salesforce/ts-sinon": "^1.3.21",
57
58
  "@types/shelljs": "^0.8.9",
@@ -65,11 +66,11 @@
65
66
  "eslint-config-salesforce-license": "^0.1.6",
66
67
  "eslint-config-salesforce-typescript": "^0.2.7",
67
68
  "eslint-plugin-header": "^3.1.1",
68
- "eslint-plugin-import": "2.24.2",
69
+ "eslint-plugin-import": "2.25.4",
69
70
  "eslint-plugin-jsdoc": "^37.0.1",
70
71
  "eslint-plugin-prettier": "^3.4.0",
71
72
  "husky": "^7.0.4",
72
- "mocha": "^9.0.3",
73
+ "mocha": "^9.1.3",
73
74
  "nyc": "^15.1.0",
74
75
  "prettier": "^2.3.2",
75
76
  "pretty-quick": "^3.1.1",