Skip to content

Commit d13865d

Browse files
committed
sail said to not actually use the code of this commit
1 parent e8c3d09 commit d13865d

File tree

4 files changed

+671
-0
lines changed

4 files changed

+671
-0
lines changed

src/utils/prop/PropAccess.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
export enum PROP_ACCESS_TYPE {
2+
OBJECT = 'object',
3+
ARRAY = 'array',
4+
}
5+
6+
export class PropAccessResult {
7+
parent: unknown;
8+
access: PropAccess;
9+
child: unknown;
10+
11+
constructor(parent: unknown, access: PropAccess, child: unknown) {
12+
this.parent = parent;
13+
this.access = access;
14+
this.child = child;
15+
}
16+
}
17+
18+
function accessGet(obj: unknown, prop: string): unknown {
19+
// @ts-ignore
20+
return obj[prop];
21+
}
22+
23+
function accessSet(obj: unknown, prop: string, value: unknown): void {
24+
// @ts-ignore
25+
obj[prop] = value;
26+
}
27+
28+
export class PropAccess {
29+
type: PROP_ACCESS_TYPE;
30+
prop: string;
31+
index: number;
32+
33+
constructor(type: PROP_ACCESS_TYPE, prop: string) {
34+
this.type = type;
35+
this.prop = type === PROP_ACCESS_TYPE.OBJECT ? prop : '';
36+
this.index = type === PROP_ACCESS_TYPE.ARRAY ? Number(prop) : 0;
37+
38+
if (Number.isNaN(this.index)) {
39+
throw new Error('can not access array with non number index');
40+
}
41+
}
42+
43+
get(obj: unknown): PropAccessResult {
44+
if (this.type === PROP_ACCESS_TYPE.OBJECT) {
45+
if (typeof obj !== 'object' || obj == null) {
46+
throw new Error('can not access property of non-object');
47+
}
48+
49+
return new PropAccessResult(obj, this, accessGet(obj, this.prop));
50+
} else {
51+
if (typeof obj !== 'object' || obj == null || !Array.isArray(obj)) {
52+
throw new Error('can not access property of non-array');
53+
}
54+
55+
return new PropAccessResult(obj, this, obj[this.index]);
56+
}
57+
}
58+
59+
set(obj: unknown, value: unknown): void {
60+
if (this.type === PROP_ACCESS_TYPE.OBJECT) {
61+
if (typeof obj !== 'object' || obj == null) {
62+
throw new Error('can not access property of non-object');
63+
}
64+
65+
accessSet(obj, this.prop, value);
66+
} else {
67+
if (typeof obj !== 'object' || obj == null || !Array.isArray(obj)) {
68+
throw new Error('can not access property of non-array');
69+
}
70+
71+
obj[this.index] = value;
72+
}
73+
}
74+
75+
create(obj: unknown): void {
76+
if (this.type === PROP_ACCESS_TYPE.OBJECT) {
77+
if (typeof obj !== 'object' || obj == null) {
78+
throw new Error('can not access property of non-object');
79+
}
80+
81+
accessSet(obj, this.prop, undefined);
82+
} else {
83+
if (typeof obj !== 'object' || obj == null || !Array.isArray(obj)) {
84+
throw new Error('can not access property of non-array');
85+
}
86+
87+
obj[this.index] = undefined;
88+
}
89+
}
90+
}

src/utils/prop/PropPath.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { PropAccess, PropAccessResult } from './PropAccess';
2+
3+
export class PropPath {
4+
path: PropAccess[];
5+
6+
constructor(path: PropAccess[]) {
7+
this.path = path;
8+
}
9+
10+
get(obj: unknown): PropAccessResult {
11+
if (this.path.length === 0) {
12+
throw new Error('can not use empty path to access object');
13+
}
14+
15+
let result = this.path[0].get(obj);
16+
17+
for (let access of this.path.slice(1)) {
18+
result = access.get(result.child);
19+
}
20+
21+
return result;
22+
}
23+
24+
tryGet(obj: unknown): PropAccessResult | undefined {
25+
try {
26+
return this.get(obj);
27+
} catch (e) {
28+
console.error(e);
29+
return undefined;
30+
}
31+
}
32+
33+
set(obj: unknown, value: unknown): void {
34+
if (this.path.length === 0) {
35+
throw new Error('can not use empty path to access object');
36+
}
37+
38+
let result = this.path[0].get(obj);
39+
40+
for (let access of this.path.slice(1)) {
41+
result = access.get(result.child);
42+
}
43+
44+
result.access.set(result.parent, value);
45+
}
46+
47+
setAndCreate(obj: unknown, value: unknown): void {
48+
if (this.path.length === 0) {
49+
throw new Error('can not use empty path to access object');
50+
}
51+
52+
let result = this.path[0].get(obj);
53+
54+
if (result.child === undefined) {
55+
result.access.set(result.parent, this.getNextPathElementValue(0, value));
56+
result = result.access.get(result.parent);
57+
}
58+
59+
for (let i = 1; i < this.path.length; i++) {
60+
let access = this.path[i];
61+
result = access.get(result.child);
62+
63+
if (result.child === undefined) {
64+
result.access.set(result.parent, this.getNextPathElementValue(i, value));
65+
result = result.access.get(result.parent);
66+
}
67+
}
68+
69+
result.access.set(result.parent, value);
70+
}
71+
72+
getNextPathElement(index: number): PropAccess | undefined {
73+
return this.path[index + 1];
74+
}
75+
76+
getNextPathElementValue(index: number, value: unknown): unknown {
77+
const nextPathElement = this.getNextPathElement(index);
78+
79+
if (nextPathElement === undefined) {
80+
return value;
81+
}
82+
83+
return nextPathElement.type === 'object' ? {} : [];
84+
}
85+
}

src/utils/prop/PropUtils.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { PropPath } from './PropPath';
2+
import { PropAccessResult } from './PropAccess';
3+
4+
export class PropUtils {
5+
static get(obj: unknown, path: PropPath): unknown {
6+
return path.get(obj).child;
7+
}
8+
9+
static fullGet(obj: unknown, path: PropPath): PropAccessResult {
10+
return path.get(obj);
11+
}
12+
13+
static set(obj: unknown, path: PropPath, value: unknown): void {
14+
return path.set(obj, value);
15+
}
16+
17+
static setAndCreate(obj: unknown, path: PropPath, value: unknown): void {
18+
return path.setAndCreate(obj, value);
19+
}
20+
}

0 commit comments

Comments
 (0)