@fuzdev/fuz_ui 0.189.1 → 0.191.0
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/dist/ContextmenuEntry.svelte +3 -3
- package/dist/ContextmenuLinkEntry.svelte +3 -3
- package/dist/ContextmenuRootForSafariCompatibility.svelte +1 -1
- package/dist/ContextmenuSubmenu.svelte +3 -3
- package/dist/DocsMenu.svelte +1 -1
- package/dist/DocsPageLinks.svelte +1 -1
- package/dist/DocsTertiaryNav.svelte +3 -3
- package/dist/MdzNodeView.svelte +3 -2
- package/dist/MdzNodeView.svelte.d.ts +1 -1
- package/dist/MdzNodeView.svelte.d.ts.map +1 -1
- package/dist/analysis_context.d.ts +2 -2
- package/dist/analysis_context.js +2 -2
- package/dist/contextmenu_state.svelte.d.ts +7 -7
- package/dist/contextmenu_state.svelte.js +7 -7
- package/dist/docs_helpers.svelte.d.ts +7 -5
- package/dist/docs_helpers.svelte.d.ts.map +1 -1
- package/dist/docs_helpers.svelte.js +7 -5
- package/dist/intersect.svelte.d.ts +1 -1
- package/dist/intersect.svelte.js +1 -1
- package/dist/library_analysis.d.ts +5 -5
- package/dist/library_analysis.js +5 -5
- package/dist/library_gen.d.ts +4 -4
- package/dist/library_gen.js +4 -4
- package/dist/library_generate.d.ts +2 -2
- package/dist/library_helpers.d.ts +8 -8
- package/dist/library_helpers.js +8 -8
- package/dist/library_pipeline.d.ts +5 -5
- package/dist/library_pipeline.js +5 -5
- package/dist/mdz.d.ts +1 -14
- package/dist/mdz.d.ts.map +1 -1
- package/dist/mdz.js +57 -156
- package/dist/mdz_helpers.d.ts +26 -2
- package/dist/mdz_helpers.d.ts.map +1 -1
- package/dist/mdz_helpers.js +59 -5
- package/dist/mdz_lexer.d.ts.map +1 -1
- package/dist/mdz_lexer.js +18 -9
- package/dist/mdz_to_svelte.d.ts +5 -5
- package/dist/mdz_to_svelte.d.ts.map +1 -1
- package/dist/mdz_to_svelte.js +5 -5
- package/dist/mdz_token_parser.js +4 -3
- package/dist/module_helpers.d.ts +8 -8
- package/dist/module_helpers.js +8 -8
- package/dist/package_helpers.d.ts +12 -12
- package/dist/package_helpers.js +12 -12
- package/dist/storage.d.ts +3 -3
- package/dist/storage.js +3 -3
- package/dist/svelte_helpers.d.ts +9 -9
- package/dist/svelte_helpers.js +9 -9
- package/dist/svelte_preprocess_mdz.d.ts +1 -1
- package/dist/svelte_preprocess_mdz.js +1 -1
- package/dist/ts_helpers.d.ts +19 -19
- package/dist/ts_helpers.js +19 -19
- package/dist/tsdoc_helpers.d.ts +5 -5
- package/dist/tsdoc_helpers.js +5 -5
- package/dist/tsdoc_mdz.js +1 -1
- package/package.json +7 -6
- package/src/lib/analysis_context.ts +2 -2
- package/src/lib/contextmenu_state.svelte.ts +7 -7
- package/src/lib/docs_helpers.svelte.ts +7 -5
- package/src/lib/intersect.svelte.ts +1 -1
- package/src/lib/library_analysis.ts +5 -5
- package/src/lib/library_gen.ts +4 -4
- package/src/lib/library_generate.ts +2 -2
- package/src/lib/library_helpers.ts +8 -8
- package/src/lib/library_pipeline.ts +5 -5
- package/src/lib/mdz.ts +63 -167
- package/src/lib/mdz_helpers.ts +60 -5
- package/src/lib/mdz_lexer.ts +20 -9
- package/src/lib/mdz_to_svelte.ts +6 -5
- package/src/lib/mdz_token_parser.ts +4 -3
- package/src/lib/module_helpers.ts +8 -8
- package/src/lib/package_helpers.ts +12 -12
- package/src/lib/storage.ts +3 -3
- package/src/lib/svelte_helpers.ts +9 -9
- package/src/lib/svelte_preprocess_mdz.ts +1 -1
- package/src/lib/ts_helpers.ts +19 -19
- package/src/lib/tsdoc_helpers.ts +5 -5
- package/src/lib/tsdoc_mdz.ts +1 -1
package/dist/mdz.js
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
*
|
|
29
29
|
* @module
|
|
30
30
|
*/
|
|
31
|
-
import { BACKTICK, ASTERISK, UNDERSCORE, TILDE, NEWLINE, HYPHEN, HASH, SPACE, TAB, LEFT_ANGLE, RIGHT_ANGLE, SLASH, LEFT_BRACKET, RIGHT_BRACKET, LEFT_PAREN, RIGHT_PAREN, A_UPPER, Z_UPPER, HR_HYPHEN_COUNT, MIN_CODEBLOCK_BACKTICKS, MAX_HEADING_LEVEL, HTTPS_PREFIX_LENGTH, HTTP_PREFIX_LENGTH, is_letter, is_tag_name_char, is_word_char, PERIOD, is_valid_path_char, trim_trailing_punctuation, is_at_absolute_path, is_at_relative_path, extract_single_tag, } from './mdz_helpers.js';
|
|
31
|
+
import { BACKTICK, ASTERISK, UNDERSCORE, TILDE, NEWLINE, HYPHEN, HASH, SPACE, TAB, LEFT_ANGLE, RIGHT_ANGLE, SLASH, LEFT_BRACKET, RIGHT_BRACKET, LEFT_PAREN, RIGHT_PAREN, A_UPPER, Z_UPPER, HR_HYPHEN_COUNT, MIN_CODEBLOCK_BACKTICKS, MAX_HEADING_LEVEL, HTTPS_PREFIX_LENGTH, HTTP_PREFIX_LENGTH, is_letter, is_tag_name_char, is_word_char, PERIOD, is_valid_path_char, trim_trailing_punctuation, is_at_absolute_path, is_at_relative_path, extract_single_tag, mdz_heading_id, mdz_is_url, } from './mdz_helpers.js';
|
|
32
32
|
// TODO design incremental parsing or some system that preserves Svelte components across re-renders when possible
|
|
33
33
|
/**
|
|
34
34
|
* Parses text to an array of `MdzNode`.
|
|
@@ -507,89 +507,32 @@ export class MdzParser {
|
|
|
507
507
|
*/
|
|
508
508
|
#parse_tag() {
|
|
509
509
|
const start = this.#index;
|
|
510
|
-
//
|
|
511
|
-
|
|
512
|
-
//
|
|
513
|
-
|
|
514
|
-
this.#nodes.length = 0;
|
|
515
|
-
// Consume <
|
|
516
|
-
if (!this.#match('<')) {
|
|
517
|
-
// Restore parent state before returning
|
|
518
|
-
this.#restore_accumulation_state(saved_state);
|
|
519
|
-
const content = this.#template[this.#index];
|
|
520
|
-
this.#index++;
|
|
521
|
-
return {
|
|
522
|
-
type: 'Text',
|
|
523
|
-
content,
|
|
524
|
-
start,
|
|
525
|
-
end: this.#index,
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
this.#index++;
|
|
529
|
-
// Parse tag name
|
|
530
|
-
const tag_name_start = this.#index;
|
|
531
|
-
let tag_name_end = this.#index;
|
|
510
|
+
// Phase 1: Validate tag structure using a local scan index.
|
|
511
|
+
// Avoids save/restore of accumulation state on the fast path
|
|
512
|
+
// (most `<` characters are not valid tags).
|
|
513
|
+
let i = start + 1; // skip <
|
|
532
514
|
// Tag name must start with a letter
|
|
533
|
-
if (this.#
|
|
534
|
-
|
|
535
|
-
this.#
|
|
536
|
-
return {
|
|
537
|
-
type: 'Text',
|
|
538
|
-
content: '<',
|
|
539
|
-
start,
|
|
540
|
-
end: this.#index,
|
|
541
|
-
};
|
|
542
|
-
}
|
|
543
|
-
const first_char = this.#template.charCodeAt(this.#index);
|
|
544
|
-
if (!is_letter(first_char)) {
|
|
545
|
-
// Not a valid tag, treat as text - restore parent state
|
|
546
|
-
this.#restore_accumulation_state(saved_state);
|
|
547
|
-
return {
|
|
548
|
-
type: 'Text',
|
|
549
|
-
content: '<',
|
|
550
|
-
start,
|
|
551
|
-
end: start + 1,
|
|
552
|
-
};
|
|
515
|
+
if (i >= this.#template.length || !is_letter(this.#template.charCodeAt(i))) {
|
|
516
|
+
this.#index = start + 1;
|
|
517
|
+
return this.#make_text_node('<', start);
|
|
553
518
|
}
|
|
554
519
|
// Collect tag name (letters, numbers, hyphens, underscores)
|
|
555
|
-
while (this.#
|
|
556
|
-
|
|
557
|
-
if (is_tag_name_char(char_code)) {
|
|
558
|
-
this.#index++;
|
|
559
|
-
}
|
|
560
|
-
else {
|
|
561
|
-
break;
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
tag_name_end = this.#index;
|
|
565
|
-
const tag_name = this.#template.slice(tag_name_start, tag_name_end);
|
|
566
|
-
if (tag_name.length === 0) {
|
|
567
|
-
// Empty tag name - restore parent state
|
|
568
|
-
this.#restore_accumulation_state(saved_state);
|
|
569
|
-
return {
|
|
570
|
-
type: 'Text',
|
|
571
|
-
content: '<',
|
|
572
|
-
start,
|
|
573
|
-
end: start + 1,
|
|
574
|
-
};
|
|
520
|
+
while (i < this.#template.length && is_tag_name_char(this.#template.charCodeAt(i))) {
|
|
521
|
+
i++;
|
|
575
522
|
}
|
|
576
|
-
|
|
523
|
+
const tag_name = this.#template.slice(start + 1, i);
|
|
577
524
|
const first_char_code = tag_name.charCodeAt(0);
|
|
578
|
-
const
|
|
579
|
-
const node_type = is_component ? 'Component' : 'Element';
|
|
525
|
+
const node_type = first_char_code >= A_UPPER && first_char_code <= Z_UPPER ? 'Component' : 'Element';
|
|
580
526
|
// Skip whitespace after tag name (for future attribute support)
|
|
581
|
-
while (
|
|
582
|
-
|
|
583
|
-
this.#index++;
|
|
527
|
+
while (i < this.#template.length && this.#template.charCodeAt(i) === SPACE) {
|
|
528
|
+
i++;
|
|
584
529
|
}
|
|
585
530
|
// TODO: Parse attributes here
|
|
586
531
|
// Check for self-closing />
|
|
587
|
-
if (
|
|
588
|
-
this.#template.charCodeAt(
|
|
589
|
-
this.#template.charCodeAt(
|
|
590
|
-
this.#index
|
|
591
|
-
// Restore parent state before returning
|
|
592
|
-
this.#restore_accumulation_state(saved_state);
|
|
532
|
+
if (i + 1 < this.#template.length &&
|
|
533
|
+
this.#template.charCodeAt(i) === SLASH &&
|
|
534
|
+
this.#template.charCodeAt(i + 1) === RIGHT_ANGLE) {
|
|
535
|
+
this.#index = i + 2;
|
|
593
536
|
return {
|
|
594
537
|
type: node_type,
|
|
595
538
|
name: tag_name,
|
|
@@ -598,33 +541,38 @@ export class MdzParser {
|
|
|
598
541
|
end: this.#index,
|
|
599
542
|
};
|
|
600
543
|
}
|
|
601
|
-
//
|
|
602
|
-
if (
|
|
603
|
-
this.#template.charCodeAt(this.#index) !== RIGHT_ANGLE) {
|
|
604
|
-
// Unclosed opening tag, treat as text - restore parent state
|
|
605
|
-
this.#restore_accumulation_state(saved_state);
|
|
544
|
+
// Must have closing >
|
|
545
|
+
if (i >= this.#template.length || this.#template.charCodeAt(i) !== RIGHT_ANGLE) {
|
|
606
546
|
this.#index = start + 1;
|
|
607
|
-
return
|
|
608
|
-
type: 'Text',
|
|
609
|
-
content: '<',
|
|
610
|
-
start,
|
|
611
|
-
end: this.#index,
|
|
612
|
-
};
|
|
547
|
+
return this.#make_text_node('<', start);
|
|
613
548
|
}
|
|
614
|
-
//
|
|
615
|
-
|
|
616
|
-
//
|
|
549
|
+
const content_start = i + 1; // past >
|
|
550
|
+
// Bail early if closing tag is missing, past a paragraph break,
|
|
551
|
+
// or past the search boundary (e.g. heading line end)
|
|
617
552
|
const closing_tag = `</${tag_name}>`;
|
|
553
|
+
const search_limit = Math.min(this.#max_search_index, this.#template.length);
|
|
554
|
+
const close_tag_index = this.#template.indexOf(closing_tag, content_start);
|
|
555
|
+
if (close_tag_index === -1 || close_tag_index >= search_limit) {
|
|
556
|
+
this.#index = start + 1;
|
|
557
|
+
return this.#make_text_node('<', start);
|
|
558
|
+
}
|
|
559
|
+
const para_break = this.#template.indexOf('\n\n', content_start);
|
|
560
|
+
if (para_break !== -1 && para_break < close_tag_index) {
|
|
561
|
+
this.#index = start + 1;
|
|
562
|
+
return this.#make_text_node('<', start);
|
|
563
|
+
}
|
|
564
|
+
// Phase 2: Tag validated — save accumulation state and parse children.
|
|
565
|
+
const saved_state = this.#save_accumulation_state();
|
|
566
|
+
this.#accumulated_text = '';
|
|
567
|
+
this.#nodes.length = 0;
|
|
568
|
+
this.#index = content_start;
|
|
618
569
|
const children = [];
|
|
619
570
|
while (this.#index < this.#template.length) {
|
|
620
|
-
// Check for closing tag
|
|
621
571
|
if (this.#match(closing_tag)) {
|
|
622
|
-
// Flush any accumulated text from children
|
|
623
572
|
this.#flush_text();
|
|
624
573
|
children.push(...this.#nodes);
|
|
625
574
|
this.#nodes.length = 0;
|
|
626
575
|
this.#index += closing_tag.length;
|
|
627
|
-
// Restore parent state before returning
|
|
628
576
|
this.#restore_accumulation_state(saved_state);
|
|
629
577
|
return {
|
|
630
578
|
type: node_type,
|
|
@@ -645,16 +593,10 @@ export class MdzParser {
|
|
|
645
593
|
children.push(node);
|
|
646
594
|
}
|
|
647
595
|
}
|
|
648
|
-
//
|
|
649
|
-
// Treat the opening tag as text - restore parent state
|
|
596
|
+
// Defensive: pre-check guarantees closing tag exists, but handle EOF gracefully
|
|
650
597
|
this.#restore_accumulation_state(saved_state);
|
|
651
598
|
this.#index = start + 1;
|
|
652
|
-
return
|
|
653
|
-
type: 'Text',
|
|
654
|
-
content: '<',
|
|
655
|
-
start,
|
|
656
|
-
end: this.#index,
|
|
657
|
-
};
|
|
599
|
+
return this.#make_text_node('<', start);
|
|
658
600
|
}
|
|
659
601
|
/**
|
|
660
602
|
* Read-only check if current position matches a block element.
|
|
@@ -1038,29 +980,27 @@ export class MdzParser {
|
|
|
1038
980
|
}
|
|
1039
981
|
// Consume the space after hashes (already verified to exist)
|
|
1040
982
|
this.#index++;
|
|
1041
|
-
//
|
|
983
|
+
// Find end-of-line to bound nested parsers (prevents tag scanner from scanning past heading)
|
|
984
|
+
let eol = this.#template.indexOf('\n', this.#index);
|
|
985
|
+
if (eol === -1)
|
|
986
|
+
eol = this.#template.length;
|
|
987
|
+
const saved_max_search_index = this.#max_search_index;
|
|
988
|
+
this.#max_search_index = eol;
|
|
989
|
+
// Parse inline content until end of line
|
|
1042
990
|
const content_nodes = [];
|
|
1043
|
-
while (this.#index <
|
|
1044
|
-
const char_code = this.#template.charCodeAt(this.#index);
|
|
1045
|
-
if (char_code === NEWLINE) {
|
|
1046
|
-
break;
|
|
1047
|
-
}
|
|
991
|
+
while (this.#index < eol) {
|
|
1048
992
|
const node = this.#parse_node();
|
|
1049
993
|
if (node.type === 'Text') {
|
|
1050
|
-
//
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
if (newline_index !== -1) {
|
|
1054
|
-
const trimmed_content = node.content.slice(0, newline_index);
|
|
994
|
+
// Trim if #parse_text overshot past the newline
|
|
995
|
+
if (node.end > eol) {
|
|
996
|
+
const trimmed_content = node.content.slice(0, eol - node.start);
|
|
1055
997
|
if (trimmed_content) {
|
|
1056
998
|
this.#accumulate_text(trimmed_content, node.start);
|
|
1057
999
|
}
|
|
1058
|
-
this.#index =
|
|
1000
|
+
this.#index = eol;
|
|
1059
1001
|
break;
|
|
1060
1002
|
}
|
|
1061
|
-
|
|
1062
|
-
this.#accumulate_text(node.content, node.start);
|
|
1063
|
-
}
|
|
1003
|
+
this.#accumulate_text(node.content, node.start);
|
|
1064
1004
|
}
|
|
1065
1005
|
else {
|
|
1066
1006
|
this.#flush_text();
|
|
@@ -1069,6 +1009,7 @@ export class MdzParser {
|
|
|
1069
1009
|
content_nodes.push(node);
|
|
1070
1010
|
}
|
|
1071
1011
|
}
|
|
1012
|
+
this.#max_search_index = saved_max_search_index;
|
|
1072
1013
|
this.#flush_text();
|
|
1073
1014
|
content_nodes.push(...this.#nodes);
|
|
1074
1015
|
this.#nodes.length = 0;
|
|
@@ -1076,6 +1017,7 @@ export class MdzParser {
|
|
|
1076
1017
|
return {
|
|
1077
1018
|
type: 'Heading',
|
|
1078
1019
|
level: level,
|
|
1020
|
+
id: mdz_heading_id(content_nodes),
|
|
1079
1021
|
children: content_nodes,
|
|
1080
1022
|
start,
|
|
1081
1023
|
end: this.#index,
|
|
@@ -1234,44 +1176,3 @@ export class MdzParser {
|
|
|
1234
1176
|
throw Error('Code block not properly closed');
|
|
1235
1177
|
}
|
|
1236
1178
|
}
|
|
1237
|
-
/**
|
|
1238
|
-
* Check if a string is a URL (`https://` or `http://`).
|
|
1239
|
-
* Requires at least one valid character after the protocol.
|
|
1240
|
-
* Rejects whitespace and characters that can't start a valid hostname.
|
|
1241
|
-
*/
|
|
1242
|
-
const URL_PATTERN = /^https?:\/\/[^\s)\]}<>.,:/?#!]/;
|
|
1243
|
-
export const mdz_is_url = (s) => URL_PATTERN.test(s);
|
|
1244
|
-
/**
|
|
1245
|
-
* Resolves a relative path (`./` or `../`) against a base path.
|
|
1246
|
-
* The base is treated as a directory regardless of trailing slash
|
|
1247
|
-
* (`'/docs/mdz'` and `'/docs/mdz/'` behave identically).
|
|
1248
|
-
* Handles embedded `.` and `..` segments within the reference
|
|
1249
|
-
* (e.g., `'./a/../b'` → navigates up then down).
|
|
1250
|
-
* Clamps at root — excess `..` segments stop at `/` rather than escaping.
|
|
1251
|
-
*
|
|
1252
|
-
* @param reference A relative path starting with `./` or `../`.
|
|
1253
|
-
* @param base An absolute base path (e.g., `'/docs/mdz/'`). Empty string is treated as root.
|
|
1254
|
-
* @returns An absolute resolved path (e.g., `'/docs/mdz/grammar'`).
|
|
1255
|
-
*/
|
|
1256
|
-
export const resolve_relative_path = (reference, base) => {
|
|
1257
|
-
const segments = base.split('/');
|
|
1258
|
-
// Remove trailing empty from split (e.g., '/docs/mdz/' → ['', 'docs', 'mdz', ''])
|
|
1259
|
-
// but keep the root segment ([''] from '' base or ['', ''] from '/').
|
|
1260
|
-
if (segments.length > 1 && segments.at(-1) === '')
|
|
1261
|
-
segments.pop();
|
|
1262
|
-
const trailing = reference.endsWith('/');
|
|
1263
|
-
for (const segment of reference.split('/')) {
|
|
1264
|
-
if (segment === '.' || segment === '')
|
|
1265
|
-
continue;
|
|
1266
|
-
if (segment === '..') {
|
|
1267
|
-
if (segments.length > 1)
|
|
1268
|
-
segments.pop(); // clamp at root
|
|
1269
|
-
}
|
|
1270
|
-
else {
|
|
1271
|
-
segments.push(segment);
|
|
1272
|
-
}
|
|
1273
|
-
}
|
|
1274
|
-
if (trailing)
|
|
1275
|
-
segments.push('');
|
|
1276
|
-
return segments.join('/');
|
|
1277
|
-
};
|
package/dist/mdz_helpers.d.ts
CHANGED
|
@@ -95,14 +95,38 @@ export declare const trim_trailing_punctuation: (url: string) => string;
|
|
|
95
95
|
/**
|
|
96
96
|
* Check if position in text is the start of an absolute path (starts with `/`).
|
|
97
97
|
* Must be preceded by whitespace or be at the start of the string.
|
|
98
|
-
* Rejects `//` (comments/protocol-relative) and
|
|
98
|
+
* Rejects `//` (comments/protocol-relative) and slash followed by whitespace.
|
|
99
99
|
*/
|
|
100
100
|
export declare const is_at_absolute_path: (text: string, index: number) => boolean;
|
|
101
101
|
/**
|
|
102
102
|
* Check if position in text is the start of a relative path (`./` or `../`).
|
|
103
103
|
* Must be preceded by whitespace or be at the start of the string.
|
|
104
|
-
*
|
|
104
|
+
* Rejects prefix followed by whitespace, slash, or end of string.
|
|
105
105
|
*/
|
|
106
106
|
export declare const is_at_relative_path: (text: string, index: number) => boolean;
|
|
107
|
+
/**
|
|
108
|
+
* Extracts plain text content from an array of mdz nodes, recursing into children.
|
|
109
|
+
*/
|
|
110
|
+
export declare const mdz_text_content: (nodes: Array<MdzNode>) => string;
|
|
111
|
+
/**
|
|
112
|
+
* Generates a lowercase slug id for a heading from its child nodes.
|
|
113
|
+
* Follows standard markdown conventions (GitHub, etc.) where heading IDs are lowercased.
|
|
114
|
+
* For case-preserving IDs (e.g. API declarations), see `docs_slugify` in `docs_helpers.svelte.ts`.
|
|
115
|
+
*/
|
|
116
|
+
export declare const mdz_heading_id: (nodes: Array<MdzNode>) => string;
|
|
117
|
+
export declare const mdz_is_url: (s: string) => boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Resolves a relative path (`./` or `../`) against a base path.
|
|
120
|
+
* The base is treated as a directory regardless of trailing slash
|
|
121
|
+
* (`'/docs/mdz'` and `'/docs/mdz/'` behave identically).
|
|
122
|
+
* Handles embedded `.` and `..` segments within the reference
|
|
123
|
+
* (e.g., `'./a/../b'` → navigates up then down).
|
|
124
|
+
* Clamps at root — excess `..` segments stop at `/` rather than escaping.
|
|
125
|
+
*
|
|
126
|
+
* @param reference - a relative path starting with `./` or `../`.
|
|
127
|
+
* @param base - an absolute base path (e.g., `'/docs/mdz/'`). Empty string is treated as root.
|
|
128
|
+
* @returns An absolute resolved path (e.g., `'/docs/mdz/grammar'`).
|
|
129
|
+
*/
|
|
130
|
+
export declare const resolve_relative_path: (reference: string, base: string) => string;
|
|
107
131
|
export declare const extract_single_tag: (nodes: Array<MdzNode>) => MdzComponentNode | MdzElementNode | null;
|
|
108
132
|
//# sourceMappingURL=mdz_helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mdz_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAC,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAC,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"mdz_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_helpers.ts"],"names":[],"mappings":"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"}
|
package/dist/mdz_helpers.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
|
+
import { slugify } from '@fuzdev/fuz_util/path.js';
|
|
9
10
|
// Character codes for performance
|
|
10
11
|
export const BACKTICK = 96; // `
|
|
11
12
|
export const ASTERISK = 42; // *
|
|
@@ -172,7 +173,7 @@ export const trim_trailing_punctuation = (url) => {
|
|
|
172
173
|
/**
|
|
173
174
|
* Check if position in text is the start of an absolute path (starts with `/`).
|
|
174
175
|
* Must be preceded by whitespace or be at the start of the string.
|
|
175
|
-
* Rejects `//` (comments/protocol-relative) and
|
|
176
|
+
* Rejects `//` (comments/protocol-relative) and slash followed by whitespace.
|
|
176
177
|
*/
|
|
177
178
|
export const is_at_absolute_path = (text, index) => {
|
|
178
179
|
if (text.charCodeAt(index) !== SLASH)
|
|
@@ -185,12 +186,12 @@ export const is_at_absolute_path = (text, index) => {
|
|
|
185
186
|
if (index + 1 >= text.length)
|
|
186
187
|
return false;
|
|
187
188
|
const next_char = text.charCodeAt(index + 1);
|
|
188
|
-
return next_char !== SLASH && next_char !== SPACE && next_char !== NEWLINE;
|
|
189
|
+
return next_char !== SLASH && next_char !== SPACE && next_char !== NEWLINE && next_char !== TAB;
|
|
189
190
|
};
|
|
190
191
|
/**
|
|
191
192
|
* Check if position in text is the start of a relative path (`./` or `../`).
|
|
192
193
|
* Must be preceded by whitespace or be at the start of the string.
|
|
193
|
-
*
|
|
194
|
+
* Rejects prefix followed by whitespace, slash, or end of string.
|
|
194
195
|
*/
|
|
195
196
|
export const is_at_relative_path = (text, index) => {
|
|
196
197
|
if (text.charCodeAt(index) !== PERIOD)
|
|
@@ -206,15 +207,68 @@ export const is_at_relative_path = (text, index) => {
|
|
|
206
207
|
text.charCodeAt(index + 1) === PERIOD &&
|
|
207
208
|
text.charCodeAt(index + 2) === SLASH) {
|
|
208
209
|
const after = text.charCodeAt(index + 3);
|
|
209
|
-
return after !== SPACE && after !== NEWLINE && after !== SLASH;
|
|
210
|
+
return after !== SPACE && after !== NEWLINE && after !== TAB && after !== SLASH;
|
|
210
211
|
}
|
|
211
212
|
// Check for ./ (at least 3 chars: ./x)
|
|
212
213
|
if (remaining >= 3 && text.charCodeAt(index + 1) === SLASH) {
|
|
213
214
|
const after = text.charCodeAt(index + 2);
|
|
214
|
-
return after !== SPACE && after !== NEWLINE && after !== SLASH;
|
|
215
|
+
return after !== SPACE && after !== NEWLINE && after !== TAB && after !== SLASH;
|
|
215
216
|
}
|
|
216
217
|
return false;
|
|
217
218
|
};
|
|
219
|
+
/**
|
|
220
|
+
* Extracts plain text content from an array of mdz nodes, recursing into children.
|
|
221
|
+
*/
|
|
222
|
+
export const mdz_text_content = (nodes) => nodes
|
|
223
|
+
.map((n) => ('children' in n ? mdz_text_content(n.children) : 'content' in n ? n.content : ''))
|
|
224
|
+
.join('');
|
|
225
|
+
/**
|
|
226
|
+
* Generates a lowercase slug id for a heading from its child nodes.
|
|
227
|
+
* Follows standard markdown conventions (GitHub, etc.) where heading IDs are lowercased.
|
|
228
|
+
* For case-preserving IDs (e.g. API declarations), see `docs_slugify` in `docs_helpers.svelte.ts`.
|
|
229
|
+
*/
|
|
230
|
+
export const mdz_heading_id = (nodes) => slugify(mdz_text_content(nodes), false);
|
|
231
|
+
/**
|
|
232
|
+
* Check if a string is a URL (`https://` or `http://`).
|
|
233
|
+
* Requires at least one valid character after the protocol.
|
|
234
|
+
* Rejects whitespace and characters that can't start a valid hostname.
|
|
235
|
+
*/
|
|
236
|
+
const URL_PATTERN = /^https?:\/\/[^\s)\]}<>.,:/?#!]/;
|
|
237
|
+
export const mdz_is_url = (s) => URL_PATTERN.test(s);
|
|
238
|
+
/**
|
|
239
|
+
* Resolves a relative path (`./` or `../`) against a base path.
|
|
240
|
+
* The base is treated as a directory regardless of trailing slash
|
|
241
|
+
* (`'/docs/mdz'` and `'/docs/mdz/'` behave identically).
|
|
242
|
+
* Handles embedded `.` and `..` segments within the reference
|
|
243
|
+
* (e.g., `'./a/../b'` → navigates up then down).
|
|
244
|
+
* Clamps at root — excess `..` segments stop at `/` rather than escaping.
|
|
245
|
+
*
|
|
246
|
+
* @param reference - a relative path starting with `./` or `../`.
|
|
247
|
+
* @param base - an absolute base path (e.g., `'/docs/mdz/'`). Empty string is treated as root.
|
|
248
|
+
* @returns An absolute resolved path (e.g., `'/docs/mdz/grammar'`).
|
|
249
|
+
*/
|
|
250
|
+
export const resolve_relative_path = (reference, base) => {
|
|
251
|
+
const segments = base.split('/');
|
|
252
|
+
// Remove trailing empty from split (e.g., '/docs/mdz/' → ['', 'docs', 'mdz', ''])
|
|
253
|
+
// but keep the root segment ([''] from '' base or ['', ''] from '/').
|
|
254
|
+
if (segments.length > 1 && segments.at(-1) === '')
|
|
255
|
+
segments.pop();
|
|
256
|
+
const trailing = reference.endsWith('/');
|
|
257
|
+
for (const segment of reference.split('/')) {
|
|
258
|
+
if (segment === '.' || segment === '')
|
|
259
|
+
continue;
|
|
260
|
+
if (segment === '..') {
|
|
261
|
+
if (segments.length > 1)
|
|
262
|
+
segments.pop(); // clamp at root
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
segments.push(segment);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (trailing)
|
|
269
|
+
segments.push('');
|
|
270
|
+
return segments.join('/');
|
|
271
|
+
};
|
|
218
272
|
export const extract_single_tag = (nodes) => {
|
|
219
273
|
let tag = null;
|
|
220
274
|
for (const node of nodes) {
|
package/dist/mdz_lexer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mdz_lexer.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_lexer.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"mdz_lexer.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_lexer.ts"],"names":[],"mappings":"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"}
|
package/dist/mdz_lexer.js
CHANGED
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
|
-
import { mdz_is_url } from './
|
|
10
|
-
import { is_letter, is_tag_name_char, is_word_char, is_valid_path_char, trim_trailing_punctuation, BACKTICK, ASTERISK, UNDERSCORE, TILDE, NEWLINE, HYPHEN, HASH, SPACE, TAB, LEFT_ANGLE, RIGHT_ANGLE, SLASH, PERIOD, LEFT_BRACKET, LEFT_PAREN, RIGHT_PAREN, RIGHT_BRACKET, A_UPPER, Z_UPPER, HR_HYPHEN_COUNT, MIN_CODEBLOCK_BACKTICKS, MAX_HEADING_LEVEL, HTTPS_PREFIX_LENGTH, HTTP_PREFIX_LENGTH, is_at_absolute_path, is_at_relative_path, } from './mdz_helpers.js';
|
|
9
|
+
import { mdz_is_url, is_letter, is_tag_name_char, is_word_char, is_valid_path_char, trim_trailing_punctuation, BACKTICK, ASTERISK, UNDERSCORE, TILDE, NEWLINE, HYPHEN, HASH, SPACE, TAB, LEFT_ANGLE, RIGHT_ANGLE, SLASH, PERIOD, LEFT_BRACKET, LEFT_PAREN, RIGHT_PAREN, RIGHT_BRACKET, A_UPPER, Z_UPPER, HR_HYPHEN_COUNT, MIN_CODEBLOCK_BACKTICKS, MAX_HEADING_LEVEL, HTTPS_PREFIX_LENGTH, HTTP_PREFIX_LENGTH, is_at_absolute_path, is_at_relative_path, } from './mdz_helpers.js';
|
|
11
10
|
//
|
|
12
11
|
// Lexer
|
|
13
12
|
//
|
|
@@ -99,13 +98,16 @@ export class MdzLexer {
|
|
|
99
98
|
start,
|
|
100
99
|
end: this.#index, // end of "## " prefix
|
|
101
100
|
});
|
|
101
|
+
// Find end-of-line to bound nested tokenizers (prevents tag scanner from scanning past heading)
|
|
102
|
+
let eol = this.#text.indexOf('\n', this.#index);
|
|
103
|
+
if (eol === -1)
|
|
104
|
+
eol = this.#text.length;
|
|
105
|
+
const saved_max = this.#max_search_index;
|
|
106
|
+
this.#max_search_index = eol;
|
|
102
107
|
// Tokenize inline content until newline or EOF
|
|
103
108
|
// tokenize_text may consume a newline as part of block-element lookahead,
|
|
104
109
|
// so we check emitted text tokens for embedded newlines and trim.
|
|
105
|
-
while (this.#index <
|
|
106
|
-
if (this.#text.charCodeAt(this.#index) === NEWLINE) {
|
|
107
|
-
break;
|
|
108
|
-
}
|
|
110
|
+
while (this.#index < eol) {
|
|
109
111
|
const token_count_before = this.#tokens.length;
|
|
110
112
|
this.#tokenize_inline();
|
|
111
113
|
// Check if the last emitted token is text containing a newline
|
|
@@ -128,6 +130,7 @@ export class MdzLexer {
|
|
|
128
130
|
}
|
|
129
131
|
}
|
|
130
132
|
}
|
|
133
|
+
this.#max_search_index = saved_max;
|
|
131
134
|
// Emit heading_end marker so the token parser knows where heading content stops
|
|
132
135
|
this.#tokens.push({ type: 'heading_end', start: this.#index, end: this.#index });
|
|
133
136
|
// Skip newlines after heading (like original parser's main loop)
|
|
@@ -548,11 +551,17 @@ export class MdzLexer {
|
|
|
548
551
|
return;
|
|
549
552
|
}
|
|
550
553
|
this.#index++; // consume >
|
|
551
|
-
// Check for closing tag existence before committing
|
|
554
|
+
// Check for closing tag existence before committing —
|
|
555
|
+
// must exist within search boundary and before any paragraph break
|
|
552
556
|
const closing_tag = `</${tag_name}>`;
|
|
557
|
+
const search_limit = Math.min(this.#max_search_index, this.#text.length);
|
|
553
558
|
const closing_tag_pos = this.#text.indexOf(closing_tag, this.#index);
|
|
554
|
-
if (closing_tag_pos === -1) {
|
|
555
|
-
|
|
559
|
+
if (closing_tag_pos === -1 || closing_tag_pos >= search_limit) {
|
|
560
|
+
this.#index = start + 1;
|
|
561
|
+
this.#emit_text('<', start);
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
if (this.#has_paragraph_break_between(this.#index, closing_tag_pos)) {
|
|
556
565
|
this.#index = start + 1;
|
|
557
566
|
this.#emit_text('<', start);
|
|
558
567
|
return;
|
package/dist/mdz_to_svelte.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
|
-
import {
|
|
10
|
+
import type { MdzNode } from './mdz.js';
|
|
11
11
|
/**
|
|
12
12
|
* Result of converting `MdzNode` arrays to Svelte markup.
|
|
13
13
|
*/
|
|
@@ -28,12 +28,12 @@ export interface MdzToSvelteResult {
|
|
|
28
28
|
* Each node type produces output matching what `MdzNodeView.svelte` renders at runtime.
|
|
29
29
|
* Collects required imports and flags unconfigured component/element references.
|
|
30
30
|
*
|
|
31
|
-
* @param nodes
|
|
32
|
-
* @param components
|
|
31
|
+
* @param nodes - parsed mdz nodes to render.
|
|
32
|
+
* @param components - component name to import path mapping (e.g., `{Alert: '$lib/Alert.svelte'}`).
|
|
33
33
|
* If content references a component not in this map, `has_unconfigured_tags` is set.
|
|
34
|
-
* @param elements
|
|
34
|
+
* @param elements - allowed HTML element names (e.g., `new Set(['aside', 'details'])`).
|
|
35
35
|
* If content references an element not in this set, `has_unconfigured_tags` is set.
|
|
36
|
-
* @param base
|
|
36
|
+
* @param base - base path for resolving relative links (e.g., `'/docs/mdz/'`).
|
|
37
37
|
* When provided, relative references (`./`, `../`) are resolved to absolute paths
|
|
38
38
|
* and passed through `resolve()`. Trailing slash recommended.
|
|
39
39
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mdz_to_svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_to_svelte.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"mdz_to_svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_to_svelte.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,UAAU,CAAC;AAGtC;;GAEG;AACH,MAAM,WAAW,iBAAiB;IACjC,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IAEf,yDAAyD;IACzD,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAA;KAAC,CAAC,CAAC;IAEhE,yEAAyE;IACzE,qBAAqB,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,aAAa,GACzB,OAAO,KAAK,CAAC,OAAO,CAAC,EACrB,YAAY,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,UAAU,WAAW,CAAC,MAAM,CAAC,EAC7B,OAAO,MAAM,KACX,iBAyFF,CAAC"}
|
package/dist/mdz_to_svelte.js
CHANGED
|
@@ -10,19 +10,19 @@
|
|
|
10
10
|
import { UnreachableError } from '@fuzdev/fuz_util/error.js';
|
|
11
11
|
import { escape_svelte_text } from '@fuzdev/fuz_util/svelte_preprocess_helpers.js';
|
|
12
12
|
import { escape_js_string } from '@fuzdev/fuz_util/string.js';
|
|
13
|
-
import { resolve_relative_path } from './
|
|
13
|
+
import { resolve_relative_path } from './mdz_helpers.js';
|
|
14
14
|
/**
|
|
15
15
|
* Converts an array of `MdzNode` to a Svelte markup string.
|
|
16
16
|
*
|
|
17
17
|
* Each node type produces output matching what `MdzNodeView.svelte` renders at runtime.
|
|
18
18
|
* Collects required imports and flags unconfigured component/element references.
|
|
19
19
|
*
|
|
20
|
-
* @param nodes
|
|
21
|
-
* @param components
|
|
20
|
+
* @param nodes - parsed mdz nodes to render.
|
|
21
|
+
* @param components - component name to import path mapping (e.g., `{Alert: '$lib/Alert.svelte'}`).
|
|
22
22
|
* If content references a component not in this map, `has_unconfigured_tags` is set.
|
|
23
|
-
* @param elements
|
|
23
|
+
* @param elements - allowed HTML element names (e.g., `new Set(['aside', 'details'])`).
|
|
24
24
|
* If content references an element not in this set, `has_unconfigured_tags` is set.
|
|
25
|
-
* @param base
|
|
25
|
+
* @param base - base path for resolving relative links (e.g., `'/docs/mdz/'`).
|
|
26
26
|
* When provided, relative references (`./`, `../`) are resolved to absolute paths
|
|
27
27
|
* and passed through `resolve()`. Trailing slash recommended.
|
|
28
28
|
*/
|
package/dist/mdz_token_parser.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
|
-
import { extract_single_tag } from './mdz_helpers.js';
|
|
9
|
+
import { extract_single_tag, mdz_heading_id } from './mdz_helpers.js';
|
|
10
10
|
import { MdzLexer, } from './mdz_lexer.js';
|
|
11
11
|
/**
|
|
12
12
|
* Parses text to an array of `MdzNode` using a two-phase lexer+parser approach.
|
|
@@ -91,8 +91,9 @@ class MdzTokenParser {
|
|
|
91
91
|
if (node)
|
|
92
92
|
children.push(node);
|
|
93
93
|
}
|
|
94
|
-
const
|
|
95
|
-
|
|
94
|
+
const merged = this.#merge_adjacent_text(children);
|
|
95
|
+
const end = merged.length > 0 ? merged[merged.length - 1].end : start + level + 1;
|
|
96
|
+
return { type: 'Heading', level, id: mdz_heading_id(merged), children: merged, start, end };
|
|
96
97
|
}
|
|
97
98
|
#parse_inline() {
|
|
98
99
|
if (this.#index >= this.#tokens.length)
|