docusaurus-plugin-generate-schema-docs 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +42 -6
  2. package/__tests__/ExampleDataLayer.test.js +78 -155
  3. package/__tests__/__fixtures__/static/schemas/add-to-cart-event.json +4 -15
  4. package/__tests__/__fixtures__/static/schemas/choice-event.json +72 -0
  5. package/__tests__/__fixtures__/static/schemas/components/dataLayer.json +52 -54
  6. package/__tests__/__fixtures__/static/schemas/components/product.json +124 -210
  7. package/__tests__/__fixtures__/static/schemas/nested/child-event.json +10 -0
  8. package/__tests__/__fixtures__/static/schemas/nested/grandchild-a.json +9 -0
  9. package/__tests__/__fixtures__/static/schemas/nested/grandchild-b.json +9 -0
  10. package/__tests__/__fixtures__/static/schemas/nested/parent-event.json +7 -0
  11. package/__tests__/__fixtures__/static/schemas/root-any-of-event.json +34 -0
  12. package/__tests__/__fixtures__/static/schemas/root-choice-event.json +36 -0
  13. package/__tests__/__fixtures__/validateSchemas/circular-schema.json +6 -6
  14. package/__tests__/__fixtures__/validateSchemas/components/referenced.json +9 -7
  15. package/__tests__/__fixtures__/validateSchemas/invalid-example-schema.json +7 -7
  16. package/__tests__/__fixtures__/validateSchemas/main-schema-with-missing-ref.json +7 -7
  17. package/__tests__/__fixtures__/validateSchemas/main-schema-with-ref.json +7 -7
  18. package/__tests__/__fixtures__/validateSchemas/no-example-schema.json +11 -11
  19. package/__tests__/__fixtures__/validateSchemas/schema-A.json +5 -5
  20. package/__tests__/__fixtures__/validateSchemas/schema-B.json +5 -5
  21. package/__tests__/__fixtures__/validateSchemas/valid-schema.json +7 -7
  22. package/__tests__/__fixtures_versioned__/static/schemas/1.1.1/add-to-cart-event.json +44 -0
  23. package/__tests__/__fixtures_versioned__/static/schemas/1.1.1/components/dataLayer.json +56 -0
  24. package/__tests__/__fixtures_versioned__/static/schemas/1.1.1/components/product.json +125 -0
  25. package/__tests__/__fixtures_versioned__/static/schemas/next/add-to-cart-event.json +44 -0
  26. package/__tests__/__fixtures_versioned__/static/schemas/next/components/dataLayer.json +56 -0
  27. package/__tests__/__fixtures_versioned__/static/schemas/next/components/product.json +125 -0
  28. package/__tests__/__fixtures_versioned__/versions.json +1 -0
  29. package/__tests__/__snapshots__/ExampleDataLayer.test.js.snap +117 -0
  30. package/__tests__/__snapshots__/generateEventDocs.nested.test.js.snap +92 -0
  31. package/__tests__/__snapshots__/generateEventDocs.test.js.snap +113 -15
  32. package/__tests__/__snapshots__/generateEventDocs.versioned.test.js.snap +53 -0
  33. package/__tests__/components/FoldableRows.test.js +330 -0
  34. package/__tests__/components/PropertiesTable.test.js +31 -14
  35. package/__tests__/components/PropertyRow.test.js +471 -51
  36. package/__tests__/components/SchemaJsonViewer.test.js +23 -19
  37. package/__tests__/components/SchemaRows.test.js +96 -66
  38. package/__tests__/components/SchemaViewer.test.js +34 -17
  39. package/__tests__/components/TableHeader.test.js +12 -12
  40. package/__tests__/generateEventDocs.nested.test.js +80 -0
  41. package/__tests__/generateEventDocs.test.js +77 -71
  42. package/__tests__/generateEventDocs.versioned.test.js +69 -0
  43. package/__tests__/helpers/buildExampleFromSchema.test.js +160 -160
  44. package/__tests__/helpers/file-system.test.js +44 -0
  45. package/__tests__/helpers/getConstraints.test.js +48 -48
  46. package/__tests__/helpers/loadSchema.test.js +11 -5
  47. package/__tests__/helpers/path-helpers.test.js +34 -0
  48. package/__tests__/helpers/processSchema.test.js +42 -22
  49. package/__tests__/helpers/schema-processing.test.js +82 -0
  50. package/__tests__/helpers/schemaToExamples.test.js +56 -0
  51. package/__tests__/helpers/schemaToTableData.filtering.test.js +65 -0
  52. package/__tests__/helpers/schemaToTableData.hierarchicalLines.test.js +539 -0
  53. package/__tests__/helpers/schemaToTableData.test.js +222 -0
  54. package/__tests__/helpers/update-schema-ids.test.js +107 -0
  55. package/__tests__/update-schema-ids.test.js +39 -0
  56. package/__tests__/validateSchemas.test.js +125 -88
  57. package/components/ExampleDataLayer.js +59 -28
  58. package/components/FoldableRows.js +164 -0
  59. package/components/PropertiesTable.js +10 -7
  60. package/components/PropertyRow.js +169 -60
  61. package/components/SchemaJsonViewer.js +6 -6
  62. package/components/SchemaRows.css +236 -14
  63. package/components/SchemaRows.js +24 -41
  64. package/components/SchemaViewer.js +19 -13
  65. package/components/TableHeader.js +12 -12
  66. package/generateEventDocs.js +141 -61
  67. package/helpers/buildExampleFromSchema.js +58 -72
  68. package/helpers/choice-index-template.js +22 -0
  69. package/helpers/file-system.js +32 -0
  70. package/helpers/getConstraints.js +43 -44
  71. package/helpers/loadSchema.js +2 -2
  72. package/helpers/path-helpers.js +22 -0
  73. package/helpers/processSchema.js +19 -19
  74. package/helpers/{mdx-template.js → schema-doc-template.js} +12 -12
  75. package/helpers/schema-processing.js +75 -0
  76. package/helpers/schemaToExamples.js +99 -0
  77. package/helpers/schemaToTableData.js +311 -0
  78. package/helpers/update-schema-ids.js +47 -0
  79. package/index.js +143 -54
  80. package/package.json +1 -1
  81. package/validateSchemas.js +54 -71
@@ -4,64 +4,484 @@ import { render } from '@testing-library/react';
4
4
  import PropertyRow from '../../components/PropertyRow';
5
5
 
6
6
  describe('PropertyRow', () => {
7
- const getConstraints = (prop, isReq) => {
8
- const constraints = [];
9
- if (isReq) constraints.push('required');
10
- if (prop.minLength) constraints.push(`minLength: ${prop.minLength}`);
11
- if (prop.maxLength) constraints.push(`maxLength: ${prop.maxLength}`);
12
- return constraints;
7
+ it('renders a basic property', () => {
8
+ const row = {
9
+ name: 'name',
10
+ level: 0,
11
+ required: false,
12
+ propertyType: 'string',
13
+ description: 'The name of the user.',
14
+ example: 'John Doe',
15
+ constraints: [],
16
+ path: ['name'],
13
17
  };
14
18
 
15
- it('renders a basic property', () => {
16
- const prop = { type: 'string', description: 'The name of the user.' };
17
- const { getByText } = render(
18
- <table>
19
- <tbody>
20
- <PropertyRow propertyKey="name" prop={prop} requiredList={[]} getConstraints={getConstraints} />
21
- </tbody>
22
- </table>
23
- );
24
- expect(getByText('name')).toBeInTheDocument();
25
- expect(getByText('string')).toBeInTheDocument();
26
- expect(getByText('The name of the user.')).toBeInTheDocument();
19
+ const { getByText } = render(
20
+ <table>
21
+ <tbody>
22
+ <PropertyRow row={row} />
23
+ </tbody>
24
+ </table>,
25
+ );
26
+
27
+ expect(getByText('name')).toBeInTheDocument();
28
+ expect(getByText('string')).toBeInTheDocument();
29
+ expect(getByText('The name of the user.')).toBeInTheDocument();
30
+ expect(getByText('John Doe')).toBeInTheDocument();
31
+ });
32
+
33
+ it('marks required properties', () => {
34
+ const row = {
35
+ name: 'name',
36
+ level: 0,
37
+ required: true,
38
+ propertyType: 'string',
39
+ description: '',
40
+ example: '',
41
+ constraints: ['required'],
42
+ path: ['name'],
43
+ };
44
+
45
+ const { container, getByText } = render(
46
+ <table>
47
+ <tbody>
48
+ <PropertyRow row={row} />
49
+ </tbody>
50
+ </table>,
51
+ );
52
+
53
+ expect(container.querySelector('.required-row')).toBeInTheDocument();
54
+ expect(container.querySelector('.required')).toBeInTheDocument();
55
+ expect(getByText('required')).toBeInTheDocument();
56
+ });
57
+
58
+ it('renders multiple constraints', () => {
59
+ const row = {
60
+ name: 'name',
61
+ level: 0,
62
+ required: true,
63
+ propertyType: 'string',
64
+ description: '',
65
+ example: '',
66
+ constraints: ['required', 'minLength: 1', 'maxLength: 10'],
67
+ path: ['name'],
68
+ };
69
+
70
+ const { getByText } = render(
71
+ <table>
72
+ <tbody>
73
+ <PropertyRow row={row} />
74
+ </tbody>
75
+ </table>,
76
+ );
77
+ expect(getByText('required')).toBeInTheDocument();
78
+ expect(getByText('minLength: 1')).toBeInTheDocument();
79
+ expect(getByText('maxLength: 10')).toBeInTheDocument();
80
+ });
81
+
82
+ it('renders an example', () => {
83
+ const row = {
84
+ name: 'name',
85
+ level: 0,
86
+ required: false,
87
+ propertyType: 'string',
88
+ description: '',
89
+ example: 'foo',
90
+ constraints: [],
91
+ path: ['name'],
92
+ };
93
+
94
+ const { getByText } = render(
95
+ <table>
96
+ <tbody>
97
+ <PropertyRow row={row} />
98
+ </tbody>
99
+ </table>,
100
+ );
101
+ expect(getByText('foo')).toBeInTheDocument();
102
+ });
103
+
104
+ it('does not render anything for empty constraints', () => {
105
+ const row = {
106
+ name: 'name',
107
+ level: 0,
108
+ required: false,
109
+ propertyType: 'string',
110
+ description: '',
111
+ example: '',
112
+ constraints: [],
113
+ path: ['name'],
114
+ };
115
+
116
+ const { container } = render(
117
+ <table>
118
+ <tbody>
119
+ <PropertyRow row={row} />
120
+ </tbody>
121
+ </table>,
122
+ );
123
+
124
+ // The cell for constraints is the 3rd cell (index 2)
125
+ const cells = container.querySelectorAll('td');
126
+ expect(cells[2].innerHTML).toBe('');
127
+ });
128
+
129
+ describe('hierarchical lines feature', () => {
130
+ it('renders {} symbol for object containers', () => {
131
+ const row = {
132
+ name: 'user_data',
133
+ level: 0,
134
+ required: false,
135
+ propertyType: 'object',
136
+ description: '',
137
+ example: '',
138
+ constraints: [],
139
+ path: ['user_data'],
140
+ hasChildren: true,
141
+ containerType: 'object',
142
+ continuingLevels: [],
143
+ };
144
+
145
+ const { container, getByText } = render(
146
+ <table>
147
+ <tbody>
148
+ <PropertyRow row={row} />
149
+ </tbody>
150
+ </table>,
151
+ );
152
+
153
+ expect(getByText('{}')).toBeInTheDocument();
154
+ expect(container.querySelector('.container-symbol')).toBeInTheDocument();
155
+ });
156
+
157
+ it('renders [] symbol for array containers', () => {
158
+ const row = {
159
+ name: 'addresses',
160
+ level: 0,
161
+ required: false,
162
+ propertyType: 'array',
163
+ description: '',
164
+ example: '',
165
+ constraints: [],
166
+ path: ['addresses'],
167
+ hasChildren: true,
168
+ containerType: 'array',
169
+ continuingLevels: [],
170
+ };
171
+
172
+ const { container, getByText } = render(
173
+ <table>
174
+ <tbody>
175
+ <PropertyRow row={row} />
176
+ </tbody>
177
+ </table>,
178
+ );
179
+
180
+ expect(getByText('[]')).toBeInTheDocument();
181
+ expect(container.querySelector('.container-symbol')).toBeInTheDocument();
182
+ });
183
+
184
+ it('does not render container symbol for simple properties', () => {
185
+ const row = {
186
+ name: 'name',
187
+ level: 0,
188
+ required: false,
189
+ propertyType: 'string',
190
+ description: '',
191
+ example: '',
192
+ constraints: [],
193
+ path: ['name'],
194
+ hasChildren: false,
195
+ containerType: null,
196
+ continuingLevels: [],
197
+ };
198
+
199
+ const { container } = render(
200
+ <table>
201
+ <tbody>
202
+ <PropertyRow row={row} />
203
+ </tbody>
204
+ </table>,
205
+ );
206
+
207
+ expect(
208
+ container.querySelector('.container-symbol'),
209
+ ).not.toBeInTheDocument();
210
+ });
211
+
212
+ it('applies has-children class when property has children', () => {
213
+ const row = {
214
+ name: 'user_data',
215
+ level: 1,
216
+ required: false,
217
+ propertyType: 'object',
218
+ description: '',
219
+ example: '',
220
+ constraints: [],
221
+ path: ['user_data'],
222
+ hasChildren: true,
223
+ containerType: 'object',
224
+ continuingLevels: [],
225
+ };
226
+
227
+ const { container } = render(
228
+ <table>
229
+ <tbody>
230
+ <PropertyRow row={row} />
231
+ </tbody>
232
+ </table>,
233
+ );
234
+
235
+ expect(container.querySelector('.has-children')).toBeInTheDocument();
27
236
  });
28
237
 
29
- it('marks required properties', () => {
30
- const prop = { type: 'string' };
31
- const { container } = render(
32
- <table>
33
- <tbody>
34
- <PropertyRow propertyKey="name" prop={prop} requiredList={['name']} getConstraints={getConstraints} />
35
- </tbody>
36
- </table>
37
- );
38
- expect(container.querySelector('.required-row')).toBeInTheDocument();
39
- expect(container.querySelector('.required')).toBeInTheDocument();
238
+ it('applies container-object class for object containers', () => {
239
+ const row = {
240
+ name: 'user_data',
241
+ level: 1,
242
+ required: false,
243
+ propertyType: 'object',
244
+ description: '',
245
+ example: '',
246
+ constraints: [],
247
+ path: ['user_data'],
248
+ hasChildren: true,
249
+ containerType: 'object',
250
+ continuingLevels: [],
251
+ };
252
+
253
+ const { container } = render(
254
+ <table>
255
+ <tbody>
256
+ <PropertyRow row={row} />
257
+ </tbody>
258
+ </table>,
259
+ );
260
+
261
+ expect(container.querySelector('.container-object')).toBeInTheDocument();
262
+ });
263
+
264
+ it('applies container-array class for array containers', () => {
265
+ const row = {
266
+ name: 'addresses',
267
+ level: 1,
268
+ required: false,
269
+ propertyType: 'array',
270
+ description: '',
271
+ example: '',
272
+ constraints: [],
273
+ path: ['addresses'],
274
+ hasChildren: true,
275
+ containerType: 'array',
276
+ continuingLevels: [],
277
+ };
278
+
279
+ const { container } = render(
280
+ <table>
281
+ <tbody>
282
+ <PropertyRow row={row} />
283
+ </tbody>
284
+ </table>,
285
+ );
286
+
287
+ expect(container.querySelector('.container-array')).toBeInTheDocument();
288
+ });
289
+
290
+ it('applies is-last class when isLastInGroup is true', () => {
291
+ const row = {
292
+ name: 'last_item',
293
+ level: 1,
294
+ required: false,
295
+ propertyType: 'string',
296
+ description: '',
297
+ example: '',
298
+ constraints: [],
299
+ path: ['last_item'],
300
+ hasChildren: false,
301
+ containerType: null,
302
+ continuingLevels: [],
303
+ isLastInGroup: true,
304
+ };
305
+
306
+ const { container } = render(
307
+ <table>
308
+ <tbody>
309
+ <PropertyRow row={row} isLastInGroup={true} />
310
+ </tbody>
311
+ </table>,
312
+ );
313
+
314
+ expect(container.querySelector('.is-last')).toBeInTheDocument();
315
+ });
316
+
317
+ it('applies level class based on nesting level', () => {
318
+ const row = {
319
+ name: 'nested_item',
320
+ level: 2,
321
+ required: false,
322
+ propertyType: 'string',
323
+ description: '',
324
+ example: '',
325
+ constraints: [],
326
+ path: ['parent', 'nested_item'],
327
+ hasChildren: false,
328
+ containerType: null,
329
+ continuingLevels: [],
330
+ };
331
+
332
+ const { container } = render(
333
+ <table>
334
+ <tbody>
335
+ <PropertyRow row={row} />
336
+ </tbody>
337
+ </table>,
338
+ );
339
+
340
+ expect(container.querySelector('.level-2')).toBeInTheDocument();
341
+ });
342
+
343
+ it('applies padding-left based on level using rem units', () => {
344
+ const row = {
345
+ name: 'nested_item',
346
+ level: 2,
347
+ required: false,
348
+ propertyType: 'string',
349
+ description: '',
350
+ example: '',
351
+ constraints: [],
352
+ path: ['parent', 'nested_item'],
353
+ hasChildren: false,
354
+ containerType: null,
355
+ continuingLevels: [],
356
+ };
357
+
358
+ const { container } = render(
359
+ <table>
360
+ <tbody>
361
+ <PropertyRow row={row} />
362
+ </tbody>
363
+ </table>,
364
+ );
365
+
366
+ const td = container.querySelector('td');
367
+ // level 2: 2 * 1.25 + 0.5 = 3rem
368
+ expect(td.style.paddingLeft).toBe('3rem');
40
369
  });
41
370
 
42
- it('renders multiple constraints', () => {
43
- const prop = { type: 'string', minLength: 1, maxLength: 10 };
44
- const { getByText } = render(
45
- <table>
46
- <tbody>
47
- <PropertyRow propertyKey="name" prop={prop} requiredList={['name']} getConstraints={getConstraints} />
48
- </tbody>
49
- </table>
50
- );
51
- expect(getByText('required')).toBeInTheDocument();
52
- expect(getByText('minLength: 1')).toBeInTheDocument();
53
- expect(getByText('maxLength: 10')).toBeInTheDocument();
371
+ it('applies background-image for parent-to-child line when hasChildren is true', () => {
372
+ const row = {
373
+ name: 'user_data',
374
+ level: 1,
375
+ required: false,
376
+ propertyType: 'object',
377
+ description: '',
378
+ example: '',
379
+ constraints: [],
380
+ path: ['user_data'],
381
+ hasChildren: true,
382
+ containerType: 'object',
383
+ continuingLevels: [],
384
+ };
385
+
386
+ const { container } = render(
387
+ <table>
388
+ <tbody>
389
+ <PropertyRow row={row} />
390
+ </tbody>
391
+ </table>,
392
+ );
393
+
394
+ const td = container.querySelector('td');
395
+ expect(td.style.backgroundImage).toContain('linear-gradient');
54
396
  });
55
397
 
56
- it('formats examples', () => {
57
- const prop = { type: 'string', examples: ['foo', 'bar'] };
58
- const { getByText } = render(
59
- <table>
60
- <tbody>
61
- <PropertyRow propertyKey="name" prop={prop} requiredList={[]} getConstraints={getConstraints} />
62
- </tbody>
63
- </table>
64
- );
65
- expect(getByText('foo, bar')).toBeInTheDocument();
398
+ it('applies background-image for continuing ancestor lines', () => {
399
+ const row = {
400
+ name: 'deep_item',
401
+ level: 3,
402
+ required: false,
403
+ propertyType: 'string',
404
+ description: '',
405
+ example: '',
406
+ constraints: [],
407
+ path: ['a', 'b', 'deep_item'],
408
+ hasChildren: false,
409
+ containerType: null,
410
+ continuingLevels: [0, 1], // Ancestors at levels 0 and 1 have more siblings
411
+ };
412
+
413
+ const { container } = render(
414
+ <table>
415
+ <tbody>
416
+ <PropertyRow row={row} />
417
+ </tbody>
418
+ </table>,
419
+ );
420
+
421
+ const td = container.querySelector('td');
422
+ // Should have background gradients for continuing lines
423
+ // Level 0 passes filter (0 < 3-1 = 2), level 1 passes (1 < 2)
424
+ expect(td.style.backgroundImage).toContain('linear-gradient');
425
+ });
426
+
427
+ it('filters out immediate parent level from continuing lines', () => {
428
+ const row = {
429
+ name: 'nested_item',
430
+ level: 2,
431
+ required: false,
432
+ propertyType: 'string',
433
+ description: '',
434
+ example: '',
435
+ constraints: [],
436
+ path: ['parent', 'nested_item'],
437
+ hasChildren: false,
438
+ containerType: null,
439
+ continuingLevels: [0, 1], // Level 1 is immediate parent
440
+ };
441
+
442
+ const { container } = render(
443
+ <table>
444
+ <tbody>
445
+ <PropertyRow row={row} />
446
+ </tbody>
447
+ </table>,
448
+ );
449
+
450
+ const td = container.querySelector('td');
451
+ // Filter is lvl < level - 1, so for level 2: lvl < 1
452
+ // Only level 0 should pass, level 1 should be filtered out
453
+ // So we should have exactly one gradient (for level 0)
454
+ const bgImage = td.style.backgroundImage;
455
+ // Count occurrences of linear-gradient
456
+ const gradientCount = (bgImage.match(/linear-gradient/g) || []).length;
457
+ expect(gradientCount).toBe(1);
458
+ });
459
+
460
+ it('has no background-image when continuingLevels is empty and no children', () => {
461
+ const row = {
462
+ name: 'simple',
463
+ level: 1,
464
+ required: false,
465
+ propertyType: 'string',
466
+ description: '',
467
+ example: '',
468
+ constraints: [],
469
+ path: ['simple'],
470
+ hasChildren: false,
471
+ containerType: null,
472
+ continuingLevels: [],
473
+ };
474
+
475
+ const { container } = render(
476
+ <table>
477
+ <tbody>
478
+ <PropertyRow row={row} />
479
+ </tbody>
480
+ </table>,
481
+ );
482
+
483
+ const td = container.querySelector('td');
484
+ expect(td.style.backgroundImage).toBe('');
66
485
  });
486
+ });
67
487
  });
@@ -5,28 +5,32 @@ import SchemaJsonViewer from '../../components/SchemaJsonViewer';
5
5
 
6
6
  // Mock CodeBlock as it's an external theme component
7
7
  jest.mock('@theme/CodeBlock', () => {
8
- return function DummyCodeBlock({ children, language }) {
9
- return <pre data-language={language}>{children}</pre>;
10
- };
8
+ return function DummyCodeBlock({ children, language }) {
9
+ return <pre data-language={language}>{children}</pre>;
10
+ };
11
11
  });
12
12
 
13
13
  describe('SchemaJsonViewer', () => {
14
- it('renders the schema in a CodeBlock', () => {
15
- const schema = {
16
- type: 'object',
17
- properties: {
18
- name: { type: 'string' },
19
- },
20
- };
14
+ it('renders the schema in a CodeBlock', () => {
15
+ const schema = {
16
+ type: 'object',
17
+ properties: {
18
+ name: { type: 'string' },
19
+ },
20
+ };
21
21
 
22
- const { getByText, container } = render(<SchemaJsonViewer schema={schema} />);
22
+ const { getByText, container } = render(
23
+ <SchemaJsonViewer schema={schema} />,
24
+ );
23
25
 
24
- expect(getByText('View Raw JSON Schema')).toBeInTheDocument();
25
- const detailsElement = container.querySelector('details');
26
- expect(detailsElement).toHaveClass('schema-json-viewer');
27
- const codeBlockElement = container.querySelector('pre');
28
- expect(codeBlockElement).toBeInTheDocument();
29
- expect(codeBlockElement).toHaveAttribute('data-language', 'json');
30
- expect(codeBlockElement.textContent).toEqual(JSON.stringify(schema, null, 2));
31
- });
26
+ expect(getByText('View Raw JSON Schema')).toBeInTheDocument();
27
+ const detailsElement = container.querySelector('details');
28
+ expect(detailsElement).toHaveClass('schema-json-viewer');
29
+ const codeBlockElement = container.querySelector('pre');
30
+ expect(codeBlockElement).toBeInTheDocument();
31
+ expect(codeBlockElement).toHaveAttribute('data-language', 'json');
32
+ expect(codeBlockElement.textContent).toEqual(
33
+ JSON.stringify(schema, null, 2),
34
+ );
35
+ });
32
36
  });