##// END OF EJS Templates
linting
cin -
r109:4a375b9c654a default
parent child
Show More
@@ -0,0 +1,1
1 .eslintrc.js No newline at end of file
@@ -0,0 +1,39
1 module.exports = {
2 root: true,
3 extends: [
4 "plugin:react/recommended",
5 "eslint:recommended",
6 "plugin:@typescript-eslint/eslint-recommended",
7 "plugin:@typescript-eslint/recommended",
8 "plugin:@typescript-eslint/recommended-requiring-type-checking"
9 ],
10 parser: "@typescript-eslint/parser",
11 parserOptions: {
12 ecmaFeatures: {
13 jsx: true
14 },
15 ecmaVersion: 5,
16 tsconfigRootDir: __dirname + "/src",
17 project: [
18 "tsconfig.eslint.json",
19 "*/tsconfig.json"
20 ]
21 },
22 plugins: [
23 "react",
24 "@typescript-eslint"
25 ],
26 rules: {
27 "react/react-in-jsx-scope": "off",
28 "react/no-unknown-property": "off",
29 "@typescript-eslint/no-empty-function": "off",
30 "max-classes-per-file": [
31 "error",
32 { "ignoreExpressions": true, "max": 1 }
33 ],
34 "@typescript-eslint/prefer-readonly": ["error"],
35 "semi": "off",
36 "@typescript-eslint/semi": ["error"]
37
38 }
39 }
@@ -0,0 +1,39
1 module.exports = {
2 root: true,
3 extends: [
4 "plugin:react/recommended",
5 "eslint:recommended",
6 "plugin:@typescript-eslint/eslint-recommended",
7 "plugin:@typescript-eslint/recommended",
8 "plugin:@typescript-eslint/recommended-requiring-type-checking"
9 ],
10 parser: "@typescript-eslint/parser",
11 parserOptions: {
12 ecmaFeatures: {
13 jsx: true
14 },
15 ecmaVersion: 5,
16 tsconfigRootDir: __dirname + "/src",
17 project: [
18 "tsconfig.eslint.json",
19 "*/tsconfig.json"
20 ]
21 },
22 plugins: [
23 "react",
24 "@typescript-eslint"
25 ],
26 rules: {
27 "react/react-in-jsx-scope": "off",
28 "react/no-unknown-property": "off",
29 "@typescript-eslint/no-empty-function": "off",
30 "max-classes-per-file": [
31 "error",
32 { "ignoreExpressions": true, "max": 1 }
33 ],
34 "@typescript-eslint/prefer-readonly": ["error"],
35 "semi": "off",
36 "@typescript-eslint/semi": ["error"],
37 "react/jsx-key": "off"
38 }
39 }
@@ -0,0 +1,3
1 {
2 "extends": "../tsconfig",
3 } No newline at end of file
@@ -10,7 +10,7
10 10 "license": "BSD-2-Clause",
11 11 "devDependencies": {
12 12 "@implab/core-amd": "^1.4.0",
13 "@implab/dojo-typings": "1.0.0",
13 "@implab/dojo-typings": "1.0.3",
14 14 "@types/chai": "4.1.3",
15 15 "@types/requirejs": "2.1.31",
16 16 "@types/tap": "15.0.7",
@@ -458,9 +458,9
458 458 "dev": true
459 459 },
460 460 "node_modules/@implab/dojo-typings": {
461 "version": "1.0.0",
462 "resolved": "https://registry.npmjs.org/@implab/dojo-typings/-/dojo-typings-1.0.0.tgz",
463 "integrity": "sha512-B2kvlKJgvyIQAl/k1pVyNmtp4ADvBDCs4Lw/qfBC+Sz/ft4c7EuRXmN/+2dhWrd6A5SMjEgex5oeq6Ja2ntrig==",
461 "version": "1.0.3",
462 "resolved": "https://registry.npmjs.org/@implab/dojo-typings/-/dojo-typings-1.0.3.tgz",
463 "integrity": "sha512-oyCiuU5ay9MfvdQtZNJSeV30jKufdiLBAcq6rn360pww2hzdqvWEeoU9/New8fMzyNiaEumOlgbcS11EVIH+Jg==",
464 464 "dev": true
465 465 },
466 466 "node_modules/@istanbuljs/load-nyc-config": {
@@ -7030,9 +7030,9
7030 7030 "dev": true
7031 7031 },
7032 7032 "@implab/dojo-typings": {
7033 "version": "1.0.0",
7034 "resolved": "https://registry.npmjs.org/@implab/dojo-typings/-/dojo-typings-1.0.0.tgz",
7035 "integrity": "sha512-B2kvlKJgvyIQAl/k1pVyNmtp4ADvBDCs4Lw/qfBC+Sz/ft4c7EuRXmN/+2dhWrd6A5SMjEgex5oeq6Ja2ntrig==",
7033 "version": "1.0.3",
7034 "resolved": "https://registry.npmjs.org/@implab/dojo-typings/-/dojo-typings-1.0.3.tgz",
7035 "integrity": "sha512-oyCiuU5ay9MfvdQtZNJSeV30jKufdiLBAcq6rn360pww2hzdqvWEeoU9/New8fMzyNiaEumOlgbcS11EVIH+Jg==",
7036 7036 "dev": true
7037 7037 },
7038 7038 "@istanbuljs/load-nyc-config": {
@@ -25,7 +25,7
25 25 "@types/yaml": "1.2.0",
26 26 "@types/tap": "15.0.7",
27 27 "dojo": "1.16.0",
28 "@implab/dojo-typings": "1.0.0",
28 "@implab/dojo-typings": "1.0.3",
29 29 "@typescript-eslint/eslint-plugin": "^5.23.0",
30 30 "@typescript-eslint/parser": "^5.23.0",
31 31 "eslint": "^8.23.0",
@@ -3,31 +3,18 import { argumentNotEmptyString, isPromi
3 3
4 4 export type LocaleProvider<T> = () => PromiseOrValue<T | { default: T }>;
5 5
6 type ResolveCallback<T> = () => PromiseOrValue<T>;
7
8 6 function when<T, T2>(value: PromiseOrValue<T>, cb: (v: T) => PromiseOrValue<T2>): PromiseOrValue<T2> {
9 7 return isPromise(value) ?
10 8 value.then(cb) :
11 9 cb(value);
12 10 }
13 11
14 function isCallback<T>(v: ResolveCallback<T> | PromiseOrValue<T>): v is ResolveCallback<T> {
15 return typeof v === "function";
16 }
12 const chainObjects = <T extends object, T2 extends object>(o1: T, o2: T2) =>
13 mixin(Object.create(o1) as T, o2);
14 export class NlsBundle<T extends object> {
15 private readonly _locales: MapOf<LocaleProvider<Partial<T>>>;
17 16
18 function chainObjects<T extends object>(o1: T, o2: T) {
19 if (!o1)
20 return o2;
21 if (!o2)
22 return o1;
23
24 return mixin(Object.create(o1) as T, o2);
25 }
26
27 export class NlsBundle<T extends object> {
28 private _locales: MapOf<LocaleProvider<Partial<T>>>;
29
30 private _default: T;
17 private readonly _default: T;
31 18
32 19 private _cache: MapOf<PromiseOrValue<T>>;
33 20
@@ -65,9 +52,7 export class NlsBundle<T extends object>
65 52 });
66 53 }
67 54
68 _loadPackage(localeData: any) {
69 if (isCallback(localeData))
70 return when(localeData(), data => data && "default" in data ? data.default : data);
71 return localeData;
55 _loadPackage(localeData: LocaleProvider<Partial<T>>) {
56 return when(localeData(), data => data && "default" in data ? data.default : data);
72 57 }
73 58 }
@@ -1,8 +1,8
1 1 import inject from "./dom-inject";
2 2
3 3 interface OnLoad {
4 (result?: any): void;
5 error(err: any): void;
4 (result?: unknown): void;
5 error(err: unknown): void;
6 6 }
7 7
8 8 const plugin = {
@@ -137,9 +137,10 export function djclass<T extends Abstra
137 137
138 138 // proxy - фабрика для создания прокси-методов, которые внутри
139 139 // себя вызовут this.inherited с правильными параметрами.
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 });
142 return f ? f.apply(this, args) as unknown : undefined;
140 const proxy = (m: (...args: unknown[]) => unknown) => function (this: dojo._base.DeclareCreatedObject) {
141 const f = this.getInherited({ callee: m } as unknown as IArguments);
142 // eslint-disable-next-line prefer-rest-params
143 return f ? f.apply(this, arguments) as unknown : undefined;
143 144
144 145 // так сделать можно только dojo 1.15+
145 146 // return this.inherited(m, arguments);
@@ -153,7 +154,7 export function djclass<T extends Abstra
153 154 each(target.prototype, (m: unknown, p: string) => {
154 155 if (typeof m === "function" &&
155 156 p !== "constructor" &&
156 Object.prototype.hasOwnProperty.call(target, p)
157 Object.prototype.hasOwnProperty.call(target.prototype, p)
157 158 ) {
158 159 nbp[p] = proxy(m as (...args: unknown[]) => unknown);
159 160 }
@@ -224,18 +225,18 export function bind(params: NodeBindSpe
224 225 target[makeSetterName(name) as K /** hack to not go insane) */] = params;
225 226 };
226 227 } else {
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) {
231 this._set(name, v);
232 const inner = this[params.member] as Record<string, unknown>;
228 return <K extends string>(target: Record<K | "_set", unknown>, name: K) => {
229 target[name] = undefined;
230
231 target[makeSetterName(name) as K] = function (this: typeof target, v: unknown) {
232 (this._set as (n: K, v: unknown) => void)(name, v);
233 const inner = this[params.member as K] as Record<string, unknown>;
233 234 if (typeof inner.set === "function")
234 235 inner.set(params.property, v);
235 } as T[K];
236 };
236 237 if (params.getter)
237 target[makeGetterName(name)] = function () {
238 const inner = this[params.member] as Record<string, unknown>;
238 target[makeGetterName(name) as K] = function (this: typeof target) {
239 const inner = this[params.member as K] as Record<string, unknown>;
239 240 if (typeof inner.get === "function")
240 241 return inner.get(params.property) as unknown;
241 242 };
@@ -6,7 +6,7 import { mixin } from "@implab/core-amd/
6 6 const trace = TraceSource.get(mid);
7 7
8 8
9 function on<T extends keyof HTMLElementEventMap>(node: HTMLElement, eventName: T, handler: (this: HTMLElement, ev: HTMLElementEventMap[T]) => any): () => void {
9 function on<T extends keyof HTMLElementEventMap>(node: HTMLElement, eventName: T, handler: (this: HTMLElement, ev: HTMLElementEventMap[T]) => unknown): () => void {
10 10 // Add an event listener to a DOM node
11 11 node.addEventListener(eventName, handler, false);
12 12
@@ -57,7 +57,7 class DomInject {
57 57
58 58 async injectScript(url: string) {
59 59 let d = this._map[url];
60 if (!d) {
60 if (d === undefined) {
61 61 trace.log("js {0}", url);
62 62 d = this._inject("script", {
63 63 type: "text/javascript",
@@ -77,7 +77,7 class DomInject {
77 77
78 78 async injectStylesheet(url: string) {
79 79 let d = this._map[url];
80 if (!d) {
80 if (d === undefined) {
81 81 trace.log("js {0}", url);
82 82 d = this._inject("link", {
83 83 type: "text/css",
@@ -1,6 +1,6
1 1 import { id as mid} from "module";
2 2 import { MapOf } from "@implab/core-amd/interfaces";
3 import { NlsBundle } from "./NlsBundle";
3 import { LocaleProvider, NlsBundle } from "./NlsBundle";
4 4 import { isPromise } from "@implab/core-amd/safe";
5 5 import { locale as sysLocale } from "dojo/_base/kernel";
6 6 import { TraceSource } from "@implab/core-amd/log/TraceSource";
@@ -10,11 +10,11 const trace = TraceSource.get(mid);
10 10 trace.debug("Current sysLocale: {0}", sysLocale);
11 11
12 12 export interface OnLoad {
13 (result?: any): void;
14 error(err: any): void;
13 (result?: unknown): void;
14 error(err: unknown): void;
15 15 }
16 16
17 export function bundle<T extends object>(nls: T, locales?: MapOf<any>) {
17 export function bundle<T extends object>(nls: T, locales?: MapOf<LocaleProvider<object>>) {
18 18 const nlsBundle = new NlsBundle(nls, locales);
19 19
20 20 const fn = (_locale?: string) => {
@@ -28,7 +28,7 export function bundle<T extends object>
28 28 };
29 29
30 30 fn.define = (pack: Partial<T>) => pack;
31 fn.load = async (id: string, require: Require, cb: OnLoad, config: any) => {
31 fn.load = async (id: string, require: Require, cb: OnLoad, config: {isBuild?: boolean}) => {
32 32 const locale = id || sysLocale;
33 33 if (config && config.isBuild) {
34 34 cb();
@@ -74,17 +74,17 const sink = <T>(consumer: Partial<Obser
74 74 next: next ? next.bind(consumer) : noop,
75 75 error: error ? error.bind(consumer) : noop,
76 76 complete: complete ? complete.bind(consumer) : noop
77 }
77 };
78 78 };
79 79
80 80 const fuse = <T>({ next, error, complete }: Sink<T>) => {
81 81 let done = false;
82 82 return {
83 next: (value: T) => { !done && next(value) },
84 error: (e: unknown) => { !done && (done = true, error(e)) },
85 complete: () => { !done && (done = true, complete()) }
86 }
87 }
83 next: (value: T) => { !done && next(value); },
84 error: (e: unknown) => { !done && (done = true, error(e)); },
85 complete: () => { !done && (done = true, complete()); }
86 };
87 };
88 88
89 89 const _observe = <T>(producer: Producer<T>): Observable<T> => ({
90 90 subscribe: (consumer: Partial<Observer<T>>) => ({
@@ -12,7 +12,7 import djAttr = require("dojo/dom-attr")
12 12 import djClass = require("dojo/dom-class");
13 13 import { AnimationAttrs, WatchForRendition } from "./tsx/WatchForRendition";
14 14
15 export function createElement<T extends Constructor | string | ((props: any) => Element)>(elementType: T, ...args: any[]): Rendition {
15 export function createElement<T extends Constructor | string | ((props: object) => Element)>(elementType: T, ...args: unknown[]): Rendition {
16 16 if (typeof elementType === "string") {
17 17 const ctx = new HtmlRendition(elementType);
18 18 if (args)
@@ -26,17 +26,17 export function createElement<T extends
26 26
27 27 return ctx;
28 28 } else if (typeof elementType === "function") {
29 const ctx = new FunctionRendition(elementType as (props: any) => Element);
29 const ctx = new FunctionRendition(elementType as (props: unknown) => Element);
30 30 if (args)
31 31 args.forEach(x => ctx.visitNext(x));
32 32
33 33 return ctx;
34 34 } else {
35 throw new Error(`The element type '${elementType}' is unsupported`);
35 throw new Error(`The element type '${String(elementType)}' is unsupported`);
36 36 }
37 37 }
38 38
39 export interface EventDetails<T = any> {
39 export interface EventDetails<T = unknown> {
40 40 detail: T;
41 41 }
42 42
@@ -56,7 +56,7 export interface QueryResultUpdate<T> {
56 56 newIndex: number;
57 57 }
58 58
59 export type DojoMouseEvent<T = any> = MouseEvent & EventSelector & EventDetails<T>;
59 export type DojoMouseEvent<T = unknown> = MouseEvent & EventSelector & EventDetails<T>;
60 60
61 61 type StatefulProps<T> = T extends Stateful<infer A> ? A :
62 62 T extends _WidgetBase ? T : never;
@@ -73,7 +73,7 type StatefulProps<T> = T extends Statef
73 73 export function watch<W extends _WidgetBase, K extends keyof W>(
74 74 target: W,
75 75 prop: K,
76 render: (model: W[K]) => any
76 render: (model: W[K]) => unknown
77 77 ): Rendition;
78 78 /**
79 79 * Observers the property and calls render callback each change.
@@ -86,7 +86,7 export function watch<W extends _WidgetB
86 86 export function watch<T extends Stateful, K extends keyof StatefulProps<T>>(
87 87 target: T,
88 88 prop: K,
89 render: (model: StatefulProps<T>[K]) => any
89 render: (model: StatefulProps<T>[K]) => unknown
90 90 ): Rendition;
91 91 export function watch<V>(subj: Subscribable<V>, render: (model: V) => unknown): Rendition;
92 92 export function watch(
@@ -98,7 +98,7 export function watch(
98 98 return new WatchRendition(
99 99 render,
100 100 observe(({next}) => {
101 const h = target.watch<any>(
101 const h = target.watch(
102 102 prop,
103 103 (_prop, oldValue, newValue) => oldValue !== newValue && next(newValue)
104 104 );
@@ -118,7 +118,7 export const watchFor = <T>(source: T[]
118 118 subject: source,
119 119 component: render
120 120 });
121 }
121 };
122 122
123 123
124 124 export const prop: {
@@ -132,7 +132,7 export const prop: {
132 132 );
133 133 next(target.get(name));
134 134 return () => h.remove();
135 })
135 });
136 136 };
137 137
138 138 export const attach = <W extends DjxWidgetBase, K extends keyof W>(target: W, name: K) => (v: W[K]) => target.set(name, v);
@@ -140,7 +140,7 export const attach = <W extends DjxWidg
140 140 export const bind = <K extends string, T>(attr: K, subj: Subscribable<T>) => {
141 141 let h = { unsubscribe() { } };
142 142
143 return <E extends (HTMLElement & { [p in K]: T }) | { set(name: K, value: T): void; }>(el: E | undefined) => {
143 return (el: Element | { set(name: K, value: T): void; } | undefined) => {
144 144 if (el) {
145 145 if (isElementNode(el)) {
146 146 h = subj.subscribe({
@@ -154,7 +154,7 export const bind = <K extends string, T
154 154 } else {
155 155 h.unsubscribe();
156 156 }
157 }
157 };
158 158 };
159 159
160 160 export const toggleClass = (className: string, subj: Subscribable<boolean>) => {
@@ -168,8 +168,8 export const toggleClass = (className: s
168 168 } else {
169 169 h.unsubscribe();
170 170 }
171 }
172 }
171 };
172 };
173 173
174 174 export const all = <T, A extends JSX.Ref<T>[]>(...cbs: A): JSX.Ref<T> => (arg: T | undefined) => cbs.forEach(cb => cb(arg));
175 175
@@ -185,13 +185,14 export const all = <T, A extends JSX.Ref
185 185 */
186 186 export const on = <E extends string>(...eventNames: E[]) =>
187 187 <K extends string,
188 T extends DjxWidgetBase<any, { [p in E]: EV }>,
188 T extends DjxWidgetBase<object, { [p in E]: EV }>,
189 189 EV extends Event
190 190 >(
191 191 target: T,
192 192 key: K,
193 // eslint-disable-next-line @typescript-eslint/no-unused-vars
193 194 _descriptor: TypedPropertyDescriptor<(eventObj: EV) => void> | TypedPropertyDescriptor<() => void>
194 ): any => {
195 ) => {
195 196 const handlers = eventNames.map(eventName => ({ eventName, handlerMethod: key }));
196 197 target._eventHandlers = target._eventHandlers ? target._eventHandlers.concat(handlers) : handlers;
197 198 };
@@ -17,7 +17,8 export interface EventArgs {
17 17 composed?: boolean;
18 18 }
19 19
20 export interface DjxWidgetBase<Attrs = {}, Events extends { [name in keyof Events]: Event } = {}> extends
20 // eslint-disable-next-line @typescript-eslint/no-unused-vars
21 export interface DjxWidgetBase<Attrs = object, Events extends { [name in keyof Events]: Event } = object> extends
21 22 _WidgetBase<Events> {
22 23
23 24 /** This property is declared only for type inference to work, it is never assigned
@@ -32,7 +33,7 export interface DjxWidgetBase<Attrs = {
32 33 */
33 34 _eventHandlers: Array<{
34 35 eventName: string,
35 handlerMethod: keyof any;
36 handlerMethod: string;
36 37 }>;
37 38 }
38 39
@@ -43,7 +44,8 type _super = {
43 44 };
44 45
45 46 @djclass
46 export abstract class DjxWidgetBase<Attrs = {}, Events = {}> extends djbase<_super, _AttachMixin>(_WidgetBase, _AttachMixin) {
47 // eslint-disable-next-line @typescript-eslint/no-unused-vars
48 export abstract class DjxWidgetBase<Attrs = object, Events = object> extends djbase<_super, _AttachMixin>(_WidgetBase, _AttachMixin) {
47 49 private readonly _scope = new Scope();
48 50
49 51 buildRendering() {
@@ -68,29 +70,29 export abstract class DjxWidgetBase<Attr
68 70 }
69 71 }
70 72
71 abstract render(): Rendition<HTMLElement>;
73 abstract render(): Rendition;
72 74
73 75 private _connectEventHandlers() {
74 76 if (this._eventHandlers)
75 77 this._eventHandlers.forEach(({ eventName, handlerMethod }) => {
76 78 const handler = this[handlerMethod as keyof this];
77 79 if (typeof handler === "function")
78 on(this.domNode, eventName, handler.bind(this));
80 on(this.domNode, eventName, handler.bind(this) as (...args: unknown[]) => unknown);
79 81 });
80 82 }
81 83
82 84 _processTemplateNode<T extends (Element | Node | _WidgetBase)>(
83 85 baseNode: T,
84 getAttrFunc: (baseNode: T, attr: string) => any,
86 getAttrFunc: (baseNode: T, attr: string) => string,
85 87 // tslint:disable-next-line: ban-types
86 attachFunc: (node: T, type: string, func?: Function) => dojo.Handle
88 attachFunc: (node: T, type: string, func?: (...args: unknown[]) => unknown) => dojo.Handle
87 89 ): boolean {
88 90 if (isNode(baseNode)) {
89 91 const w = registry.byNode(baseNode);
90 92 if (w) {
91 93 // from dijit/_WidgetsInTemplateMixin
92 94 this._processTemplateNode(w,
93 (n, p) => n.get(p as any), // callback to get a property of a widget
95 (n, p) => String(n.get(p as keyof typeof n)), // callback to get a property of a widget
94 96 (widget, type, callback) => {
95 97 if (!callback)
96 98 throw new Error("The callback must be specified");
@@ -101,7 +103,7 export abstract class DjxWidgetBase<Attr
101 103 return widget.connect(widget, type, callback as EventListener);
102 104 } else {
103 105 // 1.x may never hit this branch, but it's the default for 2.0
104 return widget.on(type, callback);
106 return widget.on(type as keyof GlobalEventHandlersEventMap, callback);
105 107 }
106 108
107 109 });
@@ -109,7 +111,8 export abstract class DjxWidgetBase<Attr
109 111 return false;
110 112 }
111 113 }
112 return super._processTemplateNode(baseNode, getAttrFunc, attachFunc);
114 // eslint-disable-next-line @typescript-eslint/ban-types
115 return super._processTemplateNode(baseNode, getAttrFunc, attachFunc as (node: T, type: string, func?: Function) => dojo.Handle);
113 116 }
114 117
115 118 /** Starts current widget and all its supporting widgets (placed outside
@@ -3,19 +3,19 import { getItemDom } from "./render";
3 3 import { RenditionBase } from "./RenditionBase";
4 4
5 5 export class FunctionRendition extends RenditionBase<Node> {
6 private _component: (...args: any[]) => any;
6 private readonly _component: (...args: unknown[]) => unknown;
7 7
8 8 private _node: Node | undefined;
9 9
10 constructor(component: (...args: any[]) => any) {
10 constructor(component: (...args: unknown[]) => unknown) {
11 11 super();
12 12 argumentNotNull(component, "component");
13 13
14 14 this._component = component;
15 15 }
16 16
17 protected _create(attrs: object, children: any[]) {
18 const _attrs: any = attrs || {};
17 protected _create(attrs: object, children: unknown[]) {
18 const _attrs = attrs || {};
19 19 const _children = children.map(x => getItemDom(x));
20 20 this._node = getItemDom(
21 21 this._component.call(null, { ..._attrs, children: _children }));
@@ -3,11 +3,11 import { isPlainObject, DojoNodePosition
3 3 export abstract class RenditionBase<TNode extends Node> implements Rendition<TNode> {
4 4 private _attrs = {};
5 5
6 private _children = new Array();
6 private _children: unknown[] = [];
7 7
8 private _created: boolean = false;
8 private _created = false;
9 9
10 visitNext(v: any) {
10 visitNext(v: unknown) {
11 11 if (this._created)
12 12 throw new Error("The Element is already created");
13 13
@@ -30,7 +30,7 export class Scope implements IDestroyab
30 30 } catch {
31 31 // guard
32 32 }
33 }
33 };
34 34
35 35 this._cleanup.forEach(guard);
36 36 this._cleanup.length = 0;
@@ -49,10 +49,10 export interface WatchForRenditionAttrs<
49 49 component: (arg: T, index: number) => unknown;
50 50 }
51 51
52 const isObservable = <T>(v: PromiseLike<ArrayLike<T>> | ArrayLike<T>): v is ArrayLike<T> & ObservableResults<T> =>
53 v && (typeof (v as any).observe === "function");
52 const isObservable = <T>(v: ArrayLike<T>): v is ArrayLike<T> & ObservableResults<T> =>
53 v && (typeof (v as { observe?: unknown; }).observe === "function");
54 54
55 const noop = () => {};
55 const noop = () => { };
56 56
57 57 const fadeIn = (nodes: Node[]) => Promise.all(nodes
58 58 .filter(isElementNode)
@@ -112,7 +112,7 export class WatchForRendition<T> extend
112 112 if (isSubsribable<QueryResultUpdate<T>>(result)) {
113 113 let animate = false;
114 114 const subscription = result.subscribe({
115 next: ({item, prevIndex, newIndex}) => this._onItemUpdated({ item, prevIndex, newIndex, animate })
115 next: ({ item, prevIndex, newIndex }) => this._onItemUpdated({ item, prevIndex, newIndex, animate })
116 116 });
117 117 scope.own(subscription);
118 118 animate = this._animate;
@@ -127,7 +127,7 export class WatchForRendition<T> extend
127 127 this._ct = new Cancellation(cancel => scope.own(cancel));
128 128 }
129 129
130 private _onItemUpdated = (item: RenderTask<T>) => {
130 private readonly _onItemUpdated = (item: RenderTask<T>) => {
131 131 if (!this._renderTasks.length) {
132 132 // schedule a new job
133 133 this._renderTasks.push(item);
@@ -136,7 +136,7 export class WatchForRendition<T> extend
136 136 // update existing job
137 137 this._renderTasks.push(item);
138 138 }
139 }
139 };
140 140
141 141 private async _render() {
142 142 // fork
@@ -149,7 +149,7 export class WatchForRendition<T> extend
149 149 this._renderTasks.length = 0;
150 150 }
151 151
152 _onRenderItem = ({ item, newIndex, prevIndex, animate: _animate }: RenderTask<T>) => {
152 private readonly _onRenderItem = ({ item, newIndex, prevIndex, animate: _animate }: RenderTask<T>) => {
153 153 const animate = _animate && prevIndex !== newIndex;
154 154
155 155 if (prevIndex > -1) {
@@ -205,7 +205,7 export class WatchForRendition<T> extend
205 205 if (animate)
206 206 this._animateIn(nodes).catch(e => trace.error(e));
207 207 }
208 }
208 };
209 209
210 210 protected _getDomNode() {
211 211 if (!this._node)
@@ -17,7 +17,7 export interface _Widget {
17 17 addChild?(widget: unknown, index?: number): void;
18 18 }
19 19
20 export type _WidgetCtor = new (attrs: {}, srcNode?: string | Node) => _Widget;
20 export type _WidgetCtor = new (attrs: object, srcNode?: string | Node) => _Widget;
21 21
22 22 export class WidgetRendition extends RenditionBase<Node> {
23 23 readonly widgetClass: _WidgetCtor;
@@ -14,11 +14,11 interface Context {
14 14
15 15 let _context: Context = {
16 16 scope: Scope.dummy
17 }
17 };
18 18
19 19 const guard = (cb: () => unknown) => {
20 20 try {
21 const result = cb()
21 const result = cb();
22 22 if (isPromise(result)) {
23 23 const warn = (ret: unknown) => trace.error("The callback {0} competed asynchronously. result = {1}", cb, ret);
24 24 result.then(warn, warn);
@@ -26,7 +26,7 const guard = (cb: () => unknown) => {
26 26 } catch (e) {
27 27 trace.error(e);
28 28 }
29 }
29 };
30 30
31 31 export const beginRender = (scope: IScope = getScope()) => {
32 32 const prev = _context;
@@ -35,7 +35,7 export const beginRender = (scope: IScop
35 35 hooks: []
36 36 };
37 37 return endRender(prev);
38 }
38 };
39 39
40 40 /**
41 41 * Completes render operation
@@ -46,7 +46,7 const endRender = (prev: Context) => ()
46 46 hooks.forEach(guard);
47 47
48 48 _context = prev;
49 }
49 };
50 50
51 51 export const renderHook = (hook: () => void) => {
52 52 const { hooks } = _context;
@@ -54,7 +54,7 export const renderHook = (hook: () => v
54 54 hooks.push(hook);
55 55 else
56 56 guard(hook);
57 }
57 };
58 58
59 59 export const refHook = <T>(value: T, ref: JSX.Ref<T>) => {
60 60 const { hooks, scope } = _context;
@@ -64,7 +64,7 export const refHook = <T>(value: T, ref
64 64 guard(() => ref(value));
65 65
66 66 scope.own(() => ref(undefined));
67 }
67 };
68 68
69 69 /** Returns the current scope */
70 70 export const getScope = () => _context.scope;
@@ -80,7 +80,7 export const render = (rendition: unknow
80 80 } finally {
81 81 complete();
82 82 }
83 }
83 };
84 84
85 85 /** Renders DOM element for different types of the argument. */
86 86 export const getItemDom = (v: unknown) => {
@@ -107,6 +107,6 export const getItemDom = (v: unknown) =
107 107 return fragment;
108 108 } else {
109 109 // bug: explicit error otherwise
110 throw new Error("Invalid parameter: " + v);
110 throw new Error(`Invalid parameter: ${String(v)}`);
111 111 }
112 }
112 };
@@ -1,81 +1,89
1 // eslint-disable-next-line @typescript-eslint/triple-slash-reference
1 2 /// <reference path="./css-plugin.d.ts"/>
2 3
3 declare namespace JSX {
4
5 type Ref<T> = ((value: T | undefined) => void);
4 import { Rendition } from "./tsx/traits";
6 5
7 interface DjxIntrinsicAttributes<E> {
8 /** alias for className */
9 class: string;
6 declare global {
7 namespace JSX {
8
9 type Ref<T> = ((value: T | undefined) => void);
10
11 type Element = Rendition;
10 12
11 /** specifies the name of the property in the widget where the the
12 * reference to the current object will be stored
13 */
14 "data-dojo-attach-point": string;
13 interface DjxIntrinsicAttributes<E> {
14 /** alias for className */
15 class?: string;
15 16
16 /** specifies handlers map for the events */
17 "data-dojo-attach-event": string;
17 /** specifies the name of the property in the widget where the the
18 * reference to the current object will be stored
19 */
20 "data-dojo-attach-point"?: string;
18 21
19 ref: Ref<E>;
22 /** specifies handlers map for the events */
23 "data-dojo-attach-event"?: string;
20 24
21 /** @deprecated */
22 [attr: string]: any;
23 }
25 ref?: Ref<E>;
24 26
25 interface DjxIntrinsicElements {
26 }
27 /** @deprecated */
28 [attr: string]: unknown;
29 }
27 30
28 type RecursivePartial<T> = T extends string | number | boolean | null | undefined | Function ?
29 T :
30 { [k in keyof T]?: RecursivePartial<T[k]> };
31 // eslint-disable-next-line @typescript-eslint/no-empty-interface
32 interface DjxIntrinsicElements {
33 }
34
35 type RecursivePartial<T> = T extends string | number | boolean | null | undefined | ((...args: unknown[]) => unknown) ?
36 T :
37 { [k in keyof T]?: RecursivePartial<T[k]> };
31 38
32 type MatchingMemberKeys<T, U> = {
33 [K in keyof T]: T[K] extends U ? K : never;
34 }[keyof T];
35 type NotMatchingMemberKeys<T, U> = {
36 [K in keyof T]: T[K] extends U ? never : K;
37 }[keyof T];
39 type MatchingMemberKeys<T, U> = {
40 [K in keyof T]: T[K] extends U ? K : never;
41 }[keyof T];
42 type NotMatchingMemberKeys<T, U> = {
43 [K in keyof T]: T[K] extends U ? never : K;
44 }[keyof T];
38 45
39 type ExtractMembers<T, U> = Pick<T, MatchingMemberKeys<T, U>>;
46 type ExtractMembers<T, U> = Pick<T, MatchingMemberKeys<T, U>>;
40 47
41 type ExcludeMembers<T, U> = Pick<T, NotMatchingMemberKeys<T, U>>;
48 type ExcludeMembers<T, U> = Pick<T, NotMatchingMemberKeys<T, U>>;
42 49
43 type ElementAttrNames<E> = NotMatchingMemberKeys<E, (...args: any[]) => any>;
50 type ElementAttrNames<E> = NotMatchingMemberKeys<E, (...args: unknown[]) => unknown>;
44 51
45 type ElementAttrType<E, K extends keyof any> = K extends keyof E ? RecursivePartial<E[K]> : string;
52 type ElementAttrType<E, K extends string | symbol> = K extends keyof E ? RecursivePartial<E[K]> : string;
46 53
47 54
48 type ElementAttrNamesBlacklist = "children" | "getRootNode" | keyof EventTarget;
55 type ElementAttrNamesBlacklist = "children" | "getRootNode" | keyof EventTarget;
49 56
50 /** This type extracts keys of the specified parameter E by the following rule:
51 * 1. skips all ElementAttrNamesBlacklist
52 * 2. skips all methods except with the signature of event handlers
53 */
54 type AssignableElementAttrNames<E> = {
55 [K in keyof E]: K extends ElementAttrNamesBlacklist ? never :
56 ((evt: Event) => any) extends E[K] ? K :
57 E[K] extends ((...args: any[]) => any) ? never :
57 /** This type extracts keys of the specified parameter E by the following rule:
58 * 1. skips all ElementAttrNamesBlacklist
59 * 2. skips all methods except with the signature of event handlers
60 */
61 type AssignableElementAttrNames<E> = {
62 [K in keyof E]: K extends ElementAttrNamesBlacklist ? never :
63 ((evt: Event) => unknown) extends E[K] ? K :
64 E[K] extends ((...args: unknown[]) => unknown) ? never :
58 65 K;
59 }[keyof E];
66 }[keyof E];
60 67
61 type LaxElement<E extends object> =
62 Pick<E, AssignableElementAttrNames<E>> &
63 DjxIntrinsicAttributes<E>;
68 type LaxElement<E extends object> =
69 RecursivePartial<Pick<E, AssignableElementAttrNames<E>>> &
70 DjxIntrinsicAttributes<E>;
64 71
65 type LaxIntrinsicElementsMap = {
66 [tag in keyof HTMLElementTagNameMap]: LaxElement<HTMLElementTagNameMap[tag]>
67 } & DjxIntrinsicElements;
72 type LaxIntrinsicElementsMap = {
73 [tag in keyof HTMLElementTagNameMap]: LaxElement<HTMLElementTagNameMap[tag]>
74 } & DjxIntrinsicElements;
68 75
69 type IntrinsicElements = {
70 [tag in keyof LaxIntrinsicElementsMap]: RecursivePartial<LaxIntrinsicElementsMap[tag]>;
71 }
76 type IntrinsicElements = {
77 [tag in keyof LaxIntrinsicElementsMap]: LaxIntrinsicElementsMap[tag];
78 };
72 79
73 interface ElementChildrenAttribute {
74 children: {};
75 }
80 interface ElementChildrenAttribute {
81 children: unknown;
82 }
76 83
77 interface IntrinsicClassAttributes<T> {
78 ref?: (value: T) => void;
79 children?: unknown;
84 interface IntrinsicClassAttributes<T> {
85 ref?: Ref<T>;
86 children?: unknown;
87 }
80 88 }
81 }
89 } No newline at end of file
@@ -2,6 +2,7 import { djbase, djclass, bind, prototyp
2 2
3 3 import { DjxWidgetBase } from "../tsx/DjxWidgetBase";
4 4 import { createElement, on } from "../tsx";
5 import { argumentNotNull } from "@implab/core-amd/safe";
5 6
6 7 interface MyWidgetAttrs {
7 8 title: string;
@@ -19,6 +20,12 interface MyWidgetEvents {
19 20 };
20 21 }
21 22
23 interface FrameProps {
24 ref?: JSX.Ref<HTMLDivElement>;
25 children?: unknown[];
26 }
27
28 const Frame = ({children, ref}: FrameProps) => <div ref={ref} >{children}</div>;
22 29
23 30 @djclass
24 31 export class MyWidget extends djbase(DjxWidgetBase as AbstractConstructor<DjxWidgetBase<MyWidgetAttrs, MyWidgetEvents>>) {
@@ -29,31 +36,40 export class MyWidget extends djbase(Djx
29 36 @prototype(0)
30 37 counter = 0;
31 38
39 frameNode?: HTMLDivElement;
40
32 41 render() {
33 const Frame = ({children, ref}: {ref: JSX.Ref<HTMLDivElement>, children: unknown[]}) => <div ref={ref} >{children}</div>;
34 return <div className="myWidget" onsubmit={e => this._onSubmit(e)} tabIndex={3} style={{ alignContent: "center", border: "1px solid" }} >
42
43 return <div className="myWidget" onsubmit={this._onSubmit} tabIndex={3} style={{ alignContent: "center", border: "1px solid" }} >
35 44 <h1 data-dojo-attach-point="titleNode"></h1>
36 <Frame ref={ v => {}}>
37 <span class="up-button" onclick={e => this._onIncClick(e)}>[+]</span>
45 <Frame ref={this._setFrameElement}>
46 <span class="up-button" onclick={this._onIncClick}>[+]</span>
38 47 <span class="down-button" onclick={() => this._onDecClick()}>[-]</span>
39 48 </Frame>
40 49 </div>;
41 50 }
42 51
52 private readonly _setFrameElement = (node?: HTMLDivElement) => {
53 this.frameNode = node;
54 };
55
43 56 postCreate() {
44 57 super.postCreate();
45 58
46 59 this.on("click", () => {});
47 60 }
48 61
49 _onSubmit(e: Event) {
50 }
62 private readonly _onSubmit = (evt: Event) => {
63 argumentNotNull(evt, "evt");
64 };
51 65
52 _onIncClick(e: MouseEvent) {
66 private readonly _onIncClick = (evt: MouseEvent) => {
67 argumentNotNull(evt, "evt");
68
53 69 this.set("counter", this.counter + 1);
54 70
55 71 this.emit("count-inc", { bubbles: false });
56 }
72 };
57 73
58 74 _onDecClick() {
59 75 this.emit("count-dec", { bubbles: false, detail: this.counter });
@@ -61,10 +77,11 export class MyWidget extends djbase(Djx
61 77
62 78 @on("count-inc")
63 79 private _onCounterInc(evt: Event & { detail: number; x?: number; }) {
80 argumentNotNull(evt, "evt");
64 81 }
65 82
66 83 @on("click", "keydown")
67 protected _onClick(event: MouseEvent | KeyboardEvent) {
68
84 protected _onClick(evt: MouseEvent | KeyboardEvent) {
85 argumentNotNull(evt, "evt");
69 86 }
70 87 } No newline at end of file
@@ -1,6 +1,7
1 1 {
2 2 "extends": "../tsconfig",
3 3 "compilerOptions": {
4 "baseUrl": ".",
4 5 "noUnusedLocals": false,
5 6 //"rootDir": "ts",
6 7 "rootDirs": [
@@ -9,6 +10,11
9 10 "../main/ts",
10 11 "../main/typings"
11 12 ],
12 "types": ["requirejs", "../main/typings", "@implab/dojo-typings"]
13 "types": [
14 "requirejs",
15 "../main/typings",
16 "@implab/dojo-typings",
17 "@implab/dojo-typings/dojo/NodeList-fx"
18 ]
13 19 }
14 20 } No newline at end of file
@@ -1,10 +1,9
1 1 {
2 "extends": "./tsconfig.json",
2 //"extends": "./tsconfig.json",
3 3 "compilerOptions": {
4 4 // ensure that nobody can accidentally use this config for a build
5 "noEmit": true
5 "noEmit": true,
6 6 },
7 7 "include": [
8 "ts"
9 8 ]
10 9 } No newline at end of file
@@ -1,7 +1,7
1 1 import MainWidget from "./view/MainWidget";
2 import "@implab/djx/css!dojo/resources/dojo.css"
3 import "@implab/djx/css!dijit/themes/dijit.css"
4 import "@implab/djx/css!dijit/themes/tundra/tundra.css"
2 import "@implab/djx/css!dojo/resources/dojo.css";
3 import "@implab/djx/css!dijit/themes/dijit.css";
4 import "@implab/djx/css!dijit/themes/tundra/tundra.css";
5 5
6 6 const w = new MainWidget();
7 7 w.placeAt(document.body); No newline at end of file
@@ -5,6 +5,7 import { Contact } from "./Contact";
5 5 import { Uuid } from "@implab/core-amd/Uuid";
6 6 import { Observable as RxjsObservable } from "rxjs";
7 7 import { QueryResultUpdate } from "@implab/djx/tsx";
8 import {isPromise} from "@implab/core-amd/safe";
8 9
9 10 type AppointmentRecord = Omit<Appointment, "getMembers"> & {id: string};
10 11
@@ -22,13 +23,13 export interface ObservableResults<T> {
22 23 }
23 24
24 25
25 export function isObservable<T>(v: PromiseLike<ArrayLike<T>> | ArrayLike<T>): v is ArrayLike<T> & ObservableResults<T> {
26 return v && (typeof (v as any).observe === "function");
26 export function isObservable<T>(v: unknown): v is ObservableResults<T> {
27 return !!v && (typeof (v as {observe?: unknown}).observe === "function");
27 28 }
28 29
29 30 export function observe<T>(results: T[], includeObjectUpdates?: boolean): RxjsObservable<QueryResultUpdate<T>>;
30 31 export function observe<T>(results: PromiseLike<T[]>, includeObjectUpdates?: boolean): PromiseLike<RxjsObservable<QueryResultUpdate<T>>>;
31 export function observe(results: any, includeObjectUpdates = true) {
32 export function observe(results: unknown[] | PromiseLike<unknown[]>, includeObjectUpdates = true) {
32 33 // results может быть асинхронным, т.е. до завершения
33 34 // получения результатов store может быть обновлен. В любом
34 35 // случае, если между подключением хотя бы одного наблюдателя
@@ -41,7 +42,7 export function observe(results: any, in
41 42 // о необработанной ошибке в Promise при обращении к методам
42 43 // обновления (add,put,remove)
43 44
44 const _subscribe = (items: any[]) => new RxjsObservable<QueryResultUpdate<any>>(subscriber => {
45 const _subscribe = (items: unknown[]) => new RxjsObservable<QueryResultUpdate<unknown>>(subscriber => {
45 46 items
46 47 .forEach((value, newIndex) => subscriber.next({ item: value, newIndex, prevIndex: -1}));
47 48
@@ -72,11 +73,11 export function observe(results: any, in
72 73
73 74
74 75 export class MainContext {
75 private _appointments = new Observable(new Memory<AppointmentRecord>());
76 private readonly _appointments = new Observable(new Memory<AppointmentRecord>());
76 77
77 private _contacts = new Observable(new Memory<ContactRecord>());
78 private readonly _contacts = new Observable(new Memory<ContactRecord>());
78 79
79 private _members = new Observable(new Memory<MemberRecord>());
80 private readonly _members = new Observable(new Memory<MemberRecord>());
80 81
81 82 createAppointment(title: string, startAt: Date, duration: number, members: Member[]) {
82 83 const id = Uuid();
@@ -91,16 +92,16 export class MainContext {
91 92 this._members.add({
92 93 appointmentId: id,
93 94 ...member
94 }, {id: Uuid()})
95 }, {id: Uuid()}) as void
95 96 );
96 97 }
97 98
98 99 queryAppointments(dateFrom: Date, dateTo: Date) {
99 this._appointments.query().map()
100 //this._appointments.query().map()
100 101 }
101 102
102 private _mapAppointment = ({startAt, title, duration, id}: AppointmentRecord) => ({
103 private readonly _mapAppointment = ({startAt, title, duration, id}: AppointmentRecord) => ({
103 104
104 })
105 });
105 106
106 107 }
@@ -5,6 +5,8 import ProgressBar from "./ProgressBar";
5 5 import Button = require("dijit/form/Button");
6 6 import { interval } from "rxjs";
7 7
8 const Counter = ({ children }: { children: unknown[] }) => <span>Counter: {children}</span>;
9
8 10 @djclass
9 11 export default class MainWidget extends djbase(DjxWidgetBase) {
10 12
@@ -21,7 +23,6 export default class MainWidget extends
21 23 paused = false;
22 24
23 25 render() {
24 const Counter = ({ children }: { children: unknown[] }) => <span>Counter: {children}</span>;
25 26
26 27 return <div className="tundra">
27 28 <h2 ref={attach(this, "titleNode")}>Hi!</h2>
@@ -31,7 +32,6 export default class MainWidget extends
31 32 <Counter><input ref={all(
32 33 bind("value", prop(this, "count")
33 34 .map(x => x/10)
34 .map(String)
35 35 ),
36 36 attach(this, "counterNode")
37 37 )} /> <span>s</span></Counter>,
@@ -71,11 +71,11 export default class MainWidget extends
71 71 });
72 72 }
73 73
74 private _onPauseClick = () => {
74 private readonly _onPauseClick = () => {
75 75 this.set("paused", !this.paused);
76 }
76 };
77 77
78 private _onToggleCounterClick = () => {
78 private readonly _onToggleCounterClick = () => {
79 79 this.set("showCounter", !this.showCounter);
80 }
80 };
81 81 }
@@ -0,0 +1,1
1 /* noop */ No newline at end of file
@@ -5,6 +5,5
5 5 "noEmit": true
6 6 },
7 7 "include": [
8 "ts"
9 8 ]
10 9 } No newline at end of file
@@ -1,35 +0,0
1 {
2 "root": true,
3 "extends": [
4 "plugin:react/recommended",
5 "eslint:recommended",
6 "plugin:@typescript-eslint/eslint-recommended",
7 "plugin:@typescript-eslint/recommended",
8 "plugin:@typescript-eslint/recommended-requiring-type-checking"
9 ],
10 "parser": "@typescript-eslint/parser",
11 "parserOptions": {
12 "ecmaFeatures": {
13 "jsx": true
14 },
15 "ecmaVersion": 5,
16 "tsconfigRootDir": "djx/src",
17 "project": ["tsconfig.eslint.json", "*/tsconfig.json"]
18 },
19 "plugins": [
20 "@typescript-eslint"
21 ],
22 "rules": {
23 "react/react-in-jsx-scope": "off",
24 "react/no-unknown-property": "off",
25 "@typescript-eslint/no-empty-function": "off",
26 "max-classes-per-file": [
27 "error",
28 { "ignoreExpressions": true, "max": 1 }
29 ],
30 "@typescript-eslint/prefer-readonly": ["error"],
31 "semi": "off",
32 "@typescript-eslint/semi": ["error"]
33
34 }
35 }
@@ -1,9 +0,0
1 import { bundle } from "../i18n";
2
3 export default bundle({
4 greeting: (name: string) => `Hello, ${name}!`,
5 goodbye: (name: string) => `Bye, ${name}!`
6 }, {
7 ru: () => import("./ru/foo")
8 });
9
@@ -1,6 +0,0
1 import foo from "../foo";
2
3 export default foo.define({
4 greeting: (name: string) => `Привет, ${name}`,
5 goodbye: (name: string) => `Пока, ${name}`
6 });
@@ -1,33 +0,0
1 {
2 "root": true,
3 "extends": [
4 "plugin:react/recommended",
5 "eslint:recommended",
6 "plugin:@typescript-eslint/eslint-recommended",
7 "plugin:@typescript-eslint/recommended",
8 "plugin:@typescript-eslint/recommended-requiring-type-checking"
9 ],
10 "parser": "@typescript-eslint/parser",
11 "parserOptions": {
12 "ecmaFeatures": {
13 "jsx": true
14 },
15 "ecmaVersion": 5,
16 "tsconfigRootDir": "src",
17 "project": ["tsconfig.eslint.json", "*/tsconfig.json"]
18 },
19 "plugins": [
20 "@typescript-eslint"
21 ],
22 "rules": {
23 "@typescript-eslint/no-empty-function": "off",
24 "max-classes-per-file": [
25 "error",
26 { "ignoreExpressions": true, "max": 1 }
27 ],
28 "@typescript-eslint/prefer-readonly": ["error"],
29 "semi": "off",
30 "@typescript-eslint/semi": ["error"]
31
32 }
33 }
General Comments 0
You need to be logged in to leave comments. Login now