UNPKG

3.96 kBPlain TextView Raw
1import {camelCase} from 'lodash'
2import {StructureNode, SerializeOptions, Serializable, Child} from './StructureNodes'
3import {Layout, layoutOptions} from './Layout'
4import {MenuItem, MenuItemBuilder, maybeSerializeMenuItem} from './MenuItem'
5import {MenuItemGroup, MenuItemGroupBuilder, maybeSerializeMenuItemGroup} from './MenuItemGroup'
6import {IntentChecker} from './Intent'
7import {SerializeError} from './SerializeError'
8
9function noChildResolver() {
10 return undefined
11}
12
13export interface ListDisplayOptions {
14 showIcons?: boolean
15}
16
17export interface BaseGenericList extends StructureNode {
18 defaultLayout?: Layout
19 canHandleIntent?: IntentChecker
20 displayOptions?: ListDisplayOptions
21 child: Child
22}
23
24// "POJO"/verbatim-version - end result
25export interface GenericList extends BaseGenericList {
26 type: string
27 menuItems: MenuItem[]
28 menuItemGroups: MenuItemGroup[]
29}
30
31// Used internally in builder classes to make everything optional
32export interface BuildableGenericList extends Partial<BaseGenericList> {
33 menuItems?: (MenuItem | MenuItemBuilder)[]
34 menuItemGroups?: (MenuItemGroup | MenuItemGroupBuilder)[]
35}
36
37// Input version, allows builders and only requires things not inferrable
38export interface GenericListInput extends StructureNode {
39 id: string
40 title: string
41 menuItems?: (MenuItem | MenuItemBuilder)[]
42 menuItemGroups?: (MenuItemGroup | MenuItemGroupBuilder)[]
43 defaultLayout?: Layout
44 canHandleIntent?: IntentChecker
45 child?: Child
46}
47
48export abstract class GenericListBuilder<L extends BuildableGenericList, ConcreteImpl>
49 implements Serializable {
50 protected spec: L = {} as L
51
52 id(id: string) {
53 return this.clone({id})
54 }
55
56 getId() {
57 return this.spec.id
58 }
59
60 title(title: string) {
61 return this.clone({title, id: this.spec.id || camelCase(title)})
62 }
63
64 getTitle() {
65 return this.spec.title
66 }
67
68 defaultLayout(defaultLayout: Layout) {
69 return this.clone({defaultLayout})
70 }
71
72 getDefaultLayout() {
73 return this.spec.defaultLayout
74 }
75
76 menuItems(menuItems: (MenuItem | MenuItemBuilder)[]) {
77 return this.clone({menuItems})
78 }
79
80 getMenuItems() {
81 return this.spec.menuItems
82 }
83
84 menuItemGroups(menuItemGroups: (MenuItemGroup | MenuItemGroupBuilder)[]) {
85 return this.clone({menuItemGroups})
86 }
87
88 getMenuItemGroups() {
89 return this.spec.menuItemGroups
90 }
91
92 child(child: Child) {
93 return this.clone({child})
94 }
95
96 getChild() {
97 return this.spec.child
98 }
99
100 canHandleIntent(canHandleIntent: IntentChecker) {
101 return this.clone({canHandleIntent})
102 }
103
104 getCanHandleIntent() {
105 return this.spec.canHandleIntent
106 }
107
108 showIcons(enabled: boolean) {
109 return this.clone({
110 displayOptions: {...(this.spec.displayOptions || {}), showIcons: enabled}
111 })
112 }
113
114 getShowIcons() {
115 return this.spec.displayOptions ? this.spec.displayOptions.showIcons : undefined
116 }
117
118 serialize(options: SerializeOptions = {path: []}): GenericList {
119 const id = this.spec.id || ''
120 const path = options.path
121
122 const defaultLayout = this.spec.defaultLayout
123 if (defaultLayout && !layoutOptions.includes(defaultLayout)) {
124 throw new SerializeError(
125 `\`layout\` must be one of ${layoutOptions.map(item => `"${item}"`).join(', ')}`,
126 path,
127 id || options.index,
128 this.spec.title
129 )
130 }
131
132 return {
133 id,
134 title: this.spec.title,
135 type: 'genericList',
136 defaultLayout,
137 child: this.spec.child || noChildResolver,
138 canHandleIntent: this.spec.canHandleIntent,
139 displayOptions: this.spec.displayOptions,
140 menuItems: (this.spec.menuItems || []).map((item, i) =>
141 maybeSerializeMenuItem(item, i, path)
142 ),
143 menuItemGroups: (this.spec.menuItemGroups || []).map((item, i) =>
144 maybeSerializeMenuItemGroup(item, i, path)
145 )
146 }
147 }
148
149 clone(withSpec?: object) {
150 const builder = new (this.constructor as {new (): ConcreteImpl})()
151 return builder
152 }
153}
154
\No newline at end of file