Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2e994b5

Browse files
committed
Add routines for merging, diffing capabilities and equality checks
1 parent daf77ed commit 2e994b5

File tree

15 files changed

+307
-187
lines changed

15 files changed

+307
-187
lines changed

.eslintrc.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ rules:
3838
- allowSeparatedGroups: true
3939
ignoreCase: true
4040
ignoreDeclarationSort: true
41+
'@typescript-eslint/ban-types': off
4142
'@typescript-eslint/explicit-module-boundary-types': off
4243
'@typescript-eslint/no-non-null-assertion': off
4344
settings:

scripts/generate-configuration.ts

Lines changed: 142 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
Configuration,
66
MeasurementTypes,
77
Properties,
8+
Property,
89
PropertyComponents,
910
TypeDefinition,
1011
TypeDefinitions,
@@ -42,6 +43,128 @@ function createConfiguration() {
4243
console.log('Successfully created configuration.');
4344
}
4445

46+
export const getPropertyIdentityKey = (capabilityName: string) => (propertyName: string) => {
47+
switch (capabilityName) {
48+
case 'adas':
49+
switch (propertyName) {
50+
case 'lane_keep_assists_states':
51+
case 'park_assists':
52+
return 'location';
53+
}
54+
55+
case 'charging':
56+
switch (propertyName) {
57+
case 'departure_times':
58+
return 'state';
59+
case 'reduction_times':
60+
return 'start_stop';
61+
}
62+
63+
case 'chassis_settings':
64+
switch (propertyName) {
65+
case 'current_spring_rates':
66+
case 'maximum_spring_rates':
67+
case 'minimum_spring_rates':
68+
return 'axle';
69+
}
70+
71+
case 'climate':
72+
switch (propertyName) {
73+
case 'hvac_weekday_starting_times':
74+
return 'weekday';
75+
}
76+
77+
case 'crash':
78+
switch (propertyName) {
79+
case 'incidents':
80+
return 'location';
81+
}
82+
83+
case 'dashboard_lights':
84+
switch (propertyName) {
85+
case 'bulb_failures':
86+
return 'id';
87+
case 'dashboard_lights':
88+
return 'name';
89+
}
90+
91+
case 'diagnostics':
92+
switch (propertyName) {
93+
case 'diesel_exhaust_filter_status':
94+
return 'status';
95+
96+
case 'tire_pressures':
97+
case 'tire_pressures_differences':
98+
case 'tire_pressure_statuses':
99+
case 'tire_pressures_targets':
100+
case 'tire_temperatures':
101+
case 'wheel_rpms':
102+
return 'location';
103+
}
104+
105+
case 'doors':
106+
switch (propertyName) {
107+
case 'inside_locks':
108+
case 'locks':
109+
case 'positions':
110+
return 'location';
111+
}
112+
113+
case 'lights':
114+
switch (propertyName) {
115+
case 'fog_lights':
116+
case 'interior_lights':
117+
case 'reading_lamps':
118+
return 'location';
119+
}
120+
121+
case 'race':
122+
switch (propertyName) {
123+
case 'accelerations':
124+
return 'direction';
125+
case 'brake_torque_vectorings':
126+
return 'axle';
127+
}
128+
129+
case 'seats':
130+
switch (propertyName) {
131+
case 'person_detected':
132+
case 'seatbelts_state':
133+
return 'location';
134+
}
135+
136+
case 'tachograph':
137+
switch (propertyName) {
138+
case 'drivers_cards_present':
139+
case 'drivers_working_states':
140+
case 'drivers_time_states':
141+
return 'driver_number';
142+
}
143+
144+
case 'trips':
145+
switch (propertyName) {
146+
case 'end_address_components':
147+
case 'start_address_components':
148+
case 'thresholds':
149+
return 'type';
150+
}
151+
152+
case 'usage':
153+
switch (propertyName) {
154+
case 'driving_modes_activation_periods':
155+
case 'driving_modes_energy_consumptions':
156+
return 'driving_mode';
157+
}
158+
159+
case 'windows':
160+
switch (propertyName) {
161+
case 'open_percentages':
162+
case 'positions':
163+
return 'location';
164+
}
165+
}
166+
};
167+
45168
function mapStateProps({
46169
properties,
47170
state,
@@ -53,6 +176,20 @@ function mapStateProps({
53176
return [];
54177
}
55178

179+
function mapPropertyIdentityKeys(identityKeyFn: (name: string) => string | undefined) {
180+
return function (property: Property) {
181+
const key = identityKeyFn(property.name);
182+
if (key) {
183+
return {
184+
...property,
185+
identity_key: key,
186+
};
187+
}
188+
189+
return property;
190+
};
191+
}
192+
56193
function mapTypesToEntity<T extends TypeDefinition>(entity: T) {
57194
return {
58195
...entity,
@@ -76,11 +213,15 @@ function parseCapabilities() {
76213
return CapabilitiesFileList.reduce<Configuration['capabilities']>(
77214
(configurationObject, fileName) => {
78215
const capability = parseYmlFile<Capability>(`${CapabilitiesPath}/${fileName}`);
216+
const identityKeyFn = getPropertyIdentityKey(capability.name);
217+
79218
return {
80219
...configurationObject,
81220
[capability.name]: {
82221
...capability,
83-
properties: capability.properties.map((property) => mapTypesToEntity(property)),
222+
properties: capability.properties
223+
.map(mapTypesToEntity)
224+
.map(mapPropertyIdentityKeys(identityKeyFn)),
84225
state: mapStateProps(capability),
85226
},
86227
};

src/configuration/configuration.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

src/core/Capability.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import { FormatError, InvalidCommandError } from './Error';
1414
import { NamedEntity } from './NamedEntity';
1515
import { Property } from './Property';
1616
import { Serializable } from './Serializable';
17-
1817
interface CapabilityEncodeDecodeOptions {
1918
bytesAsPropertyIds?: boolean;
2019
}
@@ -59,6 +58,35 @@ export abstract class Capability<P extends string = string>
5958
return this;
6059
}
6160

61+
public diff(capability: Capability<P>) {
62+
const instance = new (Object.getPrototypeOf(this).constructor)(
63+
this.definition,
64+
this.universalProperties,
65+
) as Capability<P>;
66+
67+
const properties = capability
68+
.getPropertiesArray()
69+
.reduce<Property[]>((properties, property) => {
70+
if (this.hasProperty(property.name as P)) {
71+
const ref = this.findProperty(property);
72+
if (ref && ref.equals(property)) {
73+
return properties;
74+
}
75+
}
76+
77+
return [...properties, property];
78+
}, []);
79+
80+
for (const property of properties) {
81+
instance.createPropertyFromJSON(
82+
property.name as P,
83+
property.toJSON() as Partial<Record<ComponentName, unknown>>,
84+
);
85+
}
86+
87+
return instance;
88+
}
89+
6290
public encode(options?: CapabilityEncodeDecodeOptions) {
6391
const properties = this.getPropertiesArray();
6492
if (options && options.bytesAsPropertyIds) {
@@ -133,6 +161,16 @@ export abstract class Capability<P extends string = string>
133161
return property;
134162
}
135163

164+
public findProperty(property: Property): Property | undefined {
165+
if (this.hasProperty(property.name as P)) {
166+
if (property.multiple) {
167+
return this.getProperties(property.name as P).find((ref) => ref.isInstanceOf(property));
168+
} else {
169+
return this.getProperty(property.name as P);
170+
}
171+
}
172+
}
173+
136174
public getProperties(name: P) {
137175
return getArray(this.properties[name] || []);
138176
}

src/core/Property.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ComponentName } from '../components/classes';
22
import { Property as IProperty } from '../types';
33
import { PropertyComponentFactory } from '../factories/PropertyComponentFactory';
44

5-
import { bytesToChunks, bytesWithSize, isEmptyObject } from '../utils';
5+
import { bytesToChunks, bytesWithSize, comparePropertyIdentity, isEmptyObject } from '../utils';
66

77
import { FormatError, InvalidCommandError } from './Error';
88
import { NamedEntity } from './NamedEntity';
@@ -41,6 +41,18 @@ export class Property extends Serializable implements NamedEntity {
4141
return [this.id, ...bytesWithSize(bytes)];
4242
}
4343

44+
public equals(property: Property) {
45+
return (['availability', 'data', 'failure', 'timestamp'] as ComponentName[]).every(
46+
(component) => {
47+
if (this.hasComponent(component) && property.hasComponent(component)) {
48+
return this.getComponent(component).equals(property.getComponent(component));
49+
}
50+
51+
return this.components[component] === property.components[component];
52+
},
53+
);
54+
}
55+
4456
public fromJSON(payload: Record<string, unknown>) {
4557
try {
4658
for (const [componentName, componentAsJSON] of Object.entries(payload)) {
@@ -57,6 +69,10 @@ export class Property extends Serializable implements NamedEntity {
5769
return this.definition.id;
5870
}
5971

72+
public get identityKey() {
73+
return this.definition.identity_key;
74+
}
75+
6076
public get multiple() {
6177
return !!this.definition.multiple;
6278
}
@@ -83,6 +99,24 @@ export class Property extends Serializable implements NamedEntity {
8399
return !!this.components[name];
84100
}
85101

102+
public isInstanceOf(property: Property) {
103+
const { identityKey, multiple } = property;
104+
if (property instanceof Object.getPrototypeOf(this).constructor) {
105+
if (multiple && identityKey) {
106+
if ([this, property].every((p) => p.hasComponent('data'))) {
107+
const [a, b] = [this, property].map((p) => p.valueOf() || {});
108+
return comparePropertyIdentity(a, b, identityKey);
109+
}
110+
111+
return false;
112+
}
113+
114+
return true;
115+
}
116+
117+
return false;
118+
}
119+
86120
public toJSON() {
87121
return this.valueOf();
88122
}

src/core/PropertyComponent.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,18 @@ export abstract class PropertyComponent extends Serializable implements NamedEnt
3838
return [this.id, ...bytesWithSize(this._value.encode())];
3939
}
4040

41+
public equals(component: PropertyComponent) {
42+
if (component.name === this.name) {
43+
if (this.value && component.value) {
44+
return this.value.equals(component.value);
45+
}
46+
47+
return this.value === component.value;
48+
}
49+
50+
return false;
51+
}
52+
4153
public fromJSON(payload: unknown) {
4254
(this.value || this.createValue()).fromJSON(payload);
4355
return this;

src/core/Value.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ export abstract class Value<D = unknown, S = D> extends Serializable {
99

1010
public abstract setValue(value: S): this;
1111

12+
public equals(value: Value<D, S>) {
13+
return this.value === value.value;
14+
}
15+
1216
public toJSON() {
1317
return { value: this.valueOf() };
1418
}

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export interface Property extends Omit<TypeDefinition, 'items'> {
6060
deprecated?: DeprecationInfo;
6161
description?: string;
6262
examples: PropertyExamples;
63+
identity_key?: string;
6364
multiple?: boolean;
6465
}
6566

src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './encoding';
22
export * from './json';
33
export * from './misc';
4+
export * from './state';
45
export * from './strings';

0 commit comments

Comments
 (0)