@@ -33,18 +33,13 @@ function extractFragmentContent(text, fragment, fullLine) {
3333}
3434
3535function walkFetchEmbed ( { embedTokens, compile, fetch } , cb ) {
36- let token ;
37- let step = 0 ;
38- let count = 0 ;
39-
4036 if ( ! embedTokens . length ) {
4137 return cb ( { } ) ;
4238 }
4339
44- while ( ( token = embedTokens [ step ++ ] ) ) {
45- const currentToken = token ;
40+ const processStep = step => {
41+ const currentToken = embedTokens [ step ] ;
4642
47- // eslint-disable-next-line no-loop-func
4843 const next = text => {
4944 let embedToken ;
5045 if ( text ) {
@@ -119,17 +114,21 @@ function walkFetchEmbed({ embedTokens, compile, fetch }, cb) {
119114 tokenRef : currentToken . tokenRef ,
120115 } ) ;
121116
122- if ( ++ count >= embedTokens . length ) {
117+ if ( step + 1 >= embedTokens . length ) {
123118 cb ( { } ) ;
119+ } else {
120+ processStep ( step + 1 ) ;
124121 }
125122 } ;
126123
127- if ( token . embed . url ) {
128- get ( token . embed . url ) . then ( next ) ;
124+ if ( currentToken . embed . url ) {
125+ get ( currentToken . embed . url ) . then ( next ) ;
129126 } else {
130- next ( token . embed . html ) ;
127+ next ( currentToken . embed . html ) ;
131128 }
132- }
129+ } ;
130+
131+ processStep ( 0 ) ;
133132}
134133
135134export function prerenderEmbed ( { compiler, raw = '' , fetch } , done ) {
@@ -143,46 +142,56 @@ export function prerenderEmbed({ compiler, raw = '', fetch }, done) {
143142 const compile = compiler . _marked ;
144143 let tokens = compile . lexer ( raw ) ;
145144 const embedTokens = [ ] ;
146- const linkRE = compile . Lexer . rules . inline . normal . link ;
147145 const links = tokens . links ;
148146
149- const linkMatcher = new RegExp ( linkRE . source , 'g' ) ;
150-
151147 tokens . forEach ( ( token , index ) => {
152148 if ( token . type === 'paragraph' ) {
153- token . text = token . text . replace (
154- linkMatcher ,
155- ( src , filename , href , title ) => {
156- const embed = compiler . compileEmbed ( href , title ) ;
149+ ( token . tokens || [ ] ) . forEach (
150+ (
151+ /** @type {{ type: string; href: any; title: any; } } */ inlineToken ,
152+ inlineIndex ,
153+ ) => {
154+ if ( inlineToken . type !== 'link' ) {
155+ return ;
156+ }
157+
158+ const embed = compiler . compileEmbed (
159+ inlineToken . href ,
160+ inlineToken . title ,
161+ ) ;
157162 if ( embed ) {
158163 embedTokens . push ( {
159164 index,
160165 tokenRef : token ,
166+ inlineIndex,
161167 embed,
162168 } ) ;
163169 }
164- return src ;
165170 } ,
166171 ) ;
167172 } else if ( token . type === 'table' ) {
168173 token . rows . forEach ( ( row , rowIndex ) => {
169174 row . forEach ( ( cell , cellIndex ) => {
170- cell . text = cell . text . replace (
171- linkMatcher ,
172- ( src , filename , href , title ) => {
173- const embed = compiler . compileEmbed ( href , title ) ;
174- if ( embed ) {
175- embedTokens . push ( {
176- index,
177- tokenRef : token ,
178- rowIndex,
179- cellIndex,
180- embed,
181- } ) ;
182- }
183- return src ;
184- } ,
185- ) ;
175+ ( cell . tokens || [ ] ) . forEach ( ( inlineToken , inlineIndex ) => {
176+ if ( inlineToken . type !== 'link' ) {
177+ return ;
178+ }
179+
180+ const embed = compiler . compileEmbed (
181+ inlineToken . href ,
182+ inlineToken . title ,
183+ ) ;
184+ if ( embed ) {
185+ embedTokens . push ( {
186+ index,
187+ tokenRef : token ,
188+ rowIndex,
189+ cellIndex,
190+ inlineIndex,
191+ embed,
192+ } ) ;
193+ }
194+ } ) ;
186195 } ) ;
187196 } ) ;
188197 }
@@ -192,30 +201,73 @@ export function prerenderEmbed({ compiler, raw = '', fetch }, done) {
192201 // so that we know where to insert the embedded tokens as they
193202 // are returned
194203 const moves = [ ] ;
204+ const tokenInsertState = new WeakMap ( ) ;
195205 walkFetchEmbed (
196206 { compile, embedTokens, fetch } ,
197207 ( { embedToken, token, rowIndex, cellIndex, tokenRef } ) => {
198208 if ( token ) {
209+ Object . assign ( links , embedToken . links ) ;
210+
199211 if ( typeof rowIndex === 'number' && typeof cellIndex === 'number' ) {
200212 const cell = tokenRef . rows [ rowIndex ] [ cellIndex ] ;
213+ if ( typeof token . inlineIndex === 'number' ) {
214+ cell . embedTokenMap ||= { } ;
215+ const existing = cell . embedTokenMap [ token . inlineIndex ] ;
216+ cell . embedTokenMap [ token . inlineIndex ] = existing
217+ ? existing . concat ( embedToken )
218+ : embedToken ;
219+ }
201220
202- cell . embedTokens = embedToken ;
221+ // Keep the flattened array for backward compatibility with older render paths.
222+ if ( cell . embedTokens && cell . embedTokens . length ) {
223+ cell . embedTokens = cell . embedTokens . concat ( embedToken ) ;
224+ } else {
225+ cell . embedTokens = embedToken ;
226+ }
227+ } else if ( tokenRef . type === 'paragraph' ) {
228+ if ( typeof token . inlineIndex === 'number' ) {
229+ tokenRef . embedTokenMap ||= { } ;
230+ const existing = tokenRef . embedTokenMap [ token . inlineIndex ] ;
231+ tokenRef . embedTokenMap [ token . inlineIndex ] = existing
232+ ? existing . concat ( embedToken )
233+ : embedToken ;
234+ }
235+
236+ // Keep a flattened form as a fallback for custom renderers.
237+ if ( tokenRef . embedTokens && tokenRef . embedTokens . length ) {
238+ tokenRef . embedTokens = tokenRef . embedTokens . concat ( embedToken ) ;
239+ } else {
240+ tokenRef . embedTokens = embedToken ;
241+ }
203242 } else {
204- // iterate through the array of previously inserted tokens
205- // to determine where the current embedded tokens should be inserted
206- let index = token . index ;
207- moves . forEach ( pos => {
208- if ( index > pos . start ) {
209- index += pos . length ;
210- }
211- } ) ;
243+ const state = tokenInsertState . get ( tokenRef ) ;
212244
213- Object . assign ( links , embedToken . links ) ;
245+ if ( state ) {
246+ const insertAt = state . nextIndex ;
214247
215- tokens = tokens
216- . slice ( 0 , index )
217- . concat ( embedToken , tokens . slice ( index + 1 ) ) ;
218- moves . push ( { start : index , length : embedToken . length - 1 } ) ;
248+ tokens = tokens
249+ . slice ( 0 , insertAt )
250+ . concat ( embedToken , tokens . slice ( insertAt ) ) ;
251+ moves . push ( { start : insertAt , delta : embedToken . length } ) ;
252+ state . nextIndex = insertAt + embedToken . length ;
253+ } else {
254+ // iterate through the array of previously inserted tokens
255+ // to determine where the current embedded tokens should be inserted
256+ let index = token . index ;
257+ moves . forEach ( pos => {
258+ if ( index > pos . start ) {
259+ index += pos . delta ;
260+ }
261+ } ) ;
262+
263+ tokens = tokens
264+ . slice ( 0 , index )
265+ . concat ( embedToken , tokens . slice ( index + 1 ) ) ;
266+ moves . push ( { start : index , delta : embedToken . length - 1 } ) ;
267+ tokenInsertState . set ( tokenRef , {
268+ nextIndex : index + embedToken . length ,
269+ } ) ;
270+ }
219271 }
220272 } else {
221273 cached [ raw ] = tokens . concat ( ) ;
0 commit comments