fix: correct interface types for nested global fields, add taxonomy field support - #280
Conversation
…ield support Nested global fields (a global field referencing another global field, whether inside a plain field, a group, or a modular block) got the wrong GraphQL interface type. The interface field name was derived by blindly string-replacing the parent type name onto every child field, which only works when the child's type name is literally built from that parent name. A nested global field's type name is built from its own reference_to instead, so the blind replace produced a non-existent, malformed interface type. Detect the nested-global-field case explicitly in both buildBlockCustomSchema and buildCustomSchema, and point the interface field at the referenced global field's own interface type instead. Also add support for the `taxonomy` field data type, which previously had no schema handling at all — content types with a taxonomy field now correctly expose a `[taxonomyType]` field (taxonomy_uid, term_uid) instead of the field being silently dropped. Fixes DX-10112.
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
🔒 Security Scan Results
⏱️ SLA Breach Summary
ℹ️ Vulnerabilities Without Available Fixes (Informational Only)The following vulnerabilities were detected but do not have fixes available (no upgrade or patch). These are excluded from failure thresholds:
✅ BUILD PASSED - All security checks passed |
There was a problem hiding this comment.
Pull request overview
This PR fixes schema generation issues in gatsby-source-contentstack around nested global fields and adds first-class GraphQL schema support for Contentstack taxonomy fields, along with documentation and regression tests.
Changes:
- Fixes interface field typing for global fields nested inside blocks/groups so interface types are derived from the nested global field’s own
reference_to. - Adds
taxonomyfield support inbuildCustomSchemaand documents how to query taxonomy fields. - Adds regression tests covering both nested-global-field interface typing and taxonomy schema generation.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/normalize.js |
Fixes interface type derivation for nested global fields; adds taxonomy field handling in schema generation. |
src/tests/normalize-nested-global-field-taxonomy.test.js |
Adds unit tests for nested global-field interface typing and taxonomy field schema output. |
tests/normalize-nested-global-field-taxonomy.test.js |
Adds compiled/duplicated test counterpart mirroring src/tests for the taxonomy + nested-global regression coverage. |
README.md |
Documents how to query taxonomy fields via GraphQL. |
.talismanrc |
Adds a checksum-based ignore entry for src/normalize.js in Talisman configuration. |
Files not reviewed (1)
- tests/normalize-nested-global-field-taxonomy.test.js: Generated file
Suppressed comments (1)
src/normalize.js:447
- Same O(n²) pattern here:
(field.schema || []).find(...)is executed for every nested field when building interface fields. Pre-indexfield.schemabyuidonce to avoid repeated linear scans.
const typeFields = {};
const interfaceFields = {};
for (const key in result.fields) {
typeFields[key] = result.fields[key].type || result.fields[key];
// Same nested-global-field case as buildBlockCustomSchema above.
const childField = (field.schema || []).find(f => f.uid === key);
if (childField && childField.data_type === 'global_field' && childField.reference_to) {
interfaceFields[key] = typeFields[key].replace(`${newParent}_${key}`, `${prefix}_${childField.reference_to}`);
} else {
interfaceFields[key] = typeFields[key].replace(newParent, newInterfaceParent);
}
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
🔒 Security Scan Results
⏱️ SLA Breach Summary
ℹ️ Vulnerabilities Without Available Fixes (Informational Only)The following vulnerabilities were detected but do not have fixes available (no upgrade or patch). These are excluded from failure thresholds:
✅ BUILD PASSED - All security checks passed |
- Guard the taxonomyType type definition push so a content type with more than one taxonomy field doesn't push duplicate type defs into the same createTypes() call, which Gatsby would reject as a schema build error. - Pre-index each block/group's own schema by uid once before the interface-field loop, instead of calling .find() per field — avoids an O(n^2) scan for large modular blocks. Addresses Copilot review comments on PR #280.
🔒 Security Scan Results
⏱️ SLA Breach Summary
ℹ️ Vulnerabilities Without Available Fixes (Informational Only)The following vulnerabilities were detected but do not have fixes available (no upgrade or patch). These are excluded from failure thresholds:
✅ BUILD PASSED - All security checks passed |
Addresses a Copilot review comment on PR #280 asking why these whole-file checksum ignores exist. Documents that they're false positives on the literal string "api_key" (a plugin option name, not a credential), and that each checksum is pinned to the file's content at review time so a future edit — including a real secret — changes the checksum and re-triggers scanning.
🔒 Security Scan Results
⏱️ SLA Breach Summary
ℹ️ Vulnerabilities Without Available Fixes (Informational Only)The following vulnerabilities were detected but do not have fixes available (no upgrade or patch). These are excluded from failure thresholds:
✅ BUILD PASSED - All security checks passed |
Summary
Fixes DX-10112. Reimplements a customer-supplied patch (
gatsby-source-contentstack+5.4.3 2.patch) against currentmaster, verified against the current codebase and live data rather than applied as-is.1. Broken GraphQL interface types for nested global fields
In both
buildBlockCustomSchemaandbuildCustomSchema(src/normalize.js), the interface-side field type for each field in a block/group was derived by blindly string-replacing the parent type name onto every child field's type string. This breaks when a child field is itself aglobal_fieldreferencing another global field — its type name is built from its ownreference_to, not from the parent name, so the blind replace produced a non-existent, malformed interface type.Fix: detect the nested-global-field case explicitly (
childField.data_type === 'global_field' && childField.reference_to) and point the interface field at the referenced global field's own interface type instead of doing the blind replace. Same fix applied in both places since they share the same pattern.2. No support for the
taxonomyfield data typebuildCustomSchema's switch statement had nocase 'taxonomy':— any content type with a taxonomy field had the field silently dropped from the schema. Added a case that defines ataxonomyType { taxonomy_uid: String term_uid: String }GraphQL type and resolves the field from the entry data, typed as[taxonomyType]/[taxonomyType]!permandatory.README updated with a "Querying taxonomy fields" section (nested global fields needed no new docs — that's a fix to already-documented behavior, not a new capability).
Test plan
src/tests/normalize-nested-global-field-taxonomy.test.js), verified to actually catch the regression: stashed the fix, all 3 new tests failed with the expected errors; restored, all pass.npm test— full suite passes (10 tests, 4 suites).seo_2, which itself contains another global fieldseo) — an even stronger test than the unit test's single-level nesting.Contentstack_seo_2'sglobal_fieldfield correctly resolves to typeContentstack_seo(the actual interface built one level down), not a malformed type name.taxonomyfield (referencing a taxonomy with 3 terms) to a content type, set 2 terms on a real entry, and confirmed the query returns exactly those terms (taxonomy_uid/term_uid) matching the CMS data.