##// END OF EJS Templates
linting
cin -
r108:d644dced936e default
parent child
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,33 +1,35
1 1 {
2 2 "root": true,
3 3 "extends": [
4 4 "plugin:react/recommended",
5 5 "eslint:recommended",
6 6 "plugin:@typescript-eslint/eslint-recommended",
7 7 "plugin:@typescript-eslint/recommended",
8 8 "plugin:@typescript-eslint/recommended-requiring-type-checking"
9 9 ],
10 10 "parser": "@typescript-eslint/parser",
11 11 "parserOptions": {
12 12 "ecmaFeatures": {
13 13 "jsx": true
14 14 },
15 15 "ecmaVersion": 5,
16 16 "tsconfigRootDir": "djx/src",
17 17 "project": ["tsconfig.eslint.json", "*/tsconfig.json"]
18 18 },
19 19 "plugins": [
20 20 "@typescript-eslint"
21 21 ],
22 22 "rules": {
23 "react/react-in-jsx-scope": "off",
24 "react/no-unknown-property": "off",
23 25 "@typescript-eslint/no-empty-function": "off",
24 26 "max-classes-per-file": [
25 27 "error",
26 28 { "ignoreExpressions": true, "max": 1 }
27 29 ],
28 30 "@typescript-eslint/prefer-readonly": ["error"],
29 31 "semi": "off",
30 32 "@typescript-eslint/semi": ["error"]
31 33
32 34 }
33 35 }
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,258 +1,254
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
5 5 // declare const declare: any;
6 6
7 7 type DeclareConstructor<T> = dojo._base.DeclareConstructor<T>;
8 8
9 9 export interface AbstractConstructor<T = object> {
10 10 prototype: T;
11 11 }
12 12
13 13 interface DjMockConstructor<T = object> {
14 14 new(...args: unknown[]): T;
15 15 mock: boolean;
16 16 bases: AbstractConstructor[];
17 17 }
18 18
19 19 export function djbase<T>(): DeclareConstructor<T>;
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: AbstractConstructor[]): Constructor {
96 96
97 97 const t = class {
98 98 static mock: boolean;
99 99 static bases: AbstractConstructor[];
100 100 };
101 101
102 102 t.mock = true;
103 103 t.bases = bases;
104 104
105 105 return t as Constructor;
106 106 }
107 107
108 108 function isMockConstructor<T extends object>(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 const bp = target && !!target.prototype && Object.getPrototypeOf(target.prototype) as object;
120 120 const bc = bp && bp.constructor;
121 121
122 122 // проверка того, что класс унаследован от специальной заглушки
123 123 if (isMockConstructor(bc)) {
124 124 // bc.bases - базовый класс, объявленный при помощи dojo/_base/declare
125 125 const cls = declare(bc.bases, target.prototype) as unknown as T;
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 const nbp = bc.prototype = Object.create(cls.prototype) as Record<string, unknown>;
136 136 nbp.constructor = bc;
137 137
138 138 // proxy - фабрика для создания прокси-методов, которые внутри
139 139 // себя вызовут this.inherited с правильными параметрами.
140 140 const proxy = (m: (...args: unknown[]) => unknown) => function (this: dojo._base.DeclareCreatedObject, ...args: unknown[]) {
141 const f = this.getInherited({ callee: m, ...args, length: args.length});
141 const f = this.getInherited({ callee: m, ...args, length: args.length });
142 142 return f ? f.apply(this, args) as unknown : undefined;
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: unknown, p: string) => {
154 154 if (typeof m === "function" &&
155 155 p !== "constructor" &&
156 156 Object.prototype.hasOwnProperty.call(target, p)
157 157 ) {
158 158 nbp[p] = proxy(m as (...args: unknown[]) => unknown);
159 159 }
160 160 });
161 161
162 162 // TODO mixin static members
163 163 return cls;
164 164 } else {
165 165 return target;
166 166 }
167 167 }
168 168
169 169 function makeSetterName(prop: string) {
170 170 return [
171 171 "_set",
172 172 prop.replace(/^./, x => x.toUpperCase()),
173 173 "Attr"
174 174 ].join("");
175 175 }
176 176
177 177 function makeGetterName(prop: string) {
178 178 return [
179 179 "_get",
180 180 prop.replace(/^./, x => x.toUpperCase()),
181 181 "Attr"
182 182 ].join("");
183 183 }
184 184
185 185 interface NodeBindSpec {
186 186 node: string;
187 187 type: "attribute" | "innerText" | "textContent" | "innerHTML" | "class" | "toggleClass";
188 188 attribute?: string;
189 189
190 190 className?: string;
191 191 }
192 192
193 193 /**
194 194 * Описание привязки свойства виджета к свойству внутреннего объекта.
195 195 */
196 196 interface MemberBindSpec {
197 197 /**
198 198 * Имя свойства со ссылкой на объект, к которому .
199 199 */
200 200 member: string;
201 201 /**
202 202 * Свойство объекта к которому нужно осуществить привязку.
203 203 */
204 204 property: string;
205 205
206 206 /**
207 207 * Привязка осуществляется не только на запись но и на чтение свойства.
208 208 */
209 209 getter?: boolean;
210 210 }
211 211
212 212 function isNodeBindSpec(v: object): v is NodeBindSpec {
213 213 return "node" in v;
214 214 }
215 215
216 216 /** Декорирует свойства виджета для привязки их к внутренним членам, либо DOM
217 217 * элементам, либо свойству внутреннего объекта.
218 218 *
219 219 * @param {NodeBindSpec | MemberBindSpec} params Параметры связывания.
220 220 */
221 221 export function bind(params: NodeBindSpec | MemberBindSpec) {
222 222 if (isNodeBindSpec(params)) {
223 return (target: Record<string, unknown>, name: string) => {
224 target[makeSetterName(name)] = params;
223 return <K extends string>(target: Record<K, unknown>, name: K) => {
224 target[makeSetterName(name) as K /** hack to not go insane) */] = params;
225 225 };
226 226 } else {
227 return (target: Record<string, unknown> & { _set(name: string, v: unknown): void }, name: string) => {
228 target[name] = null;
229 target[makeSetterName(name)] = function (v: unknown) {
227 return <K extends string,
228 T extends { [p in K]: p extends "_set" ? (name: p, v: unknown) => void : unknown; }> (target: T, name: K) => {
229 target[name] = undefined as T[K];
230 target[makeSetterName(name) as K] = function (this: T, v: unknown) {
230 231 this._set(name, v);
231 232 const inner = this[params.member] as Record<string, unknown>;
232 if (typeof inner.set === "function")
233 if (typeof inner.set === "function")
233 234 inner.set(params.property, v);
234 };
235 } as T[K];
235 236 if (params.getter)
236 237 target[makeGetterName(name)] = function () {
237 238 const inner = this[params.member] as Record<string, unknown>;
238 if (typeof inner.get === "function")
239 if (typeof inner.get === "function")
239 240 return inner.get(params.property) as unknown;
240 241 };
241 242 };
242 243 }
243 244 }
244 245
245 /** Создает в прототипе указанное свойство со значение `undefined`, данный
246 * декоратор следует использовать для свойств, у которых нет значения по-умолчанию
247 * и они не могут быть `null | undefined`
248 */
249 export function prototype(): (p: object, name: string) => void;
250 246 /** Создает в прототипе свойство с указанным значением.
251 247 * @param value Значение, которое будет указано в прототипе
252 248 */
253 249 export function prototype<T>(value: T): <P extends { [m in K]: T }, K extends keyof P>(p: P, name: K) => void;
254 250 export function prototype<T>(value?: T) {
255 return <P extends { [m in K]: T }, K extends keyof P>(p: P, name: K) => {
256 p[name] = value as any;
251 return (p: { [m in string]: T | undefined }, name: string) => {
252 p[name] = value;
257 253 };
258 254 }
@@ -1,215 +1,215
1 1 import { IDestroyable } from "@implab/core-amd/interfaces";
2 2 import { isDestroyable } from "@implab/core-amd/safe";
3 3 import _WidgetBase = require("dijit/_WidgetBase");
4 4 import registry = require("dijit/registry");
5 5
6 6 interface _WidgetBaseConstructor {
7 new <E extends { [k in keyof E]: Event } = {}>(params?: Partial<_WidgetBase<E>> & ThisType<_WidgetBase<E>>, srcNodeRef?: string | Node): _WidgetBase<E> & dojo._base.DeclareCreatedObject;
7 new <E extends { [k in keyof E]: Event } = object>(params?: Partial<_WidgetBase<E>> & ThisType<_WidgetBase<E>>, srcNodeRef?: string | Node): _WidgetBase<E> & dojo._base.DeclareCreatedObject;
8 8 prototype: _WidgetBase;
9 9 }
10 10
11 11 export type DojoNodePosition = "first" | "after" | "before" | "last" | "replace" | "only" | number;
12 12
13 13 export type DojoNodeLocation = [Node, DojoNodePosition];
14 14
15 15 export interface Rendition<TNode extends Node = Node> {
16 16 getDomNode(): TNode;
17 17
18 18 placeAt(refNode: string | Node, position?: DojoNodePosition): void;
19 19 }
20 20
21 21 /**
22 22 * @deprecated use Rendition
23 23 */
24 24 export type BuildContext<TNode extends Node = Node> = Rendition<TNode>;
25 25
26 26 export interface IRecursivelyDestroyable {
27 27 destroyRecursive(): void;
28 28 }
29 29
30 30 export const isNode = (el: unknown): el is Node => !!(el && (el as Node).nodeName && (el as Node).nodeType);
31 31
32 32 export const isElementNode = (el: unknown): el is Element => isNode(el) && el.nodeType === 1;
33 33
34 34 export const isTextNode = (el: unknown): el is Text => isNode(el) && el.nodeType === 3;
35 35
36 36 export const isProcessingInstructionNode = (el: unknown): el is ProcessingInstruction => isNode(el) && el.nodeType === 7;
37 37
38 38 export const isCommentNode = (el: unknown): el is Comment => isNode(el) && el.nodeType === 8;
39 39
40 40 export const isDocumentNode = (el: unknown): el is Document => isNode(el) && el.nodeType === 9;
41 41
42 42 export const isDocumentTypeNode = (el: unknown): el is DocumentType => isNode(el) && el.nodeType === 10;
43 43
44 44 export const isDocumentFragmentNode = (el: unknown): el is DocumentFragment => isNode(el) && el.nodeType === 11;
45 45
46 46 export const isWidget = (v: unknown): v is _WidgetBase => !!(v && "domNode" in (v as _WidgetBase));
47 47
48 48 export const isRendition = (v: unknown): v is Rendition => !!(v && typeof (v as Rendition).getDomNode === "function");
49 49
50 50 /**
51 51 * @deprecated use isRendition
52 52 */
53 53 export const isBuildContext = isRendition;
54 54
55 55 export const isPlainObject = (v: object) => {
56 56 if (typeof v !== "object")
57 57 return false;
58 58
59 59 const vp = Object.getPrototypeOf(v) as object;
60 60 return !vp || vp === Object.prototype;
61 61 };
62 62
63 63 export const isWidgetConstructor = (v: unknown): v is _WidgetBaseConstructor =>
64 64 typeof v === "function" && !!v.prototype && (
65 65 "domNode" in v.prototype ||
66 66 "buildRendering" in v.prototype
67 67 );
68 68
69 69
70 70 /** Tests whether the specified node is placed in visible dom.
71 71 * @param {Node} node The node to test
72 72 */
73 73 export const isInPage = (node: Node) => node === document.body ? false : document.body.contains(node);
74 74
75 75 export const isRecursivelyDestroyable = (target: unknown): target is IRecursivelyDestroyable =>
76 76 !!(target && typeof (target as IRecursivelyDestroyable).destroyRecursive === "function");
77 77
78 78
79 79
80 80 /** Destroys DOM Node with all contained widgets.
81 81 * If the specified node is the root node of a widget, then the
82 82 * widget will be destroyed.
83 83 *
84 84 * @param target DOM Node or widget to destroy
85 85 */
86 86 export const destroy = (target: Node | IDestroyable | IRecursivelyDestroyable) => {
87 87 if (isRecursivelyDestroyable(target)) {
88 88 target.destroyRecursive();
89 89 } else if (isDestroyable(target)) {
90 90 target.destroy();
91 91 } else if (isNode(target)) {
92 92 if (isElementNode(target)) {
93 93 const w = registry.byNode(target);
94 94 if (w) {
95 95 w.destroyRecursive();
96 96 return;
97 97 } else {
98 98 emptyNode(target);
99 99 }
100 100 }
101 101 const parent = target.parentNode;
102 102 if (parent)
103 103 parent.removeChild(target);
104 104
105 105 }
106 106 };
107 107
108 108 /** Empties a content of the specified node and destroys all contained widgets.
109 109 *
110 110 * @param target DOM node to empty.
111 111 */
112 112 export const emptyNode = (target: Node) => {
113 113 registry.findWidgets(target).forEach(destroy);
114 114
115 115 // eslint-disable-next-line no-cond-assign
116 116 for (let c; c = target.lastChild;) { // intentional assignment
117 117 target.removeChild(c);
118 118 }
119 119 };
120 120
121 121 /** This function starts all widgets inside the DOM node if the target is a node
122 122 * or starts widget itself if the target is the widget. If the specified node
123 123 * associated with the widget that widget will be started.
124 124 *
125 125 * @param target DOM node to find and start widgets or the widget itself.
126 126 */
127 127 export const startupWidgets = (target: Node | _WidgetBase, skipNode?: Node) => {
128 128 if (isNode(target)) {
129 129 if (isElementNode(target)) {
130 130 const w = registry.byNode(target);
131 131 if (w) {
132 132 if (w.startup)
133 133 w.startup();
134 134 } else {
135 135 registry.findWidgets(target, skipNode).forEach(x => x.startup());
136 136 }
137 137 }
138 138 } else {
139 139 if (target.startup)
140 140 target.startup();
141 141 }
142 142 };
143 143
144 144 /** Places the specified DOM node at the specified location.
145 145 *
146 146 * @param node The node which should be placed
147 147 * @param refNodeOrId The reference node where the created
148 148 * DOM should be placed.
149 149 * @param position Optional parameter, specifies the
150 150 * position relative to refNode. Default is "last" (i.e. last child).
151 151 */
152 152 export const placeAt = (node: Node, refNodeOrId: string | Node, position: DojoNodePosition = "last") => {
153 153 const ref = typeof refNodeOrId == "string" ? document.getElementById(refNodeOrId) : refNodeOrId;
154 154 if (!ref)
155 155 return;
156 156
157 157 const parent = ref.parentNode;
158 158
159 159 if (typeof position == "number") {
160 160 if (ref.childNodes.length <= position) {
161 161 ref.appendChild(node);
162 162 } else {
163 163 ref.insertBefore(node, ref.childNodes[position]);
164 164 }
165 165 } else {
166 166 switch (position) {
167 167 case "before":
168 168 parent && parent.insertBefore(node, ref);
169 169 break;
170 170 case "after":
171 171 parent && parent.insertBefore(node, ref.nextSibling);
172 172 break;
173 173 case "first":
174 174 ref.insertBefore(node, ref.firstChild);
175 175 break;
176 176 case "last":
177 177 ref.appendChild(node);
178 178 break;
179 179 case "only":
180 180 emptyNode(ref);
181 181 ref.appendChild(node);
182 182 break;
183 183 case "replace":
184 184 if (parent)
185 185 parent.replaceChild(node, ref);
186 186 destroy(ref);
187 187 break;
188 188 }
189 189 }
190 190 };
191 191
192 192 /** Collects nodes from collection to an array.
193 193 *
194 194 * @param collection The collection of nodes.
195 195 * @returns The array of nodes.
196 196 */
197 197 export const collectNodes = (collection: NodeListOf<ChildNode>) => {
198 198 const items = [];
199 199 for (let i = 0, n = collection.length; i < n; i++) {
200 200 items.push(collection[i]);
201 201 }
202 202 return items;
203 203 };
204 204
205 205
206 206 export const isMounted = (node: Node) => {
207 207 if (node.parentNode) {
208 208 const parentWidget = registry.getEnclosingWidget(node.parentNode);
209 209 if (parentWidget && parentWidget._started)
210 210 return true;
211 211 }
212 212 if (isInPage(node))
213 213 return true;
214 214 return false;
215 215 }; No newline at end of file
@@ -1,52 +1,52
1 1 import { observe } from "./observable";
2 2 import * as t from "tap";
3 3
4 4 const subj1 = observe<number>(({ next, complete }) => {
5 5 next(1);
6 6 complete();
7 7 next(2);
8 8 });
9 9
10 10 const consumer1 = {
11 11 sum: 0,
12 12 next(v: number) {
13 13 this.sum += v;
14 14 }
15 }
15 };
16 16
17 17 subj1.subscribe(consumer1);
18 18 t.equal(consumer1.sum, 1, "Should get only one value");
19 19
20 20 subj1.subscribe(consumer1);
21 21 t.equal(consumer1.sum, 2, "Should get the value again");
22 22
23 23 const consumer2 = {
24 24 value: 0,
25 25 completed: false,
26 26 next(v: number) { this.value = v; },
27 27 complete() { this.completed = true; }
28 28 };
29 29
30 30 let maps = 0;
31 31
32 32 subj1
33 33 .map(v => {
34 t.comment("map1: " + v * 2);
34 t.comment(`map1: ${v * 2}`);
35 35 maps++;
36 36 return v * 2;
37 37 })
38 38 .map (v => {
39 t.comment("map2: " + v * 2);
39 t.comment(`map2: ${v * 2}`);
40 40 maps++;
41 41 return v * 2;
42 42 })
43 43 .map(v => {
44 t.comment("map3: " + v * 2);
44 t.comment(`map3: ${v * 2}`);
45 45 maps++;
46 return v * 2
46 return v * 2;
47 47 })
48 48 .subscribe(consumer2);
49 49
50 50 t.equal(consumer2.value, 8, "Should map");
51 51 t.equal(maps, 3, "The map chain should not be executed after completion");
52 52 t.ok(consumer2.completed, "The completion signal should pass through"); No newline at end of file
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now