Skip to content

Commit 585d732

Browse files
yogevbdguyca
andauthored
Fix option processors (#6428)
* Fix option processors * Change `commandName` type to `CommandName` Co-authored-by: Guy Carmeli <[email protected]>
1 parent 2938c4c commit 585d732

File tree

8 files changed

+81
-41
lines changed

8 files changed

+81
-41
lines changed

lib/src/Navigation.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { Deprecations } from './commands/Deprecations';
2525
import { ProcessorSubscription } from './interfaces/ProcessorSubscription';
2626
import { LayoutProcessor } from './processors/LayoutProcessor';
2727
import { LayoutProcessorsStore } from './processors/LayoutProcessorsStore';
28+
import { CommandName } from './interfaces/CommandName';
2829

2930
export class NavigationRoot {
3031
public readonly TouchablePreview = TouchablePreview;
@@ -115,7 +116,7 @@ export class NavigationRoot {
115116
*/
116117
public addOptionProcessor<T>(
117118
optionPath: string,
118-
processor: (value: T, commandName: string) => T
119+
processor: (value: T, commandName: CommandName) => T
119120
): ProcessorSubscription {
120121
return this.optionProcessorsStore.addProcessor(optionPath, processor);
121122
}
@@ -124,7 +125,7 @@ export class NavigationRoot {
124125
* Method to be invoked when a layout is processed and is about to be created. This can be used to change layout options or even inject props to components.
125126
*/
126127
public addLayoutProcessor(
127-
processor: (layout: Layout, commandName: string) => Layout
128+
processor: (layout: Layout, commandName: CommandName) => Layout
128129
): ProcessorSubscription {
129130
return this.layoutProcessorsStore.addProcessor(processor);
130131
}

lib/src/commands/LayoutTreeCrawler.test.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ import { Store } from '../components/Store';
66
import { mock, instance, verify, deepEqual, when } from 'ts-mockito';
77
import { OptionsProcessor } from './OptionsProcessor';
88
import { Options } from '../interfaces/Options';
9+
import { CommandName } from '../interfaces/CommandName';
910

1011
describe('LayoutTreeCrawler', () => {
1112
let uut: LayoutTreeCrawler;
1213
let mockedStore: Store;
1314
let mockedOptionsProcessor: OptionsProcessor;
14-
const setRootCommandName = 'setRoot';
1515
beforeEach(() => {
1616
mockedStore = mock(Store);
1717
mockedOptionsProcessor = mock(OptionsProcessor);
@@ -33,7 +33,7 @@ describe('LayoutTreeCrawler', () => {
3333
],
3434
data: {},
3535
};
36-
uut.crawl(node, setRootCommandName);
36+
uut.crawl(node, CommandName.SetRoot);
3737
verify(mockedStore.updateProps('testId', deepEqual({ myProp: 123 }))).called();
3838
});
3939

@@ -52,7 +52,7 @@ describe('LayoutTreeCrawler', () => {
5252
data: { name: 'theComponentName', options: {} },
5353
children: [],
5454
};
55-
uut.crawl(node, setRootCommandName);
55+
uut.crawl(node, CommandName.SetRoot);
5656
expect(node.data.options).toEqual({ popGesture: true });
5757
});
5858

@@ -71,7 +71,7 @@ describe('LayoutTreeCrawler', () => {
7171
data: { name: 'theComponentName', options: {}, passProps: { title: 'title' } },
7272
children: [],
7373
};
74-
uut.crawl(node, setRootCommandName);
74+
uut.crawl(node, CommandName.SetRoot);
7575
expect(node.data.options).toEqual({ topBar: { title: { text: 'title' } } });
7676

7777
const node2 = {
@@ -80,7 +80,7 @@ describe('LayoutTreeCrawler', () => {
8080
data: { name: 'theComponentName', options: {} },
8181
children: [],
8282
};
83-
uut.crawl(node2, setRootCommandName);
83+
uut.crawl(node2, CommandName.SetRoot);
8484
expect(node2.data.options).toEqual({ topBar: { title: {} } });
8585
});
8686

@@ -112,7 +112,7 @@ describe('LayoutTreeCrawler', () => {
112112
children: [],
113113
};
114114

115-
uut.crawl(node, setRootCommandName);
115+
uut.crawl(node, CommandName.SetRoot);
116116

117117
expect(node.data.options).toEqual({
118118
aaa: 'exists only in passed',
@@ -124,7 +124,7 @@ describe('LayoutTreeCrawler', () => {
124124

125125
it('Components: must contain data name', () => {
126126
const node = { type: LayoutType.Component, data: {}, children: [], id: 'testId' };
127-
expect(() => uut.crawl(node, setRootCommandName)).toThrowError('Missing component data.name');
127+
expect(() => uut.crawl(node, CommandName.SetRoot)).toThrowError('Missing component data.name');
128128
});
129129

130130
it('Components: options default obj', () => {
@@ -138,7 +138,7 @@ describe('LayoutTreeCrawler', () => {
138138
data: { name: 'theComponentName', options: {} },
139139
children: [],
140140
};
141-
uut.crawl(node, setRootCommandName);
141+
uut.crawl(node, CommandName.SetRoot);
142142
expect(node.data.options).toEqual({});
143143
});
144144

@@ -152,7 +152,7 @@ describe('LayoutTreeCrawler', () => {
152152
},
153153
children: [],
154154
};
155-
uut.crawl(node, setRootCommandName);
155+
uut.crawl(node, CommandName.SetRoot);
156156
expect(node.data.passProps).toBeUndefined();
157157
});
158158
});

lib/src/commands/LayoutTreeCrawler.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { LayoutType } from './LayoutType';
44
import { OptionsProcessor } from './OptionsProcessor';
55
import { Store } from '../components/Store';
66
import { Options } from '../interfaces/Options';
7+
import { CommandName } from '../interfaces/CommandName';
78

89
export interface Data {
910
name?: string;
@@ -24,7 +25,7 @@ export class LayoutTreeCrawler {
2425
this.crawl = this.crawl.bind(this);
2526
}
2627

27-
crawl(node: LayoutNode, commandName: string): void {
28+
crawl(node: LayoutNode, commandName: CommandName): void {
2829
if (node.type === LayoutType.Component) {
2930
this.handleComponent(node);
3031
}

lib/src/commands/OptionsProcessor.test.ts

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import { mock, when, anyString, instance, anyNumber, verify } from 'ts-mockito';
77
import { ColorService } from '../adapters/ColorService';
88
import { AssetService } from '../adapters/AssetResolver';
99
import { Deprecations } from './Deprecations';
10+
import { CommandName } from '../interfaces/CommandName';
1011

1112
describe('navigation options', () => {
1213
let uut: OptionsProcessor;
1314
let optionProcessorsRegistry: OptionProcessorsStore;
1415
const mockedStore = mock(Store) as Store;
1516
const store = instance(mockedStore) as Store;
16-
const setRootCommandName = 'setRoot';
1717
beforeEach(() => {
1818
const mockedAssetService = mock(AssetService) as AssetService;
1919
when(mockedAssetService.resolveFromRequire(anyNumber())).thenReturn({
@@ -45,7 +45,7 @@ describe('navigation options', () => {
4545
modalPresentationStyle: OptionsModalPresentationStyle.fullScreen,
4646
animations: { dismissModal: { alpha: { from: 0, to: 1 } } },
4747
};
48-
uut.processOptions(options, setRootCommandName);
48+
uut.processOptions(options, CommandName.SetRoot);
4949
expect(options).toEqual({
5050
blurOnUnmount: false,
5151
popGesture: false,
@@ -65,14 +65,43 @@ describe('navigation options', () => {
6565
return !value;
6666
});
6767

68-
uut.processOptions(options, setRootCommandName);
68+
uut.processOptions(options, CommandName.SetRoot);
6969
expect(options).toEqual({
7070
topBar: {
7171
visible: false,
7272
},
7373
});
7474
});
7575

76+
it('process options object with multiple values using registered processor', () => {
77+
const options: Options = {
78+
topBar: {
79+
visible: true,
80+
background: {
81+
translucent: true,
82+
},
83+
},
84+
};
85+
86+
optionProcessorsRegistry.addProcessor('topBar.visible', (value: boolean) => {
87+
return !value;
88+
});
89+
90+
optionProcessorsRegistry.addProcessor('topBar.background.translucent', (value: boolean) => {
91+
return !value;
92+
});
93+
94+
uut.processOptions(options, CommandName.SetRoot);
95+
expect(options).toEqual({
96+
topBar: {
97+
visible: false,
98+
background: {
99+
translucent: false,
100+
},
101+
},
102+
});
103+
});
104+
76105
it('passes commandName to registered processor', () => {
77106
const options: Options = {
78107
topBar: {
@@ -81,10 +110,10 @@ describe('navigation options', () => {
81110
};
82111

83112
optionProcessorsRegistry.addProcessor('topBar.visible', (_value, commandName) => {
84-
expect(commandName).toEqual(setRootCommandName);
113+
expect(commandName).toEqual(CommandName.SetRoot);
85114
});
86115

87-
uut.processOptions(options, setRootCommandName);
116+
uut.processOptions(options, CommandName.SetRoot);
88117
});
89118

90119
it('supports multiple registered processors', () => {
@@ -97,7 +126,7 @@ describe('navigation options', () => {
97126
optionProcessorsRegistry.addProcessor('topBar.visible', () => false);
98127
optionProcessorsRegistry.addProcessor('topBar.visible', () => true);
99128

100-
uut.processOptions(options, setRootCommandName);
129+
uut.processOptions(options, CommandName.SetRoot);
101130
expect(options).toEqual({
102131
topBar: {
103132
visible: true,
@@ -110,7 +139,7 @@ describe('navigation options', () => {
110139
statusBar: { backgroundColor: 'red' },
111140
topBar: { background: { color: 'blue' } },
112141
};
113-
uut.processOptions(options, setRootCommandName);
142+
uut.processOptions(options, CommandName.SetRoot);
114143
expect(options).toEqual({
115144
statusBar: { backgroundColor: 666 },
116145
topBar: { background: { color: 666 } },
@@ -123,7 +152,7 @@ describe('navigation options', () => {
123152
rootBackgroundImage: 234,
124153
bottomTab: { icon: 345, selectedIcon: 345 },
125154
};
126-
uut.processOptions(options, setRootCommandName);
155+
uut.processOptions(options, CommandName.SetRoot);
127156
expect(options).toEqual({
128157
backgroundImage: { height: 100, scale: 1, uri: 'lol', width: 100 },
129158
rootBackgroundImage: { height: 100, scale: 1, uri: 'lol', width: 100 },
@@ -138,15 +167,15 @@ describe('navigation options', () => {
138167
const passProps = { some: 'thing' };
139168
const options = { topBar: { title: { component: { passProps, name: 'a' } } } };
140169

141-
uut.processOptions(options, setRootCommandName);
170+
uut.processOptions(options, CommandName.SetRoot);
142171

143172
verify(mockedStore.updateProps('CustomComponent1', passProps)).called();
144173
});
145174

146175
it('generates componentId for component id was not passed', () => {
147176
const options = { topBar: { title: { component: { name: 'a' } } } };
148177

149-
uut.processOptions(options, setRootCommandName);
178+
uut.processOptions(options, CommandName.SetRoot);
150179

151180
expect(options).toEqual({
152181
topBar: { title: { component: { name: 'a', componentId: 'CustomComponent1' } } },
@@ -156,7 +185,7 @@ describe('navigation options', () => {
156185
it('copies passed id to componentId key', () => {
157186
const options = { topBar: { title: { component: { name: 'a', id: 'Component1' } } } };
158187

159-
uut.processOptions(options, setRootCommandName);
188+
uut.processOptions(options, CommandName.SetRoot);
160189

161190
expect(options).toEqual({
162191
topBar: { title: { component: { name: 'a', id: 'Component1', componentId: 'Component1' } } },
@@ -167,7 +196,7 @@ describe('navigation options', () => {
167196
const passProps = { prop: 'prop' };
168197
const options = { topBar: { rightButtons: [{ passProps, id: '1' }] } };
169198

170-
uut.processOptions(options, setRootCommandName);
199+
uut.processOptions(options, CommandName.SetRoot);
171200

172201
verify(mockedStore.updateProps('1', passProps)).called();
173202
});
@@ -176,7 +205,7 @@ describe('navigation options', () => {
176205
const passProps = { prop: 'prop' };
177206
const options = { topBar: { rightButtons: [{ passProps } as any] } };
178207

179-
uut.processOptions(options, setRootCommandName);
208+
uut.processOptions(options, CommandName.SetRoot);
180209

181210
expect(options).toEqual({ topBar: { rightButtons: [{ passProps }] } });
182211
});
@@ -190,7 +219,7 @@ describe('navigation options', () => {
190219
background: { component: { name: 'helloThere2', passProps: {} } },
191220
},
192221
};
193-
uut.processOptions(options, setRootCommandName);
222+
uut.processOptions(options, CommandName.SetRoot);
194223
expect(options.topBar.rightButtons[0].passProps).toBeUndefined();
195224
expect(options.topBar.leftButtons[0].passProps).toBeUndefined();
196225
expect(options.topBar.title.component.passProps).toBeUndefined();
@@ -204,14 +233,14 @@ describe('navigation options', () => {
204233
background: { component: { name: 'helloThere2', passProps: {} } },
205234
},
206235
};
207-
uut.processOptions(options, setRootCommandName);
236+
uut.processOptions(options, CommandName.SetRoot);
208237
verify(mockedStore.ensureClassForName('helloThere1')).called();
209238
verify(mockedStore.ensureClassForName('helloThere2')).called();
210239
});
211240

212241
it('show warning on iOS when toggling bottomTabs visibility through mergeOptions', () => {
213242
jest.spyOn(console, 'warn');
214-
uut.processOptions({ bottomTabs: { visible: false } }, 'mergeOptions');
243+
uut.processOptions({ bottomTabs: { visible: false } }, CommandName.MergeOptions);
215244
expect(console.warn).toBeCalledWith(
216245
'toggling bottomTabs visibility is deprecated on iOS. For more information see https://github.com/wix/react-native-navigation/issues/6416',
217246
{

lib/src/commands/OptionsProcessor.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { AssetService } from '../adapters/AssetResolver';
1313
import { Options } from '../interfaces/Options';
1414
import { Deprecations } from './Deprecations';
1515
import { OptionProcessorsStore } from '../processors/OptionProcessorsStore';
16+
import { CommandName } from '../interfaces/CommandName';
1617

1718
export class OptionsProcessor {
1819
constructor(
@@ -24,7 +25,7 @@ export class OptionsProcessor {
2425
private deprecations: Deprecations
2526
) {}
2627

27-
public processOptions(options: Options, commandName: string) {
28+
public processOptions(options: Options, commandName: CommandName) {
2829
this.processObject(
2930
options,
3031
clone(options),
@@ -35,7 +36,7 @@ export class OptionsProcessor {
3536
);
3637
}
3738

38-
public processDefaultOptions(options: Options, commandName: string) {
39+
public processDefaultOptions(options: Options, commandName: CommandName) {
3940
this.processObject(
4041
options,
4142
clone(options),
@@ -50,12 +51,17 @@ export class OptionsProcessor {
5051
objectToProcess: object,
5152
parentOptions: object,
5253
onProcess: (key: string, parentOptions: object) => void,
53-
commandName: string,
54+
commandName: CommandName,
5455
path?: string
5556
) {
5657
forEach(objectToProcess, (value, key) => {
57-
path = this.resolveObjectPath(key, path);
58-
this.processWithRegisteredProcessor(key, value, objectToProcess, path, commandName);
58+
this.processWithRegisteredProcessor(
59+
key,
60+
value,
61+
objectToProcess,
62+
this.resolveObjectPath(key, path),
63+
commandName
64+
);
5965
this.processColor(key, value, objectToProcess);
6066

6167
if (!value) {
@@ -69,6 +75,7 @@ export class OptionsProcessor {
6975
onProcess(key, parentOptions);
7076

7177
if (!isEqual(key, 'passProps') && (isObject(value) || isArray(value))) {
78+
path = this.resolveObjectPath(key, path);
7279
this.processObject(value, parentOptions, onProcess, commandName, path);
7380
}
7481
});
@@ -91,7 +98,7 @@ export class OptionsProcessor {
9198
value: string,
9299
options: Record<string, any>,
93100
path: string,
94-
commandName: string
101+
commandName: CommandName
95102
) {
96103
const registeredProcessors = this.optionProcessorsRegistry.getProcessors(path);
97104
if (registeredProcessors) {

lib/src/interfaces/Processors.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { Layout } from './Layout';
2+
import { CommandName } from './CommandName';
23

34
export interface LayoutProcessor {
4-
(layout: Layout<{}>, commandName: string): Layout<{}>;
5+
(layout: Layout<{}>, commandName: CommandName): Layout<{}>;
56
}
67

78
export interface OptionsProcessor<T> {
8-
(value: T, commandName: string): T;
9+
(value: T, commandName: CommandName): T;
910
}

0 commit comments

Comments
 (0)