Skip to content

Commit 9f1c488

Browse files
Merge pull request #140 from contentstack/development
DX | 08-12-2025 | Release
2 parents dd41dbb + e32dd63 commit 9f1c488

File tree

7 files changed

+304
-297
lines changed

7 files changed

+304
-297
lines changed

.talismanrc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ fileignoreconfig:
33
ignore_detectors:
44
- filecontent
55
- filename: package-lock.json
6-
checksum: 57ee816f79e4f41c43091caf1bcfded44ea48f592e3f437d9aee81e5c8156382
6+
checksum: 06ab85506c97fe9ae2f99461afe8e142c262cc540e240f4f3fc10382bc3cb835
77
- filename: .husky/pre-commit
88
checksum: 5baabd7d2c391648163f9371f0e5e9484f8fb90fa2284cfc378732ec3192c193
99
- filename: src/graphqlTS/index.ts
@@ -26,4 +26,8 @@ fileignoreconfig:
2626
checksum: d8e9492f9294725f54711be06cef880993ab91a4ece37cf361c34ac18fc18a7c
2727
- filename: tests/integration/graphqlTS/graphqlTS.test.ts
2828
checksum: b111cb55740d871a3031bc0214eb445239cd6f62ebbdd922eb34af47f0714a54
29+
- filename: src/generateTS/stack/builtins.ts
30+
checksum: de5f21a1e1a6e5672231671a275e2e0f97b3eea0f5de4651d827e5afa82dbb86
31+
- filename: tests/unit/tsgen/custom-field.test.ts
32+
checksum: e76d815eaed0481ed928430548bb1b70c392e13db0a712a1365a179997226795
2933
version: "1.0"

package-lock.json

Lines changed: 230 additions & 280 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@contentstack/types-generator",
3-
"version": "3.8.0",
3+
"version": "3.9.0",
44
"description": "Contentstack type definition generation library",
55
"private": false,
66
"author": "Contentstack",
@@ -42,16 +42,16 @@
4242
"jest": "^29.7.0",
4343
"jest-json-reporter": "^1.2.2",
4444
"nock": "^13.5.6",
45-
"rollup": "^4.48.0",
45+
"rollup": "^4.53.3",
4646
"ts-jest": "^29.4.0",
47-
"tsup": "^8.5.0",
48-
"typescript": "^5.7.3"
47+
"tsup": "^8.5.1",
48+
"typescript": "^5.9.3"
4949
},
5050
"dependencies": {
51-
"@contentstack/delivery-sdk": "^4.10.0",
51+
"@contentstack/delivery-sdk": "^4.10.3",
5252
"@gql2ts/from-schema": "^2.0.0-4",
5353
"async": "^3.2.6",
54-
"axios": "^1.12.2",
54+
"axios": "^1.13.2",
5555
"lodash": "^4.17.21",
5656
"prettier": "^3.6.2"
5757
},

src/generateTS/factory.ts

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,11 @@ export default function (userOptions: TSGenOptions) {
277277
const reason = `Unknown field type: ${field.data_type}`;
278278
skippedFields.push({ uid: field.uid, path: field.uid, reason });
279279
logger?.warn(
280-
ERROR_MESSAGES.SKIPPED_FIELD_UNKNOWN_TYPE(field.uid, field.data_type, reason)
280+
ERROR_MESSAGES.SKIPPED_FIELD_UNKNOWN_TYPE(
281+
field.uid,
282+
field.data_type,
283+
reason
284+
)
281285
);
282286
type = "Record<string, unknown>"; // Use Record<string, unknown> for balanced type safety
283287
}
@@ -295,7 +299,11 @@ export default function (userOptions: TSGenOptions) {
295299
if (exclusionCheck.shouldExclude) {
296300
skippedFields.push(exclusionCheck.record!);
297301
logger?.warn(
298-
ERROR_MESSAGES.SKIPPED_GLOBAL_FIELD_REFERENCE(field.uid, field.reference_to, NUMERIC_IDENTIFIER_EXCLUSION_REASON)
302+
ERROR_MESSAGES.SKIPPED_GLOBAL_FIELD_REFERENCE(
303+
field.uid,
304+
field.reference_to,
305+
NUMERIC_IDENTIFIER_EXCLUSION_REASON
306+
)
299307
);
300308
return "string"; // Use string as fallback for global field references
301309
}
@@ -349,7 +357,11 @@ export default function (userOptions: TSGenOptions) {
349357
if (exclusionCheck.shouldExclude) {
350358
skippedFields.push(exclusionCheck.record!);
351359
logger?.warn(
352-
ERROR_MESSAGES.SKIPPED_FIELD_AT_PATH(field.uid, fieldPath, NUMERIC_IDENTIFIER_EXCLUSION_REASON)
360+
ERROR_MESSAGES.SKIPPED_FIELD_AT_PATH(
361+
field.uid,
362+
fieldPath,
363+
NUMERIC_IDENTIFIER_EXCLUSION_REASON
364+
)
353365
);
354366
continue;
355367
}
@@ -412,7 +424,11 @@ export default function (userOptions: TSGenOptions) {
412424
if (exclusionCheck.shouldExclude) {
413425
skippedBlocks.push(exclusionCheck.record!);
414426
logger?.warn(
415-
ERROR_MESSAGES.SKIPPED_BLOCK_AT_PATH(block.uid, blockPath, NUMERIC_IDENTIFIER_EXCLUSION_REASON)
427+
ERROR_MESSAGES.SKIPPED_BLOCK_AT_PATH(
428+
block.uid,
429+
blockPath,
430+
NUMERIC_IDENTIFIER_EXCLUSION_REASON
431+
)
416432
);
417433
return null; // Return null to filter out later
418434
}
@@ -433,6 +449,12 @@ export default function (userOptions: TSGenOptions) {
433449

434450
// If all blocks were skipped, return a more specific fallback type
435451
if (modularBlockDefinitions.length === 0) {
452+
if (options.systemFields) {
453+
const modularBlocksType = `${options.naming?.prefix || ""}ModularBlocksExtension`;
454+
return field.multiple
455+
? `${modularBlocksType}<Record<string, unknown>>[]`
456+
: `${modularBlocksType}<Record<string, unknown>>`;
457+
}
436458
return field.multiple
437459
? "Record<string, unknown>[]"
438460
: "Record<string, unknown>";
@@ -445,6 +467,13 @@ export default function (userOptions: TSGenOptions) {
445467
const existingInterfaceName =
446468
blockInterfacesKeyToName[modularBlockSignature];
447469
if (existingInterfaceName) {
470+
// Wrap with ModularBlocks type to add _metadata support only when systemFields is enabled
471+
if (options.systemFields) {
472+
const modularBlocksType = `${options.naming?.prefix || ""}ModularBlocksExtension`;
473+
return field.multiple
474+
? `${modularBlocksType}<${existingInterfaceName}>[]`
475+
: `${modularBlocksType}<${existingInterfaceName}>`;
476+
}
448477
return field.multiple
449478
? `${existingInterfaceName}[]`
450479
: existingInterfaceName;
@@ -468,6 +497,14 @@ export default function (userOptions: TSGenOptions) {
468497
modularBlockInterfaces.add(modularBlockInterfaceDefinition);
469498
cachedModularBlocks[modularBlockInterfaceName] = modularBlockSignature;
470499
blockInterfacesKeyToName[modularBlockSignature] = modularBlockInterfaceName;
500+
501+
// Wrap with ModularBlocks type to add _metadata support only when systemFields is enabled
502+
if (options.systemFields) {
503+
const modularBlocksType = `${options.naming?.prefix || ""}ModularBlocksExtension`;
504+
return field.multiple
505+
? `${modularBlocksType}<${modularBlockInterfaceName}>[]`
506+
: `${modularBlocksType}<${modularBlockInterfaceName}>`;
507+
}
471508
return field.multiple
472509
? `${modularBlockInterfaceName}[]`
473510
: modularBlockInterfaceName;
@@ -514,7 +551,10 @@ export default function (userOptions: TSGenOptions) {
514551
if (exclusionCheck.shouldExclude) {
515552
skippedFields.push(exclusionCheck.record!);
516553
logger?.warn(
517-
ERROR_MESSAGES.SKIPPED_GLOBAL_FIELD(field.uid, NUMERIC_IDENTIFIER_EXCLUSION_REASON)
554+
ERROR_MESSAGES.SKIPPED_GLOBAL_FIELD(
555+
field.uid,
556+
NUMERIC_IDENTIFIER_EXCLUSION_REASON
557+
)
518558
);
519559
return "string"; // Use string as fallback for global fields
520560
}
@@ -560,7 +600,10 @@ export default function (userOptions: TSGenOptions) {
560600
references.push(name_type(v));
561601
} else {
562602
logger?.warn(
563-
ERROR_MESSAGES.SKIPPED_REFERENCE(v, NUMERIC_IDENTIFIER_EXCLUSION_REASON)
603+
ERROR_MESSAGES.SKIPPED_REFERENCE(
604+
v,
605+
NUMERIC_IDENTIFIER_EXCLUSION_REASON
606+
)
564607
);
565608
}
566609
});
@@ -570,7 +613,10 @@ export default function (userOptions: TSGenOptions) {
570613
references.push(name_type(field.reference_to));
571614
} else {
572615
logger?.warn(
573-
ERROR_MESSAGES.SKIPPED_REFERENCE(field.reference_to, NUMERIC_IDENTIFIER_EXCLUSION_REASON)
616+
ERROR_MESSAGES.SKIPPED_REFERENCE(
617+
field.reference_to,
618+
NUMERIC_IDENTIFIER_EXCLUSION_REASON
619+
)
574620
);
575621
}
576622
}
@@ -669,7 +715,7 @@ export default function (userOptions: TSGenOptions) {
669715
function type_json_rte(field: ContentstackTypes.Field) {
670716
let json_rte;
671717
if (field.config && field.field_metadata?.extension) {
672-
json_rte = `{ value: { key: string; value: string }[] }`;
718+
json_rte = `unknown`;
673719
} else {
674720
json_rte = `{
675721
type: string;

src/generateTS/stack/builtins.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ export const defaultInterfaces = (
1717

1818
// Conditionally include ReferencedEntry interface
1919
if (includeReferencedEntry) {
20+
const extendsClause = systemFields ? ` extends ${prefix}SystemFields` : "";
2021
defaultInterfaces.push(
21-
`export interface ${prefix}ReferencedEntry {
22+
`export interface ${prefix}ReferencedEntry${extendsClause} {
2223
uid: string;
2324
_content_type_uid: string;
2425
}`
@@ -124,6 +125,11 @@ export const defaultInterfaces = (
124125
title?: string;
125126
}`
126127
);
128+
defaultInterfaces.push(
129+
`export type ${prefix}ModularBlocksExtension<T> = {
130+
[P in keyof T]?: T[P] & { _metadata?: { uid?: string } };
131+
}`
132+
);
127133
return defaultInterfaces;
128134
} else {
129135
return defaultInterfaces;

src/types/schema.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,5 @@ export type ContentType = {
6565
reference_to?: string;
6666
data_type?: string;
6767
schema_type?: string;
68+
title?: string;
6869
} & Identifier;

tests/unit/tsgen/custom-field.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ describe("JSON RTE", () => {
2121
{
2222
_version?: number;
2323
title: string;
24-
custom_key_value_pair?: { value: { key: string; value: string }[] };
24+
custom_key_value_pair?: unknown;
2525
}"
2626
`);
2727
});

0 commit comments

Comments
 (0)