book-source 0.3.10 → 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Cédric Ronvel
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -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
- var output = this.renderParts( renderer , this.parts , [] , [ {} ] ) ;
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.parts ) ;
218
+ str = StructuredDocument.getText( header ) ;
203
219
  if ( str ) { this.title = str ; }
204
220
  } ;
205
221
 
206
222
 
207
223
 
208
- StructuredDocument.getText = function( parts ) {
209
- var str = '' ;
224
+ StructuredDocument.prototype.postProcess = function( params = {} ) {
225
+ var data = {} ,
226
+ postProcessArray = [] ,
227
+ postProcessMap = new Map() ;
210
228
 
211
- for ( let part of parts ) {
212
- if ( part.text ) { str += part.text ; }
213
- else if ( part.parts?.length ) { str += StructuredDocument.getText( part.parts ) ; }
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
- return str ;
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
- // Backqard compatibility/API
220
- StructuredDocument.prototype.getText = function( parts = this.parts ) { return StructuredDocument.getText( parts ) ; } ;
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
- StructuredDocument.parse = function( str , options ) {
257
- if ( ! options || typeof options !== 'object' ) { options = {} ; }
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 = options.metadataParser || JSON.parse ;
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 ] ) ;
@@ -299,10 +409,6 @@ StructuredDocument.parse = function( str , options ) {
299
409
  }
300
410
  }
301
411
 
302
- // Call depthManagement() one last time, because some instanceOf may still be hanging...
303
- //ctx.depth = -1 ;
304
- //depthManagement( ctx ) ;
305
-
306
412
  return ctx.structuredDocument ;
307
413
  } ;
308
414
 
@@ -391,6 +497,9 @@ function parseBlock( str , ctx ) {
391
497
  case BLOCK_METADATA :
392
498
  parseMetadata( str , ctx ) ;
393
499
  break ;
500
+ case BLOCK_SPECIAL :
501
+ parseSpecial( str , ctx ) ;
502
+ break ;
394
503
  default :
395
504
  throw new Error( "Bad block detection: " + blockType ) ;
396
505
  }
@@ -499,6 +608,7 @@ const BLOCK_TABLE_ROW_THICK_SEPARATOR = 42 ;
499
608
  const BLOCK_TABLE_CAPTION = 43 ;
500
609
  const BLOCK_ANCHOR = 50 ;
501
610
  const BLOCK_METADATA = 60 ;
611
+ const BLOCK_SPECIAL = 80 ;
502
612
 
503
613
  function detectBlockType( str , i ) {
504
614
  if ( str[ i ] === '\\' ) {
@@ -506,14 +616,17 @@ function detectBlockType( str , i ) {
506
616
  }
507
617
 
508
618
  if ( str[ i ] === '#' ) {
509
- if ( str[ i + 1 ] === '(' ) { return BLOCK_ANCHOR ; }
619
+ if ( str[ i + 1 ] === '(' ) {
620
+ if ( str[ i + 2 ] === '%' ) { return BLOCK_SPECIAL ; }
621
+ return BLOCK_ANCHOR ;
622
+ }
510
623
  return BLOCK_HEADER ;
511
624
  }
512
625
 
513
626
  if ( str[ i ] === '!' && str[ i + 2 ] === '[' ) {
514
627
  if ( str[ i + 1 ] === '=' ) { return BLOCK_MEDIA ; }
515
- else if ( str[ i + 1 ] === '<' ) { return BLOCK_FLOAT_LEFT_MEDIA ; }
516
- else if ( str[ i + 1 ] === '>' ) { return BLOCK_FLOAT_RIGHT_MEDIA ; }
628
+ if ( str[ i + 1 ] === '<' ) { return BLOCK_FLOAT_LEFT_MEDIA ; }
629
+ if ( str[ i + 1 ] === '>' ) { return BLOCK_FLOAT_RIGHT_MEDIA ; }
517
630
  return BLOCK_PARAGRAPH ;
518
631
  }
519
632
 
@@ -864,6 +977,18 @@ function parseAnchor( str , ctx ) {
864
977
 
865
978
 
866
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
+
867
992
  function parseTableCaption( str , ctx ) {
868
993
  //console.log( "parseTableCaption()" ) ;
869
994
  var lastCharOfLine = searchLastCharOfLine( str , ctx.i + 1 ) ;
@@ -901,7 +1026,7 @@ function parseTableCaption( str , ctx ) {
901
1026
  if ( data?.style?.[ 0 ] ) { tableCaption.style = data.style[ 0 ] ; }
902
1027
  }
903
1028
 
904
- ctx.i = lastCharOfLine + 1 ;
1029
+ ctx.i = searchEndOfLine( str , lastCharOfLine !== - 1 ? lastCharOfLine : ctx.i ) + 1 ;
905
1030
  }
906
1031
 
907
1032
 
@@ -991,7 +1116,7 @@ function parseTableRow( str , ctx ) {
991
1116
  currentBar = columnSeparator ? nextBar + 1 : nextBar ;
992
1117
  }
993
1118
 
994
- // Compute cells indexes, columnSpan, rowSpan, column template
1119
+ // Compute cells indexes, columnSpan, column template, and add missing cells
995
1120
  computeIndexColumnSpan( ctx , table , tableRow ) ;
996
1121
 
997
1122
  if ( str[ currentBar + 1 ] === '<' ) {
@@ -1000,7 +1125,7 @@ function parseTableRow( str , ctx ) {
1000
1125
  if ( data?.style?.[ 0 ] ) { tableRow.style = data.style[ 0 ] ; }
1001
1126
  }
1002
1127
 
1003
- ctx.i = lastCharOfLine + 1 ;
1128
+ ctx.i = searchEndOfLine( str , lastCharOfLine !== - 1 ? lastCharOfLine : ctx.i ) + 1 ;
1004
1129
  }
1005
1130
 
1006
1131
 
@@ -1033,7 +1158,7 @@ function parseTableMultilineRow( str , ctx , lastCharOfLine , table , tableRow )
1033
1158
  columnIndex ++ ;
1034
1159
  }
1035
1160
 
1036
- ctx.i = lastCharOfLine + 1 ;
1161
+ ctx.i = searchEndOfLine( str , lastCharOfLine !== - 1 ? lastCharOfLine : ctx.i ) + 1 ;
1037
1162
  }
1038
1163
 
1039
1164
 
@@ -1143,7 +1268,7 @@ function parseTableRowSeparator( str , ctx , thick = false ) {
1143
1268
  separatorCellIndex ++ ;
1144
1269
  }
1145
1270
 
1146
- ctx.i = lastCharOfLine + 1 ;
1271
+ ctx.i = searchEndOfLine( str , lastCharOfLine !== - 1 ? lastCharOfLine : ctx.i ) + 1 ;
1147
1272
  }
1148
1273
 
1149
1274
 
@@ -1291,15 +1416,16 @@ function parseTableHeadRowSeparator( str , ctx , thick , lastCharOfLine ) {
1291
1416
  }
1292
1417
 
1293
1418
  if ( tableHeadRow ) {
1294
- // Compute cells indexes, columnSpan, rowSpan, column template
1419
+ // Compute cells indexes, columnSpan, column template, and add missing cells
1295
1420
  computeIndexColumnSpan( ctx , table , tableHeadRow ) ;
1296
1421
  }
1297
1422
 
1298
- ctx.i = lastCharOfLine + 1 ;
1423
+ ctx.i = searchEndOfLine( str , lastCharOfLine !== - 1 ? lastCharOfLine : ctx.i ) + 1 ;
1299
1424
  }
1300
1425
 
1301
1426
 
1302
1427
 
1428
+ // Compute cells indexes, columnSpan, column template, and add missing cells
1303
1429
  function computeIndexColumnSpan( ctx , table , tableRow ) {
1304
1430
  var tableCell , cellIndex , column , columnIndex , columnSpan ,
1305
1431
  columns = table.columns ,
@@ -1336,6 +1462,19 @@ function computeIndexColumnSpan( ctx , table , tableRow ) {
1336
1462
  }
1337
1463
  }
1338
1464
  }
1465
+
1466
+ // Add missing cells
1467
+ if ( columns ) {
1468
+ for ( ; extraSpan > 0 ; extraSpan -- ) {
1469
+ columnIndex = table.columns.length - extraSpan ;
1470
+ column = table.columns[ columnIndex ] ;
1471
+ tableCell = new documentParts.TableCell() ;
1472
+ tableCell.column = columnIndex ;
1473
+ tableCell.sx = column?.sx || - 1 ;
1474
+ tableCell.ex = column?.ex || - 1 ;
1475
+ tableRow.parts.push( tableCell ) ;
1476
+ }
1477
+ }
1339
1478
  }
1340
1479
 
1341
1480
 
@@ -1359,9 +1498,7 @@ function parseInlineChildrenOfParent( str , ctx , parent , blockEnd , trim = fal
1359
1498
  // Try to parse non-block content
1360
1499
  function parseInline( str , ctx , blockEnd , trim = false ) {
1361
1500
  //console.log( "parseInline() -- remaining:" , ctx.i , str.slice( ctx.i ) ) ;
1362
- var isSpace , scanEnd ;
1363
-
1364
- scanEnd = blockEnd = blockEnd ?? searchEndOfLine( str , ctx.i ) ;
1501
+ var scanEnd = blockEnd = blockEnd ?? searchEndOfLine( str , ctx.i ) ;
1365
1502
 
1366
1503
  if ( trim ) {
1367
1504
  let first = searchNextNotInSet( str , ctx.i , blockEnd , WHITE_SPACES ) ;
@@ -1647,7 +1784,7 @@ function parseInfotipedText( str , ctx , scanEnd ) {
1647
1784
  ctx.iStartOfInlineChunk = ctx.i + 1 ;
1648
1785
 
1649
1786
  if ( ! href && ! hint ) {
1650
- infotipedText.href = StructuredDocument.getText( infotipedText.parts ) ;
1787
+ infotipedText.href = StructuredDocument.getText( infotipedText ) ;
1651
1788
  }
1652
1789
  }
1653
1790
 
@@ -2001,7 +2138,7 @@ function searchBlockSwitchCloser( str , i , closer , closerMinStreak = 1 , end =
2001
2138
  Same that searchBlockSwitchCloser() but with a callback function.
2002
2139
  */
2003
2140
  function searchFixedBlockSwitchCloser( str , i , fixed , end = str.length ) {
2004
- var test , j , failed ;
2141
+ var j , failed ;
2005
2142
 
2006
2143
  while ( i < end ) {
2007
2144
  // Search next line
@@ -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
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "book-source",
3
- "version": "0.3.10",
3
+ "version": "0.3.13",
4
4
  "description": "A lightweight markup language, inspired by Markdown.",
5
5
  "main": "lib/book-source.js",
6
6
  "directories": {
package/.eslintrc.js DELETED
@@ -1,168 +0,0 @@
1
- module.exports = {
2
- 'root': true ,
3
- 'env': {
4
- 'browser': true ,
5
- 'node': true ,
6
- 'es6': true ,
7
- 'es2022': true
8
- } ,
9
- 'parserOptions': {
10
- 'ecmaVersion': 2022
11
- } ,
12
- 'extends': [ 'eslint:recommended' ] ,
13
- 'ignorePatterns': [ "*.min.js" ] ,
14
- 'rules': {
15
-
16
- /*
17
- Bad code -- detect anything that can be broken or lead to bugs
18
- */
19
-
20
-
21
-
22
- 'strict': [ 'error' , 'global' ] ,
23
- 'unicode-bom': [ 'error' , 'never' ] ,
24
- 'radix': 'error' ,
25
- 'eqeqeq': 'error' ,
26
- 'consistent-return': 'off' ,
27
- 'valid-typeof': 'error' ,
28
- 'no-unneeded-ternary': 'error' ,
29
- 'no-unused-vars': 'warn' , // During development phase, it's boring to clean unused var since they can be used later
30
- 'no-lonely-if': 'off' , // Can hurt semantic programming
31
- 'no-nested-ternary': 'off' , // Now I use the streamlined ternary operator a lot
32
- 'no-shadow': 'error' ,
33
- 'no-shadow-restricted-names': 'error' ,
34
- 'require-atomic-updates': 'off' , // check for possible race condition on assignment, interesting but too nitpicky
35
-
36
-
37
-
38
- /*
39
- Code preferences
40
- */
41
-
42
-
43
-
44
- 'prefer-arrow-callback': 'error' ,
45
- 'prefer-spread': 'warn' ,
46
- 'prefer-rest-params': 'warn' ,
47
- 'no-control-regex': 'off' , // because thing like \x00 are considered like a control even if escaped...
48
- 'no-fallthrough': 'off' ,
49
- 'no-empty': [ 'error' , {
50
- 'allowEmptyCatch': true
51
- } ] ,
52
-
53
-
54
-
55
- /*
56
- Coding styles -- cosmetic rules and opinionated preferences
57
- */
58
-
59
-
60
-
61
- // Indent & spaces (general)
62
- 'indent': [ 'error' , 'tab' , {
63
- 'SwitchCase': 1 ,
64
- 'MemberExpression': 1 ,
65
- 'flatTernaryExpressions': true
66
- } ] ,
67
- 'newline-per-chained-call': 'off',
68
- 'no-multi-spaces': 'off' ,
69
- 'block-spacing': 'error' ,
70
- 'comma-spacing': [ 'error' , {
71
- 'before': true ,
72
- 'after': true
73
- } ] ,
74
- 'no-whitespace-before-property': 'error' ,
75
- 'space-before-blocks': 'error' ,
76
- 'space-before-function-paren': [ 'error' , {
77
- 'anonymous': 'never',
78
- 'named': 'never',
79
- 'asyncArrow': 'always'
80
- } ] ,
81
- 'space-infix-ops': 'error' ,
82
- 'space-unary-ops': [ 'error' , {
83
- 'words': true ,
84
- 'nonwords': true ,
85
- 'overrides': {
86
- //'-': false ,
87
- }
88
- } ] ,
89
- 'space-in-parens': [ 'error' , 'always' , {
90
- 'exceptions': [ 'empty' ]
91
- } ] ,
92
- 'no-trailing-spaces': 'error' ,
93
- 'switch-colon-spacing': [ 'error' , {
94
- 'after': true ,
95
- 'before': true
96
- } ] ,
97
- 'arrow-spacing': 'error' ,
98
- 'rest-spread-spacing': [ 'error' , 'always' ] ,
99
- /* Troublesome with commented line of code
100
- 'spaced-comment': [ 'error' , 'always' , {
101
- 'line': {
102
- 'markers': [ '/' ],
103
- 'exceptions': [ '-', '*', '/' ]
104
- } ,
105
- 'block': {
106
- 'exceptions': [ '*' ] ,
107
- 'balanced': true
108
- }
109
- } ] ,
110
- */
111
-
112
-
113
- // Semi-colon
114
- 'semi': [ 'error' , 'always' ] ,
115
- 'semi-style': [ 'error' , 'last' ] ,
116
- 'semi-spacing': [ 'error' , {
117
- 'before': true ,
118
- 'after': true
119
- } ] ,
120
-
121
- // Objects
122
- 'key-spacing': [ 'error' , {
123
- 'beforeColon': false ,
124
- 'afterColon': true ,
125
- 'mode': 'strict'
126
- } ] ,
127
- 'object-curly-newline': [ 'error' , {
128
- 'ObjectExpression' : {
129
- 'consistent': true ,
130
- 'minProperties': 4
131
- } ,
132
- 'ObjectPattern' : {
133
- // object destructuring assigment
134
- 'consistent': true ,
135
- 'minProperties': 8
136
- }
137
- } ] ,
138
- 'object-curly-spacing': [ 'error' , 'always' ] ,
139
- 'object-property-newline': [ 'error' , { 'allowMultiplePropertiesPerLine': true } ] ,
140
-
141
-
142
- // Arrays
143
- 'array-bracket-newline': [ 'error' , 'consistent' ] ,
144
- //'array-element-newline': [ 'error' , { 'multiline': true , 'minItems': 5 } ] ,
145
- 'array-bracket-spacing': [ 'error' , 'always' ],
146
-
147
- 'brace-style': [ 'error' , 'stroustrup' , {
148
- 'allowSingleLine': true
149
- } ] ,
150
-
151
-
152
- // Misc style
153
- 'no-else-return': 'warn' ,
154
- 'comma-dangle': [ 'error' , 'never' ] ,
155
- 'quotes': 'off' ,
156
- 'camelcase': 'warn' ,
157
-
158
-
159
-
160
- /*
161
- Method limitation
162
- */
163
-
164
-
165
-
166
- 'no-console': 'off'
167
- }
168
- } ;
package/Makefile DELETED
@@ -1,112 +0,0 @@
1
-
2
-
3
-
4
- # User rules
5
-
6
- # The first rule is the default rule, when invoking "make" without argument...
7
- # Build every buildable things
8
- #all: install doc browser
9
- all: install doc
10
-
11
- # Just install things so it works, basicaly: it just performs a "npm install --production" ATM
12
- install: log/npm-install.log
13
-
14
- # Just install things so it works, basicaly: it just performs a "npm install" ATM
15
- dev-install: log/npm-dev-install.log
16
-
17
- # Build
18
- #build: browser
19
-
20
- # Build the browser lib
21
- #browser: browser/svg-kit.js browser/svg-kit.min.js
22
-
23
- # This run the JsHint & Mocha BDD test, display it to STDOUT & save it to log/mocha.log and log/jshint.log
24
- test: log/jshint.log log/mocha.log
25
-
26
- # This run the JsHint, display it to STDOUT & save it to log/jshint.log
27
- lint: log/jshint.log
28
-
29
- # This run the Mocha BDD test, display it to STDOUT & save it to log/mocha.log
30
- unit: log/mocha.log
31
-
32
- # This build the doc and README.md
33
- doc: README.md
34
-
35
- # This publish to NPM and push to Github, if we are on master branch only
36
- publish: log/npm-publish.log log/github-push.log
37
-
38
- # Clean temporary things, or things that can be automatically regenerated
39
- clean: clean-all
40
-
41
-
42
-
43
- # Variables
44
-
45
- BROWSERIFY=browserify
46
- UGLIFY=uglifyjs
47
-
48
-
49
-
50
- # Files rules
51
-
52
- # Build the browser lib
53
- #browser/svg-kit.js: lib/*.js lib/*/*.js
54
- # ${BROWSERIFY} lib/svg-kit.js -i fs -i image-size -s svgKit -o browser/svg-kit.js
55
-
56
- # Build the browser minified lib
57
- #browser/svg-kit.min.js: browser/svg-kit.js
58
- # ${UGLIFY} browser/svg-kit.js -o browser/svg-kit.min.js -m
59
-
60
- # JsHint STDOUT test
61
- log/jshint.log: log/npm-dev-install.log lib/*.js test/*.js
62
- ${JSHINT} lib/*.js test/*.js | tee log/jshint.log ; exit $${PIPESTATUS[0]}
63
-
64
- # Mocha BDD STDOUT test
65
- log/mocha.log: log/npm-dev-install.log lib/*.js test/*.js
66
- cd test ; ${MOCHA} *.js -R spec | tee ../log/mocha.log ; exit $${PIPESTATUS[0]}
67
-
68
- # README
69
- README.md: documentation.md
70
- cat documentation.md > README.md
71
-
72
- # Mocha Markdown BDD spec
73
- bdd-spec.md: log/npm-dev-install.log lib/*.js test/*.js
74
- cd test ; ${MOCHA} *.js -R markdown > ../bdd-spec.md
75
-
76
- # Upgrade version in package.json
77
- log/upgrade-package.log: lib/*.js test/*.js documentation.md
78
- npm version patch -m "Upgrade package.json version to %s" | tee log/upgrade-package.log ; exit $${PIPESTATUS[0]}
79
-
80
- # Publish to NPM
81
- log/npm-publish.log: check-if-master-branch log/upgrade-package.log
82
- npm publish | tee log/npm-publish.log ; exit $${PIPESTATUS[0]}
83
-
84
- # Push to Github/master
85
- log/github-push.log: lib/*.js test/*.js package.json
86
- #'npm version patch' create the git tag by itself...
87
- #git tag v`cat package.json | grep version | sed -r 's/.*"([0-9.]*)".*/\1/'`
88
- git push origin master --tags | tee log/github-push.log ; exit $${PIPESTATUS[0]}
89
-
90
- # NPM install
91
- log/npm-install.log: package.json
92
- npm install --production | tee log/npm-install.log ; exit $${PIPESTATUS[0]}
93
-
94
- # NPM install for developpement usage
95
- log/npm-dev-install.log: package.json
96
- npm install | tee log/npm-dev-install.log ; exit $${PIPESTATUS[0]}
97
-
98
-
99
-
100
- # PHONY rules
101
-
102
- .PHONY: clean-all check-if-master-branch
103
-
104
- # Delete files, mostly log and non-versioned files
105
- clean-all:
106
- rm -rf log/*.log README.md bdd-spec.md node_modules
107
-
108
- # This will fail if we are not on master branch (grep exit 1 if nothing found)
109
- check-if-master-branch:
110
- git branch | grep "^* master$$"
111
-
112
-
package/documentation.md DELETED
@@ -1,17 +0,0 @@
1
-
2
- # Book Source
3
-
4
- Book Source is a Lightweight Markup Language similar to Markdown.
5
-
6
- This is the parser, you may want to add a renderer, like the [Book Source HTML renderer](https://github.com/cronvel/book-source-html-renderer).
7
-
8
- New renderers can easily be created.
9
-
10
- The parser has zero regex.
11
-
12
-
13
-
14
- ## Book Source syntax
15
-
16
- TODO
17
-