1 | 'use strict'
|
2 | const diff = require('deep-diff')
|
3 |
|
4 | function toNamedObject(arr, modifier = obj => obj) {
|
5 | if (!arr) {
|
6 | return {}
|
7 | }
|
8 | return arr.reduce((obj, value) => {
|
9 | obj[value.name] = modifier(value)
|
10 | return obj
|
11 | }, {})
|
12 | }
|
13 |
|
14 | function toNamedArray(obj, modifier = obj => obj) {
|
15 | if (!obj) {
|
16 | return []
|
17 | }
|
18 | return Object.entries(obj).map(([key, value]) => {
|
19 | return modifier(Object.assign({}, value, { name: key }))
|
20 | })
|
21 | }
|
22 |
|
23 | function toDiffableSchema(schema) {
|
24 | const types = toNamedObject(schema.__schema.types, type => {
|
25 | if (type.fields) {
|
26 | type = Object.assign({}, type, {
|
27 | fields: toNamedObject(type.fields)
|
28 | })
|
29 | }
|
30 | if (type.enumValues) {
|
31 | type = Object.assign({}, type, {
|
32 | enumValues: toNamedObject(type.enumValues)
|
33 | })
|
34 | }
|
35 | return type
|
36 | })
|
37 |
|
38 | const directives = toNamedObject(schema.__schema.directives)
|
39 |
|
40 | return Object.assign({}, schema, {
|
41 | __schema: Object.assign({}, schema.__schema, {
|
42 | types,
|
43 | directives
|
44 | })
|
45 | })
|
46 | }
|
47 |
|
48 | function fromDiffableSchema(schema) {
|
49 | const types = toNamedArray(schema.__schema.types, type => {
|
50 | if (type.fields) {
|
51 | type = Object.assign({}, type, {
|
52 | fields: toNamedArray(type.fields)
|
53 | })
|
54 | }
|
55 | if (type.enumValues) {
|
56 | type = Object.assign({}, type, {
|
57 | enumValues: toNamedArray(type.enumValues)
|
58 | })
|
59 | }
|
60 | return type
|
61 | })
|
62 |
|
63 | const directives = toNamedArray(schema.__schema.directives)
|
64 |
|
65 | return Object.assign({}, schema, {
|
66 | __schema: Object.assign({}, schema.__schema, {
|
67 | types,
|
68 | directives
|
69 | })
|
70 | })
|
71 | }
|
72 |
|
73 | function diffSchema(oldSchema, newSchema, options = {}) {
|
74 | const oldDiffableSchema = toDiffableSchema(oldSchema)
|
75 | const newDiffableSchema = toDiffableSchema(newSchema)
|
76 | const changes = diff(oldDiffableSchema, newDiffableSchema)
|
77 | const diffSchema = changes.reduce((schema, change) => {
|
78 | diff.applyChange(schema, newDiffableSchema, change)
|
79 | return schema
|
80 | }, {})
|
81 | const schema = fromDiffableSchema(diffSchema)
|
82 | const newTypes = newDiffableSchema.__schema.types
|
83 | schema.__schema.types = schema.__schema.types.map(type => {
|
84 | if (options.processTypeDiff) {
|
85 | type = options.processTypeDiff(type)
|
86 | }
|
87 | type = Object.assign({}, newTypes[type.name], type)
|
88 | if (type.fields) {
|
89 | const newFields = newTypes[type.name].fields
|
90 | type.fields = type.fields.map(field => newFields[field.name])
|
91 | }
|
92 | if (type.enumValues) {
|
93 | const newEnumValues = newTypes[type.name].enumValues
|
94 | type.enumValues = type.enumValues.map(
|
95 | enumValue => newEnumValues[enumValue.name]
|
96 | )
|
97 | }
|
98 | return type
|
99 | })
|
100 | return schema
|
101 | }
|
102 |
|
103 | module.exports = diffSchema
|