-
Notifications
You must be signed in to change notification settings - Fork 10.3k
/
declare-plugin-options-schema.js
908 lines (900 loc) · 29.4 KB
/
declare-plugin-options-schema.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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
/**
* This file is intentionally not TS so it can be run in a yarn script without being transpiled.
*/
const prettier = require(`prettier`)
const wrapOptions = innerOptions =>
prettier
.format(
`const something = {
resolve: \`gatsby-source-wordpress\`, options: {
${innerOptions.trim()}
},
}`,
{ parser: `babel` }
)
.replace(`const something = `, ``)
.replace(`;`, ``)
const pluginOptionsSchema = ({ Joi }) => {
const getTypeOptions = () =>
Joi.object({
where: Joi.string()
.allow(null)
.allow(false)
.meta({
example: wrapOptions(`
type: {
Page: {
where: \`language: \${process.env.GATSBY_ACTIVE_LANGUAGE}\`
},
}
`),
})
.description(
`This string is passed as the WPGraphQL "where" arguments in the GraphQL queries that are made while initially sourcing all data from WPGraphQL into Gatsby during an uncached build. A common use-case for this is only fetching posts of a specific language. It's often used in conjunction with the beforeChangeNode type option as "where" only affects the initial data sync from WP to Gatsby while beforeChangeNode will also run when syncing individual updates from WP to Gatsby.`
),
exclude: Joi.boolean()
.allow(null)
.description(
`Completely excludes a type from node sourcing and from the ingested schema.`
)
.meta({
example: wrapOptions(`
type: {
Page: {
exclude: true,
},
},
`),
}),
limit: Joi.number()
.integer()
.allow(null)
.allow(false)
.description(
`The maximum amount of objects of this type to fetch from WordPress.`
),
excludeFieldNames: Joi.array()
.items(Joi.string())
.allow(null)
.allow(false)
.description(`Excludes fields on a type by field name.`)
.meta({
example: wrapOptions(`
type: {
Page: {
excludeFieldNames: [\`dateGmt\`, \`parent\`],
},
},
`),
}),
nodeInterface: Joi.boolean()
.allow(null)
.allow(false)
.description(
`Determines whether or not this type will be treated as an interface comprised entirely of other Gatsby node types.`
)
.meta({
example: wrapOptions(`
type: {
Page: {
nodeInterface: true
}
}
`),
}),
beforeChangeNode: Joi.any()
.allow(null)
.allow(false)
.meta({
trueType: `string|function`,
})
.description(
`A function which is invoked before a node is created, updated, or deleted. This is a hook in point to modify the node or perform side-effects related to it. This option should be a path to a JS file where the default export is the beforeChangeNode function. The path can be relative to your gatsby-node.js or absolute. Currently you can inline a function by writing it out directly in this option but starting from Gatsby v4 only a path to a function file will work.`
),
})
const joiSchema = Joi.object({
verbose: Joi.boolean()
.default(true)
.description(
`Enables verbose logging in the terminal. Set to \`false\` to turn it off.`
)
.meta({
example: wrapOptions(`
verbose: true,`),
}),
debug: Joi.object({
preview: Joi.boolean()
.default(false)
.description(
`When set to true, this option will display additional information in the terminal output about the running preview process.`
)
.meta({
example: wrapOptions(`
debug: {
preview: true
},
`),
}),
timeBuildSteps: Joi.boolean()
.default(false)
.description(
`When set to true, this option will display how long each internal step took during the build process.`
)
.meta({
example: wrapOptions(`
debug: {
timeBuildSteps: true,
},
`),
}),
disableCompatibilityCheck: Joi.boolean()
.default(false)
.description(
`This option disables the compatibility API check against the remote WPGraphQL and WPGatsby plugin versions. Note that it's highly recommended to not disable this setting. If you disable this setting you will receive no support until it's re-enabled. It's also highly likely that you'll run into major bugs without initially realizing that this was the cause.\n\nThis option should only be used for debugging.`
)
.meta({
example: wrapOptions(`
debug: {
disableCompatibilityCheck: true,
},
`),
}),
throwRefetchErrors: Joi.boolean()
.default(false)
.description(
`When this is set to true, errors thrown while updating data in gatsby develop will fail the build process instead of automatically attempting to recover.`
)
.meta({
example: wrapOptions(`
debug: {
throwRefetchErrors: true
}
`),
}),
graphql: Joi.object({
showQueryVarsOnError: Joi.boolean()
.default(false)
.description(
`When a GraphQL error is returned and the process exits, this plugin option determines whether or not to log out the query vars that were used in the query that returned GraphQL errors.`
)
.meta({
example: wrapOptions(`
debug: {
graphql: {
showQueryVarsOnError: true,
},
},
`),
}),
showQueryOnError: Joi.boolean()
.default(false)
.description(
`If enabled, GraphQL queries will be printed to the terminal output when the query returned errors.`
)
.meta({
example: wrapOptions(`
debug: {
graphql: {
showQueryOnError: true
}
}
`),
}),
copyQueryOnError: Joi.boolean()
.default(false)
.description(
`If enabled, GraphQL queries will be copied to your OS clipboard (if supported) when the query returned errors.`
)
.meta({
example: wrapOptions(`
debug: {
graphql: {
copyQueryOnError: true
}
}
`),
}),
panicOnError: Joi.boolean()
.default(false)
.description(
`Determines whether or not to panic when any GraphQL error is returned.
Default is false because sometimes non-critical errors are returned alongside valid data.`
)
.meta({
example: wrapOptions(`
debug: {
graphql: {
panicOnError: false,
},
},
`),
}),
onlyReportCriticalErrors: Joi.boolean()
.default(true)
.description(
`Determines whether or not to log non-critical errors. A non-critical error is any error which is returned alongside valid data. In previous versions of WPGraphQL this was very noisy because trying to access an entity that was private returned errors.`
)
.meta({
example: wrapOptions(`
debug: {
graphql: {
onlyReportCriticalErrors: true,
},
},
`),
}),
copyNodeSourcingQueryAndExit: Joi.string()
.allow(false)
.default(false)
.description(
`When a type name from the remote schema is entered here, the node sourcing query will be copied to the clipboard, and the process will exit.`
)
.meta({
example: wrapOptions(`
debug: {
graphql: {
copyNodeSourcingQueryAndExit: true
}
}
`),
}),
writeQueriesToDisk: Joi.boolean()
.default(false)
.description(
`When true, all internal GraphQL queries generated during node sourcing will be written out to \`./WordPress/GraphQL/[TypeName]/*.graphql\` for every type that is sourced. This is very useful for debugging GraphQL errors.`
)
.meta({
example: wrapOptions(`
debug: {
graphql: {
writeQueriesToDisk: true,
},
},
`),
}),
printIntrospectionDiff: Joi.boolean()
.default(false)
.description(
`When this is set to true it will print out the diff between types in the previous and new schema when the schema changes. This is enabled by default when debug.preview is enabled.`
)
.meta({
example: wrapOptions(`
debug: {
graphql: {
printIntrospectionDiff: true,
},
},
`),
}),
})
.description(
`An object which contains GraphQL debugging options. See below for options.`
)
.meta({
example: wrapOptions(`
debug: {
graphql: {
// Add your options here :)
},
},
`),
}),
})
.description(
`An object which contains options related to debugging. See below for options.`
)
.meta({
example: wrapOptions(`
debug: {
// Add your options here :)
},
`),
}),
production: Joi.object({
hardCacheMediaFiles: Joi.boolean()
.default(false)
.description(
`This option is experimental. When set to true, media files will be hard-cached outside the Gatsby cache at ./.wordpress-cache/path/to/media/file.jpeg. This is useful for preventing media files from being re-downloaded when the Gatsby cache automatically clears. When using this option, be sure to gitignore the wordpress-cache directory in the root of your project.`
)
.meta({
example: wrapOptions(`
production: {
hardCacheMediaFiles: true
}
`),
}),
allow404Images: Joi.boolean()
.default(false)
.description(
`This option allows images url's that return a 404 to not fail production builds.`
)
.meta({
example: wrapOptions(`
production: {
allow404Images: true
}
`),
}),
}),
develop: Joi.object({
nodeUpdateInterval: Joi.number()
.integer()
.default(5000)
.description(
`Specifies in milliseconds how often Gatsby will ask WP if data has changed during development. If you want to see data update in near-realtime while you're developing, set this low. Your server may have trouble responding to too many requests over a long period of time and in that case, set this high. Setting it higher saves electricity too ⚡️🌲`
)
.meta({
example: wrapOptions(`
develop: {
nodeUpdateInterval: 300
},
`),
}),
hardCacheMediaFiles: Joi.boolean()
.default(false)
.description(
`This option is experimental. When set to true, media files will be hard-cached outside the Gatsby cache at \`./.wordpress-cache/path/to/media/file.jpeg\`. This is useful for preventing media files from being re-downloaded when the Gatsby cache automatically clears. When using this option, be sure to gitignore the wordpress-cache directory in the root of your project.`
)
.meta({
example: wrapOptions(`
develop: {
hardCacheMediaFiles: true,
},
`),
}),
hardCacheData: Joi.boolean()
.default(false)
.description(
`This option is experimental. When set to true, WordPress data will be hard-cached outside the Gatsby cache in \`./.wordpress-cache/caches\`. This is useful for preventing the need to re-fetch all data when the Gatsby cache automatically clears. This hard cache will automatically clear itself when your remote WPGraphQL schema changes, or when you change your plugin options.
When using this option, be sure to gitignore the wordpress-cache directory in the root of your project.`
)
.meta({
example: wrapOptions(`
develop: {
hardCacheData: false,
},
`),
}),
})
.description(`Options related to the gatsby develop process.`)
.meta({
example: wrapOptions(`
develop: {
// options related to \`gatsby develop\`
},
`),
}),
auth: Joi.object({
htaccess: Joi.object({
username: Joi.string()
.allow(null)
.default(null)
.description(`The username for your .htpassword protected site.`)
.meta({
example: wrapOptions(`
auth: {
htaccess: {
username: \`admin\`,
},
},
`),
}),
password: Joi.string()
.allow(null)
.default(null)
.description(`The password for your .htpassword protected site.`)
.meta({
example: wrapOptions(`
auth: {
htaccess: {
password: \`1234strong_password\`,
},
},
`),
}),
})
.description(`Options related to htaccess authentication.`)
.meta({
example: wrapOptions(`
auth: {
htaccess: {
// Add your options here :)
},
},
`),
}),
})
.description(`Options related to authentication. See below for options.`)
.meta({
example: wrapOptions(`
auth: {
// Add your options here :)
},
`),
}),
schema: Joi.object({
queryDepth: Joi.number()
.integer()
.positive()
.default(15)
.description(
`The maximum field depth the remote schema will be queried to.`
)
.meta({
example: wrapOptions(`
schema: {
queryDepth: 15
}
`),
}),
circularQueryLimit: Joi.number()
.integer()
.positive()
.default(5)
.description(
`The maximum number times a type can appear as it's own descendant.`
)
.meta({
example: wrapOptions(`
schema: {
circularQueryLimit: 5
}
`),
}),
typePrefix: Joi.string()
.default(`Wp`)
.description(
`The prefix for all ingested types from the remote schema. For example Post becomes WpPost.`
)
.meta({
example: wrapOptions(`
schema: {
typePrefix: \`Wp\`,
},
`),
}),
timeout: Joi.number()
.integer()
.default(30 * 1000)
.description(
`The amount of time in ms before GraphQL requests will time out.`
)
.meta({
example: wrapOptions(`
schema: {
timeout: 30000,
},
`),
}),
perPage: Joi.number()
.integer()
.default(100)
.description(
`The number of nodes to fetch per page during node sourcing.`
)
.meta({
example: wrapOptions(`
schema: {
perPage: 100,
},
`),
}),
requestConcurrency: Joi.number()
.integer()
.default(15)
.description(
`The number of concurrent GraphQL requests to make at any time during node sourcing. Try lowering this if your WordPress server crashes while sourcing data.`
)
.meta({
example: wrapOptions(`
schema: {
requestConcurrency: 50,
},
`),
}),
previewRequestConcurrency: Joi.number()
.integer()
.default(5)
.description(
`The number of concurrent GraphQL requests to make at any time during preview sourcing. Try lowering this if your WordPress server crashes during previews. Normally this wont be needed and only comes into effect when multiple users are previewing simultaneously.`
)
.meta({
example: wrapOptions(`
schema: {
previewRequestConcurrency: 50,
},
`),
}),
})
.description(
`Options related to fetching and ingesting the remote schema.`
)
.meta({
example: wrapOptions(`
schema: {
// Add your options here :)
},
`),
}),
excludeFieldNames: Joi.array()
.items(Joi.string())
.allow(null)
.description(
`A list of field names to globally exclude from the ingested schema.`
)
.meta({
example: wrapOptions(`
excludeFieldNames: [\`viewer\`],
`),
}),
searchAndReplace: Joi.array()
.description(
`An array of options to search and replace strings in nodes. See below for options.`
)
.allow(null)
.items(
Joi.object({
search: Joi.string()
.description(
`The regex rule used to search when replacing strings in node data. It will search the stringified JSON of each node to capture strings at any nested depth.`
)
.meta({
example: wrapOptions(`
searchAndReplace: [
{
search: "https://some-url.com"
},
],
`),
}),
replace: Joi.string()
.description(`The replacement string for each regex match.`)
.meta({
example: wrapOptions(`
searchAndReplace: [
{
replace: "https://some-new-url.com",
},
],
`),
}),
})
)
.meta({
example: wrapOptions(`
searchAndReplace: [
{
search: "https://some-url.com",
replace: "https://some-new-url.com",
},
],
`),
}),
html: Joi.object({
useGatsbyImage: Joi.boolean()
.default(true)
.allow(null)
.description(
`Causes the source plugin to find/replace images in html with Gatsby images.`
)
.meta({
example: wrapOptions(`
html: {
useGatsbyImage: true,
},
`),
}),
imageMaxWidth: Joi.number()
.integer()
.allow(null)
.default(null)
.description(
`Adds a limit to the max width an image can be. If the image size selected in WP is smaller or the image file width is smaller than this those values will be used instead.`
)
.meta({
example: wrapOptions(`
html: {
imageMaxWidth: 1024,
},
`),
}),
fallbackImageMaxWidth: Joi.number()
.integer()
.allow(null)
.default(100)
.description(
`If a max width can't be inferred from html this value will be passed to Sharp. If the image is smaller than this, the image file's width will be used instead.`
)
.meta({
example: wrapOptions(`
html: {
fallbackImageMaxWidth: 800,
},
`),
}),
imageQuality: Joi.number()
.integer()
.default(90)
.allow(null)
.description(
`Determines the image quality that Sharp will use when generating inline html image thumbnails.`
)
.meta({
example: wrapOptions(`
html: {
imageQuality: 90,
},
`),
}),
createStaticFiles: Joi.boolean()
.default(true)
.allow(null)
.description(
`When this is true, any url's which are wrapped in "", '', or () and which contain /wp-content/uploads will be transformed into static files and the url's will be rewritten. This adds support for video, audio, and anchor tags which point at WP media item uploads as well as inline-html css like background-image: url().`
)
.meta({
example: wrapOptions(`
html: {
createStaticFiles: true,
},
`),
}),
generateWebpImages: Joi.boolean()
.default(false)
.allow(null)
.description(
`When this is true, .webp images will be generated for images in html fields in addition to the images gatsby-image normally generates.`
)
.meta({
example: wrapOptions(`
html: {
generateWebpImages: false,
},
`),
}),
})
.description(`Options related to html field processing.`)
.meta({
example: wrapOptions(`
html: {
// Add your options here :)
},
`),
}),
type: Joi.object({
__all: getTypeOptions()
.description(
`A special type setting which is applied to all types in the ingested schema.`
)
.meta({
example: wrapOptions(`
type: {
__all: {
limit: 10,
},
},
`),
}),
RootQuery: getTypeOptions()
.append({
excludeFieldNames: Joi.array()
.items(Joi.string())
.allow(null)
.default([`viewer`, `node`, `schemaMd5`])
.description(`Excludes fields on a type by field name.`),
})
.default(`{ excludeFieldNames: ['viewer', 'node', 'schemaMd5'], },`)
.description(
`A special type which is applied to any non-node root fields that are ingested and stored under the root \`wp\` field. It accepts the same options as other types.`
)
.meta({
example: wrapOptions(`
RootQuery: {
excludeFieldNames: [\`viewer\`]
},
`),
}),
MediaItem: Joi.object({
lazyNodes: Joi.boolean()
.default(false)
.description(
`Enables a different media item sourcing strategy. Instead of fetching Media Items that are referenced by other nodes, Media Items will be fetched in connection resolvers from other nodes. This may be desirable if you're not using all of the connected images in your WP instance. This is not currently recommended because it messes up cli output and can be slow due to query running concurrency.`
)
.meta({
example: wrapOptions(`
type: {
MediaItem: {
lazyNodes: true,
},
},
`),
}),
localFile: Joi.object({
excludeByMimeTypes: Joi.array()
.items(Joi.string())
.default([])
.description(
`Allows preventing the download of files associated with MediaItem nodes by their mime types.`
)
.meta({
example: wrapOptions(`
type: {
MediaItem: {
localFile: {
excludeByMimeTypes: [\`video/mp4\`]
},
},
},
`),
}),
maxFileSizeBytes: Joi.number()
.integer()
.default(15728640)
.description(
`Allows preventing the download of files that are above a certain file size (in bytes). Default is 15mb.`
)
.meta({
example: wrapOptions(`
type: {
MediaItem: {
localFile: {
maxFileSizeBytes: 10485760 // 10Mb
},
},
},
`),
}),
requestConcurrency: Joi.number()
.integer()
.default(100)
.description(
`Amount of images to download concurrently. Try lowering this if wordpress server crashes on import`
)
.meta({
example: wrapOptions(`
type: {
MediaItem: {
localFile: {
requestConcurrency: 50
},
},
},
`),
}),
})
.description(
`Options related to File nodes that are attached to MediaItem nodes`
)
.meta({
example: wrapOptions(`
type: {
MediaItem: {
localFile: {
// Add your options here :)
}
}
}`),
}),
}),
})
.pattern(Joi.string(), getTypeOptions())
.description(`Options related to specific types in the remote schema.`)
.meta({
example: wrapOptions(`
type: {
// Add your options here :)
},
`),
}),
}).meta({
// This is used in generating docs from this schema
// so that we can prevent generating all options
// nested inside themselves
portableOptions: true,
})
return Joi.object({
url: Joi.string()
.required()
.description(
`This is the only plugin option which is required for the plugin to work properly.
This should be the full url of your GraphQL endpoint.`
)
.meta({
example: wrapOptions(`
url: \`https://yoursite.com/graphql\`
`),
}),
})
.concat(joiSchema)
.append({
presets: Joi.array()
.items(
Joi.object({
presetName: Joi.string()
.description(`The name of the plugin options preset.`)
.meta({
example: wrapOptions(`
presets: [
{
presetName: \`DEVELOP\`
}
]
`),
}),
useIf: Joi.any()
.description(
`A function used to determine whether or not to apply this plugin options preset. It should return a boolean value. True will cause the preset to apply, false will disclude it.`
)
.default(`() => false`)
.meta({
trueType: `function`,
example: wrapOptions(`
presets: [
{
useIf: () => process.env.NODE_ENV === \`development\`
}
]
`),
}),
options: joiSchema
.description(
`Any valid options except for \`url\` and \`presets\``
)
.meta({
example: wrapOptions(`
presets: [
{
name: \`DEVELOP\`,
useIf: () => process.env.NODE_ENV === \`development\`,
options: {
type: {
__all: {
limit: 1
}
}
}
}
]
`),
}),
})
)
.meta({
default: `[{
presetName: \`PREVIEW_OPTIMIZATION\`,
useIf: (): boolean => process.env.NODE_ENV === \`development\` &&
!!process.env.ENABLE_GATSBY_REFRESH_ENDPOINT || process.env.RUNNER_TYPE === \`PREVIEW\`,
options: {
html: {
useGatsbyImage: false,
createStaticFiles: false,
},
type: {
__all: {
limit: 50,
},
Comment: {
limit: 0,
},
Menu: {
limit: null,
},
MenuItem: {
limit: null,
},
User: {
limit: null,
},
},
},
}]`,
})
.description(
`An array of plugin options presets that are applied if the useIf function on each returns true. The default includes an optimization for when in Gatsby Preview mode.`
)
.allow(null),
})
}
module.exports = {
pluginOptionsSchema,
}