2017-11-15 5 views
0
aufgerufen.

Entschuldigen Sie mich für das Erstellen einer neuen Frage, ich konnte keine Frage zu diesem Thema finden.Babel - Dekorator der verzierten Klasseneigenschaften wird vor der Instanziierung der Klasse

Ich habe Schwierigkeiten, meine Abhängigkeitsinjektion mit Mocha und experimentelle es6 + Dekoratoren zu testen, die mit Babel transpiliert werden. Der Klasseneigenschafts-Decorator wird aufgerufen, bevor er hätte sein sollen.

injection.test.js (Mokka-Test, mit --require babel-register)

import * as DependencyInjection from '../build/decorators/DependencyInjection'; 

@DependencyInjection.Injectable(service => service.injected = true) 
class SampleService { 

    property = 'default'; 

    constructor(property, ...data) { 
     this.property = property || this.property; 
    } 
} 

class Dependant { 

    /** @type {SampleService} */ 
    @DependencyInjection.Inject(SampleService) 
    sampleService; 
} 

describe('dependency injection',() => { 

    describe('is decoratored as injectable',() => { 
     it('should be injectable', done => done(SampleService.injectable ? void 0 : new Error('Injectable is not set'))); 

     it('should contain a predicate', done => done(SampleService.predicate ? void 0 : new Error('Predicate is not set'))); 
    }); 

    describe('inject injectable',() => { 
     it ('should inject the injectable provider', done => { 
      const dependant = new Dependant(); 

      done(!!dependant.sampleService ? void 0 : new Error('Injectable provider was not injected')); 
     }) 
    }); 
}); 

Wenn der Test läuft, wird die eingerichtete Klasse des bestimmungsgemäßen umgewandelt. Die sampleService Eigenschaft der Instanz von Dependant, die in dem zweiten Test erstellt wird, ist jedoch undefiniert.

Der fragliche Decorator sollte aufgerufen werden/aufgerufen werden, sobald eine Instanz der Klasse erstellt wird, aber der Dekorator wird aufgerufen, wenn die Klasse definiert und die Eigenschaft dekoriert ist. Das erwartete Verhalten wird beibehalten, wenn TypeScript verwendet wird.

Unten habe ich die (vereinfachte) Dekorateure und meine Babel-Konfiguration aufgelistet.

.babelrc

{ 
    "presets": [ 
     "env", 
     "stage-0", 
     "es2017" 
    ], 
    "plugins": [ 
     "syntax-decorators", 
     "transform-decorators-legacy", 
     ["transform-runtime", { 
      "polyfill": false, 
      "regenerator": true 
     }] 
    ] 
} 

exportiert Dekorateur Inject (Targeting class property):

exports.Inject = (typeFunction, ...data) => { 
    return function (target, propertyName) { 
     try { 
      const injected = target[propertyName] = new typeFunction(data); 
      if ('predicate' in typeFunction && typeof typeFunction.predicate === 'function') { 
       typeFunction.predicate(injected); 
      } 
     } 
     catch (err) { 
      throw new Error(err.message || err); 
     } 
    }; 
}; 

exportiert Dekorateur injizierbare (Targeting class):

exports.Injectable = (predicate) => { 
    return function (target) { 
     const provider = target; 
     provider.injectable = true; 
     if (predicate && typeof predicate === 'function') { 
      provider.predicate = predicate; 
     } 
    }; 
}; 

Antwort

0

Ich habe noch nicht gefunden die Hauptursache, warum es eine neue Instanz der Klasse erstellt bei der Dekoration der Klasse Eigenschaft. Ich habe jedoch eine funktionierende Lösung für mein Problem gefunden. In mocha, unter Verwendung von --require babel-register und dem Legacy Decorator-Plugin, verwendet der Klasseneigenschafts-Decorator die PropertyDescriptor. Das Ändern des vereinfachten Inject Dekorators in das folgende hat mein Problem gelöst, meine dekorierte Klasseneigenschaft nicht zu instantiieren.

exports.Inject = (typeFunction, ...data) => { 
    return function (target, propertyName, descriptor) { 
     let value = null; 
     try { 
      const injected = value = target[propertyName] = new typeFunction(...data); 
      if ('predicate' in typeFunction && typeof typeFunction.predicate === 'function') { 
       typeFunction.predicate(injected); 
      } 
     } 
     catch (err) { 
      throw new Error(err.message || err); 
     } 
     if (descriptor) { 
      delete descriptor.initializer; 
      delete descriptor.writable; 
      descriptor.value = value; 
     } 
    }; 
}; 

Das Löschen der writable Eigenschaft ist erforderlich.

Die folgenden Tests ...

const assert = require('assert'); 
const chai = require('chai'); 

import * as DependencyInjection from '../build/decorators/DependencyInjection'; 

@DependencyInjection.Injectable(service => service.injected = true) 
class SampleService { 

    property = 'default'; 

    constructor(property, ...data) { 
     this.property = property || this.property; 
    } 
} 

class Dependant { 

    /** @type {SampleService} */ 
    @DependencyInjection.Inject(SampleService) 
    sampleService; 
} 

class Dependant2 { 

    /** @type {SampleService} */ 
    @DependencyInjection.Inject(SampleService, 'overloaded') 
    sampleService; 
} 

describe('dependency injection',() => { 

    describe('is decoratored as injectable',() => { 
     it('should be injectable', done => done(SampleService.injectable ? void 0 : new Error('Injectable is not set'))); 

     it('should contain a predicate', done => done(SampleService.predicate ? void 0 : new Error('Predicate is not set'))); 
    }); 

    describe('inject at decorated class property',() => { 
     it('should inject the injectable provider at the decorated property',() => { 
      const dependant = new Dependant(); 

      chai.expect(dependant.sampleService).to.be.instanceof(SampleService, 'Injectable provider was not injected'); 

      chai.assert.isTrue(dependant.sampleService.injected, 'The predicate of the injectable service was not set'); 

      chai.expect(dependant.sampleService.property).to.equal('default', 'The initial value of \'property\' was not \'default\''); 
     }); 

     it('should inject the injectable provider with overloaded constructor arguments at the decorated property',() => { 
      const dependant = new Dependant2(); 

      chai.expect(dependant.sampleService).to.be.instanceOf(SampleService, 'Injectable provider was not injected'); 

      chai.assert.isTrue(dependant.sampleService.injected, 'The predicate of the injectable service was not set'); 

      chai.expect(dependant.sampleService.property).to.equal('overloaded', 'The value of \'property\' was not overloaded'); 
     }); 
    }); 

    describe('inject at manual target and property',() => { 
     it('should inject the injectable provider at the targeting value',() => { 
      const inject = DependencyInjection.Inject(SampleService); 

      const target = {}; 

      let err = null; 
      try { 
       inject(target, 'service'); 
      } catch (e) { 
       err = e; 
      } 

      chai.assert.isNull(err, 'Expected injection to pass'); 

      chai.expect(target.service).to.be.instanceOf(SampleService, 'Injectable provider was not injected'); 

      chai.assert.isTrue(target.service.injected, 'The predicate of the injectable service was not set'); 

      chai.expect(target.service.property).to.equal('default', 'The initial value of \'property\' was not \'default\''); 
     }); 

     it('should inject the injectable provider with overloaded constructor arguments at the targeting value',() => { 
      const inject = DependencyInjection.Inject(SampleService, 'overloaded'); 

      const target = {}; 

      let err = null; 
      try { 
       inject(target, 'service'); 
      } catch (e) { 
       err = e; 
      } 

      chai.assert.isNull(err, 'Expected injection to pass'); 

      chai.expect(target.service).to.be.instanceOf(SampleService, 'Injectable provider was not injected'); 

      chai.assert.isTrue(target.service.injected, 'The predicate of the injectable service was not set'); 

      chai.expect(target.service.property).to.equal('overloaded', 'The value of \'property\' was not overloaded'); 
     }); 

     it('should not inject anything at the targeting value',() => { 
      const inject = DependencyInjection.Inject(); 

      const target = {}; 

      let err = null; 
      try { 
       inject(target, 'service'); 
      } catch (e) { 
       err = e; 
      } 

      chai.expect(err).to.be.instanceof(Error); 

      chai.assert.notExists(target.service); 
     }); 
    }); 
}); 

... Ausgabe folgendes Ergebnis:

dependency injection 
    is decoratored as injectable 
     √ should be injectable 
     √ should contain a predicate 
    inject at decorated class property 
     √ should inject the injectable provider at the decorated property 
     √ should inject the injectable provider with overloaded constructor arguments at the decorated property 
    inject at manual target and property 
     √ should inject the injectable provider at the targeting value 
     √ should inject the injectable provider with overloaded constructor arguments at the targeting value 
     √ should not inject anything at the targeting value 


    7 passing (29ms) 
Verwandte Themen