@@ -2,6 +2,9 @@ import store from "~/store"
2
2
import { typeDefinitionFilters } from "./type-filters"
3
3
import { getPluginOptions } from "~/utils/get-gatsby-api"
4
4
import { cloneDeep , merge } from "lodash"
5
+ import { diffString } from "json-diff"
6
+ import { formatLogMessage } from "../../utils/format-log-message"
7
+ import { CODES } from "../../utils/report"
5
8
6
9
export const buildInterfacesListForType = type => {
7
10
let shouldAddNodeType = false
@@ -298,3 +301,151 @@ export const introspectionFieldTypeToSDL = fieldType => {
298
301
299
302
return openingTagsList . join ( `` ) + closingTagsList . reverse ( ) . join ( `` )
300
303
}
304
+
305
+ /**
306
+ * This is an expensive fn but it doesn't matter because it's only to show a debugging warning message when something is wrong.
307
+ */
308
+ function mergeDuplicateTypesAndReturnDedupedList ( typeDefs ) {
309
+ const clonedDefs = cloneDeep ( typeDefs )
310
+
311
+ const newList = [ ]
312
+
313
+ for ( const def of clonedDefs ) {
314
+ if ( ! def ) {
315
+ continue
316
+ }
317
+
318
+ const duplicateDefs = clonedDefs . filter (
319
+ d => d . config . name === def . config . name
320
+ )
321
+
322
+ const newDef = { }
323
+
324
+ for ( const dDef of duplicateDefs ) {
325
+ merge ( newDef , dDef )
326
+ }
327
+
328
+ newList . push ( newDef )
329
+ }
330
+
331
+ return newList
332
+ }
333
+
334
+ /**
335
+ * Diffs the built types between this build and the last one with the same remote schema hash.
336
+ * This is to catch and add helpful error messages for when an inconsistent schema between builds is inadvertently created due to some bug
337
+ */
338
+ export async function diffBuiltTypeDefs ( typeDefs ) {
339
+ if (
340
+ process . env . NODE_ENV !== `development` &&
341
+ process . env . WP_DIFF_SCHEMA_CUSTOMIZATION !== `true`
342
+ ) {
343
+ return
344
+ }
345
+
346
+ const state = store . getState ( )
347
+
348
+ const {
349
+ gatsbyApi : {
350
+ helpers : { cache, reporter } ,
351
+ } ,
352
+ remoteSchema,
353
+ } = state
354
+
355
+ const previousTypeDefinitions = await cache . get ( `previousTypeDefinitions` )
356
+ const typeDefString = JSON . stringify ( typeDefs )
357
+ const typeNames = typeDefs . map ( typeDef => typeDef . config . name )
358
+
359
+ const remoteSchemaChanged =
360
+ ! previousTypeDefinitions ||
361
+ previousTypeDefinitions ?. schemaHash !== remoteSchema . schemaHash
362
+
363
+ if ( remoteSchemaChanged ) {
364
+ await cache . set ( `previousTypeDefinitions` , {
365
+ schemaHash : remoteSchema . schemaHash ,
366
+ typeDefString,
367
+ typeNames,
368
+ } )
369
+ return
370
+ }
371
+
372
+ // type defs are the same as last time, so don't check for missing/inconsistent types
373
+ if ( previousTypeDefinitions ?. typeDefString === typeDefString ) {
374
+ return
375
+ }
376
+
377
+ const missingTypeNames = previousTypeDefinitions . typeNames . filter (
378
+ name => ! typeNames . includes ( name )
379
+ )
380
+
381
+ const previousTypeDefJson = mergeDuplicateTypesAndReturnDedupedList (
382
+ JSON . parse ( previousTypeDefinitions . typeDefString )
383
+ )
384
+
385
+ const newParsedTypeDefs = mergeDuplicateTypesAndReturnDedupedList (
386
+ JSON . parse ( typeDefString )
387
+ )
388
+
389
+ const changedTypeDefs = newParsedTypeDefs
390
+ . map ( typeDef => {
391
+ const previousTypeDef = previousTypeDefJson . find (
392
+ previousTypeDef => previousTypeDef . config . name === typeDef . config . name
393
+ )
394
+
395
+ const isDifferent = diffString ( previousTypeDef , typeDef )
396
+
397
+ if ( isDifferent ) {
398
+ return `Typename ${ typeDef . config . name } diff:\n${ diffString (
399
+ previousTypeDef ,
400
+ typeDef ,
401
+ {
402
+ // diff again to also show unchanged lines
403
+ full : true ,
404
+ }
405
+ ) } `
406
+ }
407
+
408
+ return null
409
+ } )
410
+ . filter ( Boolean )
411
+
412
+ let errorMessage = formatLogMessage (
413
+ `The remote WPGraphQL schema hasn't changed but local generated type definitions have. This is a bug, please open an issue on Github${
414
+ missingTypeNames . length || changedTypeDefs . length
415
+ ? ` and include the following text.`
416
+ : ``
417
+ } .${
418
+ missingTypeNames . length
419
+ ? `\n\nMissing type names: ${ missingTypeNames . join ( `\n` ) } \n`
420
+ : ``
421
+ } ${
422
+ changedTypeDefs . length
423
+ ? `\n\nChanged type defs:\n\n${ changedTypeDefs . join ( `\n` ) } `
424
+ : ``
425
+ } `
426
+ )
427
+
428
+ const maxErrorLength = 5000
429
+
430
+ if ( errorMessage . length > maxErrorLength ) {
431
+ errorMessage =
432
+ errorMessage . substring ( 0 , maxErrorLength ) +
433
+ `\n\n...\n[Diff exceeded ${ maxErrorLength } characters and was truncated]`
434
+ }
435
+
436
+ if ( process . env . WP_INCONSISTENT_SCHEMA_WARN !== `true` ) {
437
+ reporter . info (
438
+ formatLogMessage (
439
+ `Panicking due to inconsistent schema customization. Turn this into a warning by setting process.env.WP_INCONSISTENT_SCHEMA_WARN to a string of "true"`
440
+ )
441
+ )
442
+ reporter . panic ( {
443
+ id : CODES . InconsistentSchemaCustomization ,
444
+ context : {
445
+ sourceMessage : errorMessage ,
446
+ } ,
447
+ } )
448
+ } else {
449
+ reporter . warn ( errorMessage )
450
+ }
451
+ }
0 commit comments