@@ -6,6 +6,7 @@ const filesWithIssues = [];
6
6
7
7
/**
8
8
* Custom frontmatter parser that enforces specific formatting rules
9
+ * with support for multi-line values
9
10
*
10
11
* @param {Object } params - The parameters provided by Docusaurus
11
12
* @param {string } params.filePath - Path to the markdown file
@@ -83,42 +84,170 @@ async function customParseFrontMatter(params) {
83
84
const yamlContent = frontmatterMatch [ 1 ] ;
84
85
const yamlLines = yamlContent . split ( '\n' ) ;
85
86
86
- for ( const line of yamlLines ) {
87
+ // Track multi-line values
88
+ let inMultiLineValue = false ;
89
+ let currentFieldName = '' ;
90
+
91
+ for ( let i = 0 ; i < yamlLines . length ; i ++ ) {
92
+ const line = yamlLines [ i ] ;
87
93
if ( line . trim ( ) === '' ) continue ;
88
94
89
- // Check for single space between key and value
90
- if ( ! / ^ [ a - z A - Z _ ] + : / . test ( line ) && ! line . includes ( ': [' ) ) {
91
- issues . push ( `incorrect spacing in line: "${ line . trim ( ) } "` ) ;
92
- }
95
+ // Check if this line starts a new field
96
+ const fieldMatch = line . match ( / ^ ( [ a - z A - Z _ ] + ) : / ) ;
97
+
98
+ if ( fieldMatch ) {
99
+ // This is a new field, not a continuation
100
+ inMultiLineValue = false ;
101
+ currentFieldName = fieldMatch [ 1 ] ;
102
+
103
+ // Check for single space between key and value
104
+ if ( ! / ^ [ a - z A - Z _ ] + : / . test ( line ) && ! line . includes ( ': [' ) ) {
105
+ issues . push ( `incorrect spacing in line: "${ line . trim ( ) } "` ) ;
106
+ }
107
+
108
+ // Check for block style arrays (should be flow style with brackets)
109
+ if ( line . trim ( ) . match ( / ^ [ a - z A - Z _ ] + : ? $ / ) ) {
110
+ // This field has no value on the same line, check if next line starts with a dash
111
+ const nextLine = ( i + 1 < yamlLines . length ) ? yamlLines [ i + 1 ] . trim ( ) : '' ;
112
+ if ( nextLine . startsWith ( '-' ) ) {
113
+ issues . push ( `field '${ currentFieldName } ' should use flow style array with square brackets` ) ;
114
+ }
115
+ }
116
+
117
+ // Check for single quotes on regular single-line values
118
+ const fieldValue = line . substring ( line . indexOf ( ':' ) + 1 ) . trim ( ) ;
119
+
120
+ // Check if this might be the start of a multi-line value
121
+ if ( fieldValue . startsWith ( "'" ) && ! fieldValue . endsWith ( "'" ) ) {
122
+ inMultiLineValue = true ;
123
+ continue ;
124
+ }
125
+
126
+ // Special check for keywords array - items should be in single quotes
127
+ if ( currentFieldName === 'keywords' && line . includes ( '[' ) ) {
128
+ // Check if this is the start of a multi-line array
129
+ if ( line . includes ( '[' ) && ! line . includes ( ']' ) ) {
130
+ // This is the start of a multi-line array
131
+ inMultiLineValue = true ;
132
+ continue ;
133
+ }
134
+
135
+ // For single-line arrays
136
+ if ( line . includes ( '[' ) && line . includes ( ']' ) ) {
137
+ const arrayContent = line . substring ( line . indexOf ( '[' ) + 1 , line . lastIndexOf ( ']' ) ) ;
138
+ if ( arrayContent . trim ( ) ) { // Only check if array is not empty
139
+ const items = arrayContent . split ( ',' ) . map ( item => item . trim ( ) ) ;
140
+ for ( const item of items ) {
141
+ // Check if the item is not wrapped in single quotes
142
+ if ( item && ( ! item . startsWith ( "'" ) || ! item . endsWith ( "'" ) ) ) {
143
+ issues . push ( `keywords array item '${ item } ' should be wrapped in single quotes` ) ;
144
+ }
145
+ }
146
+ }
147
+ }
148
+ }
149
+
150
+ const isExcludedField = currentFieldName === 'slug' ||
151
+ currentFieldName === 'id' ||
152
+ currentFieldName === 'pagination_next' ||
153
+ currentFieldName === 'pagination_prev' ;
93
154
94
- // Special check for keywords array - items should be in single quotes
95
- if ( line . trim ( ) . startsWith ( 'keywords:' ) && line . includes ( '[' ) ) {
96
- const arrayContent = line . substring ( line . indexOf ( '[' ) + 1 , line . lastIndexOf ( ']' ) ) ;
97
- if ( arrayContent . trim ( ) ) { // Only check if array is not empty
98
- const items = arrayContent . split ( ',' ) . map ( item => item . trim ( ) ) ;
155
+ if ( ! isExcludedField && ! inMultiLineValue && (
156
+ line . includes ( ': "' ) || (
157
+ line . includes ( ': ' ) &&
158
+ ! line . includes ( ': \'' ) &&
159
+ ! line . includes ( ': [' ) &&
160
+ ! line . includes ( ': {' ) &&
161
+ ! line . includes ( ': true' ) &&
162
+ ! line . includes ( ': false' ) &&
163
+ ! / : \d + / . test ( line )
164
+ )
165
+ ) ) {
166
+ issues . push ( `value should use single quotes in line: "${ line . trim ( ) } "` ) ;
167
+ }
168
+ } else if ( inMultiLineValue ) {
169
+ // This is a continuation of a multi-line value
170
+
171
+ // For multi-line arrays (keywords)
172
+ if ( currentFieldName === 'keywords' ) {
173
+ // Check individual array items if this is a line in a multi-line array
174
+ const trimmedLine = line . trim ( ) ;
175
+
176
+ // Handle closing bracket properly
177
+ if ( trimmedLine === ']' ) {
178
+ inMultiLineValue = false ;
179
+ continue ;
180
+ }
181
+
182
+ // Parse items carefully to handle the closing bracket
183
+ let items = [ ] ;
184
+ let currentItem = '' ;
185
+ let inQuotes = false ;
186
+
187
+ for ( let j = 0 ; j < trimmedLine . length ; j ++ ) {
188
+ const char = trimmedLine [ j ] ;
189
+
190
+ if ( char === "'" && ( j === 0 || trimmedLine [ j - 1 ] !== '\\' ) ) {
191
+ inQuotes = ! inQuotes ;
192
+ currentItem += char ;
193
+ } else if ( char === ',' && ! inQuotes ) {
194
+ items . push ( currentItem . trim ( ) ) ;
195
+ currentItem = '' ;
196
+ } else if ( char === ']' && ! inQuotes ) {
197
+ // End of array - don't include the closing bracket in the item
198
+ if ( currentItem . trim ( ) ) {
199
+ items . push ( currentItem . trim ( ) ) ;
200
+ }
201
+ inMultiLineValue = false ;
202
+ break ;
203
+ } else {
204
+ currentItem += char ;
205
+ }
206
+ }
207
+
208
+ // Add the last item if we didn't end with a bracket
209
+ if ( currentItem . trim ( ) && ! trimmedLine . endsWith ( ']' ) ) {
210
+ items . push ( currentItem . trim ( ) ) ;
211
+ }
212
+
213
+ // Check items for proper quoting
99
214
for ( const item of items ) {
100
- // Check if the item is not wrapped in single quotes
101
- if ( item && ! item . startsWith ( "'" ) || ! item . endsWith ( "'" ) ) {
102
- issues . push ( `keywords array item '${ item } ' should be wrapped in single quotes` ) ;
215
+ if ( item && item !== ']' ) {
216
+ if ( ! item . startsWith ( "'" ) || ! item . endsWith ( "'" ) ) {
217
+ issues . push ( `keywords array item '${ item } ' should be wrapped in single quotes` ) ;
218
+ }
103
219
}
104
220
}
221
+
222
+ // Array end is now handled in the item parsing loop above
105
223
}
106
- }
224
+ // For regular multi-line strings
225
+ else if ( line . trim ( ) . endsWith ( "'" ) ) {
226
+ inMultiLineValue = false ;
227
+ }
228
+ } else {
229
+ // This is not a new field nor a continuation of a multi-line value
107
230
108
- const lineStart = line . trim ( ) ;
109
- const isExcludedField = lineStart . startsWith ( 'slug:' ) ||
110
- lineStart . startsWith ( 'id:' ) ||
111
- lineStart . startsWith ( 'pagination_next:' ) ||
112
- lineStart . startsWith ( 'pagination_prev:' ) ;
113
- if ( ! isExcludedField && (
114
- line . includes ( ': "' ) || ( line . includes ( ': ' ) &&
115
- ! line . includes ( ': \'' ) &&
116
- ! line . includes ( ': [' ) &&
117
- ! line . includes ( ': {' ) &&
118
- ! line . includes ( ': true' ) &&
119
- ! line . includes ( ': false' ) &&
120
- ! / : \d + / . test ( line ) ) ) ) {
121
- issues . push ( `value should use single quotes in line: "${ line . trim ( ) } "` ) ;
231
+ // Check for block style array items that should be flow style
232
+ if ( line . trim ( ) . startsWith ( '-' ) ) {
233
+ // Find the previous field to associate with this block array item
234
+ let j = i - 1 ;
235
+ while ( j >= 0 ) {
236
+ const prevLine = yamlLines [ j ] . trim ( ) ;
237
+ if ( prevLine . match ( / ^ [ a - z A - Z _ ] + : ? $ / ) ) {
238
+ const fieldName = prevLine . split ( ':' ) [ 0 ] . trim ( ) ;
239
+ // Only report once per field to avoid multiple errors
240
+ if ( ! issues . some ( issue => issue . includes ( `field '${ fieldName } '` ) && issue . includes ( 'flow style array' ) ) ) {
241
+ issues . push ( `field '${ fieldName } ' should use flow style array with square brackets` ) ;
242
+ }
243
+ break ;
244
+ } else if ( prevLine . match ( / ^ [ a - z A - Z _ ] + : / ) ) {
245
+ // Found a different field, so stop looking
246
+ break ;
247
+ }
248
+ j -- ;
249
+ }
250
+ }
122
251
}
123
252
}
124
253
}
0 commit comments