|
1 | 1 | import reactIntergration from './react.intergration'; |
2 | 2 | import vueIntergration from './vue.intergration'; |
| 3 | +import Pulse from '..'; |
3 | 4 |
|
4 | 5 | export interface Intergration { |
5 | | - frameworkConstructor: any; |
6 | | - name: any; |
7 | | - bind: Function; |
8 | | - wrapper: Function; |
9 | | - updateMethod: Function; |
10 | | - onReady: Function; |
| 6 | + ready?: boolean; |
| 7 | + frameworkConstructor?: any; |
| 8 | + name?: any; |
| 9 | + bind?: Function; |
| 10 | + updateMethod?: Function; |
| 11 | + wrapper?: Function; |
| 12 | + onReady?: Function; |
11 | 13 | } |
12 | 14 |
|
13 | | -export default (frameworkConstructor, PulseConstructor) => { |
14 | | - // React support |
| 15 | +// This gets assigned to the constructor Pulse.intergration |
| 16 | +const intergration: Intergration = { |
| 17 | + ready: false |
| 18 | +}; |
15 | 19 |
|
16 | | - if (!PulseConstructor.intergration) PulseConstructor.intergration = {}; |
| 20 | +export default function use(plugin: any, PulseConstructor: Pulse) { |
| 21 | + const frameworkName = getFrameworkName(plugin); |
17 | 22 |
|
18 | | - if ( |
19 | | - frameworkConstructor && |
20 | | - frameworkConstructor.hasOwnProperty( |
21 | | - '__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED' |
22 | | - ) |
23 | | - ) { |
24 | | - PulseConstructor.intergration = reactIntergration; |
25 | | - // Vue support |
26 | | - } else if (frameworkConstructor.name === 'Vue') { |
27 | | - PulseConstructor.intergration = vueIntergration; |
28 | | - |
29 | | - // Custom Intergration |
30 | | - } else if ( |
31 | | - frameworkConstructor.hasOwnProperty('name') && |
32 | | - frameworkConstructor.hasOwnProperty('bind') && |
33 | | - frameworkConstructor.hasOwnProperty('updateData') |
34 | | - ) { |
35 | | - PulseConstructor.intergration = frameworkConstructor; |
| 23 | + switch (frameworkName) { |
| 24 | + case 'react': |
| 25 | + intergrate(reactIntergration, 'react'); |
| 26 | + break; |
| 27 | + case 'vue': |
| 28 | + intergrate(vueIntergration, 'vue'); |
| 29 | + break; |
| 30 | + case 'custom': |
| 31 | + if (validateCustomFramework(plugin as Intergration)) |
| 32 | + intergrate(plugin, 'custom'); |
| 33 | + break; |
36 | 34 | } |
37 | 35 |
|
38 | | - if (!PulseConstructor.intergration) { |
| 36 | + // assign framework constructor to intergration object |
| 37 | + if (frameworkName !== 'custom') intergration.frameworkConstructor = plugin; |
| 38 | + |
| 39 | + // Inject into static property of constructor |
| 40 | + PulseConstructor.intergration = intergration; |
| 41 | + |
| 42 | + // if the intergration is ready, call bind otherwise warn user |
| 43 | + if (intergration.ready) intergration.bind(PulseConstructor); |
| 44 | + else { |
39 | 45 | console.error( |
40 | | - 'Pulse Error - Intergration not found, make sure to call "Pulse.use()" before "new Pulse()"' |
| 46 | + `Pulse: Failed to intergrate with framework! It's possible you didn't call Pulse.use() before new Pulse.` |
41 | 47 | ); |
42 | | - } else { |
43 | | - PulseConstructor.intergration.frameworkConstructor = frameworkConstructor; |
| 48 | + // TODO: in some cases one might want to use Pulse without a framework so consider making this warning only show in dev, and making a config option to hide it entirely. |
44 | 49 | } |
| 50 | +} |
45 | 51 |
|
46 | | - PulseConstructor.intergration.bind(PulseConstructor); |
| 52 | +//******** HELPERS BELOW ******* |
47 | 53 |
|
48 | | - // PulseConstructor.intergration.bind(PulseConstructor); |
49 | | -}; |
| 54 | +function intergrate(int: Intergration, frameworkName: string) { |
| 55 | + // bind all properties from intergration |
| 56 | + Object.keys(int).forEach(property => { |
| 57 | + intergration[property] = int[property]; |
| 58 | + }); |
| 59 | + // assign name and set ready |
| 60 | + intergration.name = frameworkName; |
| 61 | + intergration.ready = true; |
| 62 | +} |
| 63 | + |
| 64 | +function validateCustomFramework(customIntergration: Intergration): boolean { |
| 65 | + let valid: boolean = true; |
| 66 | + // check for required properties |
| 67 | + ['name', 'bind', 'updateData'].forEach(property => { |
| 68 | + if (!customIntergration.hasOwnProperty(property)) valid = false; |
| 69 | + }); |
| 70 | + return valid; |
| 71 | +} |
| 72 | + |
| 73 | +function getFrameworkName(frameworkConstructor): string { |
| 74 | + let name: string = 'custom'; |
| 75 | + if (!frameworkConstructor) return name; |
| 76 | + |
| 77 | + // ATTEMPT CHECK FOR REACT |
| 78 | + if ( |
| 79 | + frameworkConstructor.hasOwnProperty( |
| 80 | + '__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED' |
| 81 | + ) |
| 82 | + ) |
| 83 | + return 'react'; |
| 84 | + |
| 85 | + // ATTEMPT CHECK FOR VUE |
| 86 | + // this check works in dev, but not prod since Vue is a function that returns a constructor in prod, for some reason. |
| 87 | + if (frameworkConstructor.name === 'Vue') return 'vue'; |
| 88 | + |
| 89 | + if (typeof frameworkConstructor === 'function') { |
| 90 | + return 'vue'; // more performant than below since it's kinda annoying to contruct an instance of Vue just to check if it is Vue, but it shouldn't hurt until we add support for more frameworks. |
| 91 | + let maybeVue = new frameworkConstructor(); |
| 92 | + if (maybeVue._isVue) return 'vue'; |
| 93 | + } |
| 94 | + |
| 95 | + return name; |
| 96 | +} |
0 commit comments