-
Notifications
You must be signed in to change notification settings - Fork 0
/
rules.js
80 lines (68 loc) · 2.02 KB
/
rules.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
"use strict";
const { createSetter, createDummySetter } = require("./setter");
const numberRegexp = /^\d+$/;
function expressionLens(expression) {
const regexp = new RegExp("^" + expression
.replace(/\./g, "\\.") //dots are textual dots
.replace(/\[\]/g, "(\\d+)") //square brackets match any index in an array, it creates a capturing group
.replace(/\*/g, "([\\w\\d\\.]+)") + "$"); //star match any piece of path, it creates a capturing group
const lens = path => path.join(".").match(regexp);
lens.replace = (path, by) => path.join(".").replace(regexp, by);
return lens;
}
/**
* A transformation determines how a value associated to a certain path of the
* `original object` will be treated. It does that by replacing the
* original setter object that will be used to set the value into
* such path of the `target object` by a different implementation.
*
* Every transformation is associated to a matcher which determines if a given
* path need to be intercepted by this transformation or not.
*/
class Transformation {
constructor({ path }) {
this.matcher = expressionLens(path);
}
wrap(setter) {
return this.matcher(setter.propertyPath)
? this.apply(setter)
: setter;
}
}
/**
* If applies replaces the setter for a dummy setter
*/
class ExcludeTransformation extends Transformation {
apply(setter) {
return createDummySetter(setter.propertyPath);
}
}
class MapTransformation extends Transformation {
constructor({ path, fn }) {
super({ path });
this.fn = fn;
}
apply(setter) {
return setter.intercept(this.fn)
}
}
/**
* If applies replaces the setter for a dummy setter
*/
class RenameTransformation extends Transformation {
constructor({ path, toPath }) {
super({ path });
this.toPath = toPath;
}
apply(setter) {
const replacedPath = this.matcher
.replace(setter.propertyPath, this.toPath)
.split(".").map(x => x.match(numberRegexp) ? parseInt(x) : x);
return createSetter(replacedPath);
}
}
module.exports = {
ExcludeTransformation,
RenameTransformation,
MapTransformation
}