@fuzdev/fuz_ui 0.184.0 → 0.185.1
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/declaration.svelte.d.ts +9 -0
- package/dist/declaration.svelte.d.ts.map +1 -1
- package/dist/declaration.svelte.js +1 -0
- package/dist/library.svelte.d.ts +11 -0
- package/dist/library.svelte.d.ts.map +1 -1
- package/dist/mdz.d.ts +5 -2
- package/dist/mdz.d.ts.map +1 -1
- package/dist/mdz.js +149 -155
- package/dist/ts_helpers.js +1 -1
- package/dist/tsdoc_helpers.d.ts +2 -1
- package/dist/tsdoc_helpers.d.ts.map +1 -1
- package/dist/tsdoc_helpers.js +4 -3
- package/dist/tsdoc_mdz.d.ts +5 -1
- package/dist/tsdoc_mdz.d.ts.map +1 -1
- package/dist/tsdoc_mdz.js +13 -2
- package/package.json +8 -9
- package/src/lib/declaration.svelte.ts +2 -0
- package/src/lib/mdz.ts +150 -155
- package/src/lib/ts_helpers.ts +1 -1
- package/src/lib/tsdoc_helpers.ts +4 -3
- package/src/lib/tsdoc_mdz.ts +14 -2
|
@@ -52,6 +52,15 @@ export declare class Declaration {
|
|
|
52
52
|
description?: string | undefined;
|
|
53
53
|
default_value?: string | undefined;
|
|
54
54
|
bindable?: boolean | undefined;
|
|
55
|
+
examples?: string[] | undefined;
|
|
56
|
+
deprecated_message?: string | undefined;
|
|
57
|
+
see_also?: string[] | undefined;
|
|
58
|
+
throws?: {
|
|
59
|
+
[x: string]: unknown;
|
|
60
|
+
description: string;
|
|
61
|
+
type?: string | undefined;
|
|
62
|
+
}[] | undefined;
|
|
63
|
+
since?: string | undefined;
|
|
55
64
|
}[] | undefined;
|
|
56
65
|
return_type: string | undefined;
|
|
57
66
|
return_description: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"declaration.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/declaration.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,eAAe,EAGpB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"declaration.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/declaration.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,eAAe,EAGpB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,oBAAoB,CAAC;AAK/C;;GAEG;AACH,qBAAa,WAAW;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAiB;IACxC,QAAQ,CAAC,gBAAgB,EAAE,eAAe,CAAiB;IAE3D,OAAO,wCAAiC;IAExC;;OAEG;IACH,WAAW,SAA8B;IAEzC,IAAI,SAAwC;IAC5C,IAAI,4FAAwC;IAE5C;;OAEG;IACH,UAAU,qBAQR;IAEF;;OAEG;IACH,OAAO,SAAoF;IAE3F;;OAEG;IACH,gBAAgB,SAMd;IAEF;;OAEG;IACH,YAAY,qBAIV;IAEF;;OAEG;IACH,YAAY,SAAiE;IAE7E,cAAc,qBAAkD;IAChE,WAAW,qBAA+C;IAC1D,kBAAkB,qBAAsD;IACxE,UAAU;;;;;;;oBAA8C;IACxD,KAAK;;;;;;;;;;;;;;;;;oBAAyC;IAC9C,WAAW,qBAA+C;IAC1D,kBAAkB,qBAAsD;IACxE,cAAc;;;;;oBAAkD;IAChE,OAAO,uBAA2C;IAClD,UAAU,uBAA8C;IACxD,MAAM;;;;oBAA0C;IAChD,KAAK,qBAAyC;IAC9C,QAAQ,uBAA4C;IACpD,QAAQ,uBAA4C;IACpD,OAAO,EAAE,KAAK,CAAC,eAAe,CAAC,GAAG,SAAS,CAEzC;IACF,UAAU,EAAE,KAAK,CAAC,eAAe,CAAC,GAAG,SAAS,CAE5C;IAEF,YAAY,UAA2D;IACvE,aAAa,UAAuC;IACpD,iBAAiB,UAAgC;IACjD,cAAc,UAA+D;IAC7E,SAAS,UAAqD;IAC9D,YAAY,UAAuE;gBAEvE,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,eAAe;CAI7D"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { declaration_generate_import, declaration_get_display_name, } from '@fuzdev/fuz_util/source_json.js';
|
|
2
2
|
import { url_github_file } from './package_helpers.js';
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-deprecated */
|
|
3
4
|
/**
|
|
4
5
|
* Rich runtime representation of an exported declaration.
|
|
5
6
|
*/
|
package/dist/library.svelte.d.ts
CHANGED
|
@@ -126,6 +126,7 @@ export declare class Library {
|
|
|
126
126
|
type?: string | undefined;
|
|
127
127
|
}[] | undefined;
|
|
128
128
|
since?: string | undefined;
|
|
129
|
+
mutates?: Record<string, string> | undefined;
|
|
129
130
|
extends?: string[] | undefined;
|
|
130
131
|
implements?: string[] | undefined;
|
|
131
132
|
members?: Record<string, unknown>[] | undefined;
|
|
@@ -138,11 +139,21 @@ export declare class Library {
|
|
|
138
139
|
description?: string | undefined;
|
|
139
140
|
default_value?: string | undefined;
|
|
140
141
|
bindable?: boolean | undefined;
|
|
142
|
+
examples?: string[] | undefined;
|
|
143
|
+
deprecated_message?: string | undefined;
|
|
144
|
+
see_also?: string[] | undefined;
|
|
145
|
+
throws?: {
|
|
146
|
+
[x: string]: unknown;
|
|
147
|
+
description: string;
|
|
148
|
+
type?: string | undefined;
|
|
149
|
+
}[] | undefined;
|
|
150
|
+
since?: string | undefined;
|
|
141
151
|
}[] | undefined;
|
|
142
152
|
also_exported_from?: string[] | undefined;
|
|
143
153
|
alias_of?: {
|
|
144
154
|
module: string;
|
|
145
155
|
name: string;
|
|
156
|
+
kind: "function" | "class" | "type" | "json" | "variable" | "constructor" | "component" | "css";
|
|
146
157
|
} | undefined;
|
|
147
158
|
}[] | undefined;
|
|
148
159
|
module_comment?: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"library.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/library.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,kCAAkC,CAAC;AAIlE,OAAO,EAAC,WAAW,EAAC,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAC,MAAM,EAAC,MAAM,oBAAoB,CAAC;AAE1C;;GAEG;AACH,eAAO,MAAM,wBAAwB,GAAI,OAAO,OAAO,KAAG,MAGzD,CAAC;AAEF;;;;;;;;GAQG;AACH,qBAAa,OAAO;IACnB,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAiB;IAEnD;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAA4C;IACxD,WAAW
|
|
1
|
+
{"version":3,"file":"library.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/library.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,kCAAkC,CAAC;AAIlE,OAAO,EAAC,WAAW,EAAC,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAC,MAAM,EAAC,MAAM,oBAAoB,CAAC;AAE1C;;GAEG;AACH,eAAO,MAAM,wBAAwB,GAAI,OAAO,OAAO,KAAG,MAGzD,CAAC;AAEF;;;;;;;;GAQG;AACH,qBAAa,OAAO;IACnB,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAiB;IAEnD;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAA4C;IACxD,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAA2C;IAEtD,IAAI,SAAoC;IACxC,SAAS,SAAyC;IAClD,QAAQ,wCAAwC;IAChD,UAAU,gBAA0C;IACpD,YAAY,+CAA4C;IACxD,QAAQ,+CAAwC;IAChD,QAAQ,SAAwC;IAChD,OAAO,+CAAuC;IAC9C,aAAa,+CAA6C;IAC1D,SAAS,UAAyC;IAElD;;OAEG;IACH,OAAO,gBAML;IAEF;;OAEG;IACH,OAAO,WAIL;IAEF;;OAEG;IACH,cAAc,WAA4E;IAE1F;;OAEG;IACH,YAAY,gBAAmE;IAE/E;;OAEG;IACH,eAAe,2BAAgE;gBAEnE,YAAY,EAAE,WAAW,EAAE,UAAU,SAAK;IAKtD;;OAEG;IACH,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAIzD;;OAEG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAItC;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI/C;;OAEG;IACH,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC;CAGtD;AAED,eAAO,MAAM,eAAe;;;;CAA4B,CAAC"}
|
package/dist/mdz.d.ts
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
*
|
|
17
17
|
* ## Design philosophy
|
|
18
18
|
*
|
|
19
|
-
* - **False negatives over false positives**:
|
|
20
|
-
*
|
|
19
|
+
* - **False negatives over false positives**: When in doubt, treat as plain text.
|
|
20
|
+
* Block elements can interrupt paragraphs without blank lines; inline formatting is strict.
|
|
21
21
|
* - **One way to do things**: Single unambiguous syntax per feature. No alternatives.
|
|
22
22
|
* - **Explicit over implicit**: Clear delimiters and column-0 requirements avoid ambiguity.
|
|
23
23
|
* - **Simple over complete**: Prefer simple parsing rules over complex edge case handling.
|
|
@@ -102,6 +102,9 @@ export declare class MdzParser {
|
|
|
102
102
|
/**
|
|
103
103
|
* Main parse method. Returns flat array of nodes,
|
|
104
104
|
* with paragraph nodes wrapping content between double newlines.
|
|
105
|
+
*
|
|
106
|
+
* Block elements (headings, HR, codeblocks) are detected at every column-0
|
|
107
|
+
* position — they can interrupt paragraphs without requiring blank lines.
|
|
105
108
|
*/
|
|
106
109
|
parse(): Array<MdzNode>;
|
|
107
110
|
}
|
package/dist/mdz.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mdz.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH;;GAEG;AACH,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,KAAG,KAAK,CAAC,OAAO,CAAgC,CAAC;AAEvF,MAAM,MAAM,OAAO,GAChB,WAAW,GACX,WAAW,GACX,gBAAgB,GAChB,WAAW,GACX,aAAa,GACb,oBAAoB,GACpB,WAAW,GACX,gBAAgB,GAChB,SAAS,GACT,cAAc,GACd,cAAc,GACd,gBAAgB,CAAC;AAEpB,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACpD,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,aAAc,SAAQ,WAAW;IACjD,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,oBAAqB,SAAQ,WAAW;IACxD,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACzB,SAAS,EAAE,UAAU,GAAG,UAAU,CAAC;CACnC;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACpD,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,SAAU,SAAQ,WAAW;IAC7C,IAAI,EAAE,IAAI,CAAC;CACX;AAED,MAAM,WAAW,cAAe,SAAQ,WAAW;IAClD,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,cAAe,SAAQ,WAAW;IAClD,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACpD,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;CACzB;AA+CD;;;;GAIG;AACH,qBAAa,SAAS;;gBAQT,QAAQ,EAAE,MAAM;IAI5B
|
|
1
|
+
{"version":3,"file":"mdz.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH;;GAEG;AACH,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,KAAG,KAAK,CAAC,OAAO,CAAgC,CAAC;AAEvF,MAAM,MAAM,OAAO,GAChB,WAAW,GACX,WAAW,GACX,gBAAgB,GAChB,WAAW,GACX,aAAa,GACb,oBAAoB,GACpB,WAAW,GACX,gBAAgB,GAChB,SAAS,GACT,cAAc,GACd,cAAc,GACd,gBAAgB,CAAC;AAEpB,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACpD,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,aAAc,SAAQ,WAAW;IACjD,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,oBAAqB,SAAQ,WAAW;IACxD,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACzB,SAAS,EAAE,UAAU,GAAG,UAAU,CAAC;CACnC;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACpD,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,SAAU,SAAQ,WAAW;IAC7C,IAAI,EAAE,IAAI,CAAC;CACX;AAED,MAAM,WAAW,cAAe,SAAQ,WAAW;IAClD,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,cAAe,SAAQ,WAAW;IAClD,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACpD,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;CACzB;AA+CD;;;;GAIG;AACH,qBAAa,SAAS;;gBAQT,QAAQ,EAAE,MAAM;IAI5B;;;;;;OAMG;IACH,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC;CAslDvB;AAQD,eAAO,MAAM,UAAU,GAAI,GAAG,MAAM,KAAG,OAA8B,CAAC"}
|
package/dist/mdz.js
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
*
|
|
17
17
|
* ## Design philosophy
|
|
18
18
|
*
|
|
19
|
-
* - **False negatives over false positives**:
|
|
20
|
-
*
|
|
19
|
+
* - **False negatives over false positives**: When in doubt, treat as plain text.
|
|
20
|
+
* Block elements can interrupt paragraphs without blank lines; inline formatting is strict.
|
|
21
21
|
* - **One way to do things**: Single unambiguous syntax per feature. No alternatives.
|
|
22
22
|
* - **Explicit over implicit**: Clear delimiters and column-0 requirements avoid ambiguity.
|
|
23
23
|
* - **Simple over complete**: Prefer simple parsing rules over complex edge case handling.
|
|
@@ -95,88 +95,121 @@ export class MdzParser {
|
|
|
95
95
|
/**
|
|
96
96
|
* Main parse method. Returns flat array of nodes,
|
|
97
97
|
* with paragraph nodes wrapping content between double newlines.
|
|
98
|
+
*
|
|
99
|
+
* Block elements (headings, HR, codeblocks) are detected at every column-0
|
|
100
|
+
* position — they can interrupt paragraphs without requiring blank lines.
|
|
98
101
|
*/
|
|
99
102
|
parse() {
|
|
100
103
|
this.#nodes.length = 0;
|
|
101
104
|
const root_nodes = [];
|
|
102
105
|
const paragraph_children = [];
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
if (start_block) {
|
|
106
|
-
root_nodes.push(start_block);
|
|
107
|
-
}
|
|
106
|
+
// Skip leading newlines
|
|
107
|
+
this.#skip_newlines();
|
|
108
108
|
while (this.#index < this.#template.length) {
|
|
109
|
+
// Peek for block element (read-only match), flush paragraph first, then parse.
|
|
110
|
+
// Flush must happen before parse because parse modifies accumulation state.
|
|
111
|
+
const block_type = this.#peek_block_element();
|
|
112
|
+
if (block_type) {
|
|
113
|
+
const flushed = this.#flush_paragraph(paragraph_children, true);
|
|
114
|
+
if (flushed)
|
|
115
|
+
root_nodes.push(flushed);
|
|
116
|
+
if (block_type === 'heading')
|
|
117
|
+
root_nodes.push(this.#parse_heading());
|
|
118
|
+
else if (block_type === 'hr')
|
|
119
|
+
root_nodes.push(this.#parse_hr());
|
|
120
|
+
else
|
|
121
|
+
root_nodes.push(this.#parse_code_block());
|
|
122
|
+
this.#skip_newlines();
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
109
125
|
// Check for paragraph break (double newline)
|
|
110
126
|
if (this.#is_at_paragraph_break()) {
|
|
111
|
-
this.#
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const tag = paragraph_children.find((n) => n.type === 'Component' || n.type === 'Element');
|
|
122
|
-
root_nodes.push(tag);
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
// Regular paragraph
|
|
126
|
-
root_nodes.push({
|
|
127
|
-
type: 'Paragraph',
|
|
128
|
-
children: paragraph_children.slice(),
|
|
129
|
-
start: paragraph_children[0].start,
|
|
130
|
-
end: paragraph_children[paragraph_children.length - 1].end,
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
paragraph_children.length = 0;
|
|
134
|
-
}
|
|
135
|
-
// Consume the paragraph break
|
|
136
|
-
this.#eat('\n\n');
|
|
137
|
-
// Check for block element after paragraph break
|
|
138
|
-
const block = this.#try_parse_block_element();
|
|
139
|
-
if (block) {
|
|
140
|
-
root_nodes.push(block);
|
|
141
|
-
}
|
|
127
|
+
const flushed = this.#flush_paragraph(paragraph_children, true);
|
|
128
|
+
if (flushed)
|
|
129
|
+
root_nodes.push(flushed);
|
|
130
|
+
this.#skip_newlines();
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
// Parse inline content
|
|
134
|
+
const node = this.#parse_node();
|
|
135
|
+
if (node.type === 'Text') {
|
|
136
|
+
this.#accumulate_text(node.content, node.start);
|
|
142
137
|
}
|
|
143
138
|
else {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
this.#nodes.push(node);
|
|
151
|
-
}
|
|
152
|
-
if (this.#nodes.length > 0) {
|
|
153
|
-
paragraph_children.push(...this.#nodes);
|
|
154
|
-
this.#nodes.length = 0;
|
|
155
|
-
}
|
|
139
|
+
this.#flush_text();
|
|
140
|
+
this.#nodes.push(node);
|
|
141
|
+
}
|
|
142
|
+
if (this.#nodes.length > 0) {
|
|
143
|
+
paragraph_children.push(...this.#nodes);
|
|
144
|
+
this.#nodes.length = 0;
|
|
156
145
|
}
|
|
157
146
|
}
|
|
147
|
+
// Flush remaining content as final paragraph
|
|
148
|
+
const final_paragraph = this.#flush_paragraph(paragraph_children, true);
|
|
149
|
+
if (final_paragraph)
|
|
150
|
+
root_nodes.push(final_paragraph);
|
|
151
|
+
return root_nodes;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Flush accumulated inline content as a paragraph node (or single tag).
|
|
155
|
+
* When `trim_trailing` is true, trims trailing newlines from the last text node
|
|
156
|
+
* (the line break before a block element or paragraph break).
|
|
157
|
+
*
|
|
158
|
+
* @mutates paragraph_children - trims last text node, removes whitespace-only nodes, clears array
|
|
159
|
+
*/
|
|
160
|
+
#flush_paragraph(paragraph_children, trim_trailing = false) {
|
|
158
161
|
this.#flush_text();
|
|
159
162
|
if (this.#nodes.length > 0) {
|
|
160
163
|
paragraph_children.push(...this.#nodes);
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (paragraph_children.length
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
164
|
+
this.#nodes.length = 0;
|
|
165
|
+
}
|
|
166
|
+
if (paragraph_children.length === 0) {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
if (trim_trailing) {
|
|
170
|
+
// Trim trailing newlines from the last text node (line break before block element)
|
|
171
|
+
const last = paragraph_children[paragraph_children.length - 1];
|
|
172
|
+
if (last.type === 'Text') {
|
|
173
|
+
const trimmed = last.content.replace(/\n+$/, '');
|
|
174
|
+
if (trimmed) {
|
|
175
|
+
last.content = trimmed;
|
|
176
|
+
last.end = last.start + trimmed.length;
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
paragraph_children.pop();
|
|
180
|
+
}
|
|
168
181
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
start: paragraph_children[0].start,
|
|
175
|
-
end: paragraph_children[paragraph_children.length - 1].end,
|
|
176
|
-
});
|
|
182
|
+
// Skip whitespace-only paragraphs (e.g. newlines between consecutive blocks)
|
|
183
|
+
const has_content = paragraph_children.some((n) => n.type !== 'Text' || n.content.trim().length > 0);
|
|
184
|
+
if (!has_content) {
|
|
185
|
+
paragraph_children.length = 0;
|
|
186
|
+
return null;
|
|
177
187
|
}
|
|
178
188
|
}
|
|
179
|
-
|
|
189
|
+
// Single tag (component/element) - add directly without paragraph wrapper (MDX convention)
|
|
190
|
+
const single_tag = this.#extract_single_tag(paragraph_children);
|
|
191
|
+
if (single_tag) {
|
|
192
|
+
paragraph_children.length = 0;
|
|
193
|
+
return single_tag;
|
|
194
|
+
}
|
|
195
|
+
// Regular paragraph
|
|
196
|
+
const result = {
|
|
197
|
+
type: 'Paragraph',
|
|
198
|
+
children: paragraph_children.slice(),
|
|
199
|
+
start: paragraph_children[0].start,
|
|
200
|
+
end: paragraph_children[paragraph_children.length - 1].end,
|
|
201
|
+
};
|
|
202
|
+
paragraph_children.length = 0;
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Consume consecutive newline characters.
|
|
207
|
+
*/
|
|
208
|
+
#skip_newlines() {
|
|
209
|
+
while (this.#index < this.#template.length &&
|
|
210
|
+
this.#template.charCodeAt(this.#index) === NEWLINE) {
|
|
211
|
+
this.#index++;
|
|
212
|
+
}
|
|
180
213
|
}
|
|
181
214
|
/**
|
|
182
215
|
* Accumulate text for later flushing (performance optimization).
|
|
@@ -667,50 +700,42 @@ export class MdzParser {
|
|
|
667
700
|
};
|
|
668
701
|
}
|
|
669
702
|
/**
|
|
670
|
-
*
|
|
671
|
-
*
|
|
672
|
-
*
|
|
703
|
+
* Extract a single tag (component or element) if it's the only non-whitespace content.
|
|
704
|
+
* Returns the tag node if paragraph wrapping should be skipped (MDX convention),
|
|
705
|
+
* or null if the content should be wrapped in a paragraph.
|
|
673
706
|
*/
|
|
674
|
-
#
|
|
675
|
-
let
|
|
707
|
+
#extract_single_tag(nodes) {
|
|
708
|
+
let tag = null;
|
|
676
709
|
for (const node of nodes) {
|
|
677
710
|
if (node.type === 'Component' || node.type === 'Element') {
|
|
678
|
-
if (
|
|
679
|
-
return
|
|
680
|
-
|
|
711
|
+
if (tag)
|
|
712
|
+
return null; // Multiple tags
|
|
713
|
+
tag = node;
|
|
681
714
|
}
|
|
682
715
|
else if (node.type === 'Text') {
|
|
683
716
|
// Allow only whitespace-only text nodes
|
|
684
717
|
if (node.content.trim() !== '')
|
|
685
|
-
return
|
|
718
|
+
return null;
|
|
686
719
|
}
|
|
687
720
|
else {
|
|
688
721
|
// Any other node type means not a single tag
|
|
689
|
-
return
|
|
722
|
+
return null;
|
|
690
723
|
}
|
|
691
724
|
}
|
|
692
|
-
return
|
|
725
|
+
return tag;
|
|
693
726
|
}
|
|
694
727
|
/**
|
|
695
|
-
*
|
|
696
|
-
*
|
|
697
|
-
*
|
|
698
|
-
* Block elements must:
|
|
699
|
-
* - Start at column 0 (no leading whitespace)
|
|
700
|
-
* - Be followed by blank line or EOF
|
|
701
|
-
*
|
|
702
|
-
* This helper eliminates duplication between document start and post-paragraph-break parsing.
|
|
728
|
+
* Read-only check if current position matches a block element.
|
|
729
|
+
* Does not modify parser state — used to peek before flushing paragraph.
|
|
730
|
+
* Returns which block type matched, or null if none.
|
|
703
731
|
*/
|
|
704
|
-
#
|
|
705
|
-
if (this.#match_heading())
|
|
706
|
-
return
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
else if (this.#match_code_block()) {
|
|
712
|
-
return this.#parse_code_block();
|
|
713
|
-
}
|
|
732
|
+
#peek_block_element() {
|
|
733
|
+
if (this.#match_heading())
|
|
734
|
+
return 'heading';
|
|
735
|
+
if (this.#match_hr())
|
|
736
|
+
return 'hr';
|
|
737
|
+
if (this.#match_code_block())
|
|
738
|
+
return 'codeblock';
|
|
714
739
|
return null;
|
|
715
740
|
}
|
|
716
741
|
/**
|
|
@@ -1037,6 +1062,20 @@ export class MdzParser {
|
|
|
1037
1062
|
if (this.#is_at_paragraph_break()) {
|
|
1038
1063
|
break;
|
|
1039
1064
|
}
|
|
1065
|
+
// When next line could start a block element, consume the newline and stop.
|
|
1066
|
+
// The main loop will try block detection at the next character.
|
|
1067
|
+
// Consuming the newline here avoids a 3-iteration detour (break before \n,
|
|
1068
|
+
// fail peek at \n, safety-increment, then succeed peek at block char).
|
|
1069
|
+
if (char_code === NEWLINE) {
|
|
1070
|
+
const next_i = this.#index + 1;
|
|
1071
|
+
if (next_i < this.#template.length) {
|
|
1072
|
+
const next_char = this.#template.charCodeAt(next_i);
|
|
1073
|
+
if (next_char === HASH || next_char === HYPHEN || next_char === BACKTICK) {
|
|
1074
|
+
this.#index++; // consume the newline
|
|
1075
|
+
break;
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1040
1079
|
// Check for URL or internal path mid-text
|
|
1041
1080
|
if (this.#is_at_url() || this.#is_at_internal_path()) {
|
|
1042
1081
|
break;
|
|
@@ -1127,18 +1166,15 @@ export class MdzParser {
|
|
|
1127
1166
|
}
|
|
1128
1167
|
/**
|
|
1129
1168
|
* Check if current position matches a horizontal rule.
|
|
1130
|
-
* HR must be exactly `---` at column 0, followed by
|
|
1169
|
+
* HR must be exactly `---` at column 0, followed by newline or EOF.
|
|
1131
1170
|
*
|
|
1132
|
-
*
|
|
1133
|
-
*
|
|
1134
|
-
* Without this, `---` followed by regular text would create an hr and treat
|
|
1135
|
-
* the next line as a new paragraph, which could be surprising. The blank line
|
|
1136
|
-
* makes block element boundaries explicit and predictable.
|
|
1171
|
+
* mdz has no setext headings, so `---` after a paragraph is unambiguous
|
|
1172
|
+
* (always an HR, unlike CommonMark where it becomes a setext heading).
|
|
1137
1173
|
*/
|
|
1138
1174
|
#match_hr() {
|
|
1139
1175
|
let i = this.#index;
|
|
1140
|
-
// Must start at column 0 (
|
|
1141
|
-
if (i
|
|
1176
|
+
// Must start at column 0 (beginning of input or after newline)
|
|
1177
|
+
if (i > 0 && this.#template.charCodeAt(i - 1) !== NEWLINE) {
|
|
1142
1178
|
return false;
|
|
1143
1179
|
}
|
|
1144
1180
|
// Must have exactly three hyphens
|
|
@@ -1153,15 +1189,7 @@ export class MdzParser {
|
|
|
1153
1189
|
while (i < this.#template.length) {
|
|
1154
1190
|
const char_code = this.#template.charCodeAt(i);
|
|
1155
1191
|
if (char_code === NEWLINE) {
|
|
1156
|
-
|
|
1157
|
-
const next_i = i + 1;
|
|
1158
|
-
if (next_i >= this.#template.length) {
|
|
1159
|
-
return true; // hr followed by newline + EOF
|
|
1160
|
-
}
|
|
1161
|
-
if (this.#template.charCodeAt(next_i) === NEWLINE) {
|
|
1162
|
-
return true; // hr followed by blank line
|
|
1163
|
-
}
|
|
1164
|
-
return false; // hr followed by single newline + content
|
|
1192
|
+
return true;
|
|
1165
1193
|
}
|
|
1166
1194
|
if (char_code !== SPACE) {
|
|
1167
1195
|
return false; // Non-whitespace after ---, not an hr
|
|
@@ -1194,17 +1222,12 @@ export class MdzParser {
|
|
|
1194
1222
|
/**
|
|
1195
1223
|
* Check if current position matches a heading.
|
|
1196
1224
|
* Heading must be 1-6 hashes at column 0, followed by space and content,
|
|
1197
|
-
* followed by
|
|
1198
|
-
*
|
|
1199
|
-
* Blank line requirement rationale:
|
|
1200
|
-
* Ensures headings are visually and semantically separate from following content.
|
|
1201
|
-
* Without this, `# Heading\nText` would be ambiguous - is the text part of the
|
|
1202
|
-
* heading or a new paragraph? The blank line makes document structure explicit.
|
|
1225
|
+
* followed by newline or EOF.
|
|
1203
1226
|
*/
|
|
1204
1227
|
#match_heading() {
|
|
1205
1228
|
let i = this.#index;
|
|
1206
|
-
// Must start at column 0 (
|
|
1207
|
-
if (i
|
|
1229
|
+
// Must start at column 0 (beginning of input or after newline)
|
|
1230
|
+
if (i > 0 && this.#template.charCodeAt(i - 1) !== NEWLINE) {
|
|
1208
1231
|
return false;
|
|
1209
1232
|
}
|
|
1210
1233
|
// Count hashes (must be 1-6)
|
|
@@ -1235,23 +1258,8 @@ export class MdzParser {
|
|
|
1235
1258
|
if (!has_content) {
|
|
1236
1259
|
return false; // heading with only whitespace, treat as plain text
|
|
1237
1260
|
}
|
|
1238
|
-
// At
|
|
1239
|
-
|
|
1240
|
-
if (i >= this.#template.length) {
|
|
1241
|
-
return true; // heading at EOF
|
|
1242
|
-
}
|
|
1243
|
-
// Must have newline
|
|
1244
|
-
if (this.#template.charCodeAt(i) !== NEWLINE) {
|
|
1245
|
-
return false;
|
|
1246
|
-
}
|
|
1247
|
-
const next_i = i + 1;
|
|
1248
|
-
if (next_i >= this.#template.length) {
|
|
1249
|
-
return true; // heading followed by newline + EOF
|
|
1250
|
-
}
|
|
1251
|
-
if (this.#template.charCodeAt(next_i) === NEWLINE) {
|
|
1252
|
-
return true; // heading followed by blank line
|
|
1253
|
-
}
|
|
1254
|
-
return false; // heading followed by single newline + content
|
|
1261
|
+
// At newline or EOF — both are valid
|
|
1262
|
+
return true;
|
|
1255
1263
|
}
|
|
1256
1264
|
/**
|
|
1257
1265
|
* Parse heading: `# Heading text`
|
|
@@ -1312,19 +1320,13 @@ export class MdzParser {
|
|
|
1312
1320
|
}
|
|
1313
1321
|
/**
|
|
1314
1322
|
* Check if current position matches a code block.
|
|
1315
|
-
* Code block must be 3+ backticks at column 0, followed by
|
|
1323
|
+
* Code block must be 3+ backticks at column 0, closing fence followed by newline or EOF.
|
|
1316
1324
|
* Empty code blocks (no content) are treated as invalid.
|
|
1317
|
-
*
|
|
1318
|
-
* Blank line requirement rationale:
|
|
1319
|
-
* Separates code blocks from following content to prevent ambiguity.
|
|
1320
|
-
* Codeblocks are distinct semantic units that should be visually isolated.
|
|
1321
|
-
* The blank line makes it explicit where the code block ends and regular
|
|
1322
|
-
* content begins, following the "explicit over implicit" design principle.
|
|
1323
1325
|
*/
|
|
1324
1326
|
#match_code_block() {
|
|
1325
1327
|
let i = this.#index;
|
|
1326
|
-
// Must start at column 0 (
|
|
1327
|
-
if (i
|
|
1328
|
+
// Must start at column 0 (beginning of input or after newline)
|
|
1329
|
+
if (i > 0 && this.#template.charCodeAt(i - 1) !== NEWLINE) {
|
|
1328
1330
|
return false;
|
|
1329
1331
|
}
|
|
1330
1332
|
// Must have at least three backticks
|
|
@@ -1386,15 +1388,7 @@ export class MdzParser {
|
|
|
1386
1388
|
// closing fence has non-whitespace after it on same line - not a code block
|
|
1387
1389
|
return false;
|
|
1388
1390
|
}
|
|
1389
|
-
//
|
|
1390
|
-
const next_j = j + 1;
|
|
1391
|
-
if (next_j >= this.#template.length) {
|
|
1392
|
-
return true; // code block followed by newline + EOF
|
|
1393
|
-
}
|
|
1394
|
-
if (this.#template.charCodeAt(next_j) === NEWLINE) {
|
|
1395
|
-
return true; // code block followed by blank line
|
|
1396
|
-
}
|
|
1397
|
-
return false; // code block followed by single newline + content
|
|
1391
|
+
return true; // code block followed by newline or EOF
|
|
1398
1392
|
}
|
|
1399
1393
|
}
|
|
1400
1394
|
i++;
|
package/dist/ts_helpers.js
CHANGED
|
@@ -140,7 +140,7 @@ export const ts_analyze_module_exports = (source_file, checker, options, ctx) =>
|
|
|
140
140
|
const decl = {
|
|
141
141
|
name: export_symbol.name,
|
|
142
142
|
kind,
|
|
143
|
-
alias_of: { module: original_module, name: original_name },
|
|
143
|
+
alias_of: { module: original_module, name: original_name, kind },
|
|
144
144
|
};
|
|
145
145
|
// Renamed re-exports aren't nodocs - they're new declarations pointing to the original
|
|
146
146
|
declarations.push({ declaration: decl, nodocs: false });
|
package/dist/tsdoc_helpers.d.ts
CHANGED
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
* ## Behavioral notes
|
|
31
31
|
*
|
|
32
32
|
* Due to TS Compiler API limitations:
|
|
33
|
-
* -
|
|
33
|
+
* - `@param` and `@mutates` descriptions have leading `- ` stripped for visual consistency
|
|
34
|
+
* (TSDoc spec uses `@param name - description` but the separator is aesthetic)
|
|
34
35
|
* - `@throws` tags have `{Type}` stripped by TS API; fallback regex extracts first word as error type
|
|
35
36
|
* - TS API strips URL protocols from `@see` tag text; we use `getText()` to preserve original format including `{@link}` syntax
|
|
36
37
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tsdoc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/tsdoc_helpers.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"tsdoc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/tsdoc_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,iCAAiC,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,MAAM,CAAC,EAAE,KAAK,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;IACrD,oCAAoC;IACpC,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACzB,6CAA6C;IAC7C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qCAAqC;IACrC,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACzB,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACxB,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,WAAW,GACvB,MAAM,EAAE,CAAC,IAAI,EACb,aAAa,EAAE,CAAC,UAAU,KACxB,kBAAkB,GAAG,SAyFvB,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,0BAA0B,GACtC,aAAa,eAAe,EAC5B,OAAO,kBAAkB,GAAG,SAAS,KACnC,IAmBF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,GAAI,cAAc,MAAM,KAAG,MAAM,GAAG,SAUnE,CAAC"}
|
package/dist/tsdoc_helpers.js
CHANGED
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
* ## Behavioral notes
|
|
31
31
|
*
|
|
32
32
|
* Due to TS Compiler API limitations:
|
|
33
|
-
* -
|
|
33
|
+
* - `@param` and `@mutates` descriptions have leading `- ` stripped for visual consistency
|
|
34
|
+
* (TSDoc spec uses `@param name - description` but the separator is aesthetic)
|
|
34
35
|
* - `@throws` tags have `{Type}` stripped by TS API; fallback regex extracts first word as error type
|
|
35
36
|
* - TS API strips URL protocols from `@see` tag text; we use `getText()` to preserve original format including `{@link}` syntax
|
|
36
37
|
*
|
|
@@ -88,7 +89,7 @@ export const tsdoc_parse = (node, source_file) => {
|
|
|
88
89
|
// Extract parameter name and description
|
|
89
90
|
const param_name = ts.isIdentifier(tag.name) ? tag.name.text : tag.name.getText();
|
|
90
91
|
if (param_name && tag_text) {
|
|
91
|
-
params.set(param_name, tag_text.trim());
|
|
92
|
+
params.set(param_name, tag_text.trim().replace(/^-\s+/, ''));
|
|
92
93
|
}
|
|
93
94
|
}
|
|
94
95
|
else if (tag_name === 'returns' && tag_text) {
|
|
@@ -127,7 +128,7 @@ export const tsdoc_parse = (node, source_file) => {
|
|
|
127
128
|
since = tag_text.trim();
|
|
128
129
|
}
|
|
129
130
|
else if (tag_name === 'mutates' && tag_text) {
|
|
130
|
-
mutates.push(tag_text.trim());
|
|
131
|
+
mutates.push(tag_text.trim().replace(/^-\s+/, ''));
|
|
131
132
|
}
|
|
132
133
|
else if (tag_name === 'nodocs') {
|
|
133
134
|
nodocs = true;
|
package/dist/tsdoc_mdz.d.ts
CHANGED
|
@@ -16,8 +16,9 @@
|
|
|
16
16
|
* - `{@link identifier}` → `` `identifier` `` (code formatting)
|
|
17
17
|
* - Bare URLs → returned as-is
|
|
18
18
|
* - Bare identifiers → wrapped in backticks
|
|
19
|
+
* - `identifier description text` → `` `identifier` description text `` (first token is the reference)
|
|
19
20
|
*
|
|
20
|
-
* @param content
|
|
21
|
+
* @param content - raw `@see` tag content in TSDoc format
|
|
21
22
|
* @returns mdz-formatted string ready for `Mdz` component
|
|
22
23
|
*
|
|
23
24
|
* @example
|
|
@@ -30,6 +31,9 @@
|
|
|
30
31
|
*
|
|
31
32
|
* tsdoc_see_to_mdz('https://example.com')
|
|
32
33
|
* // → 'https://example.com'
|
|
34
|
+
*
|
|
35
|
+
* tsdoc_see_to_mdz('library_gen.ts for Gro-specific integration')
|
|
36
|
+
* // → '`library_gen.ts` for Gro-specific integration'
|
|
33
37
|
* ```
|
|
34
38
|
*/
|
|
35
39
|
export declare const tsdoc_see_to_mdz: (content: string) => string;
|
package/dist/tsdoc_mdz.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tsdoc_mdz.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/tsdoc_mdz.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH
|
|
1
|
+
{"version":3,"file":"tsdoc_mdz.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/tsdoc_mdz.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS,MAAM,KAAG,MA6BlD,CAAC"}
|
package/dist/tsdoc_mdz.js
CHANGED
|
@@ -19,8 +19,9 @@ const format_reference = (ref) => (mdz_is_url(ref) ? ref : `\`${ref}\``);
|
|
|
19
19
|
* - `{@link identifier}` → `` `identifier` `` (code formatting)
|
|
20
20
|
* - Bare URLs → returned as-is
|
|
21
21
|
* - Bare identifiers → wrapped in backticks
|
|
22
|
+
* - `identifier description text` → `` `identifier` description text `` (first token is the reference)
|
|
22
23
|
*
|
|
23
|
-
* @param content
|
|
24
|
+
* @param content - raw `@see` tag content in TSDoc format
|
|
24
25
|
* @returns mdz-formatted string ready for `Mdz` component
|
|
25
26
|
*
|
|
26
27
|
* @example
|
|
@@ -33,6 +34,9 @@ const format_reference = (ref) => (mdz_is_url(ref) ? ref : `\`${ref}\``);
|
|
|
33
34
|
*
|
|
34
35
|
* tsdoc_see_to_mdz('https://example.com')
|
|
35
36
|
* // → 'https://example.com'
|
|
37
|
+
*
|
|
38
|
+
* tsdoc_see_to_mdz('library_gen.ts for Gro-specific integration')
|
|
39
|
+
* // → '`library_gen.ts` for Gro-specific integration'
|
|
36
40
|
* ```
|
|
37
41
|
*/
|
|
38
42
|
export const tsdoc_see_to_mdz = (content) => {
|
|
@@ -52,5 +56,12 @@ export const tsdoc_see_to_mdz = (content) => {
|
|
|
52
56
|
}
|
|
53
57
|
return format_reference(inner);
|
|
54
58
|
}
|
|
55
|
-
|
|
59
|
+
// Split at first whitespace: first token is the reference, rest is description
|
|
60
|
+
const space_index = trimmed.indexOf(' ');
|
|
61
|
+
if (space_index === -1) {
|
|
62
|
+
return format_reference(trimmed);
|
|
63
|
+
}
|
|
64
|
+
const reference = trimmed.slice(0, space_index);
|
|
65
|
+
const description = trimmed.slice(space_index); // preserve leading space
|
|
66
|
+
return format_reference(reference) + description;
|
|
56
67
|
};
|
package/package.json
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fuzdev/fuz_ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.185.1",
|
|
4
4
|
"description": "Svelte UI library",
|
|
5
5
|
"motto": "friendly user zystem",
|
|
6
6
|
"glyph": "🧶",
|
|
7
7
|
"logo": "logo.svg",
|
|
8
8
|
"logo_alt": "a friendly brown spider facing you",
|
|
9
|
-
"public": true,
|
|
10
9
|
"license": "MIT",
|
|
11
10
|
"homepage": "https://ui.fuz.dev/",
|
|
12
11
|
"author": {
|
|
@@ -35,10 +34,10 @@
|
|
|
35
34
|
"node": ">=22.15"
|
|
36
35
|
},
|
|
37
36
|
"peerDependencies": {
|
|
38
|
-
"@fuzdev/fuz_code": ">=0.45.
|
|
39
|
-
"@fuzdev/fuz_css": ">=0.
|
|
40
|
-
"@fuzdev/fuz_util": ">=0.
|
|
41
|
-
"@fuzdev/gro": ">=0.
|
|
37
|
+
"@fuzdev/fuz_code": ">=0.45.1",
|
|
38
|
+
"@fuzdev/fuz_css": ">=0.53.0",
|
|
39
|
+
"@fuzdev/fuz_util": ">=0.52.0",
|
|
40
|
+
"@fuzdev/gro": ">=0.195.0",
|
|
42
41
|
"@jridgewell/trace-mapping": "^0.3",
|
|
43
42
|
"@sveltejs/kit": "^2.47.3",
|
|
44
43
|
"@types/estree": "^1",
|
|
@@ -76,9 +75,9 @@
|
|
|
76
75
|
"devDependencies": {
|
|
77
76
|
"@changesets/changelog-git": "^0.2.1",
|
|
78
77
|
"@fuzdev/fuz_code": "^0.45.1",
|
|
79
|
-
"@fuzdev/fuz_css": "^0.
|
|
80
|
-
"@fuzdev/fuz_util": "^0.
|
|
81
|
-
"@fuzdev/gro": "^0.
|
|
78
|
+
"@fuzdev/fuz_css": "^0.53.0",
|
|
79
|
+
"@fuzdev/fuz_util": "^0.52.0",
|
|
80
|
+
"@fuzdev/gro": "^0.195.0",
|
|
82
81
|
"@jridgewell/trace-mapping": "^0.3.31",
|
|
83
82
|
"@ryanatkn/eslint-config": "^0.9.0",
|
|
84
83
|
"@sveltejs/adapter-static": "^3.0.10",
|
package/src/lib/mdz.ts
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
*
|
|
17
17
|
* ## Design philosophy
|
|
18
18
|
*
|
|
19
|
-
* - **False negatives over false positives**:
|
|
20
|
-
*
|
|
19
|
+
* - **False negatives over false positives**: When in doubt, treat as plain text.
|
|
20
|
+
* Block elements can interrupt paragraphs without blank lines; inline formatting is strict.
|
|
21
21
|
* - **One way to do things**: Single unambiguous syntax per feature. No alternatives.
|
|
22
22
|
* - **Explicit over implicit**: Clear delimiters and column-0 requirements avoid ambiguity.
|
|
23
23
|
* - **Simple over complete**: Prefer simple parsing rules over complex edge case handling.
|
|
@@ -186,92 +186,130 @@ export class MdzParser {
|
|
|
186
186
|
/**
|
|
187
187
|
* Main parse method. Returns flat array of nodes,
|
|
188
188
|
* with paragraph nodes wrapping content between double newlines.
|
|
189
|
+
*
|
|
190
|
+
* Block elements (headings, HR, codeblocks) are detected at every column-0
|
|
191
|
+
* position — they can interrupt paragraphs without requiring blank lines.
|
|
189
192
|
*/
|
|
190
193
|
parse(): Array<MdzNode> {
|
|
191
194
|
this.#nodes.length = 0;
|
|
192
195
|
const root_nodes: Array<MdzNode> = [];
|
|
193
196
|
const paragraph_children: Array<MdzNode> = [];
|
|
194
197
|
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
if (start_block) {
|
|
198
|
-
root_nodes.push(start_block);
|
|
199
|
-
}
|
|
198
|
+
// Skip leading newlines
|
|
199
|
+
this.#skip_newlines();
|
|
200
200
|
|
|
201
201
|
while (this.#index < this.#template.length) {
|
|
202
|
+
// Peek for block element (read-only match), flush paragraph first, then parse.
|
|
203
|
+
// Flush must happen before parse because parse modifies accumulation state.
|
|
204
|
+
const block_type = this.#peek_block_element();
|
|
205
|
+
if (block_type) {
|
|
206
|
+
const flushed = this.#flush_paragraph(paragraph_children, true);
|
|
207
|
+
if (flushed) root_nodes.push(flushed);
|
|
208
|
+
if (block_type === 'heading') root_nodes.push(this.#parse_heading());
|
|
209
|
+
else if (block_type === 'hr') root_nodes.push(this.#parse_hr());
|
|
210
|
+
else root_nodes.push(this.#parse_code_block());
|
|
211
|
+
this.#skip_newlines();
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
|
|
202
215
|
// Check for paragraph break (double newline)
|
|
203
216
|
if (this.#is_at_paragraph_break()) {
|
|
204
|
-
this.#
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
// Wrap accumulated nodes in paragraph (or add single tag directly)
|
|
211
|
-
if (paragraph_children.length > 0) {
|
|
212
|
-
if (this.#is_single_tag(paragraph_children)) {
|
|
213
|
-
// Single tag (component/element) - add directly without paragraph wrapper (MDX convention)
|
|
214
|
-
const tag = paragraph_children.find(
|
|
215
|
-
(n) => n.type === 'Component' || n.type === 'Element',
|
|
216
|
-
)!;
|
|
217
|
-
root_nodes.push(tag);
|
|
218
|
-
} else {
|
|
219
|
-
// Regular paragraph
|
|
220
|
-
root_nodes.push({
|
|
221
|
-
type: 'Paragraph',
|
|
222
|
-
children: paragraph_children.slice(),
|
|
223
|
-
start: paragraph_children[0]!.start,
|
|
224
|
-
end: paragraph_children[paragraph_children.length - 1]!.end,
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
paragraph_children.length = 0;
|
|
228
|
-
}
|
|
229
|
-
// Consume the paragraph break
|
|
230
|
-
this.#eat('\n\n');
|
|
217
|
+
const flushed = this.#flush_paragraph(paragraph_children, true);
|
|
218
|
+
if (flushed) root_nodes.push(flushed);
|
|
219
|
+
this.#skip_newlines();
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
231
222
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
223
|
+
// Parse inline content
|
|
224
|
+
const node = this.#parse_node();
|
|
225
|
+
if (node.type === 'Text') {
|
|
226
|
+
this.#accumulate_text(node.content, node.start);
|
|
237
227
|
} else {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
245
|
-
if (this.#nodes.length > 0) {
|
|
246
|
-
paragraph_children.push(...this.#nodes);
|
|
247
|
-
this.#nodes.length = 0;
|
|
248
|
-
}
|
|
228
|
+
this.#flush_text();
|
|
229
|
+
this.#nodes.push(node);
|
|
230
|
+
}
|
|
231
|
+
if (this.#nodes.length > 0) {
|
|
232
|
+
paragraph_children.push(...this.#nodes);
|
|
233
|
+
this.#nodes.length = 0;
|
|
249
234
|
}
|
|
250
235
|
}
|
|
251
236
|
|
|
237
|
+
// Flush remaining content as final paragraph
|
|
238
|
+
const final_paragraph = this.#flush_paragraph(paragraph_children, true);
|
|
239
|
+
if (final_paragraph) root_nodes.push(final_paragraph);
|
|
240
|
+
|
|
241
|
+
return root_nodes;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Flush accumulated inline content as a paragraph node (or single tag).
|
|
246
|
+
* When `trim_trailing` is true, trims trailing newlines from the last text node
|
|
247
|
+
* (the line break before a block element or paragraph break).
|
|
248
|
+
*
|
|
249
|
+
* @mutates paragraph_children - trims last text node, removes whitespace-only nodes, clears array
|
|
250
|
+
*/
|
|
251
|
+
#flush_paragraph(paragraph_children: Array<MdzNode>, trim_trailing = false): MdzNode | null {
|
|
252
252
|
this.#flush_text();
|
|
253
253
|
if (this.#nodes.length > 0) {
|
|
254
254
|
paragraph_children.push(...this.#nodes);
|
|
255
|
+
this.#nodes.length = 0;
|
|
255
256
|
}
|
|
256
257
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
start
|
|
269
|
-
|
|
270
|
-
|
|
258
|
+
if (paragraph_children.length === 0) {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (trim_trailing) {
|
|
263
|
+
// Trim trailing newlines from the last text node (line break before block element)
|
|
264
|
+
const last = paragraph_children[paragraph_children.length - 1]!;
|
|
265
|
+
if (last.type === 'Text') {
|
|
266
|
+
const trimmed = last.content.replace(/\n+$/, '');
|
|
267
|
+
if (trimmed) {
|
|
268
|
+
last.content = trimmed;
|
|
269
|
+
last.end = last.start + trimmed.length;
|
|
270
|
+
} else {
|
|
271
|
+
paragraph_children.pop();
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Skip whitespace-only paragraphs (e.g. newlines between consecutive blocks)
|
|
276
|
+
const has_content = paragraph_children.some(
|
|
277
|
+
(n) => n.type !== 'Text' || n.content.trim().length > 0,
|
|
278
|
+
);
|
|
279
|
+
if (!has_content) {
|
|
280
|
+
paragraph_children.length = 0;
|
|
281
|
+
return null;
|
|
271
282
|
}
|
|
272
283
|
}
|
|
273
284
|
|
|
274
|
-
|
|
285
|
+
// Single tag (component/element) - add directly without paragraph wrapper (MDX convention)
|
|
286
|
+
const single_tag = this.#extract_single_tag(paragraph_children);
|
|
287
|
+
if (single_tag) {
|
|
288
|
+
paragraph_children.length = 0;
|
|
289
|
+
return single_tag;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Regular paragraph
|
|
293
|
+
const result: MdzParagraphNode = {
|
|
294
|
+
type: 'Paragraph',
|
|
295
|
+
children: paragraph_children.slice(),
|
|
296
|
+
start: paragraph_children[0]!.start,
|
|
297
|
+
end: paragraph_children[paragraph_children.length - 1]!.end,
|
|
298
|
+
};
|
|
299
|
+
paragraph_children.length = 0;
|
|
300
|
+
return result;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Consume consecutive newline characters.
|
|
305
|
+
*/
|
|
306
|
+
#skip_newlines(): void {
|
|
307
|
+
while (
|
|
308
|
+
this.#index < this.#template.length &&
|
|
309
|
+
this.#template.charCodeAt(this.#index) === NEWLINE
|
|
310
|
+
) {
|
|
311
|
+
this.#index++;
|
|
312
|
+
}
|
|
275
313
|
}
|
|
276
314
|
|
|
277
315
|
/**
|
|
@@ -870,47 +908,38 @@ export class MdzParser {
|
|
|
870
908
|
}
|
|
871
909
|
|
|
872
910
|
/**
|
|
873
|
-
*
|
|
874
|
-
*
|
|
875
|
-
*
|
|
911
|
+
* Extract a single tag (component or element) if it's the only non-whitespace content.
|
|
912
|
+
* Returns the tag node if paragraph wrapping should be skipped (MDX convention),
|
|
913
|
+
* or null if the content should be wrapped in a paragraph.
|
|
876
914
|
*/
|
|
877
|
-
#
|
|
878
|
-
let
|
|
915
|
+
#extract_single_tag(nodes: Array<MdzNode>): MdzComponentNode | MdzElementNode | null {
|
|
916
|
+
let tag: MdzComponentNode | MdzElementNode | null = null;
|
|
879
917
|
|
|
880
918
|
for (const node of nodes) {
|
|
881
919
|
if (node.type === 'Component' || node.type === 'Element') {
|
|
882
|
-
if (
|
|
883
|
-
|
|
920
|
+
if (tag) return null; // Multiple tags
|
|
921
|
+
tag = node;
|
|
884
922
|
} else if (node.type === 'Text') {
|
|
885
923
|
// Allow only whitespace-only text nodes
|
|
886
|
-
if (node.content.trim() !== '') return
|
|
924
|
+
if (node.content.trim() !== '') return null;
|
|
887
925
|
} else {
|
|
888
926
|
// Any other node type means not a single tag
|
|
889
|
-
return
|
|
927
|
+
return null;
|
|
890
928
|
}
|
|
891
929
|
}
|
|
892
930
|
|
|
893
|
-
return
|
|
931
|
+
return tag;
|
|
894
932
|
}
|
|
895
933
|
|
|
896
934
|
/**
|
|
897
|
-
*
|
|
898
|
-
*
|
|
899
|
-
*
|
|
900
|
-
* Block elements must:
|
|
901
|
-
* - Start at column 0 (no leading whitespace)
|
|
902
|
-
* - Be followed by blank line or EOF
|
|
903
|
-
*
|
|
904
|
-
* This helper eliminates duplication between document start and post-paragraph-break parsing.
|
|
935
|
+
* Read-only check if current position matches a block element.
|
|
936
|
+
* Does not modify parser state — used to peek before flushing paragraph.
|
|
937
|
+
* Returns which block type matched, or null if none.
|
|
905
938
|
*/
|
|
906
|
-
#
|
|
907
|
-
if (this.#match_heading())
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
return this.#parse_hr();
|
|
911
|
-
} else if (this.#match_code_block()) {
|
|
912
|
-
return this.#parse_code_block();
|
|
913
|
-
}
|
|
939
|
+
#peek_block_element(): 'heading' | 'hr' | 'codeblock' | null {
|
|
940
|
+
if (this.#match_heading()) return 'heading';
|
|
941
|
+
if (this.#match_hr()) return 'hr';
|
|
942
|
+
if (this.#match_code_block()) return 'codeblock';
|
|
914
943
|
return null;
|
|
915
944
|
}
|
|
916
945
|
|
|
@@ -1288,6 +1317,21 @@ export class MdzParser {
|
|
|
1288
1317
|
break;
|
|
1289
1318
|
}
|
|
1290
1319
|
|
|
1320
|
+
// When next line could start a block element, consume the newline and stop.
|
|
1321
|
+
// The main loop will try block detection at the next character.
|
|
1322
|
+
// Consuming the newline here avoids a 3-iteration detour (break before \n,
|
|
1323
|
+
// fail peek at \n, safety-increment, then succeed peek at block char).
|
|
1324
|
+
if (char_code === NEWLINE) {
|
|
1325
|
+
const next_i = this.#index + 1;
|
|
1326
|
+
if (next_i < this.#template.length) {
|
|
1327
|
+
const next_char = this.#template.charCodeAt(next_i);
|
|
1328
|
+
if (next_char === HASH || next_char === HYPHEN || next_char === BACKTICK) {
|
|
1329
|
+
this.#index++; // consume the newline
|
|
1330
|
+
break;
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1291
1335
|
// Check for URL or internal path mid-text
|
|
1292
1336
|
if (this.#is_at_url() || this.#is_at_internal_path()) {
|
|
1293
1337
|
break;
|
|
@@ -1395,19 +1439,16 @@ export class MdzParser {
|
|
|
1395
1439
|
|
|
1396
1440
|
/**
|
|
1397
1441
|
* Check if current position matches a horizontal rule.
|
|
1398
|
-
* HR must be exactly `---` at column 0, followed by
|
|
1442
|
+
* HR must be exactly `---` at column 0, followed by newline or EOF.
|
|
1399
1443
|
*
|
|
1400
|
-
*
|
|
1401
|
-
*
|
|
1402
|
-
* Without this, `---` followed by regular text would create an hr and treat
|
|
1403
|
-
* the next line as a new paragraph, which could be surprising. The blank line
|
|
1404
|
-
* makes block element boundaries explicit and predictable.
|
|
1444
|
+
* mdz has no setext headings, so `---` after a paragraph is unambiguous
|
|
1445
|
+
* (always an HR, unlike CommonMark where it becomes a setext heading).
|
|
1405
1446
|
*/
|
|
1406
1447
|
#match_hr(): boolean {
|
|
1407
1448
|
let i = this.#index;
|
|
1408
1449
|
|
|
1409
|
-
// Must start at column 0 (
|
|
1410
|
-
if (i
|
|
1450
|
+
// Must start at column 0 (beginning of input or after newline)
|
|
1451
|
+
if (i > 0 && this.#template.charCodeAt(i - 1) !== NEWLINE) {
|
|
1411
1452
|
return false;
|
|
1412
1453
|
}
|
|
1413
1454
|
|
|
@@ -1426,15 +1467,7 @@ export class MdzParser {
|
|
|
1426
1467
|
while (i < this.#template.length) {
|
|
1427
1468
|
const char_code = this.#template.charCodeAt(i);
|
|
1428
1469
|
if (char_code === NEWLINE) {
|
|
1429
|
-
|
|
1430
|
-
const next_i = i + 1;
|
|
1431
|
-
if (next_i >= this.#template.length) {
|
|
1432
|
-
return true; // hr followed by newline + EOF
|
|
1433
|
-
}
|
|
1434
|
-
if (this.#template.charCodeAt(next_i) === NEWLINE) {
|
|
1435
|
-
return true; // hr followed by blank line
|
|
1436
|
-
}
|
|
1437
|
-
return false; // hr followed by single newline + content
|
|
1470
|
+
return true;
|
|
1438
1471
|
}
|
|
1439
1472
|
if (char_code !== SPACE) {
|
|
1440
1473
|
return false; // Non-whitespace after ---, not an hr
|
|
@@ -1476,18 +1509,13 @@ export class MdzParser {
|
|
|
1476
1509
|
/**
|
|
1477
1510
|
* Check if current position matches a heading.
|
|
1478
1511
|
* Heading must be 1-6 hashes at column 0, followed by space and content,
|
|
1479
|
-
* followed by
|
|
1480
|
-
*
|
|
1481
|
-
* Blank line requirement rationale:
|
|
1482
|
-
* Ensures headings are visually and semantically separate from following content.
|
|
1483
|
-
* Without this, `# Heading\nText` would be ambiguous - is the text part of the
|
|
1484
|
-
* heading or a new paragraph? The blank line makes document structure explicit.
|
|
1512
|
+
* followed by newline or EOF.
|
|
1485
1513
|
*/
|
|
1486
1514
|
#match_heading(): boolean {
|
|
1487
1515
|
let i = this.#index;
|
|
1488
1516
|
|
|
1489
|
-
// Must start at column 0 (
|
|
1490
|
-
if (i
|
|
1517
|
+
// Must start at column 0 (beginning of input or after newline)
|
|
1518
|
+
if (i > 0 && this.#template.charCodeAt(i - 1) !== NEWLINE) {
|
|
1491
1519
|
return false;
|
|
1492
1520
|
}
|
|
1493
1521
|
|
|
@@ -1526,27 +1554,8 @@ export class MdzParser {
|
|
|
1526
1554
|
return false; // heading with only whitespace, treat as plain text
|
|
1527
1555
|
}
|
|
1528
1556
|
|
|
1529
|
-
// At
|
|
1530
|
-
|
|
1531
|
-
if (i >= this.#template.length) {
|
|
1532
|
-
return true; // heading at EOF
|
|
1533
|
-
}
|
|
1534
|
-
|
|
1535
|
-
// Must have newline
|
|
1536
|
-
if (this.#template.charCodeAt(i) !== NEWLINE) {
|
|
1537
|
-
return false;
|
|
1538
|
-
}
|
|
1539
|
-
|
|
1540
|
-
const next_i = i + 1;
|
|
1541
|
-
if (next_i >= this.#template.length) {
|
|
1542
|
-
return true; // heading followed by newline + EOF
|
|
1543
|
-
}
|
|
1544
|
-
|
|
1545
|
-
if (this.#template.charCodeAt(next_i) === NEWLINE) {
|
|
1546
|
-
return true; // heading followed by blank line
|
|
1547
|
-
}
|
|
1548
|
-
|
|
1549
|
-
return false; // heading followed by single newline + content
|
|
1557
|
+
// At newline or EOF — both are valid
|
|
1558
|
+
return true;
|
|
1550
1559
|
}
|
|
1551
1560
|
|
|
1552
1561
|
/**
|
|
@@ -1616,20 +1625,14 @@ export class MdzParser {
|
|
|
1616
1625
|
|
|
1617
1626
|
/**
|
|
1618
1627
|
* Check if current position matches a code block.
|
|
1619
|
-
* Code block must be 3+ backticks at column 0, followed by
|
|
1628
|
+
* Code block must be 3+ backticks at column 0, closing fence followed by newline or EOF.
|
|
1620
1629
|
* Empty code blocks (no content) are treated as invalid.
|
|
1621
|
-
*
|
|
1622
|
-
* Blank line requirement rationale:
|
|
1623
|
-
* Separates code blocks from following content to prevent ambiguity.
|
|
1624
|
-
* Codeblocks are distinct semantic units that should be visually isolated.
|
|
1625
|
-
* The blank line makes it explicit where the code block ends and regular
|
|
1626
|
-
* content begins, following the "explicit over implicit" design principle.
|
|
1627
1630
|
*/
|
|
1628
1631
|
#match_code_block(): boolean {
|
|
1629
1632
|
let i = this.#index;
|
|
1630
1633
|
|
|
1631
|
-
// Must start at column 0 (
|
|
1632
|
-
if (i
|
|
1634
|
+
// Must start at column 0 (beginning of input or after newline)
|
|
1635
|
+
if (i > 0 && this.#template.charCodeAt(i - 1) !== NEWLINE) {
|
|
1633
1636
|
return false;
|
|
1634
1637
|
}
|
|
1635
1638
|
|
|
@@ -1704,15 +1707,7 @@ export class MdzParser {
|
|
|
1704
1707
|
return false;
|
|
1705
1708
|
}
|
|
1706
1709
|
|
|
1707
|
-
//
|
|
1708
|
-
const next_j = j + 1;
|
|
1709
|
-
if (next_j >= this.#template.length) {
|
|
1710
|
-
return true; // code block followed by newline + EOF
|
|
1711
|
-
}
|
|
1712
|
-
if (this.#template.charCodeAt(next_j) === NEWLINE) {
|
|
1713
|
-
return true; // code block followed by blank line
|
|
1714
|
-
}
|
|
1715
|
-
return false; // code block followed by single newline + content
|
|
1710
|
+
return true; // code block followed by newline or EOF
|
|
1716
1711
|
}
|
|
1717
1712
|
}
|
|
1718
1713
|
i++;
|
package/src/lib/ts_helpers.ts
CHANGED
|
@@ -228,7 +228,7 @@ export const ts_analyze_module_exports = (
|
|
|
228
228
|
const decl: DeclarationJson = {
|
|
229
229
|
name: export_symbol.name,
|
|
230
230
|
kind,
|
|
231
|
-
alias_of: {module: original_module, name: original_name},
|
|
231
|
+
alias_of: {module: original_module, name: original_name, kind},
|
|
232
232
|
};
|
|
233
233
|
// Renamed re-exports aren't nodocs - they're new declarations pointing to the original
|
|
234
234
|
declarations.push({declaration: decl, nodocs: false});
|
package/src/lib/tsdoc_helpers.ts
CHANGED
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
* ## Behavioral notes
|
|
31
31
|
*
|
|
32
32
|
* Due to TS Compiler API limitations:
|
|
33
|
-
* -
|
|
33
|
+
* - `@param` and `@mutates` descriptions have leading `- ` stripped for visual consistency
|
|
34
|
+
* (TSDoc spec uses `@param name - description` but the separator is aesthetic)
|
|
34
35
|
* - `@throws` tags have `{Type}` stripped by TS API; fallback regex extracts first word as error type
|
|
35
36
|
* - TS API strips URL protocols from `@see` tag text; we use `getText()` to preserve original format including `{@link}` syntax
|
|
36
37
|
*
|
|
@@ -125,7 +126,7 @@ export const tsdoc_parse = (
|
|
|
125
126
|
// Extract parameter name and description
|
|
126
127
|
const param_name = ts.isIdentifier(tag.name) ? tag.name.text : tag.name.getText();
|
|
127
128
|
if (param_name && tag_text) {
|
|
128
|
-
params.set(param_name, tag_text.trim());
|
|
129
|
+
params.set(param_name, tag_text.trim().replace(/^-\s+/, ''));
|
|
129
130
|
}
|
|
130
131
|
} else if (tag_name === 'returns' && tag_text) {
|
|
131
132
|
returns = tag_text.trim();
|
|
@@ -157,7 +158,7 @@ export const tsdoc_parse = (
|
|
|
157
158
|
} else if (tag_name === 'since' && tag_text) {
|
|
158
159
|
since = tag_text.trim();
|
|
159
160
|
} else if (tag_name === 'mutates' && tag_text) {
|
|
160
|
-
mutates.push(tag_text.trim());
|
|
161
|
+
mutates.push(tag_text.trim().replace(/^-\s+/, ''));
|
|
161
162
|
} else if (tag_name === 'nodocs') {
|
|
162
163
|
nodocs = true;
|
|
163
164
|
}
|
package/src/lib/tsdoc_mdz.ts
CHANGED
|
@@ -22,8 +22,9 @@ const format_reference = (ref: string): string => (mdz_is_url(ref) ? ref : `\`${
|
|
|
22
22
|
* - `{@link identifier}` → `` `identifier` `` (code formatting)
|
|
23
23
|
* - Bare URLs → returned as-is
|
|
24
24
|
* - Bare identifiers → wrapped in backticks
|
|
25
|
+
* - `identifier description text` → `` `identifier` description text `` (first token is the reference)
|
|
25
26
|
*
|
|
26
|
-
* @param content
|
|
27
|
+
* @param content - raw `@see` tag content in TSDoc format
|
|
27
28
|
* @returns mdz-formatted string ready for `Mdz` component
|
|
28
29
|
*
|
|
29
30
|
* @example
|
|
@@ -36,6 +37,9 @@ const format_reference = (ref: string): string => (mdz_is_url(ref) ? ref : `\`${
|
|
|
36
37
|
*
|
|
37
38
|
* tsdoc_see_to_mdz('https://example.com')
|
|
38
39
|
* // → 'https://example.com'
|
|
40
|
+
*
|
|
41
|
+
* tsdoc_see_to_mdz('library_gen.ts for Gro-specific integration')
|
|
42
|
+
* // → '`library_gen.ts` for Gro-specific integration'
|
|
39
43
|
* ```
|
|
40
44
|
*/
|
|
41
45
|
export const tsdoc_see_to_mdz = (content: string): string => {
|
|
@@ -58,5 +62,13 @@ export const tsdoc_see_to_mdz = (content: string): string => {
|
|
|
58
62
|
return format_reference(inner);
|
|
59
63
|
}
|
|
60
64
|
|
|
61
|
-
|
|
65
|
+
// Split at first whitespace: first token is the reference, rest is description
|
|
66
|
+
const space_index = trimmed.indexOf(' ');
|
|
67
|
+
if (space_index === -1) {
|
|
68
|
+
return format_reference(trimmed);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const reference = trimmed.slice(0, space_index);
|
|
72
|
+
const description = trimmed.slice(space_index); // preserve leading space
|
|
73
|
+
return format_reference(reference) + description;
|
|
62
74
|
};
|