11import { PlainClientAPI , EntryProps , ContentTypeProps } from 'contentful-management' ;
22import { EntryToCreate } from '../agents/documentParserAgent/schema' ;
3+ import { markdownToRichText } from './utils/richtext' ;
34
45/**
56 * INTEG-3264: Service for creating entries in Contentful using the Contentful Management API
@@ -17,146 +18,6 @@ export interface EntryCreationResult {
1718 } > ;
1819}
1920
20- function createTextNode ( value : string , marks : Array < { type : 'bold' | 'italic' | 'underline' } > ) {
21- return {
22- nodeType : 'text' ,
23- value,
24- marks,
25- data : { } ,
26- } ;
27- }
28-
29- function createParagraph ( children : any [ ] ) {
30- return {
31- nodeType : 'paragraph' ,
32- data : { } ,
33- content : children ,
34- } ;
35- }
36-
37- function createHeading ( level : number , children : any [ ] ) {
38- const clamped = Math . min ( 6 , Math . max ( 1 , level ) ) ;
39- return {
40- nodeType : `heading-${ clamped } ` ,
41- data : { } ,
42- content : children ,
43- } ;
44- }
45-
46- function markdownToRichText ( markdown : string ) {
47- // Normalize simple HTML tags to markdown-like markers we support
48- // Bold: <strong> or <b> -> **
49- // Italic: <em> or <i> -> *
50- // Underline: <u> -> _
51- let normalized = markdown ;
52- try {
53- normalized = normalized
54- . replace ( / < s t r o n g > ( [ \s \S ] * ?) < \/ s t r o n g > / gi, '**$1**' )
55- . replace ( / < b > ( [ \s \S ] * ?) < \/ b > / gi, '**$1**' )
56- . replace ( / < e m > ( [ \s \S ] * ?) < \/ e m > / gi, '*$1*' )
57- . replace ( / < i > ( [ \s \S ] * ?) < \/ i > / gi, '*$1*' )
58- . replace ( / < u > ( [ \s \S ] * ?) < \/ u > / gi, '_$1_' ) ;
59- } catch {
60- // If any regex fails, fall back to original string
61- normalized = markdown ;
62- }
63-
64- // Basic Markdown to Contentful Rich Text for bold (**text**) and italics (*text*)
65- // Splits into paragraphs by newlines
66- const lines = normalized . split ( / \r ? \n / ) ;
67- const documentChildren : any [ ] = [ ] ;
68-
69- for ( const rawLine of lines ) {
70- if ( ! rawLine . trim ( ) ) {
71- continue ;
72- }
73-
74- const nodes : any [ ] = [ ] ;
75- let buffer = '' ;
76- let i = 0 ;
77- let bold = false ;
78- let italic = false ;
79- let underline = false ;
80-
81- // Detect Markdown heading at start of line
82- const headingMatch = rawLine . match ( / ^ \s * ( # { 1 , 6 } ) \s + ( .* ) $ / ) ;
83- // Heuristic: treat lines that are entirely bold as H2 (e.g., **Heading**)
84- const boldOnlyMatch = headingMatch
85- ? null
86- : rawLine . match ( / ^ \s * ( \* \* | _ _ ) \s * ( [ \s \S ] * ?) \s * \1\s * $ / ) ;
87- const isHeading = Boolean ( headingMatch || boldOnlyMatch ) ;
88- const headingLevel = headingMatch ? ( headingMatch [ 1 ] . length as number ) : boldOnlyMatch ? 2 : 0 ;
89- const line = headingMatch ? headingMatch [ 2 ] : boldOnlyMatch ? boldOnlyMatch [ 2 ] : rawLine ;
90-
91- const flushBuffer = ( ) => {
92- if ( buffer . length === 0 ) return ;
93- const marks : Array < { type : 'bold' | 'italic' | 'underline' } > = [ ] ;
94- if ( bold ) marks . push ( { type : 'bold' } ) ;
95- if ( italic ) marks . push ( { type : 'italic' } ) ;
96- if ( underline ) marks . push ( { type : 'underline' } ) ;
97- nodes . push ( createTextNode ( buffer , marks ) ) ;
98- buffer = '' ;
99- } ;
100-
101- while ( i < line . length ) {
102- // Toggle bold on '**'
103- if ( line . startsWith ( '**' , i ) ) {
104- flushBuffer ( ) ;
105- bold = ! bold ;
106- i += 2 ;
107- continue ;
108- }
109- // Toggle italic on '*'
110- if ( line [ i ] === '*' ) {
111- // Avoid treating '**' case here
112- if ( ! ( i + 1 < line . length && line [ i + 1 ] === '*' ) ) {
113- flushBuffer ( ) ;
114- italic = ! italic ;
115- i += 1 ;
116- continue ;
117- }
118- }
119- // Toggle underline on '__' or single '_'
120- if ( line . startsWith ( '__' , i ) ) {
121- flushBuffer ( ) ;
122- underline = ! underline ;
123- i += 2 ;
124- continue ;
125- }
126- if ( line [ i ] === '_' ) {
127- // Avoid treating '__' case here
128- if ( ! ( i + 1 < line . length && line [ i + 1 ] === '_' ) ) {
129- flushBuffer ( ) ;
130- underline = ! underline ;
131- i += 1 ;
132- continue ;
133- }
134- }
135- buffer += line [ i ] ;
136- i += 1 ;
137- }
138- flushBuffer ( ) ;
139-
140- if ( nodes . length === 0 ) {
141- nodes . push ( createTextNode ( '' , [ ] ) ) ;
142- }
143-
144- if ( isHeading ) {
145- documentChildren . push ( createHeading ( headingLevel , nodes ) ) ;
146- } else {
147- documentChildren . push ( createParagraph ( nodes ) ) ;
148- }
149- }
150-
151- return {
152- nodeType : 'document' ,
153- data : { } ,
154- content : documentChildren . length
155- ? documentChildren
156- : [ createParagraph ( [ createTextNode ( '' , [ ] ) ] ) ] ,
157- } ;
158- }
159-
16021function transformFieldsForContentType (
16122 fields : Record < string , Record < string , unknown > > ,
16223 contentType : ContentTypeProps | undefined
0 commit comments