@@ -2,43 +2,8 @@ type Header = `${'#' | '##' | '###' | '####' | '#####' | '######'} ${string}`;
22
33const HEADER_REGEX = / ^ # { 1 , 6 } .+ $ / m;
44
5- export function upsert (
6- content : string ,
7- lines : Array < string | false | undefined | null | 0 | 0n > ,
8- options ?: {
9- header ?: Header ;
10- mode ?: 'prepend' | 'append' ;
11- }
12- ) : string {
13- const { header, mode = 'append' } = options ?? { } ;
14- const linesToAdd = lines . filter ( Boolean ) . join ( '\n' ) ;
15-
16- if ( ! header ) {
17- return joinContent ( content , linesToAdd ) ;
18- }
19-
20- const headerMatch = findHeader ( content , header ) ;
21-
22- if ( ! headerMatch ) {
23- return joinContent ( content , header , linesToAdd ) ;
24- }
25- const { end : headerLineEnd , after : restOfContent } = headerMatch ;
26-
27- const nextHeaderMatch = restOfContent . match ( HEADER_REGEX ) ;
28-
29- let insertPos : number ;
30- if ( mode === 'prepend' ) {
31- insertPos = headerLineEnd + 1 ;
32- } else if ( nextHeaderMatch ) {
33- insertPos = headerLineEnd + 1 + restOfContent . indexOf ( nextHeaderMatch [ 0 ] ) ;
34- } else {
35- insertPos = content . length ;
36- }
37-
38- const before = content . slice ( 0 , insertPos ) ;
39- const after = content . slice ( insertPos ) ;
40-
41- return joinContent ( before , linesToAdd , after ) ;
5+ function getHeaderLevel ( header : Header ) : number {
6+ return header . split ( ' ' ) [ 0 ] . length ;
427}
438
449function escapeRegex ( str : string ) : string {
@@ -92,3 +57,109 @@ function findHeader(
9257 after : content . slice ( end + 1 )
9358 } ;
9459}
60+
61+ function findSection (
62+ content : string ,
63+ header : Header
64+ ) : {
65+ before : string ;
66+ after : string ;
67+ header : Header ;
68+ innerContent : string ;
69+ start : number ;
70+ end : number ;
71+ } | null {
72+ const headerMatch = findHeader ( content , header ) ;
73+
74+ if ( ! headerMatch ) return null ;
75+
76+ const { start, end : headerEnd , before } = headerMatch ;
77+ const level = getHeaderLevel ( header ) ;
78+ const nextHeaderRegex = new RegExp ( `^#{${ level } } ` , 'm' ) ;
79+ const afterHeader = content . slice ( headerEnd + 1 ) ;
80+ const nextHeaderMatch = afterHeader . match ( nextHeaderRegex ) ;
81+
82+ let end : number ;
83+ if ( nextHeaderMatch ) {
84+ end = headerEnd + 1 + afterHeader . indexOf ( nextHeaderMatch [ 0 ] ) ;
85+ } else {
86+ end = content . length ;
87+ }
88+
89+ const innerContent = content . slice ( headerEnd + 1 , end ) ;
90+ const after = content . slice ( end ) ;
91+
92+ return {
93+ before,
94+ after,
95+ header,
96+ innerContent,
97+ start,
98+ end
99+ } ;
100+ }
101+
102+ export function upsert (
103+ content : string ,
104+ lines : Array < string | false | undefined | null | 0 | 0n > ,
105+ options ?: {
106+ header ?:
107+ | Header
108+ | {
109+ name : Header ;
110+ parent ?: Header ;
111+ } ;
112+ }
113+ ) : string {
114+ const { header } = options ?? { } ;
115+ const linesToAdd = lines . filter ( Boolean ) . join ( '\n' ) ;
116+
117+ if ( ! header ) {
118+ return joinContent ( content , linesToAdd ) ;
119+ }
120+
121+ if ( typeof header === 'string' ) {
122+ return asdf ( content , linesToAdd , header ) ;
123+ } else {
124+ if ( ! header . parent ) {
125+ return asdf ( content , linesToAdd , header . name ) ;
126+ }
127+ const section = findSection ( content , header . parent ) ;
128+
129+ if ( ! section ) {
130+ return joinContent ( content , header . parent , header . name , linesToAdd ) ;
131+ }
132+
133+ return joinContent (
134+ section . before ,
135+ section . header ,
136+ section . innerContent ,
137+ header . name ,
138+ linesToAdd ,
139+ section . after
140+ ) ;
141+ }
142+ }
143+
144+ function asdf ( content : string , linesToAdd : string , header : Header ) : string {
145+ const section = findSection ( content , header ) ;
146+
147+ if ( ! section ) {
148+ return joinContent ( content , header , linesToAdd ) ;
149+ }
150+
151+ const { start, end, innerContent } = section ;
152+ const firstNextHeaderMatch = innerContent . match ( HEADER_REGEX ) ;
153+
154+ let insertPos : number ;
155+ if ( firstNextHeaderMatch ) {
156+ insertPos = start + header . length + 1 + innerContent . indexOf ( firstNextHeaderMatch [ 0 ] ) ;
157+ } else {
158+ insertPos = end ;
159+ }
160+
161+ const before = content . slice ( 0 , insertPos ) ;
162+ const after = content . slice ( insertPos ) ;
163+
164+ return joinContent ( before , linesToAdd , after ) ;
165+ }
0 commit comments