@oclif/core 2.8.11 → 2.9.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.
@@ -10,6 +10,7 @@ const util_2 = require("util");
10
10
  const stream_1 = require("../stream");
11
11
  const sw = require('string-width');
12
12
  const { orderBy } = require('natural-orderby');
13
+ const sliceAnsi = require('slice-ansi');
13
14
  class Table {
14
15
  constructor(data, columns, options = {}) {
15
16
  this.data = data;
@@ -258,7 +259,12 @@ class Table {
258
259
  const colorWidth = (d.length - visualWidth);
259
260
  let cell = d.padEnd(width + colorWidth);
260
261
  if ((cell.length - colorWidth) > width || visualWidth === width) {
261
- cell = cell.slice(0, width - 2) + '… ';
262
+ // truncate the cell, preserving ANSI escape sequences, and keeping
263
+ // into account the width of fullwidth unicode characters
264
+ cell = sliceAnsi(cell, 0, width - 2) + '… ';
265
+ // pad with spaces; this is necessary in case the original string
266
+ // contained fullwidth characters which cannot be split
267
+ cell += ' '.repeat(width - sw(cell));
262
268
  }
263
269
  l += cell;
264
270
  }
@@ -48,7 +48,7 @@ export type Metadata = {
48
48
  [key: string]: MetadataFlag;
49
49
  };
50
50
  };
51
- type MetadataFlag = {
51
+ export type MetadataFlag = {
52
52
  setFromDefault?: boolean;
53
53
  defaultHelp?: unknown;
54
54
  };
@@ -368,4 +368,3 @@ export type ArgInput<T extends ArgOutput = {
368
368
  }> = {
369
369
  [P in keyof T]: Arg<T[P]>;
370
370
  };
371
- export {};
@@ -6,17 +6,14 @@ export declare class Parser<T extends ParserInput, TFlags extends OutputFlags<T[
6
6
  private readonly booleanFlags;
7
7
  private readonly flagAliases;
8
8
  private readonly context;
9
- private readonly metaData;
10
9
  private currentFlag?;
11
10
  constructor(input: T);
12
11
  parse(): Promise<ParserOutput<TFlags, BFlags, TArgs>>;
13
12
  private _flags;
14
- private _parseFlag;
15
- private _validateOptions;
16
13
  private _args;
17
14
  private _debugOutput;
18
15
  private _debugInput;
19
16
  private get _argTokens();
20
- private get _flagTokens();
21
17
  private _setNames;
18
+ private mapAndValidateFlags;
22
19
  }
@@ -63,7 +63,6 @@ class Parser {
63
63
  this.flagAliases = Object.fromEntries(Object.values(input.flags).flatMap(flag => {
64
64
  return (flag.aliases ?? []).map(a => [a, flag]);
65
65
  }));
66
- this.metaData = {};
67
66
  }
68
67
  async parse() {
69
68
  this._debugInput();
@@ -85,11 +84,16 @@ class Parser {
85
84
  if (this.flagAliases[char]) {
86
85
  return this.flagAliases[char].name;
87
86
  }
88
- return Object.keys(this.input.flags).find(k => this.input.flags[k].char === char);
87
+ return Object.keys(this.input.flags).find(k => (this.input.flags[k].char === char && char !== undefined && this.input.flags[k].char !== undefined));
88
+ };
89
+ const findFlag = (arg) => {
90
+ const isLong = arg.startsWith('--');
91
+ const short = isLong ? false : arg.startsWith('-');
92
+ const name = isLong ? findLongFlag(arg) : (short ? findShortFlag(arg) : undefined);
93
+ return { name, isLong };
89
94
  };
90
95
  const parseFlag = (arg) => {
91
- const long = arg.startsWith('--');
92
- const name = long ? findLongFlag(arg) : findShortFlag(arg);
96
+ const { name, isLong } = findFlag(arg);
93
97
  if (!name) {
94
98
  const i = arg.indexOf('=');
95
99
  if (i !== -1) {
@@ -106,16 +110,17 @@ class Parser {
106
110
  const flag = this.input.flags[name];
107
111
  if (flag.type === 'option') {
108
112
  this.currentFlag = flag;
109
- const input = long || arg.length < 3 ? this.argv.shift() : arg.slice(arg[2] === '=' ? 3 : 2);
110
- if (typeof input !== 'string') {
113
+ const input = isLong || arg.length < 3 ? this.argv.shift() : arg.slice(arg[2] === '=' ? 3 : 2);
114
+ // if the value ends up being one of the command's flags, the user didn't provide an input
115
+ if ((typeof input !== 'string') || findFlag(input).name) {
111
116
  throw new errors_1.CLIError(`Flag --${name} expects a value`);
112
117
  }
113
- this.raw.push({ type: 'flag', flag: flag.name, input });
118
+ this.raw.push({ type: 'flag', flag: flag.name, input: input });
114
119
  }
115
120
  else {
116
121
  this.raw.push({ type: 'flag', flag: flag.name, input: arg });
117
122
  // push the rest of the short characters back on the stack
118
- if (!long && arg.length > 2) {
123
+ if (!isLong && arg.length > 2) {
119
124
  this.argv.unshift(`-${arg.slice(2)}`);
120
125
  }
121
126
  }
@@ -157,8 +162,7 @@ class Parser {
157
162
  const arg = Object.keys(this.input.args)[this._argTokens.length];
158
163
  this.raw.push({ type: 'arg', arg, input });
159
164
  }
160
- const { argv, args } = await this._args();
161
- const flags = await this._flags();
165
+ const [{ argv, args }, { flags, metadata }] = await Promise.all([this._args(), this._flags()]);
162
166
  this._debugOutput(argv, args, flags);
163
167
  const unsortedArgv = (dashdash ? [...argv, ...nonExistentFlags, '--'] : [...argv, ...nonExistentFlags]);
164
168
  return {
@@ -166,113 +170,118 @@ class Parser {
166
170
  flags,
167
171
  args: args,
168
172
  raw: this.raw,
169
- metadata: this.metaData,
173
+ metadata,
170
174
  nonExistentFlags,
171
175
  };
172
176
  }
173
- // eslint-disable-next-line complexity
174
177
  async _flags() {
175
- const flags = {};
176
- this.metaData.flags = {};
177
- for (const token of this._flagTokens) {
178
- const flag = this.input.flags[token.flag];
179
- if (!flag)
180
- throw new errors_1.CLIError(`Unexpected flag ${token.flag}`);
181
- if (flag.type === 'boolean') {
182
- if (token.input === `--no-${flag.name}`) {
183
- flags[token.flag] = false;
184
- }
185
- else {
186
- flags[token.flag] = true;
178
+ const validateOptions = (flag, input) => {
179
+ if (flag.options && !flag.options.includes(input))
180
+ throw new errors_1.FlagInvalidOptionError(flag, input);
181
+ return input;
182
+ };
183
+ const parseFlagOrThrowError = async (input, flag, token, context = {}) => {
184
+ if (!flag.parse)
185
+ return input;
186
+ try {
187
+ if (flag.type === 'boolean') {
188
+ return await flag.parse(input, { ...context, token }, flag);
187
189
  }
188
- flags[token.flag] = await this._parseFlag(flags[token.flag], flag, token);
190
+ return await flag.parse(input, { ...context, token }, flag);
189
191
  }
190
- else {
191
- const input = token.input;
192
- if (flag.delimiter && flag.multiple) {
193
- // split, trim, and remove surrounding doubleQuotes (which would hav been needed if the elements contain spaces)
194
- const values = await Promise.all(input.split(flag.delimiter).map(async (v) => this._parseFlag(v.trim().replace(/^"(.*)"$/, '$1').replace(/^'(.*)'$/, '$1'), flag, token)));
195
- // then parse that each element aligns with the `options` property
196
- for (const v of values) {
197
- this._validateOptions(flag, v);
198
- }
199
- flags[token.flag] = flags[token.flag] || [];
200
- flags[token.flag].push(...values);
192
+ catch (error) {
193
+ error.message = `Parsing --${flag.name} \n\t${error.message}\nSee more help with --help`;
194
+ throw error;
195
+ }
196
+ };
197
+ /* Could add a valueFunction (if there is a value/env/default) and could metadata.
198
+ * Value function can be resolved later.
199
+ */
200
+ const addValueFunction = (fws) => {
201
+ const tokenLength = fws.tokens?.length;
202
+ // user provided some input
203
+ if (tokenLength) {
204
+ // boolean
205
+ if (fws.inputFlag.flag.type === 'boolean' && fws.tokens?.at(-1)?.input) {
206
+ return { ...fws, valueFunction: async (i) => parseFlagOrThrowError(i.tokens?.at(-1)?.input !== `--no-${i.inputFlag.name}`, i.inputFlag.flag, i.tokens?.at(-1), this.context) };
201
207
  }
202
- else {
203
- this._validateOptions(flag, input);
204
- const value = await this._parseFlag(input, flag, token);
205
- if (flag.multiple) {
206
- flags[token.flag] = flags[token.flag] || [];
207
- flags[token.flag].push(value);
208
- }
209
- else {
210
- flags[token.flag] = value;
211
- }
208
+ // multiple with custom delimiter
209
+ if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.delimiter && fws.inputFlag.flag.multiple) {
210
+ return {
211
+ ...fws, valueFunction: async (i) => (await Promise.all(((i.tokens ?? []).flatMap(token => token.input.split(i.inputFlag.flag.delimiter)))
212
+ // trim, and remove surrounding doubleQuotes (which would hav been needed if the elements contain spaces)
213
+ .map(v => v.trim().replace(/^"(.*)"$/, '$1').replace(/^'(.*)'$/, '$1'))
214
+ .map(async (v) => parseFlagOrThrowError(v, i.inputFlag.flag, { ...i.tokens?.at(-1), input: v }, this.context)))).map(v => validateOptions(i.inputFlag.flag, v)),
215
+ };
212
216
  }
213
- }
214
- }
215
- for (const k of Object.keys(this.input.flags)) {
216
- const flag = this.input.flags[k];
217
- if (flags[k])
218
- continue;
219
- if (flag.env && Reflect.has(process.env, flag.env)) {
220
- const input = process.env[flag.env];
221
- if (flag.type === 'option') {
222
- if (input) {
223
- this._validateOptions(flag, input);
224
- flags[k] = await this._parseFlag(input, flag);
225
- }
217
+ // multiple in the oclif-core style
218
+ if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.multiple) {
219
+ return { ...fws, valueFunction: async (i) => Promise.all((fws.tokens ?? []).map(token => parseFlagOrThrowError(validateOptions(i.inputFlag.flag, token.input), i.inputFlag.flag, token, this.context))) };
226
220
  }
227
- else if (flag.type === 'boolean') {
228
- // eslint-disable-next-line no-negated-condition
229
- flags[k] = input !== undefined ? (0, util_1.isTruthy)(input) : false;
221
+ // simple option flag
222
+ if (fws.inputFlag.flag.type === 'option') {
223
+ return { ...fws, valueFunction: async (i) => parseFlagOrThrowError(validateOptions(i.inputFlag.flag, fws.tokens?.at(-1)?.input), i.inputFlag.flag, fws.tokens?.at(-1), this.context) };
230
224
  }
231
225
  }
232
- if (!(k in flags) && flag.default !== undefined) {
233
- this.metaData.flags[k] = { ...this.metaData.flags[k], setFromDefault: true };
234
- const defaultValue = (typeof flag.default === 'function' ? await flag.default({ options: flag, flags }) : flag.default);
235
- flags[k] = defaultValue;
236
- }
237
- }
238
- for (const k of Object.keys(this.input.flags)) {
239
- if ((k in flags) && Reflect.has(this.input.flags[k], 'defaultHelp')) {
240
- try {
241
- const defaultHelpProperty = Reflect.get(this.input.flags[k], 'defaultHelp');
242
- const defaultHelp = (typeof defaultHelpProperty === 'function' ? await defaultHelpProperty({
243
- options: flags[k],
244
- flags, ...this.context,
245
- }) : defaultHelpProperty);
246
- this.metaData.flags[k] = { ...this.metaData.flags[k], defaultHelp };
226
+ // no input: env flags
227
+ if (fws.inputFlag.flag.env && process.env[fws.inputFlag.flag.env]) {
228
+ const valueFromEnv = process.env[fws.inputFlag.flag.env];
229
+ if (fws.inputFlag.flag.type === 'option' && valueFromEnv) {
230
+ return { ...fws, valueFunction: async (i) => parseFlagOrThrowError(validateOptions(i.inputFlag.flag, valueFromEnv), i.inputFlag.flag, this.context) };
247
231
  }
248
- catch {
249
- // no-op
232
+ if (fws.inputFlag.flag.type === 'boolean') {
233
+ return { ...fws, valueFunction: async (i) => Promise.resolve((0, util_1.isTruthy)(process.env[i.inputFlag.flag.env] ?? 'false')) };
250
234
  }
251
235
  }
252
- }
253
- return flags;
254
- }
255
- async _parseFlag(input, flag, token) {
256
- if (!flag.parse)
257
- return input;
258
- try {
259
- const ctx = this.context;
260
- ctx.token = token;
261
- if (flag.type === 'boolean') {
262
- const ctx = this.context;
263
- ctx.token = token;
264
- return await flag.parse(input, ctx, flag);
236
+ // no input, but flag has default value
237
+ if (typeof fws.inputFlag.flag.default !== undefined) {
238
+ return {
239
+ ...fws, metadata: { setFromDefault: true },
240
+ valueFunction: typeof fws.inputFlag.flag.default === 'function' ?
241
+ (i, allFlags = {}) => fws.inputFlag.flag.default({ options: i.inputFlag.flag, flags: allFlags }) :
242
+ async () => fws.inputFlag.flag.default,
243
+ };
265
244
  }
266
- return flag.parse ? await flag.parse(input, ctx, flag) : input;
267
- }
268
- catch (error) {
269
- error.message = `Parsing --${flag.name} \n\t${error.message}\nSee more help with --help`;
270
- throw error;
271
- }
272
- }
273
- _validateOptions(flag, input) {
274
- if (flag.options && !flag.options.includes(input))
275
- throw new errors_1.FlagInvalidOptionError(flag, input);
245
+ // base case (no value function)
246
+ return fws;
247
+ };
248
+ const addHelpFunction = (fws) => {
249
+ if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.defaultHelp) {
250
+ return {
251
+ ...fws, helpFunction: typeof fws.inputFlag.flag.defaultHelp === 'function' ?
252
+ // @ts-expect-error flag type isn't specific enough to know defaultHelp will definitely be there
253
+ (i, flags, ...context) => i.inputFlag.flag.defaultHelp({ options: i.inputFlag, flags }, ...context) :
254
+ // @ts-expect-error flag type isn't specific enough to know defaultHelp will definitely be there
255
+ (i) => i.inputFlag.flag.defaultHelp,
256
+ };
257
+ }
258
+ return fws;
259
+ };
260
+ const addDefaultHelp = async (fws) => {
261
+ const valueReferenceForHelp = fwsArrayToObject(flagsWithAllValues.filter(fws => !fws.metadata?.setFromDefault));
262
+ return Promise.all(fws.map(async (fws) => fws.helpFunction ? ({ ...fws, metadata: { ...fws.metadata, defaultHelp: await fws.helpFunction?.(fws, valueReferenceForHelp, this.context) } }) : fws));
263
+ };
264
+ const fwsArrayToObject = (fwsArray) => Object.fromEntries(fwsArray.map(fws => [fws.inputFlag.name, fws.value]));
265
+ const flagTokenMap = this.mapAndValidateFlags();
266
+ const flagsWithValues = await Promise.all(Object.entries(this.input.flags)
267
+ // we check them if they have a token, or might have env, default, or defaultHelp. Also include booleans so they get their default value
268
+ .filter(([name, flag]) => flag.type === 'boolean' || flag.env || flag.default || 'defaultHelp' in flag || flagTokenMap.has(name))
269
+ // match each possible flag to its token, if there is one
270
+ .map(([name, flag]) => ({ inputFlag: { name, flag }, tokens: flagTokenMap.get(name) }))
271
+ .map(fws => addValueFunction(fws))
272
+ .filter(fws => fws.valueFunction !== undefined)
273
+ .map(fws => addHelpFunction(fws))
274
+ // we can't apply the default values until all the other flags are resolved because `flag.default` can reference other flags
275
+ .map(async (fws) => (fws.metadata?.setFromDefault ? fws : { ...fws, value: await fws.valueFunction?.(fws) })));
276
+ const valueReference = fwsArrayToObject(flagsWithValues.filter(fws => !fws.metadata?.setFromDefault));
277
+ const flagsWithAllValues = await Promise.all(flagsWithValues
278
+ .map(async (fws) => (fws.metadata?.setFromDefault ? { ...fws, value: await fws.valueFunction?.(fws, valueReference) } : fws)));
279
+ const finalFlags = (flagsWithAllValues.some(fws => typeof fws.helpFunction === 'function')) ? await addDefaultHelp(flagsWithAllValues) : flagsWithAllValues;
280
+ return {
281
+ // @ts-ignore original version returned an any. Not sure how to get to the return type for `flags` prop
282
+ flags: fwsArrayToObject(finalFlags),
283
+ metadata: { flags: Object.fromEntries(finalFlags.filter(fws => fws.metadata).map(fws => [fws.inputFlag.name, fws.metadata])) },
284
+ };
276
285
  }
277
286
  async _args() {
278
287
  const argv = [];
@@ -346,9 +355,6 @@ class Parser {
346
355
  get _argTokens() {
347
356
  return this.raw.filter(o => o.type === 'arg');
348
357
  }
349
- get _flagTokens() {
350
- return this.raw.filter(o => o.type === 'flag');
351
- }
352
358
  _setNames() {
353
359
  for (const k of Object.keys(this.input.flags)) {
354
360
  this.input.flags[k].name = k;
@@ -357,5 +363,17 @@ class Parser {
357
363
  this.input.args[k].name = k;
358
364
  }
359
365
  }
366
+ mapAndValidateFlags() {
367
+ const flagTokenMap = new Map();
368
+ for (const token of this.raw.filter(o => o.type === 'flag')) {
369
+ // fail fast if there are any invalid flags
370
+ if (!(token.flag in this.input.flags)) {
371
+ throw new errors_1.CLIError(`Unexpected flag ${token.flag}`);
372
+ }
373
+ const existing = flagTokenMap.get(token.flag) ?? [];
374
+ flagTokenMap.set(token.flag, [...existing, token]);
375
+ }
376
+ return flagTokenMap;
377
+ }
360
378
  }
361
379
  exports.Parser = Parser;
@@ -4,6 +4,7 @@ exports.validate = void 0;
4
4
  const errors_1 = require("./errors");
5
5
  const util_1 = require("../config/util");
6
6
  async function validate(parse) {
7
+ let cachedResolvedFlags;
7
8
  function validateArgs() {
8
9
  if (parse.output.nonExistentFlags?.length > 0) {
9
10
  throw new errors_1.NonExistentFlagsError({ parse, flags: parse.output.nonExistentFlags });
@@ -33,25 +34,31 @@ async function validate(parse) {
33
34
  }
34
35
  }
35
36
  async function validateFlags() {
36
- const promises = Object.entries(parse.input.flags).map(async ([name, flag]) => {
37
- const results = [];
37
+ const promises = Object.entries(parse.input.flags).flatMap(([name, flag]) => {
38
38
  if (parse.output.flags[name] !== undefined) {
39
- results.push(...await validateRelationships(name, flag), await validateDependsOn(name, flag.dependsOn ?? []), await validateExclusive(name, flag.exclusive ?? []), await validateExactlyOne(name, flag.exactlyOne ?? []));
39
+ return [
40
+ ...flag.relationships ? validateRelationships(name, flag) : [],
41
+ ...flag.dependsOn ? [validateDependsOn(name, flag.dependsOn)] : [],
42
+ ...flag.exclusive ? [validateExclusive(name, flag.exclusive)] : [],
43
+ ...flag.exactlyOne ? [validateExactlyOne(name, flag.exactlyOne)] : [],
44
+ ];
40
45
  }
41
- else if (flag.required) {
42
- results.push({ status: 'failed', name, validationFn: 'required', reason: `Missing required flag ${name}` });
46
+ if (flag.required) {
47
+ return [{ status: 'failed', name, validationFn: 'required', reason: `Missing required flag ${name}` }];
43
48
  }
44
- else if (flag.exactlyOne && flag.exactlyOne.length > 0) {
45
- results.push(validateAcrossFlags(flag));
49
+ if (flag.exactlyOne && flag.exactlyOne.length > 0) {
50
+ return [validateAcrossFlags(flag)];
46
51
  }
47
- return results;
52
+ return [];
48
53
  });
49
- const results = (await Promise.all(promises)).flat();
54
+ const results = (await Promise.all(promises));
50
55
  const failed = results.filter(r => r.status === 'failed');
51
56
  if (failed.length > 0)
52
57
  throw new errors_1.FailedFlagValidationError({ parse, failed });
53
58
  }
54
59
  async function resolveFlags(flags) {
60
+ if (cachedResolvedFlags)
61
+ return cachedResolvedFlags;
55
62
  const promises = flags.map(async (flag) => {
56
63
  if (typeof flag === 'string') {
57
64
  return [flag, parse.output.flags[flag]];
@@ -60,15 +67,10 @@ async function validate(parse) {
60
67
  return result ? [flag.name, parse.output.flags[flag.name]] : null;
61
68
  });
62
69
  const resolved = await Promise.all(promises);
63
- return Object.fromEntries(resolved.filter(r => r !== null));
64
- }
65
- function getPresentFlags(flags) {
66
- return Object.keys(flags).reduce((acc, key) => {
67
- if (flags[key] !== undefined)
68
- acc.push(key);
69
- return acc;
70
- }, []);
70
+ cachedResolvedFlags = Object.fromEntries(resolved.filter(r => r !== null));
71
+ return cachedResolvedFlags;
71
72
  }
73
+ const getPresentFlags = (flags) => Object.keys(flags).filter(key => key !== undefined);
72
74
  function validateAcrossFlags(flag) {
73
75
  const base = { name: flag.name, validationFn: 'validateAcrossFlags' };
74
76
  const intersection = Object.entries(parse.input.flags)
@@ -131,30 +133,21 @@ async function validate(parse) {
131
133
  }
132
134
  return { ...base, status: 'success' };
133
135
  }
134
- async function validateRelationships(name, flag) {
135
- if (!flag.relationships)
136
- return [];
137
- const results = await Promise.all(flag.relationships.map(async (relationship) => {
138
- const flags = relationship.flags ?? [];
139
- const results = [];
136
+ function validateRelationships(name, flag) {
137
+ return ((flag.relationships ?? []).map(relationship => {
140
138
  switch (relationship.type) {
141
139
  case 'all':
142
- results.push(await validateDependsOn(name, flags));
143
- break;
140
+ return validateDependsOn(name, relationship.flags);
144
141
  case 'some':
145
- results.push(await validateSome(name, flags));
146
- break;
142
+ return validateSome(name, relationship.flags);
147
143
  case 'none':
148
- results.push(await validateExclusive(name, flags));
149
- break;
144
+ return validateExclusive(name, relationship.flags);
150
145
  default:
151
- break;
146
+ throw new Error(`Unknown relationship type: ${relationship.type}`);
152
147
  }
153
- return results;
154
148
  }));
155
- return results.flat();
156
149
  }
157
150
  validateArgs();
158
- await validateFlags();
151
+ return validateFlags();
159
152
  }
160
153
  exports.validate = validate;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@oclif/core",
3
3
  "description": "base library for oclif CLIs",
4
- "version": "2.8.11",
4
+ "version": "2.9.0",
5
5
  "author": "Salesforce",
6
6
  "bugs": "https://github.com/oclif/core/issues",
7
7
  "dependencies": {
@@ -25,6 +25,7 @@
25
25
  "object-treeify": "^1.1.33",
26
26
  "password-prompt": "^1.1.2",
27
27
  "semver": "^7.5.3",
28
+ "slice-ansi": "^4.0.0",
28
29
  "string-width": "^4.2.3",
29
30
  "strip-ansi": "^6.0.1",
30
31
  "supports-color": "^8.1.1",
@@ -41,6 +42,7 @@
41
42
  "@oclif/plugin-plugins": "^2.4.7",
42
43
  "@oclif/test": "^2.3.15",
43
44
  "@types/ansi-styles": "^3.2.1",
45
+ "@types/benchmark": "^2.1.2",
44
46
  "@types/chai": "^4.3.4",
45
47
  "@types/chai-as-promised": "^7.1.5",
46
48
  "@types/clean-stack": "^2.1.1",
@@ -55,10 +57,12 @@
55
57
  "@types/proxyquire": "^1.3.28",
56
58
  "@types/semver": "^7.5.0",
57
59
  "@types/shelljs": "^0.8.11",
60
+ "@types/slice-ansi": "^4.0.0",
58
61
  "@types/strip-ansi": "^5.2.1",
59
62
  "@types/supports-color": "^8.1.1",
60
63
  "@types/wordwrap": "^1.0.1",
61
64
  "@types/wrap-ansi": "^3.0.0",
65
+ "benchmark": "^2.1.4",
62
66
  "chai": "^4.3.7",
63
67
  "chai-as-promised": "^7.1.1",
64
68
  "commitlint": "^12.1.4",
@@ -108,10 +112,12 @@
108
112
  "commitlint": "commitlint",
109
113
  "lint": "eslint . --ext .ts --config .eslintrc",
110
114
  "posttest": "yarn lint",
115
+ "compile": "tsc",
111
116
  "prepack": "yarn run build",
112
117
  "test": "mocha --forbid-only \"test/**/*.test.ts\"",
113
118
  "test:e2e": "mocha --forbid-only \"test/**/*.e2e.ts\" --timeout 1200000",
114
- "pretest": "yarn build --noEmit && tsc -p test --noEmit --skipLibCheck"
119
+ "pretest": "yarn build --noEmit && tsc -p test --noEmit --skipLibCheck",
120
+ "test:perf": "ts-node test/perf/parser.perf.ts"
115
121
  },
116
122
  "types": "lib/index.d.ts"
117
123
  }