danholibraryjs 1.7.0 → 1.10.0

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.
Files changed (68) hide show
  1. package/.gitattributes +2 -2
  2. package/dist/Classes/Events/Event.js +1 -1
  3. package/dist/Classes/Events/EventCollection.js +1 -1
  4. package/dist/Classes/Events/EventEmitter.d.ts +28 -4
  5. package/dist/Classes/Events/EventEmitter.js +24 -0
  6. package/dist/Classes/Time/Date.d.ts +5 -5
  7. package/dist/Classes/Time/Time.d.ts +3 -3
  8. package/dist/Classes/Time/TimeProperties.d.ts +2 -2
  9. package/dist/Classes/Time/TimeSpan.d.ts +1 -1
  10. package/dist/Classes/index.d.ts +1 -0
  11. package/dist/Classes/index.js +1 -0
  12. package/dist/Classes/store.d.ts +79 -0
  13. package/dist/Classes/store.js +84 -0
  14. package/dist/Extensions/Array.d.ts +8 -1
  15. package/dist/Extensions/Array.js +47 -10
  16. package/dist/Extensions/Document.d.ts +27 -0
  17. package/dist/Extensions/Document.js +32 -0
  18. package/dist/Extensions/Function.d.ts +14 -0
  19. package/dist/Extensions/Function.js +10 -0
  20. package/dist/Extensions/Map.d.ts +17 -1
  21. package/dist/Extensions/Map.js +24 -13
  22. package/dist/Extensions/Object/index.d.ts +49 -0
  23. package/dist/Extensions/Object/index.js +38 -0
  24. package/dist/Extensions/Object/properties.d.ts +28 -0
  25. package/dist/Extensions/Object/properties.js +20 -0
  26. package/dist/Extensions/String.d.ts +11 -1
  27. package/dist/Extensions/String.js +15 -7
  28. package/dist/Extensions/index.d.ts +5 -17
  29. package/dist/Extensions/index.js +8 -49
  30. package/dist/Functions/GetCSSProperty.d.ts +1 -1
  31. package/dist/Functions/GetNestedProperty.d.ts +9 -0
  32. package/dist/Functions/GetNestedProperty.js +23 -0
  33. package/dist/Functions/index.d.ts +1 -0
  34. package/dist/Functions/index.js +1 -0
  35. package/dist/Interfaces/ElementOptions.d.ts +4 -4
  36. package/dist/Types/BetterTypes.d.ts +3 -3
  37. package/dist/Types/Date.d.ts +6 -6
  38. package/dist/Types/Events.d.ts +2 -2
  39. package/dist/Types/PropertiesWith.d.ts +2 -2
  40. package/dist/Types/TransformTypes.d.ts +2 -2
  41. package/dist/Types/index.d.ts +21 -6
  42. package/docs/Classes.md +33 -0
  43. package/docs/Extensions.md +7 -0
  44. package/docs/Functions.md +8 -0
  45. package/docs/Types.md +30 -17
  46. package/package.json +6 -3
  47. package/src/Classes/Events/Event.ts +1 -1
  48. package/src/Classes/Events/EventCollection.ts +1 -1
  49. package/src/Classes/Events/EventEmitter.ts +40 -5
  50. package/src/Classes/index.ts +2 -1
  51. package/src/Classes/store.ts +98 -0
  52. package/src/Extensions/Array.ts +49 -11
  53. package/src/Extensions/Document.ts +58 -0
  54. package/src/Extensions/Function.ts +18 -0
  55. package/src/Extensions/Map.ts +24 -9
  56. package/src/Extensions/Object/index.ts +82 -0
  57. package/src/Extensions/Object/properties.ts +51 -0
  58. package/src/Extensions/String.ts +17 -6
  59. package/src/Extensions/index.ts +7 -66
  60. package/src/Functions/GetNestedProperty.ts +29 -0
  61. package/src/Functions/index.ts +1 -0
  62. package/src/Interfaces/ElementOptions.ts +2 -2
  63. package/src/Types/index.ts +27 -2
  64. package/tsconfig.json +2 -2
  65. package/Time.xlsx +0 -0
  66. package/dist/Extensions/Object.d.ts +0 -16
  67. package/dist/Extensions/Object.js +0 -8
  68. package/src/Extensions/Object.ts +0 -25
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "danholibraryjs",
3
- "version": "1.7.0",
3
+
4
+ "version": "1.10.0",
4
5
  "description": "Library for Javascript.",
5
6
  "main": "dist/index.js",
6
7
  "types": "dist/index.d.ts",
7
8
  "scripts": {
8
9
  "build": "npx tsc --project tsconfig.json",
9
- "build-watch": "npx tsc --project tsconfig.json --watch true"
10
+ "build-watch": "npx tsc --project tsconfig.json --watch true",
11
+ "login-github": "npm login --scope=@DanielSimonsen90 --registry=https://npm.pkg.github.com",
12
+ "login-npm": "npm login --scope@danhosaur --registry=https://registry.npmjs.org"
10
13
  },
11
14
  "repository": {
12
15
  "type": "git",
@@ -19,4 +22,4 @@
19
22
  "url": "https://github.com/DanielSimonsen90/DanhoLibraryJS/issues"
20
23
  },
21
24
  "homepage": "https://github.com/DanielSimonsen90/DanhoLibraryJS#readme"
22
- }
25
+ }
@@ -58,7 +58,7 @@ export class Event<
58
58
  */
59
59
  public on(listener: EventHandler<Events, Name>, prepend = false) {
60
60
  if (this.limit > 0 && this._listeners.length + 1 > this.limit) {
61
- throw new Error(`Event limit, ${this.limit}, reached for event ${this.name}!`);
61
+ throw new Error(`Event limit, ${this.limit}, reached for event ${this.name.toString()}!`);
62
62
  }
63
63
 
64
64
  if (prepend) this._listeners = [listener, ...this._listeners]
@@ -99,7 +99,7 @@ import Event from './Event';
99
99
  }
100
100
 
101
101
  const event = this.get(eventName);
102
- if (!event) throw new Error(`Unknown event, ${eventName}!`);
102
+ if (!event) throw new Error(`Unknown event, ${eventName.toString()}!`);
103
103
 
104
104
  event.limit = limit;
105
105
  this._events.set(eventName, event as any);
@@ -6,6 +6,30 @@ import { BaseEvent, EventHandler } from '../../Types';
6
6
  * @borrows EventCollection
7
7
  * @borrows BaseEvent
8
8
  * @borrows EventHandler
9
+ *
10
+ * @example ```ts
11
+ * import { EventEmitter } from 'danholibraryjs';
12
+ *
13
+ * type EventTypes = {
14
+ * create: [username: string, password: string],
15
+ * update: [id: string, user: User],
16
+ * delete: [id: string, reason?: string],
17
+ * }
18
+ *
19
+ * const emitter = new EventEmitter<EventTypes>(new Map([
20
+ * ['create', (username, password) => {
21
+ * return { username, password };
22
+ * }],
23
+ * ['update', (id, user) => {
24
+ * return { id, ...user };
25
+ * }]
26
+ * ]));
27
+ *
28
+ * const onDelete = (id: string, reason?: string) => console.log(`User ${id} was deleted because ${reason}`);
29
+ * emitter.on('delete', onDelete);
30
+ * emitter.emit('delete', '1', 'No longer needed');
31
+ * emitter.off('delete', onDelete);
32
+ * ```
9
33
  */
10
34
  export class EventEmitter<Events extends BaseEvent<string, Array<any>>> {
11
35
  /**@param events Map<name: string, handlers: EventHandler[]>*/
@@ -22,7 +46,10 @@ export class EventEmitter<Events extends BaseEvent<string, Array<any>>> {
22
46
  * @param listener Callback function to run, when event occurs
23
47
  * @returns this
24
48
  */
25
- public on<Return extends any, Event extends keyof Events>(event: Event, listener: EventHandler<Events, Event, Return>): this {
49
+ public on<Return extends any, Event extends keyof Events>(
50
+ event: Event,
51
+ listener: EventHandler<Events, Event, Return>
52
+ ): EventEmitter<Events> {
26
53
  this._events.add(event, listener as any);
27
54
  return this;
28
55
  }
@@ -32,7 +59,10 @@ export class EventEmitter<Events extends BaseEvent<string, Array<any>>> {
32
59
  * @param listener Callback function to run, when event occurs
33
60
  * @returns this
34
61
  */
35
- public once<Return extends any, Event extends keyof Events>(event: Event, listener: EventHandler<Events, Event, Return>): this {
62
+ public once<Return extends any, Event extends keyof Events>(
63
+ event: Event,
64
+ listener: EventHandler<Events, Event, Return>
65
+ ): EventEmitter<Events> {
36
66
  this._events.add(event, listener as any, true);
37
67
  return this;
38
68
  }
@@ -43,7 +73,10 @@ export class EventEmitter<Events extends BaseEvent<string, Array<any>>> {
43
73
  * @param listener If left null, removes all listeners tied to event, else only removes listener from event
44
74
  * @returns this
45
75
  */
46
- public off<Return extends any, Event extends keyof Events>(event: Event | 'all' = "all", listener?: EventHandler<Events, Event, Return>): this {
76
+ public off<Return extends any, Event extends keyof Events>(
77
+ event: Event | 'all' = "all",
78
+ listener?: EventHandler<Events, Event, Return>
79
+ ): EventEmitter<Events> {
47
80
  this._events.clear(event, listener);
48
81
  return this;
49
82
  }
@@ -55,7 +88,9 @@ export class EventEmitter<Events extends BaseEvent<string, Array<any>>> {
55
88
  * @fires event
56
89
  * @returns Array of listeners' reponses
57
90
  */
58
- public emit<Return extends any, Event extends keyof Events>(event: Event, ...args: Events[Event]): Array<Return> {
91
+ public emit<Return extends any, Event extends keyof Events>(
92
+ event: Event, ...args: Events[Event]
93
+ ): Array<Return> {
59
94
  return this._events.emit(event, ...args) as Array<Return>;
60
95
  }
61
96
 
@@ -65,7 +100,7 @@ export class EventEmitter<Events extends BaseEvent<string, Array<any>>> {
65
100
  * @param limit Limit of events to keep. If you want to limit amount of events saved, use 'all'.
66
101
  * @returns this with the new limit
67
102
  */
68
- public limit<Event extends keyof Events>(event: 'all' | Event, limit: number) {
103
+ public limit<Event extends keyof Events>(event: 'all' | Event, limit: number): EventEmitter<Events> {
69
104
  this._events.limit<Event>(event, limit);
70
105
  return this;
71
106
  }
@@ -1,2 +1,3 @@
1
1
  export * from './Events';
2
- export * from './Time';
2
+ export * from './Time';
3
+ export * from './store';
@@ -0,0 +1,98 @@
1
+ import { Arrayable, TransformType } from "../Types";
2
+ import { EventEmitter } from "./Events";
3
+
4
+ export type Reducer<State, Types extends Record<string, any[]>, Action extends keyof Types> = (state: State, ...args: Types[Action]) => State
5
+ export type Actions<State, ActionTypes extends Record<string, any[]>> = {
6
+ [Action in keyof ActionTypes]?: Arrayable<Reducer<State, ActionTypes, Action>>
7
+ };
8
+
9
+ /**
10
+ * EventEmitter, but it stores state and handles state change with reducers
11
+ *
12
+ * @Initialization Actions & initial state must be defined in type parameters. InitialState must be provided in constructor, whereas reducer is optional.
13
+ * The ActionType must have properties as strings and values as arrays.
14
+ *
15
+ * @HandlingActions Reducers can be added through constructor or using Store.on('action', reducer) or Store.once('action', reducer).
16
+ * Every state change must return the next state, apart from 'stateChange', which returns void/any
17
+ * Emit/Dispatch an action using Store.dispatch('action', ...args), ...args being the parameters from the ActionType.
18
+ * Store.emit should NOT be used, as it doesn't update the Store's state.
19
+ *
20
+ * Reducer functions can be removed using Store.off('action', reducer);
21
+ *
22
+ * @borrows EventEmitter
23
+ * @borrows Arrayable
24
+ *
25
+ * @example ```ts
26
+ * import { Store } from 'danholibraryjs';
27
+ *
28
+ * type Todo = {
29
+ * id: string,
30
+ * text: string,
31
+ * completed: boolean
32
+ * }
33
+ *
34
+ * type TodoActions = {
35
+ * create: [text: string],
36
+ * update: [id: string, text: string],
37
+ * toggleComplete: [id: string, force?: boolean],
38
+ * delete: [id: string],
39
+ * }
40
+ *
41
+ * const store = new Store<Array<Todo>, TodoActions>(new Array<Todo>(), new Map([
42
+ * create: (state, text) => {
43
+ * return [...state, {
44
+ * id: Math.random().toString(),
45
+ * text,
46
+ * completed: false
47
+ * }];
48
+ * },
49
+ * toggleComplete: (state, id, force) => {
50
+ * const todo = state.find(todo => todo.id === id);
51
+ * if (!todo) return state;
52
+ *
53
+ * return state.map(todo => (
54
+ * todo.id === id ? {
55
+ * ...todo,
56
+ * completed: force === undefined ? !todo.completed : force
57
+ * } : todo
58
+ * ));
59
+ * }
60
+ * ]));
61
+ *
62
+ * store.on('delete', (state, id) => {
63
+ * return state.filter(todo => todo.id !== id);
64
+ * });
65
+ *
66
+ * store.on('stateChange', (prevState, currentState) => console.log('State change', prevState, currentState));
67
+ *
68
+ * store.dispatch('create', 'Make store!');
69
+ *
70
+ * ```
71
+ */
72
+ export class Store<
73
+ State extends object,
74
+ ActionTypes extends Record<string, any[]>,
75
+ StoreActions extends Actions<State, ActionTypes> = Actions<State, ActionTypes>
76
+ > extends EventEmitter<
77
+ Record<keyof StoreActions, ActionTypes[keyof ActionTypes]>
78
+ & Record<'stateChange', [previous: State, current: State]>
79
+ > {
80
+ constructor(state: State, actions: StoreActions = {} as StoreActions) {
81
+ super(new Map(...Object.entries(actions).map(([action, reducers]) => [action, reducers as any])));
82
+
83
+ this._state = state;
84
+ }
85
+
86
+ private _state: State;
87
+ public get state(): State {
88
+ return this._state;
89
+ }
90
+
91
+ public dispatch<Action extends keyof ActionTypes>(action: Action, ...args: ActionTypes[Action]): State {
92
+ const previous = { ...this._state };
93
+ this._state = super.emit<State, Action>(action, ...args as any).reduce((state, returned) => ({ ...state, ...returned }), this.state);
94
+
95
+ super.emit<void, 'stateChange'>('stateChange', ...[previous, this.state] as any);
96
+ return this.state;
97
+ }
98
+ }
@@ -1,6 +1,4 @@
1
- export {};
2
-
3
- type UpdateFinder<T> = (item: T, index: number, self: Array<T>) => boolean
1
+ export type UpdateFinder<T> = (item: T, index: number, self: Array<T>) => boolean
4
2
 
5
3
  declare global {
6
4
  interface Array<T> {
@@ -28,30 +26,70 @@ declare global {
28
26
  * Returns item matching index. If negative number, subtracts number from length
29
27
  * @param i Index of item
30
28
  */
31
- index(i: number): T
29
+ index(i: number): T,
30
+ /**
31
+ * For every x in array, execute callback
32
+ * @param every i.e every 2nd item in array
33
+ * @param callback Function to execute
34
+ * @returns Array of results
35
+ */
36
+ nth<U>(every: number, callback: (item: T, index: number, collection: Array<T>, self: this) => U): Array<U>
32
37
  }
33
38
  }
34
39
 
35
- Array.prototype.add = function<T>(this: Array<T>, ...items: Array<T>) {
40
+ function add<T>(this: Array<T>, ...items: Array<T>) {
36
41
  this.push(...items);
37
42
  return this;
38
43
  }
39
- Array.prototype.update = function<T>(this: Array<T>, old: T | number | UpdateFinder<T>, updated: T) {
40
- const item = typeof old === 'number' ? this[old] : typeof old === 'function' ? this.find(old as UpdateFinder<T>) : old;
44
+ Array.prototype.add = add;
45
+
46
+ function update<T>(this: Array<T>, old: T | number | UpdateFinder<T>, updated: T) {
47
+ const item = typeof old === 'number' ? this[old]
48
+ : typeof old === 'function' ? this.find(old as UpdateFinder<T>)
49
+ : old;
41
50
  if (!item) throw new Error('Old was not found in array!');
42
51
 
43
52
  const index = this.indexOf(item);
44
53
  return this[index] = updated;
45
54
  }
46
- Array.prototype.remove = function<T>(this: Array<T>, value: T | number): Array<T> {
55
+ Array.prototype.update = update;
56
+
57
+ function remove<T>(this: Array<T>, value: T | number): Array<T> {
47
58
  const index = typeof value === 'number' ? value : this.indexOf(value);
48
59
  if (index > -1) this.splice(index, 1);
49
60
  return this;
50
61
  }
51
- Array.prototype.random = function<T>(this: Array<T>): T {
62
+ Array.prototype.remove = remove;
63
+
64
+ function random<T>(this: Array<T>): T {
52
65
  const randomIndex = Math.round(Math.random() * this.length);
53
66
  return this[randomIndex];
54
67
  }
55
- Array.prototype.index = function<T>(this: Array<T>, i: number): T {
68
+ Array.prototype.random = random;
69
+
70
+ function index<T>(this: Array<T>, i: number): T {
56
71
  return this[i < 0 ? this.length + i : i];
57
- }
72
+ }
73
+ Array.prototype.index = index;
74
+
75
+ function nth<T, U>(this: Array<T>, every: number, callback: (item: T, index: number, collection: Array<T>, self: Array<T>) => U): Array<U> {
76
+ const result = new Array<U>();
77
+ let collection = new Array<T>();
78
+
79
+ for (let i = 0; i < this.length; i++) {
80
+ collection.push(this[i]);
81
+
82
+ if (i % every === 0) {
83
+ result.push(callback(this[i], i, collection, this));
84
+ collection = new Array<T>();
85
+ }
86
+ }
87
+
88
+ return result;
89
+ }
90
+ Array.prototype.nth = nth;
91
+
92
+ export const ArrayExtensions = {
93
+ add, update, remove,
94
+ random, index, nth
95
+ };
@@ -0,0 +1,58 @@
1
+ import { IElement } from "../Types";
2
+
3
+ declare global {
4
+ interface Document {
5
+ /**
6
+ * Creates an element like Document#createElement, however with construction options to assign values in construction instead of after construction.
7
+ * @param tagName HTMLElement tag name
8
+ * @param options Construction options, instead of assigning values after construction
9
+ * @param children Child elements
10
+ */
11
+ createProperElement<Tag extends keyof HTMLElementTagNameMap>(tagName: Tag, options?: Partial<HTMLElementTagNameMap[Tag]>, ...children: Array<IElement>): HTMLElementTagNameMap[Tag]
12
+ createProperElement<Tag extends keyof HTMLElementTagNameMap>(tagName: Tag, ...children: Array<IElement>): HTMLElementTagNameMap[Tag]
13
+ createElementFromString<K extends keyof HTMLElementTagNameMap>(html: string, parentTag?: K): HTMLElementTagNameMap[K]
14
+ }
15
+ interface HTMLCollection {
16
+ /**
17
+ * Converts HTMLCollection to Element[]
18
+ */
19
+ array(): Element[]
20
+ }
21
+ }
22
+
23
+ function createElement<Tag extends keyof HTMLElementTagNameMap>(
24
+ this: Document, tagName: Tag,
25
+ options?: Partial<HTMLElementTagNameMap[Tag]> | string,
26
+ ...children: Array<IElement>
27
+ ): HTMLElementTagNameMap[Tag] {
28
+
29
+ const element = Object.assign(document.createElement(tagName), typeof options === 'string' ? {} : options);
30
+ children ??= typeof options === 'string' ? [options] as Array<IElement> : [];
31
+ typeof options === 'string' && children.unshift(options);
32
+
33
+ if (!children.length) return element;
34
+ else if (typeof children === 'string') element.innerHTML = children;
35
+ else if (children instanceof Array) children.forEach(child => (
36
+ typeof child === 'string' ?
37
+ element.innerHTML += child :
38
+ element.appendChild(child)
39
+ ));
40
+ else element.appendChild(children);
41
+ return element;
42
+
43
+ }
44
+ Document.prototype.createProperElement = createElement;
45
+
46
+ function createElementFromString<Tag extends keyof HTMLElementTagNameMap>(this: Document, html: string, tag?: Tag): HTMLElementTagNameMap[Tag] {
47
+ if (!html.startsWith(`<${tag}`)) html = `<${tag}>${html}</${tag}>`;
48
+ return new DOMParser().parseFromString(html, 'text/html').body.firstElementChild as HTMLElementTagNameMap[Tag];
49
+ }
50
+ Document.prototype.createElementFromString = createElementFromString;
51
+
52
+ HTMLCollection.prototype.array = function(this: HTMLCollection) {
53
+ return Array.from(this);
54
+ };
55
+
56
+ export const DocumentExtensions = {
57
+ createElement, createElementFromString
58
+ };
@@ -0,0 +1,18 @@
1
+ declare global {
2
+ interface Function {
3
+ /**
4
+ * Checks if obj is a function
5
+ * @param obj Object to check
6
+ */
7
+ is(obj: any): obj is Function;
8
+ }
9
+ }
10
+
11
+ function is(obj: any): obj is Function {
12
+ return typeof obj === 'function';
13
+ }
14
+ Function.is = is;
15
+
16
+ export const FunctionExtensions = {
17
+ is
18
+ };
@@ -1,5 +1,3 @@
1
- export {}
2
-
3
1
  declare global {
4
2
  interface Map<K, V> {
5
3
  /**
@@ -38,36 +36,53 @@ declare global {
38
36
  }
39
37
  }
40
38
 
41
- Map.prototype.array = function<K, V>(this: Map<K, V>): Array<[K, V]> {
39
+ function array<K, V>(this: Map<K, V>): Array<[K, V]> {
42
40
  let result = new Array<[K, V]>();
43
41
  for (const kvp of this) {
44
42
  result.push(kvp);
45
43
  }
46
44
  return result;
47
45
  }
48
- Map.prototype.map = function<K, V, EK, EV>(this: Map<K, V>, callback: (value: V, key: K, index: number, map: Map<K, V>) => [EK, EV]): Map<EK, EV> {
46
+ Map.prototype.array = array;
47
+
48
+ function map<K, V, EK, EV>(this: Map<K, V>, callback: (value: V, key: K, index: number, map: Map<K, V>) => [EK, EV]): Map<EK, EV> {
49
49
  return this.array()
50
50
  .map(([k, v], i) => callback(v, k, i, this))
51
51
  .reduce((map, [key, value]) =>
52
52
  map.set(key, value),
53
53
  new Map<EK, EV>())
54
54
  }
55
- Map.prototype.filter = function<K, V>(this: Map<K, V>, callback: (value: V, key: K, index: number, map: Map<K, V>) => boolean): Map<K, V> {
55
+ Map.prototype.map = map;
56
+
57
+ function filter<K, V>(this: Map<K, V>, callback: (value: V, key: K, index: number, map: Map<K, V>) => boolean): Map<K, V> {
56
58
  return this.array()
57
59
  .filter(([k, v], i) => callback(v, k, i, this))
58
60
  .reduce((map, [key, value]) =>
59
61
  map.set(key, value),
60
62
  new Map<K, V>())
61
63
  }
62
- Map.prototype.keyArr = function<K, V>(this: Map<K, V>): Array<K> {
64
+ Map.prototype.filter = filter;
65
+
66
+ function keyArr<K, V>(this: Map<K, V>): Array<K> {
63
67
  return this.array().map(([k]) => k);
64
68
  }
65
- Map.prototype.valueArr = function<K, V>(this: Map<K, V>): Array<V> {
69
+ Map.prototype.keyArr = keyArr;
70
+
71
+ function valueArr<K, V>(this: Map<K, V>): Array<V> {
66
72
  return this.array().map(([_, v]) => v);
67
73
  }
68
- Map.prototype.find = function<K, V>(this: Map<K, V>, callback: (value: V, key: K, index: number, map: Map<K, V>) => boolean) {
74
+ Map.prototype.valueArr = valueArr;
75
+
76
+ function find<K, V>(this: Map<K, V>, callback: (value: V, key: K, index: number, map: Map<K, V>) => boolean) {
69
77
  return this.array().find(([k, v], i) => callback(v, k, i, this));
70
78
  }
71
- Map.prototype.includes = function<K, V>(this: Map<K, V>, item: V, fromIndex?: number) {
79
+ Map.prototype.find = find;
80
+
81
+ function includes<K, V>(this: Map<K, V>, item: V, fromIndex?: number) {
72
82
  return this.valueArr().includes(item, fromIndex);
83
+ }
84
+ Map.prototype.includes = includes;
85
+
86
+ export const MapExtensions = {
87
+ array, map, filter, keyArr, valueArr, find, includes
73
88
  }
@@ -0,0 +1,82 @@
1
+ import { ValueOf } from "../../Types";
2
+ import { Properties, properties } from "./properties";
3
+
4
+ declare global {
5
+ interface ObjectConstructor {
6
+ /**
7
+ * Destructures object into array of [property, value]
8
+ * @param from Object to destruct
9
+ */
10
+ array<From extends {} = {}>(from: From): Array<[keyof From, ValueOf<From>]>
11
+
12
+ /**
13
+ * Omits properties from object, but for some reason the correct term is "extract"
14
+ * @param from Object to extract properties from
15
+ * @param props Properties to extract/Omit
16
+ */
17
+ extract<From extends {}, Props extends keyof From>(from: From, ...props: Array<Props | Partial<From>>): Omit<From, Props>
18
+
19
+ /**
20
+ * Pick properties from object, but for some reason the correct term is "exclude"
21
+ * @param from Object to exclude properties from
22
+ * @param props Properties to exclude/pick
23
+ */
24
+ exclude<From extends {}, Props extends keyof From>(from: From, ...props: Array<Props | Partial<From>>): Pick<From, Props>
25
+
26
+ /**
27
+ * Returns true if object is empty
28
+ * @param obj Object to check
29
+ */
30
+ isNullOrUndefined(obj: any): obj is null | undefined
31
+
32
+ /**
33
+ * Destructures object into array of property keys
34
+ * @param from Object to destruct
35
+ */
36
+ keysOf<From extends {} = {}>(from: From): Array<keyof From>
37
+
38
+ omit<From extends {}, Exclude extends keyof From>(from: From, ...exclude: Exclude[]): Omit<From, Exclude>;
39
+
40
+ properties: Properties
41
+ }
42
+ }
43
+
44
+ function array<From extends {} = {}>(this: object, from: From): Array<[keyof From, ValueOf<From>]> {
45
+ return Object.keysOf(from).map(prop => [prop, from[prop]]) as Array<[keyof From, ValueOf<From>]>;
46
+ }
47
+ Object.array = array;
48
+
49
+ function extract<From extends {}, Props extends keyof From>(from: From, ...props: Array<Props | Partial<From>>): Omit<From, Props> {
50
+ // If props are Array<keyof From>, Array<Partial<From>>, or Array<keyof From | Partial<From>>, ensure _props as Array<keyof From>
51
+ const _props = props.map(prop => typeof prop === "object" ? Object.keysOf(prop) : prop).flat();
52
+ _props.forEach(prop => delete from[prop as keyof From]);
53
+ return from;
54
+ }
55
+ Object.extract = extract;
56
+
57
+ function exclude<From extends {}, Props extends keyof From>(from: From, ...props: Array<Props | Partial<From>>): Pick<From, Props> {
58
+ // If props are Array<keyof From>, Array<Partial<From>>, or Array<keyof From | Partial<From>>, ensure _props as Array<keyof From>
59
+ const _props = props.map(prop => typeof prop === "object" ? Object.keysOf(prop) : prop).flat();
60
+ return Object.keysOf(from).reduce((result, prop) => {
61
+ if (_props.includes(prop as Props)) delete result[prop];
62
+ return result;
63
+ }, from);
64
+ }
65
+ Object.exclude = exclude;
66
+
67
+ function isNullOrUndefined(obj: any): obj is null | undefined {
68
+ return obj === null || obj === undefined;
69
+ }
70
+ Object.isNullOrUndefined = isNullOrUndefined;
71
+
72
+ function keysOf<From extends {} = {}>(this: object, from: From): Array<keyof From> {
73
+ return Object.keys(from) as Array<keyof From>;
74
+ }
75
+ Object.keysOf = keysOf;
76
+
77
+ Object.properties = properties;
78
+
79
+ export const ObjectExtensions = {
80
+ properties,
81
+ array, extract, exclude, isNullOrUndefined, keysOf,
82
+ };
@@ -0,0 +1,51 @@
1
+ import { PropertiesWith, If } from '../../Types';
2
+ import { StringExtensions } from '../String';
3
+
4
+ type PrimitiveMap = {
5
+ string: string;
6
+ number: number;
7
+ boolean: boolean;
8
+ undefined: undefined;
9
+ null: null;
10
+ object: object;
11
+ function: Function;
12
+ any: any;
13
+ Date: Date;
14
+ RegExp: RegExp;
15
+ Promise: Promise<any>;
16
+ Array: Array<any>;
17
+ Map: Map<any, any>;
18
+ Set: Set<any>;
19
+ }
20
+
21
+ /**
22
+ * Object with getPrimitiveTypes<Source, AllowFunctions extends boolean>(
23
+ * source: Source,
24
+ * allowFunctions: AllowFunctions = false
25
+ * ): Object with properties from source that matches primitive type
26
+ */
27
+ export type Properties = {
28
+ [Key in keyof PrimitiveMap as `get${Capitalize<Key>}s`]:
29
+ <Source extends {}, AllowFunctions extends boolean = false>(source: Source, withFunctions?: AllowFunctions) =>
30
+ If<AllowFunctions,
31
+ PropertiesWith<PrimitiveMap[Key] | ((...args: any[]) => PrimitiveMap[Key]), Source>,
32
+ PropertiesWith<PrimitiveMap[Key], Source>
33
+ >
34
+ }
35
+
36
+ export const properties: Properties = [
37
+ 'string', 'number', 'boolean', 'undefined', 'null',
38
+ 'object', 'function', 'any',
39
+ 'Date', 'RegExp', 'Promise', 'Array', 'Map', 'Set'
40
+ ].reduce((result, primitive) => {
41
+ result[`get${StringExtensions.toPascalCase.bind(primitive)()}s` as keyof Properties] = function<Source extends {}, AllowFunctions extends boolean = false>(source: Source, withFunctions: AllowFunctions = false as AllowFunctions) {
42
+ return Object.keysOf<Source>(source).reduce((result, key) => {
43
+ if ((source[key] as any).constructor.name === primitive ||
44
+ (withFunctions && typeof source[key] === 'function' && source[key] as any).constructor.name === primitive) {
45
+ result[key] = source[key];
46
+ }
47
+ return result;
48
+ }, {} as any);
49
+ }
50
+ return result;
51
+ }, {} as Properties);
@@ -1,5 +1,4 @@
1
1
  import IReplacement from "../Interfaces/IReplacement";
2
- export {}
3
2
 
4
3
  declare global {
5
4
  interface String {
@@ -26,18 +25,30 @@ declare global {
26
25
  }
27
26
  }
28
27
 
29
- String.prototype.toPascalCase = function(this: string) {
28
+ function toPascalCase(this: string) {
30
29
  return this.substring(0, 1).toUpperCase() + this.substring(1);
31
30
  }
31
+ String.prototype.toPascalCase = toPascalCase;
32
+
32
33
  function spaceReplacer(self: string, replacer: string | RegExp, replacement: string) {
33
34
  return self.replace(new RegExp(`${typeof replacer == 'string' ? replacer : replacer.source}+`), replacement);
34
35
  }
35
- String.prototype.toSnakeCase = function(this: string, replaceOptions: IReplacement) {
36
+
37
+ function toSnakeCase(this: string, replaceOptions: IReplacement) {
36
38
  return spaceReplacer(this, replaceOptions.replacer || ' ', replaceOptions.replacement || '_')
37
39
  }
38
- String.prototype.toKebabCase = function(this: string, replaceOptions: IReplacement) {
40
+ String.prototype.toSnakeCase = toSnakeCase;
41
+
42
+ function toKebabCase(this: string, replaceOptions: IReplacement) {
39
43
  return spaceReplacer(this, replaceOptions.replacer || ' ', replaceOptions.replacement || '-');
40
44
  }
41
- String.prototype.clip = function(this: string, start: number, end?: number) {
45
+ String.prototype.toKebabCase = toKebabCase;
46
+
47
+ function clip(this: string, start: number, end?: number) {
42
48
  return this.substring(start < 0 ? this.length - start : start, end && end < 0 ? this.length + end : end);
43
- }
49
+ }
50
+ String.prototype.clip = clip;
51
+
52
+ export const StringExtensions = {
53
+ toPascalCase, toSnakeCase, toKebabCase, clip
54
+ };