From 86cb63f3b934aa3e1adfde7f896787a7178e62cb Mon Sep 17 00:00:00 2001 From: ktsn Date: Thu, 22 Jun 2017 19:22:20 +0200 Subject: [PATCH 1/2] add test script for dev --- build/dev-test.js | 17 +++++++++++++++++ package.json | 1 + 2 files changed, 18 insertions(+) create mode 100644 build/dev-test.js diff --git a/build/dev-test.js b/build/dev-test.js new file mode 100644 index 0000000..b204ed1 --- /dev/null +++ b/build/dev-test.js @@ -0,0 +1,17 @@ +const fs = require('fs') +const spawn = require('child_process').spawn + +run('tsc -w -p .') +run('webpack --config test/webpack.config.js --watch') + +fs.watch('test/test.build.js', () => { + run('mocha --reporter min test/test.build.js') +}) + +function run(command) { + const [name, ...args] = command.split(' ') + spawn(`node_modules/.bin/${name}`, args, { + shell: true, + stdio: 'inherit' + }) +} \ No newline at end of file diff --git a/package.json b/package.json index 844c143..dd55f4d 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "clean": "rimraf ./lib", "example": "npm run build && webpack --config example/webpack.config.js", "dev": "webpack --config example/webpack.config.js --watch", + "dev:test": "node build/dev-test.js", "test": "npm run build && webpack --config test/webpack.config.js && mocha test/test.build.js" }, "repository": { From b828e135f1871c951874dfd37ae11ebdc3e8f5fe Mon Sep 17 00:00:00 2001 From: ktsn Date: Sun, 25 Jun 2017 20:14:41 +0200 Subject: [PATCH 2/2] move decorator queue under each constructor --- build/dev-test.js | 2 +- src/component.ts | 14 +++++--------- src/declarations.ts | 7 +++++++ src/util.ts | 10 +++++++--- test/test-babel.js | 2 +- test/test.ts | 40 +++++++++++++++++++++++++++++++++++++++- 6 files changed, 60 insertions(+), 15 deletions(-) diff --git a/build/dev-test.js b/build/dev-test.js index b204ed1..a612dcf 100644 --- a/build/dev-test.js +++ b/build/dev-test.js @@ -14,4 +14,4 @@ function run(command) { shell: true, stdio: 'inherit' }) -} \ No newline at end of file +} diff --git a/src/component.ts b/src/component.ts index 2404e4c..4386e24 100644 --- a/src/component.ts +++ b/src/component.ts @@ -1,5 +1,5 @@ import Vue, { ComponentOptions } from 'vue' -import { VueClass } from './declarations' +import { VueClass, DecoratedClass } from './declarations' import { collectDataFromConstructor } from './data' export const $internalHooks = [ @@ -17,11 +17,6 @@ export const $internalHooks = [ 'render' ] -// Property, method and parameter decorators created by `createDecorator` helper -// will enqueue functions that update component options for lazy processing. -// They will be executed just before creating component constructor. -export let $decoratorQueue: ((options: ComponentOptions) => void)[] = [] - export function componentFactory ( Component: VueClass, options: ComponentOptions = {} @@ -59,9 +54,10 @@ export function componentFactory ( }) // decorate options - $decoratorQueue.forEach(fn => fn(options)) - // reset for other component decoration - $decoratorQueue = [] + const decorators = (Component as DecoratedClass).__decorators__ + if (decorators) { + decorators.forEach(fn => fn(options)) + } // find super const superProto = Object.getPrototypeOf(Component.prototype) diff --git a/src/declarations.ts b/src/declarations.ts index 86a1d7a..235962c 100644 --- a/src/declarations.ts +++ b/src/declarations.ts @@ -1,3 +1,10 @@ import Vue from 'vue' export type VueClass = { new (): Vue } & typeof Vue + +export type DecoratedClass = VueClass & { + // Property, method and parameter decorators created by `createDecorator` helper + // will enqueue functions that update component options for lazy processing. + // They will be executed just before creating component constructor. + __decorators__?: ((options: Vue.ComponentOptions) => void)[] +} diff --git a/src/util.ts b/src/util.ts index 3d83da4..0dfd7a3 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,5 +1,5 @@ import Vue, { ComponentOptions } from 'vue' -import { $decoratorQueue } from './component' +import { DecoratedClass } from './declarations' export const noop = () => {} @@ -12,11 +12,15 @@ export function createDecorator ( export function createDecorator ( factory: (options: ComponentOptions, key: string, index: number) => void ): (target: Vue, key: string, index: any) => void { - return (_, key, index) => { + return (target, key, index) => { + const Ctor = target.constructor as DecoratedClass + if (!Ctor.__decorators__) { + Ctor.__decorators__ = [] + } if (typeof index !== 'number') { index = undefined } - $decoratorQueue.push(options => factory(options, key, index)) + Ctor.__decorators__.push(options => factory(options, key, index)) } } diff --git a/test/test-babel.js b/test/test-babel.js index 04984c9..4e03df6 100644 --- a/test/test-babel.js +++ b/test/test-babel.js @@ -1,4 +1,4 @@ -import Component, { createDecorator } from '../' +import Component, { createDecorator } from '../lib' import chai, { expect } from 'chai' import spies from 'chai-spies' import Vue from 'vue' diff --git a/test/test.ts b/test/test.ts index bcef77e..6057ee7 100644 --- a/test/test.ts +++ b/test/test.ts @@ -1,4 +1,4 @@ -import Component, { createDecorator } from '../' +import Component, { createDecorator } from '../lib' import { expect } from 'chai' import Vue from 'vue' @@ -218,4 +218,42 @@ describe('vue-class-component', () => { expect(c.bar).to.equal('world') expect((MyComp as any).options.computed.bar.cache).to.be.false }) + + // #104 + it('createDecorator: decorate correctly even if a component is created in another @Component decorator', () => { + // Just assigns the given value to the decorated property + const Value = (value: any) => createDecorator((options, key) => { + const data = options.data as Function || (() => ({})) + options.data = function () { + return { + ...data.call(this), + [key]: value + } + } + }) + + const createChild = () => { + @Component + class Child extends Vue { + @Value('child') + value: string + } + return Child + } + + @Component({ + components: { + Child: createChild() + } + }) + class Parent extends Vue { + @Value('parent') + value: string + } + + const parent = new Parent() + const child = new (parent as any).$options.components.Child() + expect(parent.value).to.equal('parent') + expect(child.value).to.equal('child') + }) })