create.js 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import isPlainObject from 'is-plain-obj';
  2. import {normalizeParameters} from './parameters.js';
  3. import {isTemplateString, parseTemplates} from './template.js';
  4. import {execaCoreSync} from './main-sync.js';
  5. import {execaCoreAsync} from './main-async.js';
  6. import {mergeOptions} from './bind.js';
  7. // Wraps every exported methods to provide the following features:
  8. // - template string syntax: execa`command argument`
  9. // - options binding: boundExeca = execa(options)
  10. // - optional argument/options: execa(file), execa(file, args), execa(file, options), execa(file, args, options)
  11. // `mapArguments()` and `setBoundExeca()` allows for method-specific logic.
  12. export const createExeca = (mapArguments, boundOptions, deepOptions, setBoundExeca) => {
  13. const createNested = (mapArguments, boundOptions, setBoundExeca) => createExeca(mapArguments, boundOptions, deepOptions, setBoundExeca);
  14. const boundExeca = (...execaArguments) => callBoundExeca({
  15. mapArguments,
  16. deepOptions,
  17. boundOptions,
  18. setBoundExeca,
  19. createNested,
  20. }, ...execaArguments);
  21. if (setBoundExeca !== undefined) {
  22. setBoundExeca(boundExeca, createNested, boundOptions);
  23. }
  24. return boundExeca;
  25. };
  26. const callBoundExeca = ({mapArguments, deepOptions = {}, boundOptions = {}, setBoundExeca, createNested}, firstArgument, ...nextArguments) => {
  27. if (isPlainObject(firstArgument)) {
  28. return createNested(mapArguments, mergeOptions(boundOptions, firstArgument), setBoundExeca);
  29. }
  30. const {file, commandArguments, options, isSync} = parseArguments({
  31. mapArguments,
  32. firstArgument,
  33. nextArguments,
  34. deepOptions,
  35. boundOptions,
  36. });
  37. return isSync
  38. ? execaCoreSync(file, commandArguments, options)
  39. : execaCoreAsync(file, commandArguments, options, createNested);
  40. };
  41. const parseArguments = ({mapArguments, firstArgument, nextArguments, deepOptions, boundOptions}) => {
  42. const callArguments = isTemplateString(firstArgument)
  43. ? parseTemplates(firstArgument, nextArguments)
  44. : [firstArgument, ...nextArguments];
  45. const [initialFile, initialArguments, initialOptions] = normalizeParameters(...callArguments);
  46. const mergedOptions = mergeOptions(mergeOptions(deepOptions, boundOptions), initialOptions);
  47. const {
  48. file = initialFile,
  49. commandArguments = initialArguments,
  50. options = mergedOptions,
  51. isSync = false,
  52. } = mapArguments({file: initialFile, commandArguments: initialArguments, options: mergedOptions});
  53. return {
  54. file,
  55. commandArguments,
  56. options,
  57. isSync,
  58. };
  59. };