11import type {
22 AttributeNode ,
33 CommentNode ,
4+ DoctypeNode ,
45 Node ,
56 ParentNode ,
67 TagLikeNode ,
@@ -28,36 +29,26 @@ export function isParent(node: Node): node is ParentNode {
2829/** walk element nodes */
2930export function walkElements (
3031 parent : ParentNode ,
32+ code : string ,
3133 cb : ( n : Node , parent : ParentNode ) => void ,
3234) : void {
33- let children = parent . children
34- if ( parent . type === "root" && children . every ( ( n ) => n . position ) ) {
35- // The order of comments and frontmatter may be changed.
36- children = [ ...children ] . sort (
37- ( a , b ) => a . position ! . start . offset - b . position ! . start . offset ,
38- )
39- }
35+ const children = getSortedChildren ( parent , code )
4036 for ( const node of children ) {
4137 cb ( node , parent )
4238 if ( isParent ( node ) ) {
43- walkElements ( node , cb )
39+ walkElements ( node , code , cb )
4440 }
4541 }
4642}
4743
4844/** walk nodes */
4945export function walk (
5046 parent : ParentNode ,
47+ code : string ,
5148 enter : ( n : Node | AttributeNode , parent : ParentNode ) => void ,
5249 leave ?: ( n : Node | AttributeNode , parent : ParentNode ) => void ,
5350) : void {
54- let children = parent . children
55- if ( parent . type === "root" && children . every ( ( n ) => n . position ) ) {
56- // The order of comments and frontmatter may be changed.
57- children = [ ...children ] . sort (
58- ( a , b ) => a . position ! . start . offset - b . position ! . start . offset ,
59- )
60- }
51+ const children = getSortedChildren ( parent , code )
6152 for ( const node of children ) {
6253 enter ( node , parent )
6354 if ( isTag ( node ) ) {
@@ -67,7 +58,7 @@ export function walk(
6758 }
6859 }
6960 if ( isParent ( node ) ) {
70- walk ( node , enter , leave )
61+ walk ( node , code , enter , leave )
7162 }
7263 leave ?.( node , parent )
7364 }
@@ -261,3 +252,45 @@ export function skipSpaces(string: string, position: number): number {
261252 }
262253 return position
263254}
255+
256+ /**
257+ * Get children
258+ */
259+ function getSortedChildren ( parent : ParentNode , code : string ) {
260+ if ( parent . type === "root" && parent . children [ 0 ] ?. type === "frontmatter" ) {
261+ // The order of comments and frontmatter may be changed.
262+ const children = [ ...parent . children ]
263+ if ( children . every ( ( n ) => n . position ) ) {
264+ return children . sort (
265+ ( a , b ) => a . position ! . start . offset - b . position ! . start . offset ,
266+ )
267+ }
268+ let start = skipSpaces ( code , 0 )
269+ if ( code . startsWith ( "<!" , start ) ) {
270+ const frontmatter = children . shift ( ) !
271+ const before : ( CommentNode | DoctypeNode ) [ ] = [ ]
272+ let first
273+ while ( ( first = children . shift ( ) ) ) {
274+ start = skipSpaces ( code , start )
275+ if (
276+ first . type === "comment" &&
277+ code . startsWith ( "<!--" , start )
278+ ) {
279+ start = code . indexOf ( "-->" , start + 4 ) + 3
280+ before . push ( first )
281+ } else if (
282+ first . type === "doctype" &&
283+ code . startsWith ( "<!" , start )
284+ ) {
285+ start = code . indexOf ( ">" , start + 2 ) + 1
286+ before . push ( first )
287+ } else {
288+ children . unshift ( first )
289+ break
290+ }
291+ }
292+ return [ ...before , frontmatter , ...children ]
293+ }
294+ }
295+ return parent . children
296+ }
0 commit comments