Skip to content

Commit eb32056

Browse files
committed
feat: apply changes to sys structure to js and improve sys.type edge-case handling
1 parent 0a0b8d6 commit eb32056

File tree

1 file changed

+91
-20
lines changed

1 file changed

+91
-20
lines changed

packages/gatsby-codemods/src/transforms/gatsby-source-contentful.js

Lines changed: 91 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ const SYS_FIELDS_TRANSFORMS = new Map([
4848
[`createdAt`, `firstPublishedAt`],
4949
[`updatedAt`, `publishedAt`],
5050
[`revision`, `publishedVersion`],
51-
[`type`, `contentType`],
5251
])
5352

5453
const isContentTypeSelector = selector => {
@@ -101,6 +100,60 @@ export function updateImport(babel) {
101100
)}: You may need to change "type" to "sys.contentType.name"`
102101
)
103102
}
103+
if (path.node.name === `contentType`) {
104+
console.log(
105+
`${renderFilename(
106+
path,
107+
state
108+
)}: You may need to change "file.contentType" to "contentType"`
109+
)
110+
}
111+
},
112+
ObjectPattern(path, state) {
113+
// rename sys.type to sys.contentType
114+
path.node.properties.forEach(property => {
115+
if (property.key?.name === `sys`) {
116+
property.value.properties.forEach(sysProperty => {
117+
if (sysProperty.key?.name === `type`) {
118+
sysProperty.key.name = `contentType`
119+
}
120+
})
121+
}
122+
})
123+
124+
// renamed & moved sys properties
125+
const transformedSysProperties = []
126+
path.node.properties.forEach(property => {
127+
if (SYS_FIELDS_TRANSFORMS.has(property.key?.name)) {
128+
const transformedProp = {
129+
...property,
130+
key: {
131+
...property.key,
132+
name: SYS_FIELDS_TRANSFORMS.get(property.key.name),
133+
},
134+
}
135+
136+
transformedSysProperties.push(transformedProp)
137+
}
138+
})
139+
140+
if (transformedSysProperties.length) {
141+
const sysField = {
142+
type: `Property`,
143+
key: {
144+
type: `Identifier`,
145+
name: `sys`,
146+
},
147+
value: {
148+
type: `ObjectPattern`,
149+
properties: transformedSysProperties,
150+
},
151+
}
152+
153+
path.node.properties = injectSysField(sysField, path.node.properties)
154+
155+
state.opts.hasChanged = true
156+
}
104157
},
105158
MemberExpression(path, state) {
106159
if (isContentTypeSelector(path.node.property?.name)) {
@@ -160,6 +213,7 @@ export function updateImport(babel) {
160213
}
161214
}
162215

216+
// Locate a subfield within a selection set or fields
163217
function locateSubfield(node, fieldName) {
164218
const subFields = node.selectionSet?.selections || node.value?.fields
165219
if (!subFields) {
@@ -168,6 +222,28 @@ function locateSubfield(node, fieldName) {
168222
return subFields.find(({ name }) => name?.value === fieldName)
169223
}
170224

225+
// Replace first old field occurence with new sys field
226+
const injectSysField = (sysField, selections) => {
227+
let sysInjected = false
228+
return selections
229+
.map(field => {
230+
const fieldName = field.name?.value || field.key?.name
231+
if (SYS_FIELDS_TRANSFORMS.has(fieldName)) {
232+
if (!sysInjected) {
233+
// Inject for first occurence of a sys field
234+
sysInjected = true
235+
return sysField
236+
}
237+
// Remove all later fields
238+
return null
239+
}
240+
// Keep non-sys fields as they are
241+
return field
242+
})
243+
.filter(Boolean)
244+
}
245+
246+
// Flatten the old deeply nested Contentful asset structure
171247
const flattenAssetFields = node => {
172248
const flatAssetFields = []
173249
// Flatten asset file field
@@ -218,6 +294,7 @@ function processGraphQLQuery(query, state) {
218294

219295
graphql.visit(ast, {
220296
Argument(node) {
297+
// flatten Contentful Asset filters
221298
if (node.name.value === `filter`) {
222299
const flatAssetFields = flattenAssetFields(node)
223300
if (flatAssetFields.length) {
@@ -233,12 +310,22 @@ function processGraphQLQuery(query, state) {
233310
},
234311
SelectionSet(node) {
235312
// Rename content type node selectors
236-
node.selections = node.selections.map(field => {
313+
node.selections.forEach(field => {
237314
if (isContentTypeSelector(field.name?.value)) {
238315
field.name.value = updateContentfulSelector(field.name.value)
239316
hasChanged = true
240317
}
241-
return field
318+
})
319+
320+
// Rename sys.type to sys.contentType
321+
node.selections.forEach(field => {
322+
if (field.name?.value === `sys`) {
323+
const typeField = locateSubfield(field, `type`)
324+
if (typeField) {
325+
typeField.name.value = `contentType`
326+
hasChanged = true
327+
}
328+
}
242329
})
243330

244331
// Move sys attributes into real sys
@@ -273,8 +360,6 @@ function processGraphQLQuery(query, state) {
273360
}
274361
)
275362

276-
// Replace first old field occurence with new sys field
277-
let sysInjected = false
278363
const sysField = {
279364
kind: `Field`,
280365
name: {
@@ -288,21 +373,7 @@ function processGraphQLQuery(query, state) {
288373
}
289374

290375
// Inject the new sys at the first occurence of any old sys field
291-
node.selections = node.selections
292-
.map(field => {
293-
if (SYS_FIELDS_TRANSFORMS.has(field.name?.value)) {
294-
if (!sysInjected) {
295-
// Inject for first occurence of a sys field
296-
sysInjected = true
297-
return sysField
298-
}
299-
// Remove all later fields
300-
return null
301-
}
302-
// Keep non-sys fields as they are
303-
return field
304-
})
305-
.filter(Boolean)
376+
node.selections = injectSysField(sysField, node.selections)
306377

307378
hasChanged = true
308379
return

0 commit comments

Comments
 (0)