b766db389e3a457f5ea7d59ef325d79f2357688a27b92dba1a19adc988482aa88c1412dcf30f70297e72a2a6107051c1ca0113403c6527c339bbfd7d80bad0 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. const ChainedMap = require('./ChainedMap');
  2. const Orderable = require('./Orderable');
  3. module.exports = Orderable(
  4. class extends ChainedMap {
  5. constructor(parent, name, type = 'plugin') {
  6. super(parent);
  7. this.name = name;
  8. this.type = type;
  9. this.extend(['init']);
  10. this.init((Plugin, args = []) => {
  11. if (typeof Plugin === 'function') {
  12. return new Plugin(...args);
  13. }
  14. return Plugin;
  15. });
  16. }
  17. use(plugin, args = []) {
  18. return this.set('plugin', plugin).set('args', args);
  19. }
  20. tap(f) {
  21. if (!this.has('plugin')) {
  22. throw new Error(
  23. `Cannot call .tap() on a plugin that has not yet been defined. Call ${this.type}('${this.name}').use(<Plugin>) first.`,
  24. );
  25. }
  26. this.set('args', f(this.get('args') || []));
  27. return this;
  28. }
  29. set(key, value) {
  30. if (key === 'args' && !Array.isArray(value)) {
  31. throw new Error('args must be an array of arguments');
  32. }
  33. return super.set(key, value);
  34. }
  35. merge(obj, omit = []) {
  36. if ('plugin' in obj) {
  37. this.set('plugin', obj.plugin);
  38. }
  39. if ('args' in obj) {
  40. this.set('args', obj.args);
  41. }
  42. return super.merge(obj, [...omit, 'args', 'plugin']);
  43. }
  44. toConfig() {
  45. const init = this.get('init');
  46. let plugin = this.get('plugin');
  47. const args = this.get('args');
  48. let pluginPath = null;
  49. if (plugin === undefined) {
  50. throw new Error(
  51. `Invalid ${this.type} configuration: ${this.type}('${this.name}').use(<Plugin>) was not called to specify the plugin`,
  52. );
  53. }
  54. // Support using the path to a plugin rather than the plugin itself,
  55. // allowing expensive require()s to be skipped in cases where the plugin
  56. // or webpack configuration won't end up being used.
  57. if (typeof plugin === 'string') {
  58. pluginPath = plugin;
  59. // eslint-disable-next-line global-require, import/no-dynamic-require
  60. plugin = require(pluginPath);
  61. }
  62. const constructorName = plugin.__expression
  63. ? `(${plugin.__expression})`
  64. : plugin.name;
  65. const config = init(plugin, args);
  66. Object.defineProperties(config, {
  67. __pluginName: { value: this.name },
  68. __pluginType: { value: this.type },
  69. __pluginArgs: { value: args },
  70. __pluginConstructorName: { value: constructorName },
  71. __pluginPath: { value: pluginPath },
  72. });
  73. return config;
  74. }
  75. },
  76. );