Skip to content

Commit b100478

Browse files
committed
v3
2 parents d8b2f66 + cbfff50 commit b100478

28 files changed

+257
-199
lines changed

.github/FUNDING.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
open_collective: vue-facing-decorator

.npmignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/docs
22
/test
3+
/changelog
34
/.github
45
/.gitignore
56
/.editorconfig

changelog/v3.0.0.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Description
2+
3+
In v3.0.0, v-f-d is compatible with both decorators API stage 3 and stage 2 now.
4+
5+
# Decorators API stage 3
6+
7+
To enable this, you need to update TypeScript to 5.x and set `compilerOptions.experimentalDecorators` to `false` (value `true` for stage 2).
8+
9+
> Currently some vue libraries(e.g. Volar) may not compatible with TypeScript 5.x.
10+
11+
# Breaking changes
12+
13+
### Cast class component to vue options API
14+
15+
Using `toNative` to cast a class component to vue options API, after that, the casted component could be used as a native vue component in where vue accepts it.
16+
17+
> Currently `toNative` is not necessary, because v-f-d use a vue internal API, but it is not stable and may missing in the future vue verions. So `toNameve` is recommended.
18+
19+
```typescript
20+
@Component
21+
export class MyComp extends Vue{}
22+
export default toNative(MyComp)
23+
24+
//Code also works currently:
25+
@Component
26+
export default class MyComp extends Vue{}
27+
```
28+
29+
### Depreactate init class property despends on another in constructor
30+
31+
This is not allowed now.
32+
```typescript
33+
@Component({
34+
name: "MyComponent"
35+
})
36+
export class MyComponent extends Vue {
37+
@Prop
38+
prop!: string
39+
40+
field = this.prop // this is deprecated, it will be undefined
41+
}
42+
43+
export default toNative(MyComponent)
44+
```
45+
46+
### Remove `index-return-cons`
47+
48+
Remove `vue-facing-decorator/dist/index-return-cons`, you won't need this if `toNative` exists.
49+
50+
# What's new
51+
52+
* `createDecorator` has a preserve option. see docs.
53+
54+
* `v-model` sets event name in emits option now.
55+
56+

package.json

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
{
22
"name": "vue-facing-decorator",
3-
<<<<<<< HEAD
4-
"version": "3.0.0-beta.2",
5-
=======
6-
"version": "2.1.20",
7-
>>>>>>> master
3+
"version": "3.0.0",
84
"description": "Vue typescript class and decorator based component.",
95
"main": "dist/index.js",
106
"module": "dist/esm/index.js",
@@ -21,7 +17,9 @@
2117
],
2218
"scripts": {
2319
"test-build": "npm run build && npm run test",
24-
"test": "mocha -r ts-node/register test/test.ts",
20+
"test":"npm run test-stage2 && npm run test-stage3",
21+
"test-stage2": "env TS_NODE_COMPILER_OPTIONS='{\"experimentalDecorators\": true }' mocha -r ts-node/register test/test.ts",
22+
"test-stage3": "env TS_NODE_COMPILER_OPTIONS='{\"experimentalDecorators\": false }' mocha -r ts-node/register test/test.ts",
2523
"build": "npm run build:cjs && npm run build:esm",
2624
"build:cjs": "./node_modules/.bin/tsc",
2725
"build:esm": "./node_modules/.bin/tsc -outDir dist/esm -module ES6",
@@ -31,7 +29,6 @@
3129
},
3230
"author": "",
3331
"license": "MIT",
34-
3532
"peerDependencies": {
3633
"vue": "^3.0.0"
3734
},
@@ -56,5 +53,4 @@
5653
"type": "git",
5754
"url": "[email protected]:facing-dev/vue-facing-decorator.git"
5855
}
59-
60-
}
56+
}

src/component.ts

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import { build as optionInject } from './option/inject'
1111
import { build as optionEmit } from './option/emit'
1212
import { build as optionVModel } from './option/vmodel'
1313
import { build as optionAccessor } from './option/accessor'
14-
import { CustomRecords } from './custom/custom'
1514
import type { SetupContext } from 'vue';
1615
import type { OptionBuilder } from './optionBuilder'
1716
import type { VueCons } from './index'
@@ -31,16 +30,10 @@ function ComponentOption(cons: Cons, extend?: any) {
3130
optionInject(cons, optionBuilder)
3231
optionEmit(cons, optionBuilder)
3332
optionRef(cons, optionBuilder)//after Computed
34-
optionMethodsAndHooks(cons, optionBuilder)//after Ref Computed
3533
optionAccessor(cons, optionBuilder)
36-
37-
38-
const setupFunction: OptionSetupFunction | undefined = optionBuilder.setup ? function (props, ctx) {
39-
return optionBuilder.setup!(props, ctx)
40-
} : undefined
41-
34+
optionMethodsAndHooks(cons, optionBuilder)//the last one
4235
const raw = {
43-
setup: setupFunction,
36+
setup: optionBuilder.setup,
4437
data() {
4538
delete optionBuilder.data
4639
optionData(cons, optionBuilder, this)
@@ -72,7 +65,9 @@ type ComponentOption = {
7265
mixins?: any[]
7366
setup?: ComponentSetupFunction
7467
}
68+
7569
type ComponentConsOption = Cons | ComponentOption
70+
7671
function buildComponent(cons: Cons, arg: ComponentOption, extend?: any): any {
7772
const option = ComponentOption(cons, extend)
7873
const slot = obtainSlot(cons.prototype)
@@ -83,25 +78,21 @@ function buildComponent(cons: Cons, arg: ComponentOption, extend?: any): any {
8378
option[name] = arg[name as keyof ComponentOption]
8479
return option
8580
}, option)
81+
82+
//apply event emits
8683
let emits = Array.from(slot.obtainMap('emits').keys())
8784
if (Array.isArray(arg.emits)) {
8885
emits = Array.from(new Set([...emits, ...arg.emits]))
8986
}
9087
option.emits = emits
9188

92-
93-
CustomRecords.forEach(rec => {
94-
rec.creator.apply({}, [option, rec.key])
95-
})
96-
97-
98-
arg.setup ??= function () { return {} }
89+
//merge setup function
9990
if (!option.setup) {
10091
option.setup = arg.setup
10192
} else {
10293

10394
const oldSetup: OptionSetupFunction = option.setup
104-
const newSetup: ComponentSetupFunction = arg.setup
95+
const newSetup: ComponentSetupFunction = arg.setup ?? function () { return {} }
10596

10697
const setup: ComponentSetupFunction = function (props, ctx) {
10798
const newRet = newSetup(props, ctx)
@@ -121,12 +112,24 @@ function buildComponent(cons: Cons, arg: ComponentOption, extend?: any): any {
121112
option.setup = setup
122113
}
123114

115+
//custom decorator
116+
const map = slot.getMap('customDecorator')
117+
if (map && map.size > 0) {
118+
map.forEach((v) => {
119+
v.creator.apply({}, [option, v.key])
120+
})
121+
}
122+
123+
//shallow merge options
124124
if (arg.options) {
125125
Object.assign(option, arg.options)
126126
}
127+
128+
//apply modifier
127129
if (arg.modifier) {
128130
arg.modifier(option)
129131
}
132+
130133
return defineComponent(option)
131134
}
132135
function build(cons: Cons, option: ComponentOption) {
@@ -143,8 +146,8 @@ function build(cons: Cons, option: ComponentOption) {
143146
}
144147
const component = buildComponent(cons, option, superSlot === null ? undefined : superSlot.cachedVueComponent)
145148
component.__vfdConstructor = cons
146-
slot.cachedVueComponent = component
147-
149+
slot.cachedVueComponent = component;
150+
(cons as any).__vccOpts = component
148151
}
149152
function _Component(cb: (cons: Cons, option: ComponentOption) => any, arg: ComponentConsOption, ctx?: ClassDecoratorContext) {
150153
if (typeof arg === 'function') {

src/custom/custom.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
1+
import { obtainSlot } from '../utils'
2+
import { compatibleMemberDecorator } from '../deco3/utils'
13
type Creator = { (options: any, key: string): void }
2-
interface Record {
4+
export interface Record {
35
key: string
46
creator: Creator
7+
preserve: boolean
58
}
69

7-
// const CustomDecorators: CustomDecorator[] = []
8-
export const CustomRecords: Record[] = []
9-
10-
export function createDecorator(creator: Creator) {
11-
return function (proto: any, key: string) {
12-
CustomRecords.push({
10+
export function createDecorator(creator: Creator, opt?: {
11+
preserve?: boolean
12+
}) {
13+
return compatibleMemberDecorator(function (proto: any, key: string) {
14+
const slot = obtainSlot(proto)
15+
const map = slot.obtainMap('customDecorator')
16+
map.set(key, {
1317
key,
14-
creator
18+
creator,
19+
preserve: !!opt?.preserve
1520
})
16-
}
21+
})
1722
}
1823

1924

src/index-return-cons.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// This feature is deprecated and is preserved for compatibility
2+
export * from './index'

src/option/accessor.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import type { Cons } from '../component'
2-
import { type OptionBuilder, applyAccessors} from '../optionBuilder'
2+
import { type OptionBuilder, applyAccessors } from '../optionBuilder'
33
import { toComponentReverse, obtainSlot } from '../utils'
44

55
export function build(cons: Cons, optionBuilder: OptionBuilder) {
66
const slot = obtainSlot(cons.prototype)
7-
const vanillaMap = slot.obtainMap('vanilla')
7+
const vanillaMap = slot.getMap('vanilla')
8+
if (!vanillaMap || vanillaMap.size === 0) {
9+
return
10+
}
811
const protoArr = toComponentReverse(cons.prototype)
9-
const map: Map<string, { get: (() => any) | undefined, set: ((v: any) => any) | undefined }> = new Map
12+
const map: Map<string, { get: (() => any) | undefined, set: ((v: any) => any) | undefined }> | undefined = new Map
1013

11-
applyAccessors(optionBuilder,(ctx:any)=>{
14+
applyAccessors(optionBuilder, (ctx: any) => {
1215
protoArr.forEach(proto => {
1316
const deses = Object.getOwnPropertyDescriptors(proto)
1417
for (const name in deses) {

src/option/data.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,13 @@ import type { Cons } from '../component'
22
import type { OptionBuilder } from '../optionBuilder'
33
import { makeObject, obtainSlot, excludeNames, getValidNames } from '../utils'
44

5-
export function build(cons: Cons, optionBuilder: OptionBuilder, vueInstance: any, _propNames?: string[]) {
5+
export function build(cons: Cons, optionBuilder: OptionBuilder, vueInstance: any) {
66
optionBuilder.data ??= {}
7-
87
const sample = new cons(optionBuilder,vueInstance)
9-
108
let names = getValidNames(sample, (des) => {
119
return !!des.enumerable
1210
})
13-
14-
1511
const slot = obtainSlot(cons.prototype)
1612
names = excludeNames(names, slot)
17-
console.log(names)
1813
Object.assign(optionBuilder.data, makeObject(names, sample))
1914
}

src/option/emit.ts

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { Cons } from '../component'
22
import type { OptionBuilder } from '../optionBuilder'
33
import { obtainSlot, optoinNullableMemberDecorator } from '../utils'
4-
import { compatibleMemberDecorator } from '../deco3/utils'
54
export type EmitConfig = null | string
65

76
export const decorator = optoinNullableMemberDecorator(function (proto: any, name: string, key?: string) {
@@ -14,25 +13,25 @@ export function build(cons: Cons, optionBuilder: OptionBuilder) {
1413
optionBuilder.methods ??= {}
1514
const proto = cons.prototype
1615
const slot = obtainSlot(proto)
17-
const names = slot.obtainMap('emit')
16+
const names = slot.getMap('emit')
17+
if (!names || names.size === 0) {
18+
return
19+
}
1820
const emits = slot.obtainMap('emits')
21+
names.forEach((value, key) => {
22+
const eventName = value === null ? key : value
23+
emits.set(eventName, true)
24+
optionBuilder.methods![key] = async function (this: any) {
1925

20-
if (names) {
21-
names.forEach((value, key) => {
22-
const eventName = value === null ? key : value
23-
emits.set(eventName, true)
24-
optionBuilder.methods![key] = async function (this: any) {
25-
26-
const ret = proto[key].apply(this, arguments)
27-
if (ret instanceof Promise) {
28-
const proRet = await ret
29-
this.$emit(eventName, proRet)
30-
}
31-
else {
32-
this.$emit(eventName, ret)
33-
}
26+
const ret = proto[key].apply(this, arguments)
27+
if (ret instanceof Promise) {
28+
const proRet = await ret
29+
this.$emit(eventName, proRet)
3430
}
35-
})
36-
}
31+
else {
32+
this.$emit(eventName, ret)
33+
}
34+
}
35+
})
3736

3837
}

0 commit comments

Comments
 (0)