book-source 0.3.11 → 0.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/StructuredDocument.js +153 -26
- package/lib/documentParts.js +24 -3
- package/lib/postProcesses.js +150 -0
- package/package.json +1 -1
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
|
|
31
31
|
const documentParts = require( './documentParts.js' ) ;
|
|
32
32
|
const Style = require( './Style.js' ) ;
|
|
33
|
-
const Theme = require( './Theme.js' ) ;
|
|
34
33
|
const textPostFilters = require( './textPostFilters.js' ) ;
|
|
35
34
|
|
|
36
35
|
const inPlaceFilter = require( 'array-kit/lib/inPlaceFilter.js' ) ;
|
|
@@ -38,24 +37,41 @@ const inPlaceFilter = require( 'array-kit/lib/inPlaceFilter.js' ) ;
|
|
|
38
37
|
|
|
39
38
|
|
|
40
39
|
function StructuredDocument() {
|
|
40
|
+
this.type = 'document' ;
|
|
41
41
|
this.title = 'Document' ;
|
|
42
42
|
this.metadata = null ;
|
|
43
43
|
this.theme = null ;
|
|
44
|
+
this.summary = null ;
|
|
44
45
|
this.parts = [] ;
|
|
46
|
+
//this.idList = new Set() ;
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
module.exports = StructuredDocument ;
|
|
48
50
|
|
|
51
|
+
// Circular require, should come after exporting
|
|
52
|
+
const postProcesses = require( './postProcesses.js' ) ;
|
|
49
53
|
|
|
50
54
|
|
|
51
|
-
StructuredDocument.prototype.render = function( renderer ) {
|
|
52
|
-
var meta = {
|
|
53
|
-
title: this.title
|
|
54
|
-
} ;
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
StructuredDocument.prototype.render = function( renderer , special = null ) {
|
|
57
|
+
let toRender ;
|
|
58
|
+
|
|
59
|
+
switch ( special ) {
|
|
60
|
+
case 'summary' :
|
|
61
|
+
toRender = this.summary ? [ this.summary ] : [] ;
|
|
62
|
+
break ;
|
|
63
|
+
default :
|
|
64
|
+
toRender = this.parts ;
|
|
65
|
+
break ;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let output = this.renderParts( renderer , toRender , [] , [ {} ] ) ;
|
|
57
69
|
|
|
58
70
|
if ( renderer.document ) {
|
|
71
|
+
let meta = {
|
|
72
|
+
title: this.title
|
|
73
|
+
} ;
|
|
74
|
+
|
|
59
75
|
output = renderer.document( meta , output ) ;
|
|
60
76
|
}
|
|
61
77
|
|
|
@@ -199,25 +215,79 @@ StructuredDocument.prototype.autoTitle = function() {
|
|
|
199
215
|
|
|
200
216
|
if ( ! header ) { return ; }
|
|
201
217
|
|
|
202
|
-
str = StructuredDocument.getText( header
|
|
218
|
+
str = StructuredDocument.getText( header ) ;
|
|
203
219
|
if ( str ) { this.title = str ; }
|
|
204
220
|
} ;
|
|
205
221
|
|
|
206
222
|
|
|
207
223
|
|
|
208
|
-
StructuredDocument.
|
|
209
|
-
var
|
|
224
|
+
StructuredDocument.prototype.postProcess = function( params = {} ) {
|
|
225
|
+
var data = {} ,
|
|
226
|
+
postProcessArray = [] ,
|
|
227
|
+
postProcessMap = new Map() ;
|
|
210
228
|
|
|
211
|
-
for ( let
|
|
212
|
-
if (
|
|
213
|
-
|
|
229
|
+
for ( let postProcessName of Object.keys( params ) ) {
|
|
230
|
+
if ( ! postProcesses[ postProcessName ] || ! params[ postProcessName ] ) { continue ; }
|
|
231
|
+
|
|
232
|
+
let postProcess = postProcesses[ postProcessName ] ;
|
|
233
|
+
|
|
234
|
+
// Add required post-process first
|
|
235
|
+
if ( postProcess.require ) {
|
|
236
|
+
for ( let requiredName of postProcess.require ) {
|
|
237
|
+
if ( ! postProcessMap.has( requiredName ) ) {
|
|
238
|
+
let entry = { name: requiredName , params: {} } ;
|
|
239
|
+
postProcessArray.push( entry ) ;
|
|
240
|
+
postProcessMap.set( requiredName , entry ) ;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if ( postProcessMap.has( postProcessName ) ) {
|
|
246
|
+
// It was already added by a dependency, just patch the params if needed
|
|
247
|
+
if ( typeof params[ postProcessName ] === 'object' ) {
|
|
248
|
+
let entry = postProcessMap.get( postProcessName ) ;
|
|
249
|
+
entry.params = Object.assign( {} , params[ postProcessName ] ) ;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
let entry = {
|
|
254
|
+
name: postProcessName ,
|
|
255
|
+
params: typeof params[ postProcessName ] === 'object' ? Object.assign( {} , params[ postProcessName ] ) : {}
|
|
256
|
+
} ;
|
|
257
|
+
|
|
258
|
+
postProcessArray.push( entry ) ;
|
|
259
|
+
postProcessMap.set( postProcessName , entry ) ;
|
|
260
|
+
}
|
|
214
261
|
}
|
|
215
262
|
|
|
216
|
-
|
|
263
|
+
for ( let entry of postProcessArray ) {
|
|
264
|
+
if ( postProcesses[ entry.name ].init ) {
|
|
265
|
+
postProcesses[ entry.name ].init( this , entry.params , data ) ;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
this.postProcessRecursive( this , postProcessArray , data ) ;
|
|
270
|
+
|
|
271
|
+
for ( let entry of postProcessArray ) {
|
|
272
|
+
if ( postProcesses[ entry.name ].finalize ) {
|
|
273
|
+
postProcesses[ entry.name ].finalize( this , entry.params , data ) ;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
217
276
|
} ;
|
|
218
277
|
|
|
219
|
-
|
|
220
|
-
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
StructuredDocument.prototype.postProcessRecursive = function( object , postProcessArray , data ) {
|
|
281
|
+
for ( let entry of postProcessArray ) {
|
|
282
|
+
postProcesses[ entry.name ]( this , object , entry.params , data ) ;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if ( object.parts && object.parts.length ) {
|
|
286
|
+
for ( let part of object.parts ) {
|
|
287
|
+
this.postProcessRecursive( part , postProcessArray , data ) ;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
} ;
|
|
221
291
|
|
|
222
292
|
|
|
223
293
|
|
|
@@ -251,10 +321,49 @@ StructuredDocument.prototype.oneTextPostFilter = function( postFilter , parts ,
|
|
|
251
321
|
|
|
252
322
|
|
|
253
323
|
|
|
324
|
+
// Utility methods
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
StructuredDocument.getText = function( object ) {
|
|
329
|
+
if ( Array.isArray( object ) ) {
|
|
330
|
+
object = { parts: object } ;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if ( object.text ) { return object.text ; }
|
|
334
|
+
if ( ! object.parts || ! object.parts.length ) { return '' ; }
|
|
335
|
+
|
|
336
|
+
let str = '' ;
|
|
337
|
+
|
|
338
|
+
for ( let part of object.parts ) {
|
|
339
|
+
str += StructuredDocument.getText( part ) ;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return str ;
|
|
343
|
+
} ;
|
|
344
|
+
|
|
345
|
+
// Backward compatibility/API
|
|
346
|
+
StructuredDocument.prototype.getText = function( object = this ) { return StructuredDocument.getText( object ) ; } ;
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
StructuredDocument.textToId = function( text ) {
|
|
351
|
+
return text
|
|
352
|
+
.trim()
|
|
353
|
+
.normalize( 'NFC' )
|
|
354
|
+
.replace( /[\s]+/g , '_' )
|
|
355
|
+
.replace( /[^\p{L}\p{N}_.:-]/gu , '' )
|
|
356
|
+
.replace( /_+/g , '_' ) ;
|
|
357
|
+
} ;
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
|
|
254
361
|
// Parser
|
|
255
362
|
|
|
256
|
-
|
|
257
|
-
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
StructuredDocument.parse = function( str , params ) {
|
|
366
|
+
if ( ! params || typeof params !== 'object' ) { params = {} ; }
|
|
258
367
|
|
|
259
368
|
if ( typeof str !== 'string' ) {
|
|
260
369
|
if ( str && typeof str === 'object' ) { str = str.toString() ; }
|
|
@@ -281,10 +390,11 @@ StructuredDocument.parse = function( str , options ) {
|
|
|
281
390
|
parseBlocks( str , ctx ) ;
|
|
282
391
|
|
|
283
392
|
for ( let table of ctx.rowSpanTables ) { postProcessTableRowSpan( table ) ; }
|
|
393
|
+
|
|
284
394
|
ctx.structuredDocument.autoTitle() ;
|
|
285
395
|
|
|
286
396
|
if ( ctx.rawMetadata ) {
|
|
287
|
-
let metadataParser =
|
|
397
|
+
let metadataParser = params.metadataParser || JSON.parse ;
|
|
288
398
|
for ( let type in ctx.rawMetadata ) {
|
|
289
399
|
try {
|
|
290
400
|
let parsed = metadataParser( ctx.rawMetadata[ type ] ) ;
|
|
@@ -387,6 +497,9 @@ function parseBlock( str , ctx ) {
|
|
|
387
497
|
case BLOCK_METADATA :
|
|
388
498
|
parseMetadata( str , ctx ) ;
|
|
389
499
|
break ;
|
|
500
|
+
case BLOCK_SPECIAL :
|
|
501
|
+
parseSpecial( str , ctx ) ;
|
|
502
|
+
break ;
|
|
390
503
|
default :
|
|
391
504
|
throw new Error( "Bad block detection: " + blockType ) ;
|
|
392
505
|
}
|
|
@@ -495,6 +608,7 @@ const BLOCK_TABLE_ROW_THICK_SEPARATOR = 42 ;
|
|
|
495
608
|
const BLOCK_TABLE_CAPTION = 43 ;
|
|
496
609
|
const BLOCK_ANCHOR = 50 ;
|
|
497
610
|
const BLOCK_METADATA = 60 ;
|
|
611
|
+
const BLOCK_SPECIAL = 80 ;
|
|
498
612
|
|
|
499
613
|
function detectBlockType( str , i ) {
|
|
500
614
|
if ( str[ i ] === '\\' ) {
|
|
@@ -502,14 +616,17 @@ function detectBlockType( str , i ) {
|
|
|
502
616
|
}
|
|
503
617
|
|
|
504
618
|
if ( str[ i ] === '#' ) {
|
|
505
|
-
if ( str[ i + 1 ] === '(' ) {
|
|
619
|
+
if ( str[ i + 1 ] === '(' ) {
|
|
620
|
+
if ( str[ i + 2 ] === '%' ) { return BLOCK_SPECIAL ; }
|
|
621
|
+
return BLOCK_ANCHOR ;
|
|
622
|
+
}
|
|
506
623
|
return BLOCK_HEADER ;
|
|
507
624
|
}
|
|
508
625
|
|
|
509
626
|
if ( str[ i ] === '!' && str[ i + 2 ] === '[' ) {
|
|
510
627
|
if ( str[ i + 1 ] === '=' ) { return BLOCK_MEDIA ; }
|
|
511
|
-
|
|
512
|
-
|
|
628
|
+
if ( str[ i + 1 ] === '<' ) { return BLOCK_FLOAT_LEFT_MEDIA ; }
|
|
629
|
+
if ( str[ i + 1 ] === '>' ) { return BLOCK_FLOAT_RIGHT_MEDIA ; }
|
|
513
630
|
return BLOCK_PARAGRAPH ;
|
|
514
631
|
}
|
|
515
632
|
|
|
@@ -860,6 +977,18 @@ function parseAnchor( str , ctx ) {
|
|
|
860
977
|
|
|
861
978
|
|
|
862
979
|
|
|
980
|
+
function parseSpecial( str , ctx ) {
|
|
981
|
+
//console.log( "parseSpecial()" ) ;
|
|
982
|
+
var end = searchCloser( str , ctx.i + 3 , '(' , ')' , true ) ;
|
|
983
|
+
if ( end < 0 ) { return parseParagraph( str , ctx ) ; }
|
|
984
|
+
|
|
985
|
+
ctx.parts.push( new documentParts.Special( str.slice( ctx.i + 3 , end ) ) ) ;
|
|
986
|
+
|
|
987
|
+
ctx.i = end + 1 ;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
|
|
991
|
+
|
|
863
992
|
function parseTableCaption( str , ctx ) {
|
|
864
993
|
//console.log( "parseTableCaption()" ) ;
|
|
865
994
|
var lastCharOfLine = searchLastCharOfLine( str , ctx.i + 1 ) ;
|
|
@@ -1369,9 +1498,7 @@ function parseInlineChildrenOfParent( str , ctx , parent , blockEnd , trim = fal
|
|
|
1369
1498
|
// Try to parse non-block content
|
|
1370
1499
|
function parseInline( str , ctx , blockEnd , trim = false ) {
|
|
1371
1500
|
//console.log( "parseInline() -- remaining:" , ctx.i , str.slice( ctx.i ) ) ;
|
|
1372
|
-
var
|
|
1373
|
-
|
|
1374
|
-
scanEnd = blockEnd = blockEnd ?? searchEndOfLine( str , ctx.i ) ;
|
|
1501
|
+
var scanEnd = blockEnd = blockEnd ?? searchEndOfLine( str , ctx.i ) ;
|
|
1375
1502
|
|
|
1376
1503
|
if ( trim ) {
|
|
1377
1504
|
let first = searchNextNotInSet( str , ctx.i , blockEnd , WHITE_SPACES ) ;
|
|
@@ -1657,7 +1784,7 @@ function parseInfotipedText( str , ctx , scanEnd ) {
|
|
|
1657
1784
|
ctx.iStartOfInlineChunk = ctx.i + 1 ;
|
|
1658
1785
|
|
|
1659
1786
|
if ( ! href && ! hint ) {
|
|
1660
|
-
infotipedText.href = StructuredDocument.getText( infotipedText
|
|
1787
|
+
infotipedText.href = StructuredDocument.getText( infotipedText ) ;
|
|
1661
1788
|
}
|
|
1662
1789
|
}
|
|
1663
1790
|
|
|
@@ -2011,7 +2138,7 @@ function searchBlockSwitchCloser( str , i , closer , closerMinStreak = 1 , end =
|
|
|
2011
2138
|
Same that searchBlockSwitchCloser() but with a callback function.
|
|
2012
2139
|
*/
|
|
2013
2140
|
function searchFixedBlockSwitchCloser( str , i , fixed , end = str.length ) {
|
|
2014
|
-
var
|
|
2141
|
+
var j , failed ;
|
|
2015
2142
|
|
|
2016
2143
|
while ( i < end ) {
|
|
2017
2144
|
// Search next line
|
package/lib/documentParts.js
CHANGED
|
@@ -33,13 +33,17 @@ module.exports = documentParts ;
|
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
function Part() {
|
|
36
|
+
function Part() {
|
|
37
|
+
this.id = null ;
|
|
38
|
+
}
|
|
37
39
|
|
|
38
40
|
documentParts.Part = Part ;
|
|
39
41
|
|
|
40
42
|
|
|
41
43
|
|
|
42
|
-
function InlinePart() {
|
|
44
|
+
function InlinePart() {
|
|
45
|
+
Part.call( this ) ;
|
|
46
|
+
}
|
|
43
47
|
|
|
44
48
|
InlinePart.prototype = Object.create( Part.prototype ) ;
|
|
45
49
|
InlinePart.prototype.constructor = InlinePart ;
|
|
@@ -48,6 +52,7 @@ documentParts.InlinePart = InlinePart ;
|
|
|
48
52
|
|
|
49
53
|
|
|
50
54
|
function InlineContainerPart() {
|
|
55
|
+
Part.call( this ) ;
|
|
51
56
|
this.parts = [] ;
|
|
52
57
|
}
|
|
53
58
|
|
|
@@ -58,6 +63,7 @@ documentParts.InlineContainerPart = InlineContainerPart ;
|
|
|
58
63
|
|
|
59
64
|
|
|
60
65
|
function InlineTextPart( text ) {
|
|
66
|
+
Part.call( this ) ;
|
|
61
67
|
this.text = text ;
|
|
62
68
|
}
|
|
63
69
|
|
|
@@ -67,7 +73,9 @@ documentParts.InlineTextPart = InlineTextPart ;
|
|
|
67
73
|
|
|
68
74
|
|
|
69
75
|
|
|
70
|
-
function BlockPart() {
|
|
76
|
+
function BlockPart() {
|
|
77
|
+
Part.call( this ) ;
|
|
78
|
+
}
|
|
71
79
|
|
|
72
80
|
BlockPart.prototype = Object.create( Part.prototype ) ;
|
|
73
81
|
BlockPart.prototype.constructor = BlockPart ;
|
|
@@ -76,6 +84,7 @@ documentParts.BlockPart = BlockPart ;
|
|
|
76
84
|
|
|
77
85
|
|
|
78
86
|
function BlockContainerPart() {
|
|
87
|
+
Part.call( this ) ;
|
|
79
88
|
this.parts = [] ;
|
|
80
89
|
}
|
|
81
90
|
|
|
@@ -362,6 +371,18 @@ documentParts.Anchor = Anchor ;
|
|
|
362
371
|
|
|
363
372
|
|
|
364
373
|
|
|
374
|
+
function Special( special ) {
|
|
375
|
+
this.type = 'special' ;
|
|
376
|
+
this.special = special ;
|
|
377
|
+
BlockContainerPart.call( this ) ;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
Special.prototype = Object.create( BlockContainerPart.prototype ) ;
|
|
381
|
+
Special.prototype.constructor = Special ;
|
|
382
|
+
documentParts.Special = Special ;
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
|
|
365
386
|
function ImageBlock( href , altText , float , caption , hint ) {
|
|
366
387
|
this.type = 'imageBlock' ;
|
|
367
388
|
this.href = href ;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Book Source
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2023 Cédric Ronvel
|
|
5
|
+
|
|
6
|
+
The MIT License (MIT)
|
|
7
|
+
|
|
8
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
10
|
+
in the Software without restriction, including without limitation the rights
|
|
11
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
furnished to do so, subject to the following conditions:
|
|
14
|
+
|
|
15
|
+
The above copyright notice and this permission notice shall be included in all
|
|
16
|
+
copies or substantial portions of the Software.
|
|
17
|
+
|
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
|
+
SOFTWARE.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
"use strict" ;
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
const StructuredDocument = require( './StructuredDocument.js' ) ;
|
|
32
|
+
const documentParts = require( './documentParts.js' ) ;
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
exports.autoId = ( structuredDocument , object , params , data ) => {
|
|
37
|
+
if ( ! params.types.has( object.type ) ) { return ; }
|
|
38
|
+
|
|
39
|
+
let text = StructuredDocument.getText( object ) ;
|
|
40
|
+
let id = data.idPrefix + StructuredDocument.textToId( text ) ;
|
|
41
|
+
|
|
42
|
+
if ( data.idList.has( id ) ) {
|
|
43
|
+
let originalId = id ;
|
|
44
|
+
let count = data.idList.get( originalId ) ;
|
|
45
|
+
count ++ ;
|
|
46
|
+
id = originalId + '_' + count ;
|
|
47
|
+
|
|
48
|
+
while ( data.idList.has( id ) ) {
|
|
49
|
+
count ++ ;
|
|
50
|
+
id = originalId + '_' + count ;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
data.idList.set( originalId , count ) ;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Always add the current ID, even if originalId was added too
|
|
57
|
+
data.idList.set( id , 1 ) ;
|
|
58
|
+
|
|
59
|
+
object.id = id ;
|
|
60
|
+
} ;
|
|
61
|
+
|
|
62
|
+
const DEFAULT_AUTO_ID_TYPES = new Set( [ 'header' ] ) ;
|
|
63
|
+
|
|
64
|
+
exports.autoId.init = ( structuredDocument , params , data ) => {
|
|
65
|
+
if ( Array.isArray( params.types ) ) { params.types = new Set( params.types ) ; }
|
|
66
|
+
else if ( ! params.types || ! ( params.types instanceof Set ) ) { params.types = DEFAULT_AUTO_ID_TYPES ; }
|
|
67
|
+
|
|
68
|
+
if ( data.idPrefix === undefined ) { data.idPrefix = params.idPrefix || '' ; }
|
|
69
|
+
|
|
70
|
+
data.idList = new Map() ;
|
|
71
|
+
} ;
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
exports.summary = ( structuredDocument , object , params , data ) => {
|
|
76
|
+
if ( object.type === 'special' ) {
|
|
77
|
+
switch ( object.special ) {
|
|
78
|
+
case 'summary' :
|
|
79
|
+
data.summaryObjects.push( object ) ;
|
|
80
|
+
break ;
|
|
81
|
+
case 'summary-start' :
|
|
82
|
+
resetSummary( data ) ;
|
|
83
|
+
break ;
|
|
84
|
+
case 'summary-end' :
|
|
85
|
+
data.summaryEnded = true ;
|
|
86
|
+
break ;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return ;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if ( data.summaryEnded || object.type !== 'header' || object.level > params.maxLevel ) { return ; }
|
|
93
|
+
|
|
94
|
+
let item = new documentParts.ListItem( object.level - 1 ) ;
|
|
95
|
+
let link = new documentParts.Link( '#' + object.id ) ;
|
|
96
|
+
item.parts.push( link ) ;
|
|
97
|
+
let text = new documentParts.Text( StructuredDocument.getText( object ) ) ;
|
|
98
|
+
link.parts.push( text ) ;
|
|
99
|
+
|
|
100
|
+
if ( ! data.summaryHeaderLevelStack.length ) {
|
|
101
|
+
data.summaryHeaderLevelStack.push( object.level ) ;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let lastListLevel = data.summaryHeaderLevelStack.length - 1 ;
|
|
105
|
+
let lastHeaderLevel = data.summaryHeaderLevelStack[ lastListLevel ] ;
|
|
106
|
+
|
|
107
|
+
while ( object.level < lastHeaderLevel && lastListLevel > 0 ) {
|
|
108
|
+
lastListLevel -- ;
|
|
109
|
+
lastHeaderLevel = data.summaryHeaderLevelStack[ lastListLevel ] ;
|
|
110
|
+
data.summaryHeaderLevelStack.length = data.summaryListStack.length = lastListLevel + 1 ;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if ( object.level > lastHeaderLevel ) {
|
|
114
|
+
let parentList = data.summaryListStack[ lastListLevel ] ;
|
|
115
|
+
let currentList = new documentParts.List( object.level - 1 ) ;
|
|
116
|
+
data.summaryListStack.push( currentList ) ;
|
|
117
|
+
data.summaryHeaderLevelStack.push( object.level ) ;
|
|
118
|
+
currentList.parts.push( item ) ;
|
|
119
|
+
parentList.parts.push( currentList ) ;
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
// It's equal OR the doc is not well-formed and it's less, nevertheless, we just act as if it's equal
|
|
123
|
+
let currentList = data.summaryListStack[ lastListLevel ] ;
|
|
124
|
+
currentList.parts.push( item ) ;
|
|
125
|
+
}
|
|
126
|
+
} ;
|
|
127
|
+
|
|
128
|
+
exports.summary.init = ( structuredDocument , params , data ) => {
|
|
129
|
+
params.maxLevel = params.maxLevel || Infinity ;
|
|
130
|
+
data.summaryObjects = [] ;
|
|
131
|
+
resetSummary( data ) ;
|
|
132
|
+
} ;
|
|
133
|
+
|
|
134
|
+
function resetSummary( data ) {
|
|
135
|
+
data.summaryList = new documentParts.List( 0 ) ;
|
|
136
|
+
data.summaryListStack = [ data.summaryList ] ;
|
|
137
|
+
data.summaryHeaderLevelStack = [] ;
|
|
138
|
+
data.summaryEnded = false ;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
exports.summary.finalize = ( structuredDocument , params , data ) => {
|
|
142
|
+
structuredDocument.summary = data.summaryList ;
|
|
143
|
+
|
|
144
|
+
for ( let summaryObject of data.summaryObjects ) {
|
|
145
|
+
summaryObject.parts.push( data.summaryList ) ;
|
|
146
|
+
}
|
|
147
|
+
} ;
|
|
148
|
+
|
|
149
|
+
exports.summary.require = [ 'autoId' ] ;
|
|
150
|
+
|