@hamak/shared-utils 0.4.6 → 0.4.8
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.
- package/package.json +4 -1
- package/src/core-utils-chrono.ts +0 -21
- package/src/core-utils-comparator.ts +0 -27
- package/src/core-utils-file.ts +0 -10
- package/src/core-utils-filesystem.spec.ts +0 -63
- package/src/core-utils-filesystem.ts +0 -232
- package/src/core-utils-fqn.ts +0 -17
- package/src/core-utils-pathway-resolver.ts +0 -36
- package/src/core-utils-pathway.ts +0 -270
- package/src/core-utils-registry.ts +0 -23
- package/src/core-utils-resolver.ts +0 -75
- package/src/core-utils-stack.spec.ts +0 -42
- package/src/core-utils-stack.ts +0 -62
- package/src/core-utils-types-hkt.ts +0 -9
- package/src/core-utils-types.ts +0 -127
- package/src/core-utils-validations.ts +0 -36
- package/src/core-utils.spec.ts +0 -56
- package/src/core-utils.ts +0 -139
- package/src/index.ts +0 -34
- package/src/itinerary/hyper-layer-node.ts +0 -25
- package/src/itinerary/itinerary.spec.ts +0 -388
- package/src/itinerary/itinerary.ts +0 -363
- package/src/itinerary/stack.spec.ts +0 -46
- package/src/itinerary/stack.ts +0 -62
- package/tsconfig.es2015.json +0 -21
- package/tsconfig.json +0 -19
- package/vitest.config.ts +0 -8
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Resolver } from './core-utils-resolver';
|
|
2
|
-
export class SimpleRegistry<T> implements Resolver<T>{
|
|
3
|
-
private readonly records : Map<string | undefined, Record<string, T>> = new Map()
|
|
4
|
-
resolve(namespace: string | undefined, prefix: string | undefined, variableName: string): T | undefined {
|
|
5
|
-
if (prefix !== undefined){
|
|
6
|
-
throw new Error(`Not support namespace prefix for name resolution : '${prefix}'`)
|
|
7
|
-
} else {
|
|
8
|
-
const record = this.records.get(namespace)
|
|
9
|
-
return record?.[variableName]
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
register(namespace: string | undefined, variableName: string, t : T) {
|
|
14
|
-
let namespaceRecord = this.records.get(namespace)
|
|
15
|
-
if(namespaceRecord === undefined){
|
|
16
|
-
namespaceRecord = {}
|
|
17
|
-
this.records.set(namespace, namespaceRecord)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
namespaceRecord[variableName] = t
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
export interface Resolver<T> {
|
|
2
|
-
resolve(namespace: string | undefined, prefix: string | undefined, variableName: string): T | undefined
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export class RecordResolver<T> implements Resolver<T> {
|
|
6
|
-
constructor(readonly variables: Record<string, T>, readonly parent?: Resolver<T>) {
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
resolve(namespace: string | undefined, prefix: string | undefined, variableName: string): T | undefined {
|
|
10
|
-
return this.variables[variableName] ?? this.parent?.resolve(undefined, undefined, variableName)
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export class QualifiedNameResolverImpl<T> implements Resolver<T> {
|
|
15
|
-
readonly entries = new Map<string| undefined, Map<string, T>>()
|
|
16
|
-
constructor(readonly ignoreNs = false) {
|
|
17
|
-
}
|
|
18
|
-
resolve(namespace: string | undefined, prefix: string | undefined, name: string): T | undefined {
|
|
19
|
-
if(!this.ignoreNs && namespace !== undefined && namespace !== null){
|
|
20
|
-
throw new Error(`Not support namespace URI but passed as parameter: ${namespace}`)
|
|
21
|
-
}
|
|
22
|
-
return this.entries.get(namespace)?.get(name)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
setEntries(prefix: string | undefined, entries : Record<string, T>){
|
|
26
|
-
const prefixEntry = this.getOrCreatePrefixEntry(prefix)
|
|
27
|
-
Object.entries(entries).forEach(([k, v]) => prefixEntry.set(k, v))
|
|
28
|
-
}
|
|
29
|
-
setEntry(prefix: string | undefined, name : string, entry : T){
|
|
30
|
-
const prefixEntry = this.getOrCreatePrefixEntry(prefix)
|
|
31
|
-
prefixEntry.set(name, entry)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
private getOrCreatePrefixEntry(prefix : string | undefined) : Map<string, T> {
|
|
35
|
-
let prefixEntry = this.entries.get(prefix)
|
|
36
|
-
if(prefixEntry === undefined){
|
|
37
|
-
prefixEntry = new Map<string, T>()
|
|
38
|
-
this.entries.set(prefix, prefixEntry)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return prefixEntry
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export type ResolverPredicate = (namespace: string | undefined, prefix: string | undefined, name: string) => boolean
|
|
47
|
-
|
|
48
|
-
export class SimpleResolver<T> implements Resolver<T> {
|
|
49
|
-
constructor(readonly parent: Resolver<T> | undefined, readonly namespace: string | undefined, readonly variableName: string | undefined, readonly variableValue: T) {
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
resolve(namespace: string | undefined, prefix: string | undefined, variableName: string): T | undefined {
|
|
53
|
-
if (this.namespace === namespace && this.variableName === variableName) {
|
|
54
|
-
return this.variableValue
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return this.parent?.resolve(namespace, prefix, variableName)
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export class ChainedResolver<T> implements Resolver<T> {
|
|
62
|
-
constructor(readonly resolvers: Resolver<T>[]) {
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
resolve(namespace: string | undefined, prefix: string | undefined, variableName: string): T | undefined {
|
|
66
|
-
for (const resolver of this.resolvers) {
|
|
67
|
-
const s = resolver.resolve(namespace, prefix, variableName)
|
|
68
|
-
if (s !== undefined) {
|
|
69
|
-
return s
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return undefined
|
|
74
|
-
}
|
|
75
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import stack from "./core-utils-stack";
|
|
2
|
-
|
|
3
|
-
describe("Core util stack", () => {
|
|
4
|
-
it("fromArray should work", () => {
|
|
5
|
-
const itinerary = stack.fromArray([1, 2, 3, 4])
|
|
6
|
-
|
|
7
|
-
expect(itinerary?.value).toBe(4)
|
|
8
|
-
expect(itinerary?.parent?.parent?.parent?.value).toBe(1)
|
|
9
|
-
|
|
10
|
-
expect(stack.fromArray([])).toBe(undefined)
|
|
11
|
-
expect(stack.fromArray(undefined)).toBe(undefined)
|
|
12
|
-
})
|
|
13
|
-
it("reduce should work", () => {
|
|
14
|
-
const itinerary = stack.fromArray([1, 2, 3, 4])
|
|
15
|
-
|
|
16
|
-
const result = stack.reduce(itinerary, (acc, t) => acc + t, 0);
|
|
17
|
-
expect(result).toBe(10)
|
|
18
|
-
})
|
|
19
|
-
it("reduce order should work", () => {
|
|
20
|
-
const itinerary = stack.fromArray([1, 2, 3, 4])
|
|
21
|
-
|
|
22
|
-
const result = stack.reduce(itinerary, (acc, t) => [...acc, t], [] as number[]);
|
|
23
|
-
expect(result).toStrictEqual([1, 2, 3, 4])
|
|
24
|
-
})
|
|
25
|
-
it("equal should work", () => {
|
|
26
|
-
expect(stack.equal(undefined, undefined)).toBe(false)
|
|
27
|
-
expect(stack.equal(null, null)).toBe(false)
|
|
28
|
-
expect(stack.equal(undefined, null)).toBe(false)
|
|
29
|
-
expect(stack.equal(null, undefined)).toBe(false)
|
|
30
|
-
|
|
31
|
-
expect(stack.equal(stack.fromArray([1, 2, 3, 4]), undefined)).toBe(false)
|
|
32
|
-
expect(stack.equal(stack.fromArray([1, 2, 3, 4]), null)).toBe(false)
|
|
33
|
-
|
|
34
|
-
expect(stack.equal(undefined, stack.fromArray([1, 2, 3, 4]))).toBe(false)
|
|
35
|
-
expect(stack.equal(null, stack.fromArray([1, 2, 3, 4]))).toBe(false)
|
|
36
|
-
|
|
37
|
-
expect(stack.equal(stack.fromArray([1]), stack.fromArray([2]))).toBe(false)
|
|
38
|
-
expect(stack.equal(stack.fromArray([1]), stack.fromArray([1, 2]))).toBe(false)
|
|
39
|
-
|
|
40
|
-
expect(stack.equal(stack.fromArray([1, 2, 3, 4]), stack.fromArray([1, 2, 3, 4]))).toBe(true)
|
|
41
|
-
})
|
|
42
|
-
})
|
package/src/core-utils-stack.ts
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
export interface StackElement<T> {
|
|
2
|
-
value : T
|
|
3
|
-
parent? : StackElement<T>
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export function head<T>(value : T) : StackElement<T> {
|
|
7
|
-
return {value}
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function push<T>(head : StackElement<T> | undefined, value : T) : StackElement<T> {
|
|
11
|
-
return {value, parent: head}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function concat<T>(tail : StackElement<T> | undefined, stack : StackElement<T> | undefined) : StackElement<T> | undefined{
|
|
15
|
-
if(tail === undefined) return stack
|
|
16
|
-
if(stack === undefined) return tail
|
|
17
|
-
|
|
18
|
-
const {parent, value} = stack
|
|
19
|
-
|
|
20
|
-
return {value, parent:concat(tail, parent)}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function fromArray<T = any>(t : T[] | undefined) : StackElement<T> | undefined {
|
|
24
|
-
return t?.reduce((acc, t) => push(acc, t), undefined as undefined | StackElement<T>)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function reduce<T, R>(head : StackElement<T> | undefined, reducer : (r: R, t : T) => R, initial : R) : R {
|
|
28
|
-
if(head === undefined){
|
|
29
|
-
return initial
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const {parent, value} = head
|
|
33
|
-
const acc = reduce(parent, reducer, initial)
|
|
34
|
-
return reducer(acc, value)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function equal<T>(a:StackElement<T> | null | undefined, b : StackElement<T> | null | undefined) : boolean {
|
|
38
|
-
// Not equal if both are nullish
|
|
39
|
-
if( a === undefined || a === null || b === undefined || b === null ){
|
|
40
|
-
return false
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
while (a !== undefined && b !== undefined){
|
|
44
|
-
if(a.value !== b.value){
|
|
45
|
-
return false
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
a = a.parent
|
|
49
|
-
b = b.parent
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Equal if traversed all stack at both side
|
|
53
|
-
if((a === undefined || a === null) && (b === undefined || b === null) ){
|
|
54
|
-
return true
|
|
55
|
-
} else {
|
|
56
|
-
return false
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const stack = {push, head, concat, reduce, fromArray, equal}
|
|
61
|
-
|
|
62
|
-
export default stack;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export interface HKT3<Obj, Key extends PropertyKey, Value> {
|
|
2
|
-
_Obj: Obj;
|
|
3
|
-
_Key: Key;
|
|
4
|
-
_Value: Value;
|
|
5
|
-
_Result: unknown;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export type Apply3<F extends HKT3<any, any, any>, Obj, Key extends PropertyKey, Value> =
|
|
9
|
-
(F & { _Obj: Obj; _Key: Key; _Value: Value })["_Result"];
|
package/src/core-utils-types.ts
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import {Apply3, HKT3} from "./core-utils-types-hkt";
|
|
2
|
-
|
|
3
|
-
export type TypedObject<T extends string = string> = {type : T}
|
|
4
|
-
export type AnyFunction = (...args : any[]) => any
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Intended to hold value which can be undefined.
|
|
8
|
-
* It helps to know if a value (incl. undefined) is present or not.
|
|
9
|
-
*/
|
|
10
|
-
export interface Holder<T = any>{
|
|
11
|
-
value:T
|
|
12
|
-
}
|
|
13
|
-
export function holder<T=any>(value : T) : Holder<T> {
|
|
14
|
-
return {value}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface GenericReason {
|
|
18
|
-
code? : string
|
|
19
|
-
message? : string
|
|
20
|
-
parameters? : Record<string, any>
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export type GenericError = GenericReason
|
|
24
|
-
|
|
25
|
-
export type ExpressionString = string
|
|
26
|
-
|
|
27
|
-
export interface HyperLayerNode<T> {
|
|
28
|
-
keys?: Record<PropertyKey, any> // Keys to use for property based navigation when applicable
|
|
29
|
-
data? : T
|
|
30
|
-
children? : Record<string, HyperLayerNode<T>> | Array<HyperLayerNode<T>>
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function hyper<T>(data : T, children?: Record<string, HyperLayerNode<T>> | Array<HyperLayerNode<T>>) : HyperLayerNode<T> {
|
|
34
|
-
return {data, children}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Utility function that create Overlay which mirror original object
|
|
40
|
-
* @param o
|
|
41
|
-
*/
|
|
42
|
-
export function hyperReflect(o : any) : HyperLayerNode<any> {
|
|
43
|
-
if(o === null || o === undefined){
|
|
44
|
-
return hyper(o)
|
|
45
|
-
} else if (Array.isArray(o)) {
|
|
46
|
-
return hyper(o, o.map(e => hyperReflect(e)))
|
|
47
|
-
} else if(typeof o === "object"){
|
|
48
|
-
return hyper(o, Object.entries(o).reduce((acc, [k, v]) => ({...acc, [k] : hyperReflect(v)}), {}))
|
|
49
|
-
} else {
|
|
50
|
-
return hyper(o)
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export type HyperLayerNodeHKT<T, F extends HKT3<any, any, any>, Host = never, Key extends PropertyKey = never> =
|
|
55
|
-
T extends Array<infer U> ? {
|
|
56
|
-
data?: Apply3<F, Host, Key, T>;
|
|
57
|
-
children?: HyperLayerNodeHKT<U, F, T, never>[];
|
|
58
|
-
} :
|
|
59
|
-
T extends Record<string, any> ? {
|
|
60
|
-
data?: Apply3<F, Host, Key, T>;
|
|
61
|
-
children?: {
|
|
62
|
-
[K in keyof T]?: HyperLayerNodeHKT<T[K], F, T, K>;
|
|
63
|
-
};
|
|
64
|
-
} :
|
|
65
|
-
{
|
|
66
|
-
data?: Apply3<F, Host, Key, T>;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
export interface OverlayNodeBase<A> {
|
|
70
|
-
type : "object" | "array" | "scalar"
|
|
71
|
-
annotation?: A
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
export interface ObjectOverlayNode<A> extends OverlayNodeBase<A> {
|
|
76
|
-
type : "object"
|
|
77
|
-
children : Record<string, OverlayNode<A>>
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
export interface ArrayOverlayNode<A> extends OverlayNodeBase<A> {
|
|
82
|
-
type : "array"
|
|
83
|
-
children : Array<OverlayNode<A>>
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
export interface ScalarOverlayNode<A> extends OverlayNodeBase<A> {
|
|
88
|
-
type : "scalar"
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export type OverlayNode<A> = ObjectOverlayNode<A> | ArrayOverlayNode<A> | ScalarOverlayNode<A>
|
|
92
|
-
|
|
93
|
-
export interface Annotation<A> {
|
|
94
|
-
annotation?: A;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export type Overlay<T, A> =
|
|
98
|
-
T extends Array<infer U> ? {
|
|
99
|
-
type: "array";
|
|
100
|
-
children: Overlay<U, A>[];
|
|
101
|
-
} & Annotation<A> :
|
|
102
|
-
T extends Record<string, any> ? {
|
|
103
|
-
type: "object";
|
|
104
|
-
children: {
|
|
105
|
-
[K in keyof T]?: Overlay<T[K], A>
|
|
106
|
-
};
|
|
107
|
-
} & Annotation<A> :
|
|
108
|
-
{
|
|
109
|
-
type: "scalar";
|
|
110
|
-
} & Annotation<A>;
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Mainly used to prevent re-entrant navitation
|
|
115
|
-
*/
|
|
116
|
-
export class ExplorationContext<T> {
|
|
117
|
-
constructor(readonly parent : ExplorationContext<T> | undefined, readonly values : T[]) {
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
explored(t : T) : boolean {
|
|
121
|
-
return this.values.includes(t)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
newChild(values : T[]): ExplorationContext<T>{
|
|
125
|
-
return new ExplorationContext<T>(this, values)
|
|
126
|
-
}
|
|
127
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
export interface NodeValidation {
|
|
2
|
-
type: "core:node-validation"
|
|
3
|
-
notes : ValidationNote[]
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export interface ValidationNote {
|
|
7
|
-
uuid?: string // TODO use UUID type
|
|
8
|
-
severity : "info" | "warning" | "error"
|
|
9
|
-
key?: string
|
|
10
|
-
message?: string
|
|
11
|
-
params?: Record<string, any>
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class NoteUtils {
|
|
16
|
-
add(nv : NodeValidation, ...notes : ValidationNote[]) : NodeValidation {
|
|
17
|
-
return {...(nv ?? {type: "core:node-validation"}), notes}
|
|
18
|
-
}
|
|
19
|
-
of(...notes : ValidationNote[]) : NodeValidation {
|
|
20
|
-
return {type: "core:node-validation", notes}
|
|
21
|
-
}
|
|
22
|
-
info(key?: string, message?: string, params?: Record<string, any>): ValidationNote {
|
|
23
|
-
return { severity: "info", key, message, params };
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
warning(key?: string, message?: string, params?: Record<string, any>): ValidationNote {
|
|
27
|
-
return { severity: "warning", key, message, params };
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
error(key?: string, message?: string, params?: Record<string, any>): ValidationNote {
|
|
31
|
-
return { severity: "error", key, message, params };
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
export const notes = new NoteUtils()
|
package/src/core-utils.spec.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import {removeDuplicates} from './core-utils';
|
|
2
|
-
import {utils} from './core-utils'
|
|
3
|
-
|
|
4
|
-
describe('Stack', () => {
|
|
5
|
-
it('concat should work', () => {
|
|
6
|
-
|
|
7
|
-
expect(removeDuplicates([1,1,1])).toEqual([1]);
|
|
8
|
-
expect(removeDuplicates([1,1,2])).toEqual([1, 2]);
|
|
9
|
-
expect(removeDuplicates([1,2,1])).toEqual([1, 2]);
|
|
10
|
-
expect(removeDuplicates([])).toEqual([]);
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
test('Should correctly compare various cases', () => {
|
|
14
|
-
// Identical objects
|
|
15
|
-
expect(utils.deepEqual({ a: 1 }, { a: 1 })).toBe(true);
|
|
16
|
-
|
|
17
|
-
// Objects with different values
|
|
18
|
-
expect(utils.deepEqual({ a: 1, b: 2 }, { a: 1, b: 3 })).toBe(false);
|
|
19
|
-
|
|
20
|
-
// Deeply identical objects
|
|
21
|
-
expect(utils.deepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 2 } })).toBe(true);
|
|
22
|
-
|
|
23
|
-
// Deeply different objects
|
|
24
|
-
expect(utils.deepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 3 } })).toBe(false);
|
|
25
|
-
|
|
26
|
-
// Identical numbers
|
|
27
|
-
expect(utils.deepEqual(1, 1)).toBe(true);
|
|
28
|
-
|
|
29
|
-
// Different numbers
|
|
30
|
-
expect(utils.deepEqual(1, 2)).toBe(false);
|
|
31
|
-
|
|
32
|
-
// Identical strings
|
|
33
|
-
expect(utils.deepEqual('hello', 'hello')).toBe(true);
|
|
34
|
-
|
|
35
|
-
// Different strings
|
|
36
|
-
expect(utils.deepEqual('hello', 'world')).toBe(false);
|
|
37
|
-
|
|
38
|
-
// Identical booleans
|
|
39
|
-
expect(utils.deepEqual(true, true)).toBe(true);
|
|
40
|
-
|
|
41
|
-
// Different booleans
|
|
42
|
-
expect(utils.deepEqual(true, false)).toBe(false);
|
|
43
|
-
|
|
44
|
-
// Null compared to null
|
|
45
|
-
expect(utils.deepEqual(null, null)).toBe(true);
|
|
46
|
-
|
|
47
|
-
// Null compared to undefined
|
|
48
|
-
expect(utils.deepEqual(null, undefined)).toBe(false);
|
|
49
|
-
|
|
50
|
-
// Null compared to object
|
|
51
|
-
expect(utils.deepEqual(null, {})).toBe(false);
|
|
52
|
-
|
|
53
|
-
// Undefined compared to object
|
|
54
|
-
expect(utils.deepEqual(undefined, {})).toBe(false);
|
|
55
|
-
});
|
|
56
|
-
});
|
package/src/core-utils.ts
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
function includes<T extends U, U> (arr : Array<T>, t : U) : t is U {
|
|
2
|
-
return arr === undefined ? false : arr.includes(t as T)
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export function isNonNullObject(data : any) : boolean {
|
|
6
|
-
if(data === null || data === undefined){
|
|
7
|
-
return false
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const dataType = typeof data
|
|
11
|
-
return dataType === 'object' && !Array.isArray(data)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
function isBlank(s : string) : boolean {
|
|
16
|
-
return s === null || s === undefined || s.trim() === ""
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function isDefined(data : any) : boolean {
|
|
20
|
-
return data !== null && data !== undefined
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function isNotDefined(data : any) : boolean {
|
|
24
|
-
return ! isDefined(data)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function isNullish(o : any) : o is (null | undefined) {
|
|
28
|
-
return o === null || o === undefined
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function isEmptyObject(object : Record<any, any> ) {
|
|
32
|
-
for (const property in object) {
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
return true;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function equalSet(a : Set<unknown>, b : Set<unknown>){
|
|
39
|
-
return a.size === b.size && [...a].every((x) => b.has(x));
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export type EqualFn<T> = (a:T, b:T) => boolean
|
|
43
|
-
export const DEFAULT_EQUAL_FN : EqualFn<any> = (a, b) => a === b
|
|
44
|
-
|
|
45
|
-
export function areSameDefined<T>(a : T | undefined, b: T | undefined, equalFn? : EqualFn<T>) : boolean {
|
|
46
|
-
if(a === undefined || b === undefined){
|
|
47
|
-
return false
|
|
48
|
-
}
|
|
49
|
-
if(a === null || b === null){
|
|
50
|
-
return false
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return a === b || (equalFn ? equalFn(a, b) : false)
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Warning: non performant O(n2)
|
|
57
|
-
* @param arr
|
|
58
|
-
* @param equals
|
|
59
|
-
*/
|
|
60
|
-
export function removeDuplicates<T>(arr : T[], equals : EqualFn<T> = DEFAULT_EQUAL_FN) : T[] {
|
|
61
|
-
return arr.filter((item, index) => arr.findIndex((e,i) => i < index && equals(item, e)) === -1)
|
|
62
|
-
}
|
|
63
|
-
// export function removeDuplicatesAndUndefined<T>(arr : (T|undefined)[], equals : EqualFn<T> = DEFAULT_EQUAL_FN) : T[] {
|
|
64
|
-
// return arr.filter((item, index) : item is T => item !== undefined && arr.findIndex((e,i) => i < index && equals(item, e)) === -1)
|
|
65
|
-
// }
|
|
66
|
-
|
|
67
|
-
function intersection<T>(o1 : Record<string, T>, o2 : Record<string, T>) {
|
|
68
|
-
return Object.keys(o1).filter({}.hasOwnProperty.bind(o2));
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function deepEqual(obj1: any, obj2: any): boolean {
|
|
72
|
-
if (obj1 === obj2) {
|
|
73
|
-
return true;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (obj1 === null || obj2 === null || typeof obj1 !== 'object' || typeof obj2 !== 'object') {
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (Array.isArray(obj1) !== Array.isArray(obj2)) {
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const keys1 = Object.keys(obj1);
|
|
85
|
-
const keys2 = Object.keys(obj2);
|
|
86
|
-
|
|
87
|
-
if (keys1.length !== keys2.length) {
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
for (const key of keys1) {
|
|
92
|
-
if (!keys2.includes(key)) {
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (!deepEqual(obj1[key], obj2[key])) {
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return true;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function escapeForXPath(input: string): string {
|
|
105
|
-
if (input.includes("'")) {
|
|
106
|
-
if (input.includes('"')) {
|
|
107
|
-
// Si la chaîne contient à la fois des guillemets simples et doubles
|
|
108
|
-
const parts = input.split("'");
|
|
109
|
-
return "concat(" + parts.map(part => `'${part}'`).join(", \"'\", ") + ")";
|
|
110
|
-
} else {
|
|
111
|
-
// Si la chaîne ne contient que des guillemets simples
|
|
112
|
-
return `"${input}"`;
|
|
113
|
-
}
|
|
114
|
-
} else {
|
|
115
|
-
// Si la chaîne ne contient que des guillemets doubles ou aucun guillemet
|
|
116
|
-
return `'${input}'`;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export type ArrayFilterFn<T> = (value:T, index : number, array : Array<T>) => boolean
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
// TODO rename this function
|
|
124
|
-
function cascadeFilter<T>(arr : Array<T>, fns : ArrayFilterFn<T>[]) : Array<T> {
|
|
125
|
-
if(arr.length === 0){
|
|
126
|
-
return arr
|
|
127
|
-
} else {
|
|
128
|
-
for (const filterFn of fns) {
|
|
129
|
-
const filtered = arr.filter(filterFn)
|
|
130
|
-
if(filtered.length > 0){
|
|
131
|
-
return filtered
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return arr
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
export const utils = {includes, isNonNullObject, isEmptyObject, equalSet, isDefined, isBlank, isNotDefined, removeDuplicates, areSameDefined, intersection, deepEqual, escapeForXPath, cascadeFilter}
|
|
139
|
-
|
package/src/index.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
// Type utilities
|
|
2
|
-
export * from './core-utils-types-hkt';
|
|
3
|
-
export * from './core-utils-types';
|
|
4
|
-
|
|
5
|
-
// Stack utilities
|
|
6
|
-
export type { StackElement } from './core-utils-stack';
|
|
7
|
-
export { default } from './core-utils-stack';
|
|
8
|
-
|
|
9
|
-
// Core utilities
|
|
10
|
-
export { utils, DEFAULT_EQUAL_FN, removeDuplicates, areSameDefined } from './core-utils';
|
|
11
|
-
export type { EqualFn } from './core-utils';
|
|
12
|
-
|
|
13
|
-
// Resolvers
|
|
14
|
-
export * from './core-utils-resolver';
|
|
15
|
-
|
|
16
|
-
// Path and navigation utilities
|
|
17
|
-
export * from './core-utils-pathway';
|
|
18
|
-
export * from './core-utils-pathway-resolver';
|
|
19
|
-
|
|
20
|
-
// Itinerary utilities
|
|
21
|
-
export * from './itinerary/itinerary';
|
|
22
|
-
export * from './itinerary/stack';
|
|
23
|
-
// Note: HyperLayerNode is exported from core-utils-types (more complete version with HKT)
|
|
24
|
-
|
|
25
|
-
// Filesystem utilities
|
|
26
|
-
export * from './core-utils-filesystem';
|
|
27
|
-
|
|
28
|
-
// Other utilities
|
|
29
|
-
export * from './core-utils-file';
|
|
30
|
-
export * from './core-utils-registry';
|
|
31
|
-
export * from './core-utils-chrono';
|
|
32
|
-
export * from './core-utils-comparator';
|
|
33
|
-
export * from './core-utils-fqn';
|
|
34
|
-
export * from './core-utils-validations';
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export interface HyperLayerNode<T> {
|
|
2
|
-
keys?: Record<PropertyKey, any> // Keys to use for property based navigation when applicable
|
|
3
|
-
data? : T
|
|
4
|
-
children? : Record<string, HyperLayerNode<T>> | Array<HyperLayerNode<T>>
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function hyper<T>(data : T, children?: Record<string, HyperLayerNode<T>> | Array<HyperLayerNode<T>>) : HyperLayerNode<T> {
|
|
8
|
-
return {data, children}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Utility function that create Overlay which mirror original object
|
|
13
|
-
* @param o
|
|
14
|
-
*/
|
|
15
|
-
export function hyperReflect(o : any) : HyperLayerNode<any> {
|
|
16
|
-
if(o === null || o === undefined){
|
|
17
|
-
return hyper(o)
|
|
18
|
-
} else if (Array.isArray(o)) {
|
|
19
|
-
return hyper(o, o.map(e => hyperReflect(e)))
|
|
20
|
-
} else if(typeof o === "object"){
|
|
21
|
-
return hyper(o, Object.entries(o).reduce((acc, [k, v]) => ({...acc, [k] : hyperReflect(v)}), {}))
|
|
22
|
-
} else {
|
|
23
|
-
return hyper(o)
|
|
24
|
-
}
|
|
25
|
-
}
|