@oclif/core 2.0.2-beta.8 → 2.0.3

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.
@@ -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
  });
@@ -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() {
@@ -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;
@@ -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;
@@ -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;
@@ -182,13 +182,13 @@ class Parser {
182
182
  else {
183
183
  flags[token.flag] = true;
184
184
  }
185
- flags[token.flag] = await flag.parse(flags[token.flag], this.context, flag);
185
+ flags[token.flag] = await this._parseFlag(flags[token.flag], flag);
186
186
  }
187
187
  else {
188
188
  const input = token.input;
189
189
  this._validateOptions(flag, input);
190
190
  if (flag.delimiter && flag.multiple) {
191
- 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)));
192
192
  flags[token.flag] = flags[token.flag] || [];
193
193
  flags[token.flag].push(...values);
194
194
  }
@@ -229,6 +229,17 @@ class Parser {
229
229
  }
230
230
  return flags;
231
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
+ }
232
243
  _validateOptions(flag, input) {
233
244
  if (flag.options && !flag.options.includes(input))
234
245
  throw new errors_1.FlagInvalidOptionError(flag, input);
package/lib/util.js CHANGED
@@ -94,11 +94,11 @@ 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) {
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.0.2-beta.8",
4
+ "version": "2.0.3",
5
5
  "author": "Salesforce",
6
6
  "bugs": "https://github.com/oclif/core/issues",
7
7
  "dependencies": {