ddan-js 2.4.1 → 2.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,17 +11,17 @@ declare const dUtil: {
11
11
  fields?: string[] | undefined;
12
12
  camel?: boolean | undefined;
13
13
  pure?: boolean | undefined;
14
- } & import("./typings").dd.IIgnoreParams) => any;
14
+ } & import("./typings").Ddan.IIgnoreParams) => any;
15
15
  clone: (source: any) => any;
16
- merge: (target: any, source: any, options?: import("./typings").dd.IIgnoreParams) => {};
16
+ merge: (target: any, source: any, options?: import("./typings").Ddan.IIgnoreParams) => {};
17
17
  isEmpty: (source: any) => boolean;
18
18
  parseValue: (source: any, { number, boolean }?: {
19
19
  number?: boolean | undefined;
20
20
  boolean?: boolean | undefined;
21
21
  }) => any;
22
22
  cloneClass: <T>(source: T) => T;
23
- combine: (target: any, source: any, options?: import("./typings").dd.IIgnoreParams) => any;
24
- combines: (objs: any[], options?: import("./typings").dd.IIgnoreParams) => {};
23
+ combine: (target: any, source: any, options?: import("./typings").Ddan.IIgnoreParams) => any;
24
+ combines: (objs: any[], options?: import("./typings").Ddan.IIgnoreParams) => {};
25
25
  observe: (obj: any, key: any, watchFun: any, owner: any, deep?: boolean) => void;
26
26
  getTag: (value: any) => string;
27
27
  getType: (value: any) => string;
@@ -94,7 +94,7 @@ declare const dUtil: {
94
94
  number?: boolean | undefined;
95
95
  boolean?: boolean | undefined;
96
96
  }) => any;
97
- replace: (source: string, rules: import("./typings").dd.IRegexRule | import("./typings").dd.IRegexRule[]) => string;
97
+ replace: (source: string, rules: import("./typings").Ddan.IRegexRule | import("./typings").Ddan.IRegexRule[]) => string;
98
98
  };
99
99
  time: {
100
100
  now: () => import("./modules/time/dtime").default;
@@ -109,7 +109,7 @@ declare const dUtil: {
109
109
  }) => number;
110
110
  todayZero: () => number;
111
111
  format: (time: string | number | Date, reg?: string) => string;
112
- countdown: (endTime: string | number | Date, reg?: string) => "" | import("./modules/time/dtime").IDCountdownFormat;
112
+ countdown: (endTime: string | number | Date, reg?: string) => "" | import("./typings").Ddan.ICountdown;
113
113
  dtime: (time: string | number | Date) => import("./modules/time/dtime").default;
114
114
  loopFrame: (interval?: number) => import("./modules/time/frame").default;
115
115
  oneDay: number;
@@ -122,17 +122,17 @@ declare const dUtil: {
122
122
  fields?: string[] | undefined;
123
123
  camel?: boolean | undefined;
124
124
  pure?: boolean | undefined;
125
- } & import("./typings").dd.IIgnoreParams) => any;
125
+ } & import("./typings").Ddan.IIgnoreParams) => any;
126
126
  clone: (source: any) => any;
127
- merge: (target: any, source: any, options?: import("./typings").dd.IIgnoreParams) => {};
127
+ merge: (target: any, source: any, options?: import("./typings").Ddan.IIgnoreParams) => {};
128
128
  isEmpty: (source: any) => boolean;
129
129
  parseValue: (source: any, { number, boolean }?: {
130
130
  number?: boolean | undefined;
131
131
  boolean?: boolean | undefined;
132
132
  }) => any;
133
133
  cloneClass: <T>(source: T) => T;
134
- combine: (target: any, source: any, options?: import("./typings").dd.IIgnoreParams) => any;
135
- combines: (objs: any[], options?: import("./typings").dd.IIgnoreParams) => {};
134
+ combine: (target: any, source: any, options?: import("./typings").Ddan.IIgnoreParams) => any;
135
+ combines: (objs: any[], options?: import("./typings").Ddan.IIgnoreParams) => {};
136
136
  observe: (obj: any, key: any, watchFun: any, owner: any, deep?: boolean) => void;
137
137
  };
138
138
  crypto: {
@@ -187,12 +187,7 @@ declare const dHook: {
187
187
  task: (param?: import("./typings").Ddan.Func1<any, any> | undefined) => import("./class/pipeTask").default;
188
188
  mutex: typeof import("./modules/hook/mutex").default;
189
189
  polling: typeof import("./modules/hook/polling").default;
190
- singleton: <T_1>() => {
191
- new (): {};
192
- __instance__: any;
193
- readonly Instance: T_1;
194
- };
195
- to: <T_2 = any, U extends object = any>(promise: Promise<T_2>, errorExt?: object | undefined) => Promise<[null, T_2] | [U, undefined]>;
190
+ to: <T_1 = any, U extends object = any>(promise: Promise<T_1>, errorExt?: object | undefined) => Promise<[null, T_1] | [U, undefined]>;
196
191
  delay: (time?: number) => Promise<unknown>;
197
192
  };
198
193
  declare const dMini: {
@@ -424,7 +419,7 @@ declare const _default: {
424
419
  }) => number;
425
420
  todayZero: () => number;
426
421
  format: (time: string | number | Date, reg?: string) => string;
427
- countdown: (endTime: string | number | Date, reg?: string) => "" | import("./modules/time/dtime").IDCountdownFormat;
422
+ countdown: (endTime: string | number | Date, reg?: string) => "" | import("./typings").Ddan.ICountdown;
428
423
  dtime: (time: string | number | Date) => import("./modules/time/dtime").default;
429
424
  loopFrame: (interval?: number) => import("./modules/time/frame").default;
430
425
  oneDay: number;
@@ -440,12 +435,7 @@ declare const _default: {
440
435
  task: (param?: import("./typings").Ddan.Func1<any, any> | undefined) => import("./class/pipeTask").default;
441
436
  mutex: typeof import("./modules/hook/mutex").default;
442
437
  polling: typeof import("./modules/hook/polling").default;
443
- singleton: <T_1>() => {
444
- new (): {};
445
- __instance__: any;
446
- readonly Instance: T_1;
447
- };
448
- to: <T_2 = any, U extends object = any>(promise: Promise<T_2>, errorExt?: object | undefined) => Promise<[null, T_2] | [U, undefined]>;
438
+ to: <T_1 = any, U extends object = any>(promise: Promise<T_1>, errorExt?: object | undefined) => Promise<[null, T_1] | [U, undefined]>;
449
439
  delay: (time?: number) => Promise<unknown>;
450
440
  };
451
441
  math: {
@@ -475,17 +465,17 @@ declare const _default: {
475
465
  fields?: string[] | undefined;
476
466
  camel?: boolean | undefined;
477
467
  pure?: boolean | undefined;
478
- } & import("./typings").dd.IIgnoreParams) => any;
468
+ } & import("./typings").Ddan.IIgnoreParams) => any;
479
469
  clone: (source: any) => any;
480
- merge: (target: any, source: any, options?: import("./typings").dd.IIgnoreParams) => {};
470
+ merge: (target: any, source: any, options?: import("./typings").Ddan.IIgnoreParams) => {};
481
471
  isEmpty: (source: any) => boolean;
482
472
  parseValue: (source: any, { number, boolean }?: {
483
473
  number?: boolean | undefined;
484
474
  boolean?: boolean | undefined;
485
475
  }) => any;
486
- cloneClass: <T_3>(source: T_3) => T_3;
487
- combine: (target: any, source: any, options?: import("./typings").dd.IIgnoreParams) => any;
488
- combines: (objs: any[], options?: import("./typings").dd.IIgnoreParams) => {};
476
+ cloneClass: <T_2>(source: T_2) => T_2;
477
+ combine: (target: any, source: any, options?: import("./typings").Ddan.IIgnoreParams) => any;
478
+ combines: (objs: any[], options?: import("./typings").Ddan.IIgnoreParams) => {};
489
479
  observe: (obj: any, key: any, watchFun: any, owner: any, deep?: boolean) => void;
490
480
  getTag: (value: any) => string;
491
481
  getType: (value: any) => string;
@@ -509,16 +499,16 @@ declare const _default: {
509
499
  isPromise: (value: any) => boolean;
510
500
  };
511
501
  list: {
512
- stepAction: <T_4>(list: T_4[], func: import("./typings").Ddan.Task<T_4, void>, stepCount?: number) => void;
513
- skip: <T_5>(list: T_5[], count: number) => T_5[];
514
- take: <T_6>(list: T_6[], count: number, skip?: number) => T_6[];
515
- distinct: <T_7>(list: T_7[]) => T_7[];
516
- randoms: <T_8>(list: T_8[], count?: number, repeat?: boolean) => T_8[];
502
+ stepAction: <T_3>(list: T_3[], func: import("./typings").Ddan.Task<T_3, void>, stepCount?: number) => void;
503
+ skip: <T_4>(list: T_4[], count: number) => T_4[];
504
+ take: <T_5>(list: T_5[], count: number, skip?: number) => T_5[];
505
+ distinct: <T_6>(list: T_6[]) => T_6[];
506
+ randoms: <T_7>(list: T_7[], count?: number, repeat?: boolean) => T_7[];
517
507
  toKV: (list: import("./typings").Ddan.KV<any>[], key: string, value: string) => import("./typings").Ddan.KV<any>;
518
- groupBy: <T_9>(list: T_9[], key: string) => Record<string, T_9[]>;
519
- first: <T_10>(list: T_10[]) => T_10 | undefined;
520
- last: <T_11>(list: T_11[]) => T_11 | undefined;
521
- toList: <T_12>(val: T_12 | T_12[]) => T_12[];
508
+ groupBy: <T_8>(list: T_8[], key: string) => Record<string, T_8[]>;
509
+ first: <T_9>(list: T_9[]) => T_9 | undefined;
510
+ last: <T_10>(list: T_10[]) => T_10 | undefined;
511
+ toList: <T_11>(val: T_11 | T_11[]) => T_11[];
522
512
  };
523
513
  string: {
524
514
  toString: (value: any) => any;
@@ -535,24 +525,24 @@ declare const _default: {
535
525
  number?: boolean | undefined;
536
526
  boolean?: boolean | undefined;
537
527
  }) => any;
538
- replace: (source: string, rules: import("./typings").dd.IRegexRule | import("./typings").dd.IRegexRule[]) => string;
528
+ replace: (source: string, rules: import("./typings").Ddan.IRegexRule | import("./typings").Ddan.IRegexRule[]) => string;
539
529
  };
540
530
  obj: {
541
531
  copy: (source: any, options?: {
542
532
  fields?: string[] | undefined;
543
533
  camel?: boolean | undefined;
544
534
  pure?: boolean | undefined;
545
- } & import("./typings").dd.IIgnoreParams) => any;
535
+ } & import("./typings").Ddan.IIgnoreParams) => any;
546
536
  clone: (source: any) => any;
547
- merge: (target: any, source: any, options?: import("./typings").dd.IIgnoreParams) => {};
537
+ merge: (target: any, source: any, options?: import("./typings").Ddan.IIgnoreParams) => {};
548
538
  isEmpty: (source: any) => boolean;
549
539
  parseValue: (source: any, { number, boolean }?: {
550
540
  number?: boolean | undefined;
551
541
  boolean?: boolean | undefined;
552
542
  }) => any;
553
- cloneClass: <T_3>(source: T_3) => T_3;
554
- combine: (target: any, source: any, options?: import("./typings").dd.IIgnoreParams) => any;
555
- combines: (objs: any[], options?: import("./typings").dd.IIgnoreParams) => {};
543
+ cloneClass: <T_2>(source: T_2) => T_2;
544
+ combine: (target: any, source: any, options?: import("./typings").Ddan.IIgnoreParams) => any;
545
+ combines: (objs: any[], options?: import("./typings").Ddan.IIgnoreParams) => {};
556
546
  observe: (obj: any, key: any, watchFun: any, owner: any, deep?: boolean) => void;
557
547
  };
558
548
  crypto: {
@@ -1,4 +1,3 @@
1
- import { dd } from '../../typings';
2
1
  import { Ddan } from '../../typings';
3
2
  /**
4
3
  * 防抖 一段时间内,规定时间间隔多次执行,回调触发一次
@@ -7,7 +6,7 @@ import { Ddan } from '../../typings';
7
6
  * @param options 参数:leading 开始执行, trailing结束执行
8
7
  * @returns
9
8
  */
10
- declare function debounce(func: Ddan.Action, wait?: number, options?: dd.IDebounceOption): {
9
+ declare function debounce(func: Ddan.Action, wait?: number, options?: Ddan.IDebounceOption): {
11
10
  (...debouncedArgs: any[]): any;
12
11
  cancel: () => void;
13
12
  flush: () => any;
@@ -11,15 +11,6 @@ import polling from "./polling";
11
11
  * @returns
12
12
  */
13
13
  declare function run<T = any>(task?: Promise<T> | Function, wait?: number): Promise<[any, undefined] | [null, T]>;
14
- /**
15
- * 设置单例模式
16
- * @returns
17
- */
18
- declare function singleton<T>(): {
19
- new (): {};
20
- __instance__: any;
21
- readonly Instance: T;
22
- };
23
14
  declare const _default: {
24
15
  run: typeof run;
25
16
  exec: (func: Function, taskId?: string) => Promise<any[]>;
@@ -28,7 +19,6 @@ declare const _default: {
28
19
  task: (param?: Ddan.Func1<any, any> | undefined) => DPipeTask;
29
20
  mutex: typeof mutex;
30
21
  polling: typeof polling;
31
- singleton: typeof singleton;
32
22
  to: <T = any, U extends object = any>(promise: Promise<T>, errorExt?: object | undefined) => Promise<[null, T] | [U, undefined]>;
33
23
  delay: (time?: number) => Promise<unknown>;
34
24
  };
@@ -1,4 +1,3 @@
1
- import { dd } from "../../typings";
2
1
  import { Ddan } from "../../typings";
3
2
  /**
4
3
  * 节流 每个间隔内,触发一次
@@ -7,7 +6,7 @@ import { Ddan } from "../../typings";
7
6
  * @param options 参数:leading 开始执行, trailing结束执行
8
7
  * @returns
9
8
  */
10
- declare function throttle(func: Ddan.Action, wait?: number, options?: Omit<dd.IDebounceOption, 'maxWait'>): {
9
+ declare function throttle(func: Ddan.Action, wait?: number, options?: Omit<Ddan.IDebounceOption, 'maxWait'>): {
11
10
  (...debouncedArgs: any[]): any;
12
11
  cancel: () => void;
13
12
  flush: () => any;
@@ -1,21 +1,21 @@
1
- import { dd } from '../../typings';
1
+ import { Ddan } from '../../typings';
2
2
  declare function cloneClass<T>(source: T): T;
3
3
  declare const _default: {
4
4
  copy: (source: any, options?: {
5
5
  fields?: string[] | undefined;
6
6
  camel?: boolean | undefined;
7
7
  pure?: boolean | undefined;
8
- } & dd.IIgnoreParams) => any;
8
+ } & Ddan.IIgnoreParams) => any;
9
9
  clone: (source: any) => any;
10
- merge: (target: any, source: any, options?: dd.IIgnoreParams) => {};
10
+ merge: (target: any, source: any, options?: Ddan.IIgnoreParams) => {};
11
11
  isEmpty: (source: any) => boolean;
12
12
  parseValue: (source: any, { number, boolean }?: {
13
13
  number?: boolean | undefined;
14
14
  boolean?: boolean | undefined;
15
15
  }) => any;
16
16
  cloneClass: typeof cloneClass;
17
- combine: (target: any, source: any, options?: dd.IIgnoreParams) => any;
18
- combines: (objs: any[], options?: dd.IIgnoreParams) => {};
17
+ combine: (target: any, source: any, options?: Ddan.IIgnoreParams) => any;
18
+ combines: (objs: any[], options?: Ddan.IIgnoreParams) => {};
19
19
  observe: (obj: any, key: any, watchFun: any, owner: any, deep?: boolean) => void;
20
20
  };
21
21
  export default _default;
@@ -1,4 +1,4 @@
1
- import { dd } from "../../typings";
1
+ import { Ddan } from "../../typings";
2
2
  declare function toString(value: any): any;
3
3
  declare const _default: {
4
4
  toString: typeof toString;
@@ -15,6 +15,6 @@ declare const _default: {
15
15
  number?: boolean | undefined;
16
16
  boolean?: boolean | undefined;
17
17
  }) => any;
18
- replace: (source: string, rules: dd.IRegexRule | dd.IRegexRule[]) => string;
18
+ replace: (source: string, rules: Ddan.IRegexRule | Ddan.IRegexRule[]) => string;
19
19
  };
20
20
  export default _default;
@@ -1,21 +1,5 @@
1
- export interface IDCountdownFormat {
2
- countdown: number;
3
- timestamp: number;
4
- seconds: number;
5
- d: number;
6
- dd: string;
7
- h: number;
8
- hh: string;
9
- m: number;
10
- mm: string;
11
- s: number;
12
- ss: string;
13
- S: number;
14
- SS: string;
15
- SSS: string;
16
- desc: string;
17
- }
18
- export default class DTime {
1
+ import { Ddan } from "../../typings";
2
+ export default class DTime implements Ddan.ITime {
19
3
  date?: Date;
20
4
  timestamp: number;
21
5
  yyyy?: number;
@@ -35,7 +19,7 @@ export default class DTime {
35
19
  SSS: string;
36
20
  constructor(time: string | number | Date);
37
21
  toDate(): this;
38
- toCountdown(reg?: string): IDCountdownFormat;
22
+ toCountdown(regFormat?: string): Ddan.ICountdown;
39
23
  add(ms?: number): this;
40
24
  format(reg?: string): string;
41
25
  }
@@ -1,6 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import DEvent from "../../class/event";
3
- export default class DLoopFrame {
3
+ import { Ddan } from "../../typings";
4
+ export default class DLoopFrame implements Ddan.ILoopFrame {
4
5
  _loopTimer: string | number | NodeJS.Timeout | undefined;
5
6
  _event: DEvent;
6
7
  started: boolean;
@@ -24,7 +24,7 @@ declare const _default: {
24
24
  parseTimestamp: typeof parseTimestamp;
25
25
  todayZero: () => number;
26
26
  format: (time: string | number | Date, reg?: string) => string;
27
- countdown: (endTime: string | number | Date, reg?: string) => "" | import("./dtime").IDCountdownFormat;
27
+ countdown: (endTime: string | number | Date, reg?: string) => "" | import("../..").Ddan.ICountdown;
28
28
  dtime: (time: string | number | Date) => DTime;
29
29
  loopFrame: (interval?: number) => LoopFrame;
30
30
  oneDay: number;
@@ -15,6 +15,10 @@ export declare namespace Ddan {
15
15
  type Func3<T0 = any, T1 = any, T2 = any, R = any> = Callback<[T0, T1, T2], R>;
16
16
  type Func4<T0 = any, T1 = any, T2 = any, T3 = any, R = any> = Callback<[T0, T1, T2, T3], R>;
17
17
  type Result<T = any> = T | Promise<T>;
18
+ interface IGetset<T> {
19
+ set(value: T): void;
20
+ get(): T | undefined;
21
+ }
18
22
  interface IEvent {
19
23
  clear: () => void;
20
24
  on: (name: string, handler: Function, tag?: string) => void;
@@ -60,9 +64,66 @@ export declare namespace Ddan {
60
64
  type TStoreActionFunction = (arg: IDStore & {
61
65
  commit: TStoreCommitFunction;
62
66
  }, payload: any) => any;
63
- }
64
- export declare namespace dd {
65
- type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
67
+ interface ILoopFrame {
68
+ start: () => ILoopFrame;
69
+ stop: () => ILoopFrame;
70
+ restart: () => ILoopFrame;
71
+ on: (cb: Function) => ILoopFrame;
72
+ off: (cb: Function) => ILoopFrame;
73
+ }
74
+ interface ICountdown {
75
+ countdown: number;
76
+ timestamp: number;
77
+ seconds: number;
78
+ d: number;
79
+ dd: string;
80
+ h: number;
81
+ hh: string;
82
+ m: number;
83
+ mm: string;
84
+ s: number;
85
+ ss: string;
86
+ S: number;
87
+ SS: string;
88
+ SSS: string;
89
+ desc: string;
90
+ }
91
+ interface ITime {
92
+ date?: Date;
93
+ timestamp: number;
94
+ yyyy?: number;
95
+ yy?: string;
96
+ M?: number;
97
+ MM?: string;
98
+ d: number;
99
+ dd: string;
100
+ h: number;
101
+ hh: string;
102
+ m: number;
103
+ mm: string;
104
+ s: number;
105
+ ss: string;
106
+ S: number;
107
+ SS: string;
108
+ SSS: string;
109
+ toDate: () => ITime;
110
+ toCountdown: (regFormat?: string) => Ddan.ICountdown;
111
+ add: (ms: number) => ITime;
112
+ format: (regFormat?: string) => string;
113
+ }
114
+ interface IRegexRule {
115
+ key: string;
116
+ flag?: "i" | "g" | "m" | "gi" | "mi";
117
+ value: string;
118
+ }
119
+ interface IIgnoreParams {
120
+ ignoreUndefined?: boolean;
121
+ ignoreNull?: boolean;
122
+ ignoreZero?: boolean;
123
+ ignoreEmptyArray?: boolean;
124
+ ignoreEmptyString?: boolean;
125
+ cover?: boolean;
126
+ }
66
127
  /**
67
128
  * leading 开始执行
68
129
  * trailing 结束执行
@@ -72,6 +133,8 @@ export declare namespace dd {
72
133
  maxWait?: number;
73
134
  trailing?: boolean;
74
135
  }
136
+ }
137
+ export declare namespace dd {
75
138
  interface IHttpRequest {
76
139
  url: string;
77
140
  host: string;
@@ -138,17 +201,4 @@ export declare namespace dd {
138
201
  padx?: number;
139
202
  pady?: number;
140
203
  }
141
- interface IRegexRule {
142
- key: string;
143
- flag?: "i" | "g" | "m" | "gi" | "mi";
144
- value: string;
145
- }
146
- interface IIgnoreParams {
147
- ignoreUndefined?: boolean;
148
- ignoreNull?: boolean;
149
- ignoreZero?: boolean;
150
- ignoreEmptyArray?: boolean;
151
- ignoreEmptyString?: boolean;
152
- cover?: boolean;
153
- }
154
204
  }
@@ -0,0 +1,16 @@
1
+ import { Ddan } from "../typings";
2
+ /**
3
+ * 设置单例模式
4
+ * @returns
5
+ */
6
+ declare function singleton<T>(): {
7
+ new (): {};
8
+ __instance__: any;
9
+ readonly Instance: T;
10
+ };
11
+ declare function getset<T = any>(): Ddan.IGetset<T>;
12
+ declare const _default: {
13
+ singleton: typeof singleton;
14
+ getset: typeof getset;
15
+ };
16
+ export default _default;
@@ -6,17 +6,17 @@ declare const _default: {
6
6
  fields?: string[] | undefined;
7
7
  camel?: boolean | undefined;
8
8
  pure?: boolean | undefined;
9
- } & import("../typings").dd.IIgnoreParams) => any;
9
+ } & import("..").Ddan.IIgnoreParams) => any;
10
10
  clone: (source: any) => any;
11
- merge: (target: any, source: any, options?: import("../typings").dd.IIgnoreParams) => {};
11
+ merge: (target: any, source: any, options?: import("..").Ddan.IIgnoreParams) => {};
12
12
  isEmpty: (source: any) => boolean;
13
13
  parseValue: (source: any, { number, boolean }?: {
14
14
  number?: boolean | undefined;
15
15
  boolean?: boolean | undefined;
16
16
  }) => any;
17
17
  cloneClass: <T>(source: T) => T;
18
- combine: (target: any, source: any, options?: import("../typings").dd.IIgnoreParams) => any;
19
- combines: (objs: any[], options?: import("../typings").dd.IIgnoreParams) => {};
18
+ combine: (target: any, source: any, options?: import("..").Ddan.IIgnoreParams) => any;
19
+ combines: (objs: any[], options?: import("..").Ddan.IIgnoreParams) => {};
20
20
  observe: (obj: any, key: any, watchFun: any, owner: any, deep?: boolean) => void;
21
21
  getTag: (value: any) => string;
22
22
  getType: (value: any) => string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ddan-js",
3
- "version": "2.4.1",
3
+ "version": "2.4.3",
4
4
  "description": "",
5
5
  "keywords": [
6
6
  "ddan-js",