pict-section-content 0.0.3 → 0.0.5

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "Generated": "2026-02-18T04:48:09.555Z",
2
+ "Generated": "2026-02-18T05:42:00.270Z",
3
3
  "GitHubOrg": "stevenvelozo",
4
4
  "DefaultBranch": "master",
5
5
  "Groups": [
@@ -20,6 +20,25 @@
20
20
  }
21
21
  ]
22
22
  },
23
+ {
24
+ "Name": "Docs",
25
+ "Key": "docs",
26
+ "Description": "",
27
+ "Modules": [
28
+ {
29
+ "Name": "css",
30
+ "Repo": "css",
31
+ "Group": "docs",
32
+ "Branch": "master",
33
+ "HasDocs": true,
34
+ "HasCover": false,
35
+ "Sidebar": [],
36
+ "DocFiles": [
37
+ "css/docuserve.css"
38
+ ]
39
+ }
40
+ ]
41
+ },
23
42
  {
24
43
  "Name": "Source",
25
44
  "Key": "source",
@@ -0,0 +1,19 @@
1
+ {
2
+ "Generated": "2026-02-18T05:42:00.361Z",
3
+ "DocumentCount": 0,
4
+ "LunrIndex": {
5
+ "version": "2.3.9",
6
+ "fields": [
7
+ "title",
8
+ "module",
9
+ "group",
10
+ "body"
11
+ ],
12
+ "fieldVectors": [],
13
+ "invertedIndex": [],
14
+ "pipeline": [
15
+ "stemmer"
16
+ ]
17
+ },
18
+ "Documents": {}
19
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pict-section-content",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "Pict content rendering section - markdown parsing, Mermaid diagrams, and KaTeX equations",
5
5
  "main": "source/Pict-Section-Content.js",
6
6
  "scripts": {
@@ -21,14 +21,14 @@
21
21
  },
22
22
  "homepage": "https://github.com/stevenvelozo/pict-section-content#readme",
23
23
  "dependencies": {
24
- "pict-provider": "^1.0.7",
25
- "pict-view": "^1.0.64"
24
+ "pict-provider": "^1.0.10",
25
+ "pict-view": "^1.0.66"
26
26
  },
27
27
  "devDependencies": {
28
28
  "chai": "^6.2.2",
29
29
  "mocha": "^11.7.5",
30
- "pict": "^1.0.343",
31
- "quackage": "^1.0.47"
30
+ "pict": "^1.0.348",
31
+ "quackage": "^1.0.51"
32
32
  },
33
33
  "mocha": {
34
34
  "diff": true,
@@ -46,6 +46,17 @@ class PictContentProvider extends libPictProvider
46
46
  let tmpBlockquoteLines = [];
47
47
  let tmpInMathBlock = false;
48
48
  let tmpMathLines = [];
49
+ let tmpParagraphLines = [];
50
+
51
+ // Helper to flush accumulated paragraph lines into a single <p> tag
52
+ let fFlushParagraph = () =>
53
+ {
54
+ if (tmpParagraphLines.length > 0)
55
+ {
56
+ tmpHTML.push('<p>' + tmpParagraphLines.map((pLine) => { return this.parseInline(pLine, pLinkResolver); }).join(' ') + '</p>');
57
+ tmpParagraphLines = [];
58
+ }
59
+ };
49
60
 
50
61
  for (let i = 0; i < tmpLines.length; i++)
51
62
  {
@@ -63,6 +74,8 @@ class PictContentProvider extends libPictProvider
63
74
  }
64
75
  else
65
76
  {
77
+ // Flush any pending paragraph
78
+ fFlushParagraph();
66
79
  // Close any open list or blockquote
67
80
  if (tmpInList)
68
81
  {
@@ -122,6 +135,8 @@ class PictContentProvider extends libPictProvider
122
135
  }
123
136
  else
124
137
  {
138
+ // Flush any pending paragraph
139
+ fFlushParagraph();
125
140
  // Close any open list or blockquote
126
141
  if (tmpInList)
127
142
  {
@@ -153,6 +168,8 @@ class PictContentProvider extends libPictProvider
153
168
  {
154
169
  if (!tmpInBlockquote)
155
170
  {
171
+ // Flush any pending paragraph
172
+ fFlushParagraph();
156
173
  // Close any open list
157
174
  if (tmpInList)
158
175
  {
@@ -175,6 +192,7 @@ class PictContentProvider extends libPictProvider
175
192
  // Horizontal rule
176
193
  if (tmpLine.match(/^(-{3,}|\*{3,}|_{3,})\s*$/))
177
194
  {
195
+ fFlushParagraph();
178
196
  if (tmpInList)
179
197
  {
180
198
  tmpHTML.push(tmpListType === 'ul' ? '</ul>' : '</ol>');
@@ -188,6 +206,7 @@ class PictContentProvider extends libPictProvider
188
206
  let tmpHeadingMatch = tmpLine.match(/^(#{1,6})\s+(.+)/);
189
207
  if (tmpHeadingMatch)
190
208
  {
209
+ fFlushParagraph();
191
210
  if (tmpInList)
192
211
  {
193
212
  tmpHTML.push(tmpListType === 'ul' ? '</ul>' : '</ol>');
@@ -204,6 +223,7 @@ class PictContentProvider extends libPictProvider
204
223
  let tmpULMatch = tmpLine.match(/^(\s*)[-*+]\s+(.*)/);
205
224
  if (tmpULMatch)
206
225
  {
226
+ fFlushParagraph();
207
227
  if (!tmpInList || tmpListType !== 'ul')
208
228
  {
209
229
  if (tmpInList)
@@ -222,6 +242,7 @@ class PictContentProvider extends libPictProvider
222
242
  let tmpOLMatch = tmpLine.match(/^(\s*)\d+\.\s+(.*)/);
223
243
  if (tmpOLMatch)
224
244
  {
245
+ fFlushParagraph();
225
246
  if (!tmpInList || tmpListType !== 'ol')
226
247
  {
227
248
  if (tmpInList)
@@ -243,15 +264,17 @@ class PictContentProvider extends libPictProvider
243
264
  tmpInList = false;
244
265
  }
245
266
 
246
- // Empty line
267
+ // Empty line — flush any accumulated paragraph
247
268
  if (tmpLine.trim() === '')
248
269
  {
270
+ fFlushParagraph();
249
271
  continue;
250
272
  }
251
273
 
252
274
  // Table detection
253
275
  if (tmpLine.match(/^\|/) && i + 1 < tmpLines.length && tmpLines[i + 1].match(/^\|[\s-:|]+\|/))
254
276
  {
277
+ fFlushParagraph();
255
278
  // Close any open list
256
279
  if (tmpInList)
257
280
  {
@@ -291,10 +314,14 @@ class PictContentProvider extends libPictProvider
291
314
  continue;
292
315
  }
293
316
 
294
- // Regular paragraph
295
- tmpHTML.push('<p>' + this.parseInline(tmpLine, pLinkResolver) + '</p>');
317
+ // Accumulate paragraph lines — consecutive non-blank text lines
318
+ // will be joined into a single <p> tag when flushed
319
+ tmpParagraphLines.push(tmpLine);
296
320
  }
297
321
 
322
+ // Flush any remaining accumulated paragraph
323
+ fFlushParagraph();
324
+
298
325
  // Close any trailing open elements
299
326
  if (tmpInList)
300
327
  {
@@ -328,8 +355,14 @@ class PictContentProvider extends libPictProvider
328
355
 
329
356
  let tmpResult = pText;
330
357
 
331
- // Inline code (backticks) - handle first to avoid interfering with other patterns
332
- tmpResult = tmpResult.replace(/`([^`]+)`/g, '<code>$1</code>');
358
+ // Extract inline code spans into placeholders so bold/italic regexes don't mangle their contents
359
+ let tmpCodeSpans = [];
360
+ tmpResult = tmpResult.replace(/`([^`]+)`/g, (pMatch, pCode) =>
361
+ {
362
+ let tmpIndex = tmpCodeSpans.length;
363
+ tmpCodeSpans.push('<code>' + pCode + '</code>');
364
+ return '\x00CODEINLINE' + tmpIndex + '\x00';
365
+ });
333
366
 
334
367
  // Inline LaTeX equations ($...$) — must be processed before other inline patterns
335
368
  // Match single $ delimiters that aren't adjacent to spaces (to avoid false positives with currency)
@@ -369,6 +402,12 @@ class PictContentProvider extends libPictProvider
369
402
  tmpResult = tmpResult.replace(/\*([^*]+)\*/g, '<em>$1</em>');
370
403
  tmpResult = tmpResult.replace(/_([^_]+)_/g, '<em>$1</em>');
371
404
 
405
+ // Restore inline code spans from placeholders
406
+ tmpResult = tmpResult.replace(/\x00CODEINLINE(\d+)\x00/g, (pMatch, pIndex) =>
407
+ {
408
+ return tmpCodeSpans[parseInt(pIndex)];
409
+ });
410
+
372
411
  return tmpResult;
373
412
  }
374
413
 
@@ -255,6 +255,146 @@ suite
255
255
  }
256
256
  );
257
257
 
258
+ suite
259
+ (
260
+ 'Multi-line Paragraph Handling',
261
+ function()
262
+ {
263
+ test
264
+ (
265
+ 'parseMarkdown should join consecutive lines into a single paragraph.',
266
+ (fDone) =>
267
+ {
268
+ var tmpProvider = createProvider();
269
+ var tmpResult = tmpProvider.parseMarkdown('This is the first line\nof a single paragraph\nthat spans three lines.');
270
+ // All three lines should be in one <p> tag
271
+ Expect(tmpResult).to.contain('<p>This is the first line of a single paragraph that spans three lines.</p>');
272
+ fDone();
273
+ }
274
+ );
275
+ test
276
+ (
277
+ 'parseMarkdown should separate paragraphs on blank lines.',
278
+ (fDone) =>
279
+ {
280
+ var tmpProvider = createProvider();
281
+ var tmpResult = tmpProvider.parseMarkdown('First paragraph line one\nfirst paragraph line two.\n\nSecond paragraph line one\nsecond paragraph line two.');
282
+ Expect(tmpResult).to.contain('<p>First paragraph line one first paragraph line two.</p>');
283
+ Expect(tmpResult).to.contain('<p>Second paragraph line one second paragraph line two.</p>');
284
+ // Should produce exactly two <p> tags
285
+ var tmpParagraphCount = (tmpResult.match(/<p>/g) || []).length;
286
+ Expect(tmpParagraphCount).to.equal(2);
287
+ fDone();
288
+ }
289
+ );
290
+ test
291
+ (
292
+ 'parseMarkdown should flush paragraph before a heading.',
293
+ (fDone) =>
294
+ {
295
+ var tmpProvider = createProvider();
296
+ var tmpResult = tmpProvider.parseMarkdown('Some introductory text\nthat spans two lines.\n## A Heading');
297
+ Expect(tmpResult).to.contain('<p>Some introductory text that spans two lines.</p>');
298
+ Expect(tmpResult).to.contain('<h2');
299
+ Expect(tmpResult).to.contain('A Heading');
300
+ fDone();
301
+ }
302
+ );
303
+ test
304
+ (
305
+ 'parseMarkdown should flush paragraph before a list.',
306
+ (fDone) =>
307
+ {
308
+ var tmpProvider = createProvider();
309
+ var tmpResult = tmpProvider.parseMarkdown('Here is a paragraph\nbefore a list.\n- Item 1\n- Item 2');
310
+ Expect(tmpResult).to.contain('<p>Here is a paragraph before a list.</p>');
311
+ Expect(tmpResult).to.contain('<ul>');
312
+ Expect(tmpResult).to.contain('<li>Item 1</li>');
313
+ fDone();
314
+ }
315
+ );
316
+ test
317
+ (
318
+ 'parseMarkdown should flush paragraph before a code block.',
319
+ (fDone) =>
320
+ {
321
+ var tmpProvider = createProvider();
322
+ var tmpResult = tmpProvider.parseMarkdown('Some text before code\nstill the same paragraph.\n```\ncode here\n```');
323
+ Expect(tmpResult).to.contain('<p>Some text before code still the same paragraph.</p>');
324
+ Expect(tmpResult).to.contain('<pre>');
325
+ Expect(tmpResult).to.contain('code here');
326
+ fDone();
327
+ }
328
+ );
329
+ test
330
+ (
331
+ 'parseMarkdown should flush paragraph before a blockquote.',
332
+ (fDone) =>
333
+ {
334
+ var tmpProvider = createProvider();
335
+ var tmpResult = tmpProvider.parseMarkdown('A multi-line\nparagraph here.\n> A blockquote');
336
+ Expect(tmpResult).to.contain('<p>A multi-line paragraph here.</p>');
337
+ Expect(tmpResult).to.contain('<blockquote>');
338
+ Expect(tmpResult).to.contain('A blockquote');
339
+ fDone();
340
+ }
341
+ );
342
+ test
343
+ (
344
+ 'parseMarkdown should handle a paragraph after a code block.',
345
+ (fDone) =>
346
+ {
347
+ var tmpProvider = createProvider();
348
+ var tmpResult = tmpProvider.parseMarkdown('```\ncode\n```\nA paragraph that\nfollows the code block.');
349
+ Expect(tmpResult).to.contain('<pre>');
350
+ Expect(tmpResult).to.contain('<p>A paragraph that follows the code block.</p>');
351
+ fDone();
352
+ }
353
+ );
354
+ test
355
+ (
356
+ 'parseMarkdown should handle inline formatting within multi-line paragraphs.',
357
+ (fDone) =>
358
+ {
359
+ var tmpProvider = createProvider();
360
+ var tmpResult = tmpProvider.parseMarkdown('This paragraph has **bold** on the first line\nand *italic* on the second line.');
361
+ Expect(tmpResult).to.contain('<strong>bold</strong>');
362
+ Expect(tmpResult).to.contain('<em>italic</em>');
363
+ // Should be a single paragraph
364
+ var tmpParagraphCount = (tmpResult.match(/<p>/g) || []).length;
365
+ Expect(tmpParagraphCount).to.equal(1);
366
+ fDone();
367
+ }
368
+ );
369
+ test
370
+ (
371
+ 'parseMarkdown should handle hand-wrapped README-style paragraphs.',
372
+ (fDone) =>
373
+ {
374
+ var tmpProvider = createProvider();
375
+ var tmpInput = 'Ultravisor is a process supervisor and service\n'
376
+ + 'orchestrator built on the Fable ecosystem.\n'
377
+ + 'It manages the lifecycle of multiple child\n'
378
+ + 'processes from a single configuration.\n'
379
+ + '\n'
380
+ + 'Designed for development and production\n'
381
+ + 'environments alike, it provides log\n'
382
+ + 'aggregation and automatic restarts.';
383
+ var tmpResult = tmpProvider.parseMarkdown(tmpInput);
384
+ var tmpParagraphCount = (tmpResult.match(/<p>/g) || []).length;
385
+ Expect(tmpParagraphCount).to.equal(2, 'Should produce exactly two paragraphs.');
386
+ // First paragraph should contain all four lines joined
387
+ Expect(tmpResult).to.contain('Ultravisor is a process supervisor and service');
388
+ Expect(tmpResult).to.contain('orchestrator built on the Fable ecosystem.');
389
+ // Second paragraph should contain all three lines joined
390
+ Expect(tmpResult).to.contain('Designed for development and production');
391
+ Expect(tmpResult).to.contain('aggregation and automatic restarts.');
392
+ fDone();
393
+ }
394
+ );
395
+ }
396
+ );
397
+
258
398
  suite
259
399
  (
260
400
  'Inline Markdown Parsing',