##// END OF EJS Templates
fixed strict mode @bind decorator
cin -
r28:b88fac0e76c0 v1.0.0-rc13 default
parent child
Show More
@@ -0,0 +1,22
1 import { djbase, djclass, bind, prototype } from "../declare";
2
3 import { DjxWidgetBase } from "../tsx/DjxWidgetBase";
4 import { createElement } from "../tsx";
5
6
7 @djclass
8 export class MyWidget extends djbase(DjxWidgetBase) {
9
10 @bind({node: "titleNode", type:"innerHTML"})
11 title = "";
12
13 @prototype()
14 counter = 0;
15
16 render() {
17 return <div>
18 <h1 data-dojo-attach-point="titleNode"></h1>
19 </div>;
20 }
21
22 }
@@ -1,78 +1,74
1 1 plugins {
2 2 id "org.implab.gradle-typescript" version "1.3.3"
3 3 id "ivy-publish"
4 4 }
5 5
6 6 typescript {
7 7 compilerOptions {
8 8 lib = ["es5", "dom", "scripthost", "es2015.promise", "es2015.symbol", "es2015.iterable"]
9 9 //listFiles = true
10 10 declaration = true
11 11 strict = true
12 12 types = []
13 13 module = "amd"
14 14 it.target = "es5"
15 15 experimentalDecorators = true
16 16 jsx = "react"
17 17 jsxFactory = "createElement"
18 18 moduleResolution = "node"
19 19 // dojo-typings are sick
20 20 skipLibCheck = true
21 21 // traceResolution = true
22 22 // baseUrl = "./"
23 23 // paths = [ "*": [ "$projectDir/src/typings/*" ] ]
24 24 // baseUrl = "$projectDir/src/typings"
25 25 // typeRoots = ["$projectDir/src/typings"]
26 26 }
27 27
28 28 tscCmd = "$projectDir/node_modules/.bin/tsc"
29 29 tsLintCmd = "$projectDir/node_modules/.bin/tslint"
30 30 esLintCmd = "$projectDir/node_modules/.bin/eslint"
31 31 }
32 32
33 33 configureTsMain {
34 34 compilerOptions {
35 35 /*baseUrl = "$projectDir/src"
36 36 paths = [
37 37 "dojo/*" : [ "typings/dojo/*" ],
38 38 "dijit/*" : [ "typings/dijit/*" ]
39 39 ]*/
40 40 types = ["requirejs", "dojo-typings"]
41 41 }
42 42 }
43 43
44 44 configureTsTest {
45 45 compilerOptions {
46 baseUrl = "."
47 paths = [
48 "@implab/djx" : [ sources.main.output.typingsDir.get().toString() ],
49 "@implab/djx/*" : [ "${sources.main.output.typingsDir.get().toString()}/*" ]
50 ]
51 types = ["requirejs", sources.main.output.typingsDir.get().toString()]
46 typeRoots = []
47 types = ["requirejs", sources.main.output.typingsDir.get().toString() ]
52 48 }
53 49 }
54 50
55 51 npmPackMeta {
56 52 meta {
57 53 name = "@$npmScope/$project.name"
58 54 }
59 55 }
60 56
61 57 task npmPackTypings(type: Copy) {
62 58 dependsOn typings
63 59
64 60 npmPackContents.dependsOn it
65 61
66 62 from typescript.typingsDir
67 63 into npm.packageDir
68 64 }
69 65
70 66 task printVersion {
71 67 doLast {
72 68 println "packageName: ${npmPackMeta.metadata.get().name}";
73 69 println "version: $version";
74 70 println "target: $typescript.compilerOptions.target";
75 71 println "module: $typescript.compilerOptions.module";
76 72 println "symbols: $symbols";
77 73 }
78 74 } No newline at end of file
@@ -1,260 +1,256
1 1 import declare = require("dojo/_base/declare");
2 2 import { each } from "@implab/core-amd/safe";
3 3 import { Constructor } from "@implab/core-amd/interfaces";
4 4 import dojo = require("dojo/_base/kernel");
5 5
6 6 // declare const declare: any;
7 7
8 8 type DeclareConstructor<T> = dojo._base.DeclareConstructor<T>;
9 9
10 10 export interface AbstractConstructor<T = {}> {
11 11 prototype: T;
12 12 }
13 13
14 14 interface DjMockConstructor<T = {}> {
15 15 new(...args: any[]): T;
16 16 mock: boolean;
17 17 base: AbstractConstructor;
18 18 }
19 19
20 20 export function djbase<T>(
21 21 b0: AbstractConstructor<T>
22 22 ): DeclareConstructor<T>;
23 23
24 24 export function djbase<T0, T1>(
25 25 b0: AbstractConstructor<T0>,
26 26 b1: AbstractConstructor<T1>
27 27 ): DeclareConstructor<T0 & T1>;
28 28
29 29 export function djbase<T0, T1, T2>(
30 30 b0: AbstractConstructor<T0>,
31 31 b1: AbstractConstructor<T1>,
32 32 b2: AbstractConstructor<T2>
33 33 ): DeclareConstructor<T0 & T1 & T2>;
34 34
35 35 export function djbase<T0, T1, T2, T3>(
36 36 b0: AbstractConstructor<T0>,
37 37 b1: AbstractConstructor<T1>,
38 38 b2: AbstractConstructor<T2>,
39 39 b3: AbstractConstructor<T3>
40 40 ): DeclareConstructor<T0 & T1 & T2 & T3>;
41 41
42 42 export function djbase<T0, T1, T2, T3, T4>(
43 43 b0: AbstractConstructor<T0>,
44 44 b1: AbstractConstructor<T1>,
45 45 b2: AbstractConstructor<T2>,
46 46 b3: AbstractConstructor<T3>,
47 47 b4: AbstractConstructor<T4>
48 48 ): DeclareConstructor<T0 & T1 & T2 & T3 & T4>;
49 49
50 50 export function djbase<T0, T1, T2, T3, T4, T5>(
51 51 b0: AbstractConstructor<T0>,
52 52 b1: AbstractConstructor<T1>,
53 53 b2: AbstractConstructor<T2>,
54 54 b3: AbstractConstructor<T3>,
55 55 b4: AbstractConstructor<T4>,
56 56 b5: AbstractConstructor<T5>
57 57 ): DeclareConstructor<T0 & T1 & T2 & T3 & T4 & T5>;
58 58
59 59 export function djbase<T0, T1, T2, T3, T4, T5, T6>(
60 60 b0: AbstractConstructor<T0>,
61 61 b1: AbstractConstructor<T1>,
62 62 b2: AbstractConstructor<T2>,
63 63 b3: AbstractConstructor<T3>,
64 64 b4: AbstractConstructor<T4>,
65 65 b5: AbstractConstructor<T5>,
66 66 b6: AbstractConstructor<T6>
67 67 ): DeclareConstructor<T0 & T1 & T2 & T3 & T4 & T5 & T6>;
68 68
69 69 export function djbase<T0, T1, T2, T3, T4, T5, T6, T7>(
70 70 b0: AbstractConstructor<T0>,
71 71 b1: AbstractConstructor<T1>,
72 72 b2: AbstractConstructor<T2>,
73 73 b3: AbstractConstructor<T3>,
74 74 b4: AbstractConstructor<T4>,
75 75 b5: AbstractConstructor<T5>,
76 76 b6: AbstractConstructor<T6>,
77 77 b7: AbstractConstructor<T7>
78 78 ): DeclareConstructor<T0 & T1 & T2 & T3 & T4 & T5 & T6 & T7>;
79 79
80 80 /** Создает конструктор-заглушку из списка базовых классов, используется
81 81 * для объявления классов при помощи `dojo/_base/declare`.
82 82 *
83 * Создает пустой конструтор, с пустым стандартным прототипом, это нужно,
83 * Создает пустой конструктор, с пустым стандартным прототипом, это нужно,
84 84 * поскольку в унаследованном классе конструктор обязательно должен вызвать
85 85 * `super(...)`, таким образом он вызовет пустую функцию.
86 86 *
87 * Созданный конструтор хранит в себе список базовых классов, который будет
87 * Созданный конструктор хранит в себе список базовых классов, который будет
88 88 * использован декоратором `djclass`, который вернет класс, объявленный при
89 89 * помощи `dojo/_base/declare`.
90 90 *
91 91 * @param bases список базовых классов, от которых требуется унаследовать
92 92 * новый класс.
93 93 *
94 94 */
95 95 export function djbase(...bases: any[]): Constructor {
96 96
97 97 const t = class {
98 98 static mock: boolean;
99 99 static base: AbstractConstructor;
100 100 };
101 101
102 102 t.mock = true;
103 103 t.base = declare(bases);
104 104
105 105 return t as any;
106 106 }
107 107
108 108 function isMockConstructor<T extends {}>(v: AbstractConstructor<T>): v is DjMockConstructor<T> {
109 109 return v && "mock" in v;
110 110 }
111 111
112 112 /** Создает класс при помощи `dojo/_base/declare`. Для этого исходный класс
113 113 * должен быть унаследован от `djbase(...)`.
114 114 *
115 115 * @param target Класс, который нужно объявить при помощи `dojo/_base/declare`
116 116 */
117 117 export function djclass<T extends AbstractConstructor>(target: T): T {
118 118 // получаем базовый конструктор и его прототип
119 119 let bp = target && target.prototype && Object.getPrototypeOf(target.prototype);
120 120 const bc = bp && bp.constructor;
121 121
122 122 // проверка того, что класс унаследован от специальной заглушки
123 123 if (isMockConstructor(bc)) {
124 124 // t - базовый класс, объявленный при помощи dojo/_base/declare
125 125 const t = bc.base;
126 126
127 127 // bc - базовый класс, bc.prototype используется как super
128 128 // при вызове базовых методов. Нужно создать bc.prototype
129 129 // таким образом, чтобы он вызывал this.inherited().
130 130
131 131 // создаем новый порототип, он не в цепочке прототипов у текущего
132 132 // класса, но super.some_method будет использовать именно его.
133 133 // в этом объекте будут размещены прокси для переопределенных
134 134 // методов.
135 135 bp = bc.prototype = Object.create(t.prototype);
136 136 bp.constructor = bc;
137 137
138 138 // proxy - фабрика для создания прокси-методов, которые внутри
139 139 // себя вызовут this.inherited с правильными параметрами.
140 140 const proxy = (m: (...args: any[]) => any) => function (this: any) {
141 141 const f = this.getInherited({ callee: m });
142 142 return f && f.apply(this, arguments);
143 143
144 144 // так сделать можно только dojo 1.15+
145 145 // return this.inherited(m, arguments);
146 146 };
147 147
148 148 // у текущего класса прототип содержит методы, объявленные в этом
149 149 // классе и его конструктор. Нужно пройти по всем методам и
150 150 // создать для них прокси.
151 151 // При этом только те, методы, которые есть в базовых классах
152 152 // могут быть переопределены.
153 153 each(target.prototype, (m: any, p: string | number | symbol) => {
154 154 if (typeof m === "function" &&
155 155 p !== "constructor" &&
156 156 target.prototype.hasOwnProperty(p) &&
157 157 p in t.prototype
158 158 ) {
159 159 bp[p] = proxy(m);
160 160 }
161 161 });
162 162
163 163 const cls = declare(t, target.prototype);
164 164 // TODO mixin static members
165 165 return cls as any;
166 166 } else {
167 167 return target as any;
168 168 }
169 169 }
170 170
171 171 function makeSetterName(prop: string) {
172 172 return [
173 173 "_set",
174 174 prop.replace(/^./, x => x.toUpperCase()),
175 175 "Attr"
176 176 ].join("");
177 177 }
178 178
179 179 function makeGetterName(prop: string) {
180 180 return [
181 181 "_get",
182 182 prop.replace(/^./, x => x.toUpperCase()),
183 183 "Attr"
184 184 ].join("");
185 185 }
186 186
187 187 interface NodeBindSpec {
188 188 node: string;
189 189 type: "attribute" | "innerText" | "textContent" | "innerHTML" | "class" | "toggleClass";
190 190 attribute?: string;
191 191
192 192 className?: string;
193 193 }
194 194
195 195 /**
196 196 * Описание привязки свойства виджета к свойству внутреннего объекта.
197 197 */
198 198 interface MemberBindSpec {
199 199 /**
200 200 * Имя свойства со ссылкой на объект, к которому .
201 201 */
202 202 member: string;
203 203 /**
204 204 * Свойство объекта к которому нужно осуществить привязку.
205 205 */
206 206 property: string;
207 207
208 208 /**
209 209 * Привязка осуществляется не только на запись но и на чтение свойства.
210 210 */
211 211 getter?: boolean;
212 212 }
213 213
214 214 function isNodeBindSpec(v: any): v is NodeBindSpec {
215 215 return "node" in v;
216 216 }
217 217
218 function isMemberBindSpec(v: any): v is MemberBindSpec {
219 return "member" in v;
220 }
221
222 218 /** Декорирует свойства виджета для привязки их к внутренним членам, либо DOM
223 219 * элементам, либо свойству внутреннего объекта.
224 220 *
225 221 * @param {NodeBindSpec | MemberBindSpec} params Параметры связывания.
226 222 */
227 223 export function bind(params: NodeBindSpec | MemberBindSpec) {
228 if (isNodeBindSpec(params))
224 if (isNodeBindSpec(params)) {
229 225 return (target: any, name: string) => {
230 226 target[makeSetterName(name)] = params;
231 227 };
232 else if (isMemberBindSpec(params)) {
228 } else {
233 229 return (target: any, name: string) => {
234 230 target[name] = null;
235 231 target[makeSetterName(name)] = function (v: any) {
236 232 this._set(name, v);
237 233 this[params.member].set(params.property, v);
238 234 };
239 235 if (params.getter)
240 236 target[makeGetterName(name)] = function () {
241 237 return this[params.member].get(params.property);
242 238 };
243 239 };
244 240 }
245 241 }
246 242
247 243 /** Создает в прототипе указанное свойство со значение `undefined`, данный
248 244 * декоратор следует использовать для свойств, у которых нет значения по-умолчанию
249 245 * и они не могут быть `null | undefined`
250 246 */
251 247 export function prototype(): (p: any, name: string) => void;
252 248 /** Создает в прототипе свойство с указанным значением.
253 249 * @param value Значение, которое будет указано в прототипе
254 250 */
255 251 export function prototype<T>(value: T): <P extends { [m in K]: T }, K extends keyof P>(p: P, name: K) => void;
256 252 export function prototype<T>(value?: T) {
257 253 return <P extends { [m in K]: T }, K extends keyof P>(p: P, name: K) => {
258 254 p[name] = value as any;
259 255 };
260 256 }
@@ -1,13 +1,13
1 1 {
2 2 "extends": "../tsconfig",
3 3 "compilerOptions": {
4 4 "rootDir": "ts",
5 5 "rootDirs": [
6 6 "ts",
7 7 "typings"
8 8 ],
9 9 "types": [
10 "requirejs", "./typings/index", "dojo-typings"
10 "requirejs", "./typings", "dojo-typings"
11 11 ]
12 12 }
13 } No newline at end of file
13 }
@@ -1,4 +1,10
1 1 declare module "@implab/djx/css!*" {
2 2 const result: { url: string };
3 3 export = result;
4 4 }
5
6 declare namespace JSX {
7 interface IntrinsicElements {
8 [name: string]: any;
9 }
10 }
@@ -1,18 +1,17
1 1 import { test } from "./TestTraits";
2 2 import { delay } from "@implab/core-amd/safe";
3 3 import { assert } from "chai";
4 import css = require("@implab/djx/css!my,css");
5 import {} from "@implab/djx/i18n";
4 import css = require("@implab/djx/css!my.css");
6 5
7 6 test("simple", (ok, fail, log) => {
8 7 setTimeout(() => {
9 8 // end should be called after the last assertion
10 9 ok("async assert");
11 10 }, 100);
12 11 });
13 12
14 13 test("simple", async (log, fail) => {
15 14 await delay(0);
16 15
17 16 assert.ok(true); // everything is fine
18 17 });
@@ -1,18 +1,13
1 1 {
2 2 "extends": "../tsconfig",
3 3 "compilerOptions": {
4 "baseUrl": ".",
5 4 //"rootDir": "ts",
6 5 "rootDirs": [
7 6 "ts",
8 7 "typings",
9 8 "../main/ts",
10 9 "../main/typings"
11 10 ],
12 "paths": {
13 "@implab/djx" : ["../main/ts", "../main/typings"],
14 "@implab/djx/*" : ["../main/ts/*", "../main/typings/*" ]
15 },
16 "types": ["requirejs", "../main/typings"]
11 "types": ["requirejs", "../main/typings", "dojo-typings"]
17 12 }
18 13 } No newline at end of file
@@ -1,13 +1,13
1 1 {
2 2 "compilerOptions": {
3 3 "moduleResolution": "node",
4 4 "noEmitOnError": true,
5 5 "strict": true,
6 6 "types": [],
7 7 "experimentalDecorators": true,
8 8 "jsxFactory": "createElement",
9 //"skipLibCheck": true,
9 "skipLibCheck": true,
10 10 "jsx": "react",
11 11 "lib": ["es5", "es2015.promise", "es2015.symbol", "es2015.iterable", "dom", "scripthost"]
12 12 }
13 13 } No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now