@oclif/core 2.0.2-beta.1 → 2.0.2-beta.11

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.
@@ -1,2 +1,2 @@
1
- import * as cliProgress from 'cli-progress';
2
- export default function progress(options?: cliProgress.Options): cliProgress.SingleBar;
1
+ import { Options, SingleBar } from 'cli-progress';
2
+ export default function progress(options?: Options): SingleBar;
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  // 3pp
4
- const cliProgress = require("cli-progress");
4
+ const cli_progress_1 = require("cli-progress");
5
5
  function progress(options = {}) {
6
6
  // set noTTYOutput for options
7
7
  options.noTTYOutput = Boolean(process.env.TERM === 'dumb' || !process.stdin.isTTY);
8
- return new cliProgress.SingleBar(options);
8
+ return new cli_progress_1.SingleBar(options);
9
9
  }
10
10
  exports.default = progress;
@@ -40,6 +40,7 @@ export declare class Config implements IConfig {
40
40
  constructor(options: Options);
41
41
  static load(opts?: LoadOptions): Promise<Config>;
42
42
  load(): Promise<void>;
43
+ loadPluginsAndCommands(): Promise<void>;
43
44
  loadCorePlugins(): Promise<void>;
44
45
  loadDevPlugins(): Promise<void>;
45
46
  loadUserPlugins(): Promise<void>;
@@ -106,6 +107,7 @@ export declare class Config implements IConfig {
106
107
  detail: string;
107
108
  }, scope?: string): void;
108
109
  protected get isProd(): boolean;
110
+ private isJitPluginCommand;
109
111
  private getCmdLookupId;
110
112
  private getTopicLookupId;
111
113
  private loadCommands;
@@ -134,6 +134,10 @@ class Config {
134
134
  ...s3.templates && s3.templates.vanilla,
135
135
  },
136
136
  };
137
+ await this.loadPluginsAndCommands();
138
+ debug('config done');
139
+ }
140
+ async loadPluginsAndCommands() {
137
141
  await this.loadUserPlugins();
138
142
  await this.loadDevPlugins();
139
143
  await this.loadCorePlugins();
@@ -141,7 +145,6 @@ class Config {
141
145
  this.loadCommands(plugin);
142
146
  this.loadTopics(plugin);
143
147
  }
144
- debug('config done');
145
148
  }
146
149
  async loadCorePlugins() {
147
150
  if (this.pjson.oclif.plugins) {
@@ -250,21 +253,44 @@ class Config {
250
253
  }
251
254
  async runCommand(id, argv = [], cachedCommand = null) {
252
255
  debug('runCommand %s %o', id, argv);
253
- const c = cachedCommand ?? this.findCommand(id);
256
+ let c = cachedCommand ?? this.findCommand(id);
254
257
  if (!c) {
255
258
  const matches = this.flexibleTaxonomy ? this.findMatches(id, argv) : [];
256
259
  const hookResult = this.flexibleTaxonomy && matches.length > 0 ?
257
260
  await this.runHook('command_incomplete', { id, argv, matches }) :
258
261
  await this.runHook('command_not_found', { id, argv });
259
- if (hookResult.successes[0]) {
260
- const cmdResult = hookResult.successes[0].result;
261
- return cmdResult;
262
- }
263
- if (hookResult.failures[0]) {
262
+ if (hookResult.successes[0])
263
+ return hookResult.successes[0].result;
264
+ if (hookResult.failures[0])
264
265
  throw hookResult.failures[0].error;
265
- }
266
266
  throw new errors_1.CLIError(`command ${id} not found`);
267
267
  }
268
+ if (this.isJitPluginCommand(c)) {
269
+ const pluginName = c.pluginName;
270
+ const pluginVersion = this.pjson.oclif.jitPlugins[pluginName];
271
+ const jitResult = await this.runHook('jit_plugin_not_installed', {
272
+ id,
273
+ argv,
274
+ command: c,
275
+ pluginName,
276
+ pluginVersion,
277
+ });
278
+ if (jitResult.failures[0])
279
+ throw jitResult.failures[0].error;
280
+ if (jitResult.successes[0]) {
281
+ await this.loadPluginsAndCommands();
282
+ c = this.findCommand(id) ?? c;
283
+ }
284
+ else {
285
+ // this means that no jit_plugin_not_installed hook exists, so we should run the default behavior
286
+ const result = await this.runHook('command_not_found', { id, argv });
287
+ if (result.successes[0])
288
+ return result.successes[0].result;
289
+ if (result.failures[0])
290
+ throw result.failures[0].error;
291
+ throw new errors_1.CLIError(`command ${id} not found`);
292
+ }
293
+ }
268
294
  const command = await c.load();
269
295
  await this.runHook('prerun', { Command: command, argv });
270
296
  const result = (await command.run(argv, this));
@@ -487,6 +513,9 @@ class Config {
487
513
  get isProd() {
488
514
  return (0, util_3.isProd)();
489
515
  }
516
+ isJitPluginCommand(c) {
517
+ return Object.keys(this.pjson.oclif.jitPlugins ?? {}).includes(c.pluginName ?? '') && !this.plugins.find(p => p.name === c?.pluginName);
518
+ }
490
519
  getCmdLookupId(id) {
491
520
  if (this._commands.has(id))
492
521
  return id;
@@ -595,6 +624,14 @@ class Config {
595
624
  if (a.pluginType === 'core' && b.pluginType !== 'core') {
596
625
  return -1;
597
626
  }
627
+ // if a is a jit plugin and b is not sort b first
628
+ if (a.pluginType === 'jit' && b.pluginType !== 'jit') {
629
+ return 1;
630
+ }
631
+ // if b is a jit plugin and a is not sort a first
632
+ if (b.pluginType === 'jit' && a.pluginType !== 'jit') {
633
+ return -1;
634
+ }
598
635
  // neither plugin is core, so do not change the order
599
636
  return 0;
600
637
  });
@@ -698,12 +735,8 @@ async function toCached(c, plugin) {
698
735
  }
699
736
  }
700
737
  }
701
- // v1 commands have args as an array, so we need to normalize it to an object for backwards compatibility
702
- const normalized = (Array.isArray(c.args) ? (c.args ?? []).reduce((x, y) => {
703
- return { ...x, [y.name]: y };
704
- }, {}) : c.args ?? {});
705
738
  const args = {};
706
- for (const [name, arg] of Object.entries(normalized)) {
739
+ for (const [name, arg] of Object.entries((0, util_3.ensureArgObject)(c.args))) {
707
740
  args[name] = {
708
741
  name,
709
742
  description: arg.description,
@@ -731,7 +764,8 @@ async function toCached(c, plugin) {
731
764
  flags,
732
765
  args,
733
766
  };
734
- const ignoreCommandProperties = ['plugin', '_flags', '_enableJsonFlag', '_baseFlags'];
767
+ // do not include these properties in manifest
768
+ const ignoreCommandProperties = ['plugin', '_flags', '_enableJsonFlag', '_globalFlags', '_baseFlags'];
735
769
  const stdKeys = Object.keys(stdProperties);
736
770
  const keysToAdd = Object.keys(c).filter(property => ![...stdKeys, ...ignoreCommandProperties].includes(property));
737
771
  const additionalProperties = {};
@@ -127,7 +127,12 @@ class Plugin {
127
127
  this.manifest = await this._manifest(Boolean(this.options.ignoreManifest), Boolean(this.options.errorOnManifestCreate));
128
128
  this.commands = Object
129
129
  .entries(this.manifest.commands)
130
- .map(([id, c]) => ({ ...c, pluginAlias: this.alias, pluginType: this.type, load: async () => this.findCommand(id, { must: true }) }))
130
+ .map(([id, c]) => ({
131
+ ...c,
132
+ pluginAlias: this.alias,
133
+ pluginType: c.pluginType === 'jit' ? 'jit' : this.type,
134
+ load: async () => this.findCommand(id, { must: true }),
135
+ }))
131
136
  .sort((a, b) => a.id.localeCompare(b.id));
132
137
  }
133
138
  get topics() {
@@ -31,7 +31,7 @@ class CommandHelp extends formatter_1.HelpFormatter {
31
31
  v.name = k;
32
32
  return v;
33
33
  }), f => [!f.char, f.char, f.name]);
34
- const args = Object.values(cmd.args ?? {}).filter(a => !a.hidden);
34
+ const args = Object.values((0, util_1.ensureArgObject)(cmd.args)).filter(a => !a.hidden);
35
35
  const output = (0, util_1.compact)(this.sections().map(({ header, generate }) => {
36
36
  const body = generate({ cmd, flags, args }, header);
37
37
  // Generate can return a list of sections
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DocOpts = void 0;
4
+ const util_1 = require("../util");
4
5
  /**
5
6
  * DocOpts - See http://docopt.org/.
6
7
  *
@@ -75,7 +76,7 @@ class DocOpts {
75
76
  toString() {
76
77
  const opts = this.cmd.id === '.' || this.cmd.id === '' ? [] : ['<%= command.id %>'];
77
78
  if (this.cmd.args) {
78
- const a = Object.values(this.cmd.args ?? {}).map(arg => `[${arg.name.toUpperCase()}]`) || [];
79
+ const a = Object.values((0, util_1.ensureArgObject)(this.cmd.args)).map(arg => `[${arg.name.toUpperCase()}]`) || [];
79
80
  opts.push(...a);
80
81
  }
81
82
  try {
@@ -1,11 +1,10 @@
1
- import * as ejs from 'ejs';
2
1
  import { Config as IConfig, HelpOptions, Deprecation } from '../interfaces';
3
2
  import { HelpBase } from '.';
4
3
  interface HelpBaseDerived {
5
4
  new (config: IConfig, opts?: Partial<HelpOptions>): HelpBase;
6
5
  }
7
6
  export declare function loadHelpClass(config: IConfig): Promise<HelpBaseDerived>;
8
- export declare function template(context: ejs.Data): (t: string) => string;
7
+ export declare function template(context: any): (t: string) => string;
9
8
  export declare function toStandardizedId(commandID: string, config: IConfig): string;
10
9
  export declare function toConfiguredId(commandID: string, config: IConfig): string;
11
10
  export declare function standardizeIDFromArgv(argv: string[], config: IConfig): string[];
package/lib/help/util.js CHANGED
@@ -23,6 +23,7 @@ async function loadHelpClass(config) {
23
23
  return _1.Help;
24
24
  }
25
25
  exports.loadHelpClass = loadHelpClass;
26
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
26
27
  function template(context) {
27
28
  function render(t) {
28
29
  return ejs.render(t, context);
@@ -58,6 +58,16 @@ export interface Hooks {
58
58
  };
59
59
  return: unknown;
60
60
  };
61
+ 'jit_plugin_not_installed': {
62
+ options: {
63
+ id: string;
64
+ argv: string[];
65
+ command: Command.Loadable;
66
+ pluginName: string;
67
+ pluginVersion: string;
68
+ };
69
+ return: unknown;
70
+ };
61
71
  'plugins:preinstall': {
62
72
  options: {
63
73
  plugin: {
@@ -84,6 +94,7 @@ export declare namespace Hook {
84
94
  type Update = Hook<'update'>;
85
95
  type CommandNotFound = Hook<'command_not_found'>;
86
96
  type CommandIncomplete = Hook<'command_incomplete'>;
97
+ type JitPluginNotInstalled = Hook<'jit_plugin_not_installed'>;
87
98
  interface Context {
88
99
  config: Config;
89
100
  exit(code?: number): void;
@@ -73,7 +73,7 @@ export type Relationship = {
73
73
  export type Deprecation = {
74
74
  to?: string;
75
75
  message?: string;
76
- version?: string;
76
+ version?: string | number;
77
77
  };
78
78
  export type FlagProps = {
79
79
  name: string;
@@ -27,6 +27,7 @@ export declare namespace PJSON {
27
27
  default?: string;
28
28
  plugins?: string[];
29
29
  devPlugins?: string[];
30
+ jitPlugins?: Record<string, string>;
30
31
  helpClass?: string;
31
32
  helpOptions?: HelpOptions;
32
33
  aliases?: {
@@ -83,6 +84,7 @@ export declare namespace PJSON {
83
84
  scope?: string;
84
85
  dirname?: string;
85
86
  flexibleTaxonomy?: boolean;
87
+ jitPlugins?: Record<string, string>;
86
88
  };
87
89
  }
88
90
  interface User extends PJSON {
@@ -13,6 +13,7 @@ export interface PluginOptions {
13
13
  }
14
14
  export interface Options extends PluginOptions {
15
15
  devPlugins?: boolean;
16
+ jitPlugins?: boolean;
16
17
  userPlugins?: boolean;
17
18
  channel?: string;
18
19
  version?: string;
package/lib/main.js CHANGED
@@ -72,7 +72,7 @@ async function run(argv, options) {
72
72
  // command id.
73
73
  if (config.pjson.oclif.default === '.' && id === '.' && argv[0] === '.')
74
74
  argvSlice = ['.', ...argvSlice];
75
- await config.runCommand(id, argvSlice, cmd);
75
+ return config.runCommand(id, argvSlice, cmd);
76
76
  }
77
77
  exports.run = run;
78
78
  function getTsConfigPath(dir, type) {
@@ -1,6 +1,6 @@
1
1
  import { CLIError } from '../errors';
2
2
  import { OptionFlag, Flag } from '../interfaces';
3
- import { Arg, ArgInput, CLIParseErrorOptions } from '../interfaces/parser';
3
+ import { Arg, ArgInput, BooleanFlag, CLIParseErrorOptions } from '../interfaces/parser';
4
4
  export { CLIError } from '../errors';
5
5
  export type Validation = {
6
6
  name: string;
@@ -47,6 +47,9 @@ export declare class NonExistentFlagsError extends CLIParseError {
47
47
  export declare class FlagInvalidOptionError extends CLIParseError {
48
48
  constructor(flag: OptionFlag<any>, input: string);
49
49
  }
50
+ export declare class FailedFlagParseError extends CLIParseError {
51
+ constructor(flag: BooleanFlag<any> | OptionFlag<any>, errMsg: string);
52
+ }
50
53
  export declare class ArgInvalidOptionError extends CLIParseError {
51
54
  constructor(arg: Arg<any>, input: string);
52
55
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FailedFlagValidationError = exports.ArgInvalidOptionError = exports.FlagInvalidOptionError = exports.NonExistentFlagsError = exports.UnexpectedArgsError = exports.RequiredFlagError = exports.RequiredArgsError = exports.InvalidArgsSpecError = exports.CLIParseError = exports.CLIError = void 0;
3
+ exports.FailedFlagValidationError = exports.ArgInvalidOptionError = exports.FailedFlagParseError = exports.FlagInvalidOptionError = exports.NonExistentFlagsError = exports.UnexpectedArgsError = exports.RequiredFlagError = exports.RequiredArgsError = exports.InvalidArgsSpecError = exports.CLIParseError = exports.CLIError = void 0;
4
4
  const errors_1 = require("../errors");
5
5
  const help_1 = require("./help");
6
6
  const list_1 = require("../cli-ux/list");
@@ -74,6 +74,13 @@ class FlagInvalidOptionError extends CLIParseError {
74
74
  }
75
75
  }
76
76
  exports.FlagInvalidOptionError = FlagInvalidOptionError;
77
+ class FailedFlagParseError extends CLIParseError {
78
+ constructor(flag, errMsg) {
79
+ const message = `Parsing --${flag.name} \n\t${errMsg}`;
80
+ super({ parse: {}, message });
81
+ }
82
+ }
83
+ exports.FailedFlagParseError = FailedFlagParseError;
77
84
  class ArgInvalidOptionError extends CLIParseError {
78
85
  constructor(arg, input) {
79
86
  const message = `Expected ${input} to be one of: ${arg.options.join(', ')}`;
@@ -11,6 +11,7 @@ export declare class Parser<T extends ParserInput, TFlags extends OutputFlags<T[
11
11
  constructor(input: T);
12
12
  parse(): Promise<ParserOutput<TFlags, BFlags, TArgs>>;
13
13
  private _flags;
14
+ private _parseFlag;
14
15
  private _validateOptions;
15
16
  private _args;
16
17
  private _debugOutput;
@@ -41,7 +41,6 @@ const readStdin = async () => {
41
41
  debug('resolved from stdin', result);
42
42
  resolve(result);
43
43
  });
44
- // @ts-expect-error because the AbortSignal interface is missing addEventListener
45
44
  signal.addEventListener('abort', () => {
46
45
  debug('stdin aborted');
47
46
  clearTimeout(timeout);
@@ -183,13 +182,13 @@ class Parser {
183
182
  else {
184
183
  flags[token.flag] = true;
185
184
  }
186
- flags[token.flag] = await flag.parse(flags[token.flag], this.context, flag);
185
+ flags[token.flag] = await this._parseFlag(flags[token.flag], flag);
187
186
  }
188
187
  else {
189
188
  const input = token.input;
190
189
  this._validateOptions(flag, input);
191
190
  if (flag.delimiter && flag.multiple) {
192
- const values = await Promise.all(input.split(flag.delimiter).map(async (v) => flag.parse ? flag.parse(v.trim(), this.context, flag) : v.trim()));
191
+ const values = await Promise.all(input.split(flag.delimiter).map(async (v) => this._parseFlag(v.trim(), flag)));
193
192
  flags[token.flag] = flags[token.flag] || [];
194
193
  flags[token.flag].push(...values);
195
194
  }
@@ -230,6 +229,17 @@ class Parser {
230
229
  }
231
230
  return flags;
232
231
  }
232
+ async _parseFlag(input, flag) {
233
+ try {
234
+ if (flag.type === 'boolean') {
235
+ return await flag.parse(input, this.context, flag);
236
+ }
237
+ return flag.parse ? await flag.parse(input, this.context, flag) : input;
238
+ }
239
+ catch (error) {
240
+ throw new errors_1.FailedFlagParseError(flag, error.message);
241
+ }
242
+ }
233
243
  _validateOptions(flag, input) {
234
244
  if (flag.options && !flag.options.includes(input))
235
245
  throw new errors_1.FlagInvalidOptionError(flag, input);
package/lib/util.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { Command } from './command';
2
+ import { ArgInput } from './interfaces/parser';
1
3
  export declare function pickBy<T extends {
2
4
  [s: string]: T[keyof T];
3
5
  } | ArrayLike<T[keyof T]>>(obj: T, fn: (i: T[keyof T]) => boolean): Partial<T>;
@@ -15,4 +17,14 @@ export declare const fileExists: (input: string) => Promise<string>;
15
17
  export declare function isTruthy(input: string): boolean;
16
18
  export declare function isNotFalsy(input: string): boolean;
17
19
  export declare function requireJson<T>(...pathParts: string[]): T;
20
+ /**
21
+ * Ensure that the provided args are an object. This is for backwards compatibility with v1 commands which
22
+ * defined args as an array.
23
+ *
24
+ * @param args Either an array of args or an object of args
25
+ * @returns ArgInput
26
+ */
27
+ export declare function ensureArgObject(args?: any[] | ArgInput | {
28
+ [name: string]: Command.Arg.Cached;
29
+ }): ArgInput;
18
30
  export {};
package/lib/util.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.requireJson = exports.isNotFalsy = exports.isTruthy = exports.fileExists = exports.dirExists = exports.capitalize = exports.sumBy = exports.maxBy = exports.isProd = exports.castArray = exports.sortBy = exports.uniqBy = exports.compact = exports.pickBy = void 0;
3
+ exports.ensureArgObject = exports.requireJson = exports.isNotFalsy = exports.isTruthy = exports.fileExists = exports.dirExists = exports.capitalize = exports.sumBy = exports.maxBy = exports.isProd = exports.castArray = exports.sortBy = exports.uniqBy = exports.compact = exports.pickBy = void 0;
4
4
  const fs = require("fs");
5
5
  const path_1 = require("path");
6
6
  function pickBy(obj, fn) {
@@ -94,14 +94,27 @@ const fileExists = async (input) => {
94
94
  };
95
95
  exports.fileExists = fileExists;
96
96
  function isTruthy(input) {
97
- return ['true', 'TRUE', '1', 'yes', 'YES', 'y', 'Y'].includes(input);
97
+ return ['true', '1', 'yes', 'y'].includes(input.toLowerCase());
98
98
  }
99
99
  exports.isTruthy = isTruthy;
100
100
  function isNotFalsy(input) {
101
- return !['false', 'FALSE', '0', 'no', 'NO', 'n', 'N'].includes(input);
101
+ return !['false', '0', 'no', 'n'].includes(input.toLowerCase());
102
102
  }
103
103
  exports.isNotFalsy = isNotFalsy;
104
104
  function requireJson(...pathParts) {
105
105
  return JSON.parse(fs.readFileSync((0, path_1.join)(...pathParts), 'utf8'));
106
106
  }
107
107
  exports.requireJson = requireJson;
108
+ /**
109
+ * Ensure that the provided args are an object. This is for backwards compatibility with v1 commands which
110
+ * defined args as an array.
111
+ *
112
+ * @param args Either an array of args or an object of args
113
+ * @returns ArgInput
114
+ */
115
+ function ensureArgObject(args) {
116
+ return (Array.isArray(args) ? (args ?? []).reduce((x, y) => {
117
+ return { ...x, [y.name]: y };
118
+ }, {}) : args ?? {});
119
+ }
120
+ exports.ensureArgObject = ensureArgObject;
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@oclif/core",
3
3
  "description": "base library for oclif CLIs",
4
- "version": "2.0.2-beta.1",
4
+ "version": "2.0.2-beta.11",
5
5
  "author": "Salesforce",
6
6
  "bugs": "https://github.com/oclif/core/issues",
7
7
  "dependencies": {
8
+ "@types/cli-progress": "^3.11.0",
8
9
  "ansi-escapes": "^4.3.2",
9
10
  "ansi-styles": "^4.3.0",
10
11
  "cardinal": "^2.1.1",
@@ -37,19 +38,18 @@
37
38
  "@commitlint/config-conventional": "^12.1.4",
38
39
  "@oclif/plugin-help": "^5.1.22",
39
40
  "@oclif/plugin-plugins": "^2.1.12",
40
- "@oclif/test": "^2.2.19",
41
+ "@oclif/test": "^2.2.20",
41
42
  "@types/ansi-styles": "^3.2.1",
42
43
  "@types/chai": "^4.3.4",
43
44
  "@types/chai-as-promised": "^7.1.5",
44
45
  "@types/clean-stack": "^2.1.1",
45
- "@types/cli-progress": "^3.9.2",
46
46
  "@types/ejs": "^3.1.0",
47
47
  "@types/fs-extra": "^9.0.13",
48
48
  "@types/indent-string": "^4.0.1",
49
49
  "@types/js-yaml": "^3.12.7",
50
50
  "@types/mocha": "^8.2.3",
51
51
  "@types/nock": "^11.1.0",
52
- "@types/node": "^15.14.9",
52
+ "@types/node": "^16",
53
53
  "@types/node-notifier": "^8.0.2",
54
54
  "@types/proxyquire": "^1.3.28",
55
55
  "@types/semver": "^7.3.13",
@@ -64,11 +64,11 @@
64
64
  "eslint": "^7.32.0",
65
65
  "eslint-config-oclif": "^4.0.0",
66
66
  "eslint-config-oclif-typescript": "^1.0.2",
67
- "fancy-test": "^1.4.10",
67
+ "fancy-test": "^2.0.12",
68
68
  "globby": "^11.1.0",
69
69
  "husky": "6",
70
70
  "mocha": "^8.4.0",
71
- "nock": "^13.2.4",
71
+ "nock": "^13.3.0",
72
72
  "proxyquire": "^2.1.3",
73
73
  "shelljs": "^0.8.5",
74
74
  "shx": "^0.3.4",
@@ -109,7 +109,7 @@
109
109
  "lint": "eslint . --ext .ts --config .eslintrc",
110
110
  "posttest": "yarn lint",
111
111
  "prepack": "yarn run build",
112
- "test": "mocha \"test/**/*.test.ts\"",
112
+ "test": "mocha --forbid-only \"test/**/*.test.ts\"",
113
113
  "test:e2e": "mocha \"test/**/*.e2e.ts\" --timeout 1200000",
114
114
  "pretest": "yarn build --noEmit && tsc -p test --noEmit --skipLibCheck"
115
115
  },