Skip to content

Commit f060f7d

Browse files
authored
Move $decoratorQueue under each component constructor (fix #104) (#110)
* add test script for dev * move decorator queue under each constructor
1 parent cb8d9de commit f060f7d

File tree

7 files changed

+77
-14
lines changed

7 files changed

+77
-14
lines changed

build/dev-test.js

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const fs = require('fs')
2+
const spawn = require('child_process').spawn
3+
4+
run('tsc -w -p .')
5+
run('webpack --config test/webpack.config.js --watch')
6+
7+
fs.watch('test/test.build.js', () => {
8+
run('mocha --reporter min test/test.build.js')
9+
})
10+
11+
function run(command) {
12+
const [name, ...args] = command.split(' ')
13+
spawn(`node_modules/.bin/${name}`, args, {
14+
shell: true,
15+
stdio: 'inherit'
16+
})
17+
}

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"clean": "rimraf ./lib",
1616
"example": "npm run build && webpack --config example/webpack.config.js",
1717
"dev": "webpack --config example/webpack.config.js --watch",
18+
"dev:test": "node build/dev-test.js",
1819
"test": "npm run build && webpack --config test/webpack.config.js && mocha test/test.build.js"
1920
},
2021
"repository": {

src/component.ts

+5-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Vue, { ComponentOptions } from 'vue'
2-
import { VueClass } from './declarations'
2+
import { VueClass, DecoratedClass } from './declarations'
33
import { collectDataFromConstructor } from './data'
44

55
export const $internalHooks = [
@@ -17,11 +17,6 @@ export const $internalHooks = [
1717
'render'
1818
]
1919

20-
// Property, method and parameter decorators created by `createDecorator` helper
21-
// will enqueue functions that update component options for lazy processing.
22-
// They will be executed just before creating component constructor.
23-
export let $decoratorQueue: ((options: ComponentOptions<Vue>) => void)[] = []
24-
2520
export function componentFactory (
2621
Component: VueClass,
2722
options: ComponentOptions<any> = {}
@@ -59,9 +54,10 @@ export function componentFactory (
5954
})
6055

6156
// decorate options
62-
$decoratorQueue.forEach(fn => fn(options))
63-
// reset for other component decoration
64-
$decoratorQueue = []
57+
const decorators = (Component as DecoratedClass).__decorators__
58+
if (decorators) {
59+
decorators.forEach(fn => fn(options))
60+
}
6561

6662
// find super
6763
const superProto = Object.getPrototypeOf(Component.prototype)

src/declarations.ts

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
11
import Vue from 'vue'
22

33
export type VueClass = { new (): Vue } & typeof Vue
4+
5+
export type DecoratedClass = VueClass & {
6+
// Property, method and parameter decorators created by `createDecorator` helper
7+
// will enqueue functions that update component options for lazy processing.
8+
// They will be executed just before creating component constructor.
9+
__decorators__?: ((options: Vue.ComponentOptions<Vue>) => void)[]
10+
}

src/util.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Vue, { ComponentOptions } from 'vue'
2-
import { $decoratorQueue } from './component'
2+
import { DecoratedClass } from './declarations'
33

44
export const noop = () => {}
55

@@ -12,11 +12,15 @@ export function createDecorator (
1212
export function createDecorator (
1313
factory: (options: ComponentOptions<Vue>, key: string, index: number) => void
1414
): (target: Vue, key: string, index: any) => void {
15-
return (_, key, index) => {
15+
return (target, key, index) => {
16+
const Ctor = target.constructor as DecoratedClass
17+
if (!Ctor.__decorators__) {
18+
Ctor.__decorators__ = []
19+
}
1620
if (typeof index !== 'number') {
1721
index = undefined
1822
}
19-
$decoratorQueue.push(options => factory(options, key, index))
23+
Ctor.__decorators__.push(options => factory(options, key, index))
2024
}
2125
}
2226

test/test-babel.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Component, { createDecorator } from '../'
1+
import Component, { createDecorator } from '../lib'
22
import chai, { expect } from 'chai'
33
import spies from 'chai-spies'
44
import Vue from 'vue'

test/test.ts

+39-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Component, { createDecorator } from '../'
1+
import Component, { createDecorator } from '../lib'
22
import { expect } from 'chai'
33
import Vue from 'vue'
44

@@ -218,4 +218,42 @@ describe('vue-class-component', () => {
218218
expect(c.bar).to.equal('world')
219219
expect((MyComp as any).options.computed.bar.cache).to.be.false
220220
})
221+
222+
// #104
223+
it('createDecorator: decorate correctly even if a component is created in another @Component decorator', () => {
224+
// Just assigns the given value to the decorated property
225+
const Value = (value: any) => createDecorator((options, key) => {
226+
const data = options.data as Function || (() => ({}))
227+
options.data = function () {
228+
return {
229+
...data.call(this),
230+
[key]: value
231+
}
232+
}
233+
})
234+
235+
const createChild = () => {
236+
@Component
237+
class Child extends Vue {
238+
@Value('child')
239+
value: string
240+
}
241+
return Child
242+
}
243+
244+
@Component({
245+
components: {
246+
Child: createChild()
247+
}
248+
})
249+
class Parent extends Vue {
250+
@Value('parent')
251+
value: string
252+
}
253+
254+
const parent = new Parent()
255+
const child = new (parent as any).$options.components.Child()
256+
expect(parent.value).to.equal('parent')
257+
expect(child.value).to.equal('child')
258+
})
221259
})

0 commit comments

Comments
 (0)