forked from TypeScriptToLua/TypeScriptToLua
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdecorators.spec.ts
More file actions
186 lines (158 loc) · 5.44 KB
/
Copy pathdecorators.spec.ts
File metadata and controls
186 lines (158 loc) · 5.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
import { decoratorInvalidContext } from "../../../src/transformation/utils/diagnostics";
import * as util from "../../util";
test("Class decorator with no parameters", () => {
util.testFunction`
function setBool<T extends new (...args: any[]) => {}>(constructor: T) {
return class extends constructor {
decoratorBool = true;
}
}
@setBool
class TestClass {
public decoratorBool = false;
}
return new TestClass();
`.expectToMatchJsResult();
});
test("Class decorator with parameters", () => {
util.testFunction`
function setNum(numArg: number) {
return <T extends new (...args: any[]) => {}>(constructor: T) => {
return class extends constructor {
decoratorNum = numArg;
};
};
}
@setNum(420)
class TestClass {
public decoratorNum;
}
return new TestClass();
`.expectToMatchJsResult();
});
test("Multiple class decorators", () => {
util.testFunction`
function setTen<T extends new (...args: any[]) => {}>(constructor: T) {
return class extends constructor {
decoratorTen = 10;
}
}
function setNum<T extends new (...args: any[]) => {}>(constructor: T) {
return class extends constructor {
decoratorNum = 410;
}
}
@setTen
@setNum
class TestClass {
public decoratorTen;
public decoratorNum;
}
return new TestClass();
`.expectToMatchJsResult();
});
test("Class decorator with inheritance", () => {
util.testFunction`
function setTen<T extends new (...args: any[]) => {}>(constructor: T) {
return class extends constructor {
decoratorTen = 10;
}
}
class TestClass {
public decoratorTen = 0;
}
@setTen
class SubTestClass extends TestClass {
public decoratorTen = 5;
}
return new SubTestClass();
`.expectToMatchJsResult();
});
test("Class decorators are applied in order and executed in reverse order", () => {
util.testFunction`
const order = [];
function pushOrder(index: number) {
order.push("eval " + index);
return (constructor: new (...args: any[]) => {}) => {
order.push("execute " + index);
};
}
@pushOrder(1)
@pushOrder(2)
@pushOrder(3)
class TestClass {}
return order;
`.expectToMatchJsResult();
});
test("Throws error if decorator function has void context", () => {
util.testFunction`
function decorator(this: void, constructor: new (...args: any[]) => {}) {}
@decorator
class TestClass {}
`.expectDiagnosticsToMatchSnapshot([decoratorInvalidContext.code]);
});
test("Exported class decorator", () => {
util.testModule`
function decorator<T extends new (...args: any[]) => any>(Class: T): T {
return class extends Class {
public bar = "foobar";
};
}
@decorator
export class Foo {}
`
.setReturnExport("Foo", "bar")
.expectToMatchJsResult();
});
test.each([
["@decorator method() {}"],
["@decorator property;"],
["@decorator propertyWithInitializer = () => {};"],
["@decorator ['evaluated property'];"],
["@decorator get getter() { return 5 }"],
["@decorator set setter(value) {}"],
["@decorator static method() {}"],
["@decorator static property;"],
["@decorator static propertyWithInitializer = () => {}"],
["@decorator static get getter() { return 5 }"],
["@decorator static set setter(value) {}"],
["@decorator static ['evaluated property'];"],
["method(@decorator a) {}"],
["static method(@decorator a) {}"],
])("Decorate class member (%p)", classMember => {
util.testFunction`
let decoratorParameters: any;
const decorator = (target, key, index?) => {
const targetKind = target === Foo ? "Foo" : target === Foo.prototype ? "Foo.prototype" : "unknown";
decoratorParameters = { targetKind, key, index: typeof index };
};
class Foo {
${classMember}
}
return decoratorParameters;
`.expectToMatchJsResult();
});
describe("Decorators /w descriptors", () => {
test.each([
["return { writable: true }", "return { configurable: true }"],
["desc.writable = true", "return { configurable: true }"],
])("Combine decorators (%p + %p)", (decorateA, decorateB) => {
util.testFunction`
const A = (target, key, desc): any => { ${decorateA} };
const B = (target, key, desc): any => { ${decorateB} };
class Foo { @A @B static method() {} }
const { value, ...rest } = Object.getOwnPropertyDescriptor(Foo, "method");
return rest;
`.expectToMatchJsResult();
});
test.each(["return { value: true }", "desc.value = true"])(
"Use decorator to override method value",
overrideStatement => {
util.testFunction`
const decorator = (target, key, desc): any => { ${overrideStatement} };
class Foo { @decorator static method() {} }
return Foo.method;
`.expectToMatchJsResult();
}
);
});