@effected/markdown 0.6.2 → 0.7.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/FrontmatterSource.js +188 -0
- package/Markdown.js +146 -0
- package/MarkdownDocument.js +4 -3
- package/MarkdownNode.js +154 -3
- package/Mdast.js +74 -1
- package/README.md +65 -0
- package/index.d.ts +443 -8
- package/index.js +3 -2
- package/internal/blockParser.js +1 -1
- package/internal/blocks/frontmatter.js +47 -1
- package/internal/phrasing.js +57 -0
- package/internal/rawInline.js +3 -1
- package/internal/stringify.js +143 -3
- package/package.json +3 -3
package/index.d.ts
CHANGED
|
@@ -353,11 +353,14 @@ declare class FootnoteReference extends FootnoteReference_base {}
|
|
|
353
353
|
*/
|
|
354
354
|
declare const PhrasingContent: Schema.Codec<PhrasingContent>;
|
|
355
355
|
/**
|
|
356
|
-
* The union of all phrasing-content node types.
|
|
356
|
+
* The union of all phrasing-content node types. Widened for MDX with
|
|
357
|
+
* {@link MdxJsxTextElement} and {@link MdxTextExpression}, per
|
|
358
|
+
* mdast-util-mdx's `PhrasingContentMap` registrations — the parser never
|
|
359
|
+
* produces either; they serve constructed trees.
|
|
357
360
|
*
|
|
358
361
|
* @public
|
|
359
362
|
*/
|
|
360
|
-
type PhrasingContent = Break | Delete | Emphasis | FootnoteReference | Html | Image | ImageReference | InlineCode | Link | LinkReference | Strong | Text;
|
|
363
|
+
type PhrasingContent = Break | Delete | Emphasis | FootnoteReference | Html | Image | ImageReference | InlineCode | Link | LinkReference | MdxJsxTextElement | MdxTextExpression | Strong | Text;
|
|
361
364
|
declare const ThematicBreak_base: Schema.Class<ThematicBreak, Schema.Struct<{
|
|
362
365
|
readonly type: Schema.tag<"thematicBreak">;
|
|
363
366
|
readonly position: Schema.withConstructorDefault<typeof Position>;
|
|
@@ -618,11 +621,14 @@ declare const FlowContent: Schema.Codec<FlowContent>;
|
|
|
618
621
|
/**
|
|
619
622
|
* The union of all flow-content node types. Includes mdast's `Content`
|
|
620
623
|
* category (`Definition | Paragraph`) inline, as the spec's `FlowContent`
|
|
621
|
-
* definition does,
|
|
624
|
+
* definition does, the GFM extras `FootnoteDefinition` and `Table`, and the
|
|
625
|
+
* MDX extras {@link MdxJsxFlowElement} and {@link MdxFlowExpression} per
|
|
626
|
+
* mdast-util-mdx's `BlockContentMap` registrations — the parser never
|
|
627
|
+
* produces the MDX members; they serve constructed trees.
|
|
622
628
|
*
|
|
623
629
|
* @public
|
|
624
630
|
*/
|
|
625
|
-
type FlowContent = Blockquote | Code | Definition | FootnoteDefinition | Heading | Html | List | Paragraph | Table | ThematicBreak;
|
|
631
|
+
type FlowContent = Blockquote | Code | Definition | FootnoteDefinition | Heading | Html | List | MdxFlowExpression | MdxJsxFlowElement | Paragraph | Table | ThematicBreak;
|
|
626
632
|
/**
|
|
627
633
|
* The union of every node that may appear where mdast expects **list**
|
|
628
634
|
* content. A one-member union, kept because mdast names the category and
|
|
@@ -638,6 +644,155 @@ declare const ListContent: Schema.Codec<ListContent>;
|
|
|
638
644
|
* @public
|
|
639
645
|
*/
|
|
640
646
|
type ListContent = ListItem;
|
|
647
|
+
declare const MdxJsxAttributeValueExpression_base: Schema.Class<MdxJsxAttributeValueExpression, Schema.Struct<{
|
|
648
|
+
readonly type: Schema.tag<"mdxJsxAttributeValueExpression">;
|
|
649
|
+
readonly value: Schema.String;
|
|
650
|
+
readonly position: Schema.withConstructorDefault<typeof Position>;
|
|
651
|
+
}>, {}>;
|
|
652
|
+
/**
|
|
653
|
+
* MdxJsxAttributeValueExpression — a JSX attribute value written as an
|
|
654
|
+
* expression (`<a b={c} />`); `value` holds the expression source text
|
|
655
|
+
* between the braces, never evaluated or parsed.
|
|
656
|
+
*
|
|
657
|
+
* The primary construction path is a JSON-encoded prop:
|
|
658
|
+
* `MdxJsxAttributeValueExpression.make({ value: JSON.stringify(props) })`.
|
|
659
|
+
*
|
|
660
|
+
* @public
|
|
661
|
+
*/
|
|
662
|
+
declare class MdxJsxAttributeValueExpression extends MdxJsxAttributeValueExpression_base {}
|
|
663
|
+
declare const MdxJsxAttribute_base: Schema.Class<MdxJsxAttribute, Schema.Struct<{
|
|
664
|
+
readonly type: Schema.tag<"mdxJsxAttribute">;
|
|
665
|
+
readonly name: Schema.String;
|
|
666
|
+
readonly value: Schema.optionalKey<Schema.NullOr<Schema.Union<readonly [typeof MdxJsxAttributeValueExpression, Schema.String]>>>;
|
|
667
|
+
readonly position: Schema.withConstructorDefault<typeof Position>;
|
|
668
|
+
}>, {}>;
|
|
669
|
+
/**
|
|
670
|
+
* MdxJsxAttribute — a named JSX attribute (`<a b="c" />`). `value` is a
|
|
671
|
+
* string literal, a {@link MdxJsxAttributeValueExpression}, or — for a
|
|
672
|
+
* boolean attribute (`<a b />`) — absent or `null`, both of which the
|
|
673
|
+
* mdast-util-mdx-jsx contract spells (its parser writes `null`; absence is
|
|
674
|
+
* the constructed-tree spelling). The serializer treats the two identically.
|
|
675
|
+
*
|
|
676
|
+
* `name` must be non-empty — an attribute without a name has no MDX spelling,
|
|
677
|
+
* so the schema refuses it at construction and decode (the oracle's
|
|
678
|
+
* serialize-time crash, moved to the admission boundary).
|
|
679
|
+
*
|
|
680
|
+
* @public
|
|
681
|
+
*/
|
|
682
|
+
declare class MdxJsxAttribute extends MdxJsxAttribute_base {}
|
|
683
|
+
declare const MdxJsxExpressionAttribute_base: Schema.Class<MdxJsxExpressionAttribute, Schema.Struct<{
|
|
684
|
+
readonly type: Schema.tag<"mdxJsxExpressionAttribute">;
|
|
685
|
+
readonly value: Schema.String;
|
|
686
|
+
readonly position: Schema.withConstructorDefault<typeof Position>;
|
|
687
|
+
}>, {}>;
|
|
688
|
+
/**
|
|
689
|
+
* MdxJsxExpressionAttribute — a JSX attribute written whole as an expression
|
|
690
|
+
* (`<a {...b} />`); `value` holds the expression source text between the
|
|
691
|
+
* braces.
|
|
692
|
+
*
|
|
693
|
+
* @public
|
|
694
|
+
*/
|
|
695
|
+
declare class MdxJsxExpressionAttribute extends MdxJsxExpressionAttribute_base {}
|
|
696
|
+
/**
|
|
697
|
+
* The union of every node that may appear in a JSX element's `attributes`
|
|
698
|
+
* array. A real `Schema.Union` for the construction pass-through documented
|
|
699
|
+
* on `RowContent`.
|
|
700
|
+
*
|
|
701
|
+
* Attribute carriers are node-shaped values — they carry `type` and
|
|
702
|
+
* `position` per the mdast-util-mdx-jsx contract — but they are **not tree
|
|
703
|
+
* content**: they never appear in a `children` array, so they are excluded
|
|
704
|
+
* from `MarkdownNode` and invisible to the visitor and to
|
|
705
|
+
* `MarkdownDocument.find`.
|
|
706
|
+
*
|
|
707
|
+
* @public
|
|
708
|
+
*/
|
|
709
|
+
declare const MdxJsxAttributeContent: Schema.Codec<MdxJsxAttributeContent>;
|
|
710
|
+
/**
|
|
711
|
+
* The union of all JSX attribute node types.
|
|
712
|
+
*
|
|
713
|
+
* @public
|
|
714
|
+
*/
|
|
715
|
+
type MdxJsxAttributeContent = MdxJsxAttribute | MdxJsxExpressionAttribute;
|
|
716
|
+
declare const MdxJsxFlowElement_base: Schema.Class<MdxJsxFlowElement, Schema.Struct<{
|
|
717
|
+
readonly type: Schema.tag<"mdxJsxFlowElement">;
|
|
718
|
+
readonly name: Schema.NullOr<Schema.String>;
|
|
719
|
+
readonly attributes: Schema.$Array<Schema.Codec<MdxJsxAttributeContent, MdxJsxAttributeContent, never, never>>;
|
|
720
|
+
readonly children: Schema.$Array<Schema.suspend<Schema.Codec<FlowContent, FlowContent, never, never>>>;
|
|
721
|
+
readonly position: Schema.withConstructorDefault<typeof Position>;
|
|
722
|
+
}>, {}>;
|
|
723
|
+
/**
|
|
724
|
+
* MdxJsxFlowElement — a JSX element in flow (block) position (`<Component />`
|
|
725
|
+
* on its own lines). `name` is `null` for a fragment (`<></>`); children are
|
|
726
|
+
* flow content, per the oracle's `BlockContent | DefinitionContent` model.
|
|
727
|
+
*
|
|
728
|
+
* A fragment cannot carry attributes — that shape has no MDX spelling — so
|
|
729
|
+
* the schema refuses it at construction and decode. A **named** element's
|
|
730
|
+
* name must be non-empty on the same terms: `""` has no MDX spelling either
|
|
731
|
+
* (the oracle's parser only ever produces a real name or `null`, and its
|
|
732
|
+
* serializer treats a falsy name as the fragment), so `null` is the one
|
|
733
|
+
* fragment spelling and the empty string fails typed.
|
|
734
|
+
*
|
|
735
|
+
* @public
|
|
736
|
+
*/
|
|
737
|
+
declare class MdxJsxFlowElement extends MdxJsxFlowElement_base {}
|
|
738
|
+
declare const MdxJsxTextElement_base: Schema.Class<MdxJsxTextElement, Schema.Struct<{
|
|
739
|
+
readonly type: Schema.tag<"mdxJsxTextElement">;
|
|
740
|
+
readonly name: Schema.NullOr<Schema.String>;
|
|
741
|
+
readonly attributes: Schema.$Array<Schema.Codec<MdxJsxAttributeContent, MdxJsxAttributeContent, never, never>>;
|
|
742
|
+
readonly children: Schema.$Array<Schema.suspend<Schema.Codec<PhrasingContent, PhrasingContent, never, never>>>;
|
|
743
|
+
readonly position: Schema.withConstructorDefault<typeof Position>;
|
|
744
|
+
}>, {}>;
|
|
745
|
+
/**
|
|
746
|
+
* MdxJsxTextElement — a JSX element in text (phrasing) position
|
|
747
|
+
* (`a <b>c</b> d`). `name` is `null` for a fragment; children are phrasing
|
|
748
|
+
* content. Refuses attributes on a fragment and an empty-string name, on the
|
|
749
|
+
* same terms as {@link MdxJsxFlowElement}.
|
|
750
|
+
*
|
|
751
|
+
* @public
|
|
752
|
+
*/
|
|
753
|
+
declare class MdxJsxTextElement extends MdxJsxTextElement_base {}
|
|
754
|
+
declare const MdxFlowExpression_base: Schema.Class<MdxFlowExpression, Schema.Struct<{
|
|
755
|
+
readonly type: Schema.tag<"mdxFlowExpression">;
|
|
756
|
+
readonly value: Schema.String;
|
|
757
|
+
readonly position: Schema.withConstructorDefault<typeof Position>;
|
|
758
|
+
}>, {}>;
|
|
759
|
+
/**
|
|
760
|
+
* MdxFlowExpression — an expression in flow (block) position (`{a + b}` on
|
|
761
|
+
* its own lines); `value` holds the expression source text between the
|
|
762
|
+
* braces.
|
|
763
|
+
*
|
|
764
|
+
* @public
|
|
765
|
+
*/
|
|
766
|
+
declare class MdxFlowExpression extends MdxFlowExpression_base {}
|
|
767
|
+
declare const MdxTextExpression_base: Schema.Class<MdxTextExpression, Schema.Struct<{
|
|
768
|
+
readonly type: Schema.tag<"mdxTextExpression">;
|
|
769
|
+
readonly value: Schema.String;
|
|
770
|
+
readonly position: Schema.withConstructorDefault<typeof Position>;
|
|
771
|
+
}>, {}>;
|
|
772
|
+
/**
|
|
773
|
+
* MdxTextExpression — an expression in text (phrasing) position
|
|
774
|
+
* (`a {b} c`); `value` holds the expression source text between the braces.
|
|
775
|
+
*
|
|
776
|
+
* @public
|
|
777
|
+
*/
|
|
778
|
+
declare class MdxTextExpression extends MdxTextExpression_base {}
|
|
779
|
+
declare const MdxjsEsm_base: Schema.Class<MdxjsEsm, Schema.Struct<{
|
|
780
|
+
readonly type: Schema.tag<"mdxjsEsm">;
|
|
781
|
+
readonly value: Schema.String;
|
|
782
|
+
readonly position: Schema.withConstructorDefault<typeof Position>;
|
|
783
|
+
}>, {}>;
|
|
784
|
+
/**
|
|
785
|
+
* MdxjsEsm — an MDX ESM block (`import`/`export` statements); `value` holds
|
|
786
|
+
* the statement source verbatim.
|
|
787
|
+
*
|
|
788
|
+
* Only ever a child of {@link Root}, per the mdast-util-mdxjs-esm content
|
|
789
|
+
* registration — ESM cannot nest inside a JSX element or any other
|
|
790
|
+
* container. As with the frontmatter head node, the constraint is structural
|
|
791
|
+
* (the `Root` children union admits it, no other union does), not validated.
|
|
792
|
+
*
|
|
793
|
+
* @public
|
|
794
|
+
*/
|
|
795
|
+
declare class MdxjsEsm extends MdxjsEsm_base {}
|
|
641
796
|
/**
|
|
642
797
|
* The frontmatter formats the capture recognizes, keyed by their opening
|
|
643
798
|
* fence: `---` is yaml, `+++` is toml and `---json` is json.
|
|
@@ -694,7 +849,7 @@ declare const FrontmatterContent: Schema.Codec<FrontmatterContent>;
|
|
|
694
849
|
type FrontmatterContent = Frontmatter;
|
|
695
850
|
declare const Root_base: Schema.Class<Root, Schema.Struct<{
|
|
696
851
|
readonly type: Schema.tag<"root">;
|
|
697
|
-
readonly children: Schema.$Array<Schema.suspend<Schema.Codec<Frontmatter | FlowContent, Frontmatter | FlowContent, never, never>>>;
|
|
852
|
+
readonly children: Schema.$Array<Schema.suspend<Schema.Codec<Frontmatter | MdxjsEsm | FlowContent, Frontmatter | MdxjsEsm | FlowContent, never, never>>>;
|
|
698
853
|
readonly position: Schema.withConstructorDefault<typeof Position>;
|
|
699
854
|
}>, {}>;
|
|
700
855
|
/**
|
|
@@ -703,7 +858,8 @@ declare const Root_base: Schema.Class<Root, Schema.Struct<{
|
|
|
703
858
|
* mdast leaves a root's content model open; a parsed markdown document is
|
|
704
859
|
* flow content, optionally headed by one {@link Frontmatter} node — mdast's
|
|
705
860
|
* `FlowContentFrontmatter` merge, which admits frontmatter at the root and
|
|
706
|
-
* nowhere else.
|
|
861
|
+
* nowhere else. {@link MdxjsEsm} is likewise admitted at the root and nowhere
|
|
862
|
+
* else, per mdast-util-mdxjs-esm's `RootContentMap` registration.
|
|
707
863
|
*
|
|
708
864
|
* @public
|
|
709
865
|
*/
|
|
@@ -714,7 +870,7 @@ declare class Root extends Root_base {}
|
|
|
714
870
|
*
|
|
715
871
|
* @public
|
|
716
872
|
*/
|
|
717
|
-
type MarkdownNode = Root | FrontmatterContent | FlowContent | ListContent | PhrasingContent | RowContent | TableContent;
|
|
873
|
+
type MarkdownNode = Root | FrontmatterContent | FlowContent | ListContent | MdxjsEsm | PhrasingContent | RowContent | TableContent;
|
|
718
874
|
/**
|
|
719
875
|
* A schema matching any node in the tree.
|
|
720
876
|
*
|
|
@@ -929,6 +1085,67 @@ declare class Markdown {
|
|
|
929
1085
|
* fails with {@link MarkdownParseError}.
|
|
930
1086
|
*/
|
|
931
1087
|
static readonly parse: (text: string, options?: MarkdownParseOptions | undefined) => Effect.Effect<Root, MarkdownParseError, never>;
|
|
1088
|
+
/**
|
|
1089
|
+
* Parse a text fragment as a single paragraph's inline content,
|
|
1090
|
+
* synchronously, as a `Result` — the phrasing-level twin of
|
|
1091
|
+
* {@link Markdown.parseResult}, for callers holding already-markdown
|
|
1092
|
+
* prose (a link-carrying sentence, a backtick span) who want its
|
|
1093
|
+
* phrasing nodes without a full document parse and a paragraph splice.
|
|
1094
|
+
*
|
|
1095
|
+
* @remarks
|
|
1096
|
+
* The whole input is prepared exactly the way the block pass prepares one
|
|
1097
|
+
* paragraph's content — leading and trailing whitespace trimmed, line
|
|
1098
|
+
* terminators normalized to `\n` — and handed to the inline pass, so the
|
|
1099
|
+
* result matches the `children` of the paragraph a full parse of the same
|
|
1100
|
+
* fragment would produce. Node positions are correct relative to the
|
|
1101
|
+
* input string.
|
|
1102
|
+
*
|
|
1103
|
+
* Two consequences of the single-paragraph contract:
|
|
1104
|
+
*
|
|
1105
|
+
* - **Blank lines do not break blocks.** A `\n\n` in the input stays
|
|
1106
|
+
* inline content (literal newlines in a text node); nothing at this
|
|
1107
|
+
* level opens a heading, list or code block — `# foo` is the text
|
|
1108
|
+
* `# foo`.
|
|
1109
|
+
* - **No reference context exists.** The fragment carries no definitions,
|
|
1110
|
+
* so `[foo]`, `![foo]` and `[^foo]` remain literal text — the same
|
|
1111
|
+
* result a full parse of the isolated fragment produces.
|
|
1112
|
+
*
|
|
1113
|
+
* `options.dialect` selects the inline dialect (default `"gfm"`);
|
|
1114
|
+
* `options.frontmatter` has no effect at phrasing level. Failure is rare
|
|
1115
|
+
* by design, on {@link Markdown.parseResult}'s terms: only a
|
|
1116
|
+
* hardening-guard trip (delimiter or bracket nesting past the cap) fails.
|
|
1117
|
+
*
|
|
1118
|
+
* @example
|
|
1119
|
+
* ```ts
|
|
1120
|
+
* import { Markdown } from "@effected/markdown";
|
|
1121
|
+
* import { Result } from "effect";
|
|
1122
|
+
*
|
|
1123
|
+
* const ok = Markdown.parsePhrasingResult("see [the docs](./docs.md)");
|
|
1124
|
+
* if (Result.isSuccess(ok)) {
|
|
1125
|
+
* console.log(ok.success.map((node) => node.type)); // => ["text", "link"]
|
|
1126
|
+
* }
|
|
1127
|
+
* ```
|
|
1128
|
+
*
|
|
1129
|
+
* @param text - The prose fragment to parse.
|
|
1130
|
+
* @param options - Optional {@link MarkdownParseOptions}; the dialect
|
|
1131
|
+
* defaults to `"gfm"`.
|
|
1132
|
+
* @returns A `Result` succeeding with the fragment's phrasing content, or
|
|
1133
|
+
* failing with {@link MarkdownParseError}.
|
|
1134
|
+
*/
|
|
1135
|
+
static parsePhrasingResult(text: string, options?: MarkdownParseOptions): Result.Result<ReadonlyArray<PhrasingContent>, MarkdownParseError>;
|
|
1136
|
+
/**
|
|
1137
|
+
* Parse a text fragment as a single paragraph's inline content. Defined
|
|
1138
|
+
* in terms of {@link Markdown.parsePhrasingResult} — synchronous callers
|
|
1139
|
+
* can use that variant directly; the single-paragraph contract (blank
|
|
1140
|
+
* lines stay inline, references never form) is documented there.
|
|
1141
|
+
*
|
|
1142
|
+
* @param text - The prose fragment to parse.
|
|
1143
|
+
* @param options - Optional {@link MarkdownParseOptions}; the dialect
|
|
1144
|
+
* defaults to `"gfm"`.
|
|
1145
|
+
* @returns An `Effect` that succeeds with the fragment's phrasing
|
|
1146
|
+
* content, or fails with {@link MarkdownParseError}.
|
|
1147
|
+
*/
|
|
1148
|
+
static readonly parsePhrasing: (text: string, options?: MarkdownParseOptions | undefined) => Effect.Effect<readonly PhrasingContent[], MarkdownParseError, never>;
|
|
932
1149
|
/**
|
|
933
1150
|
* Serialize a {@link Root} tree to canonical markdown, synchronously, as a
|
|
934
1151
|
* `Result`. The pure primitive twin of {@link Markdown.stringify}, on the
|
|
@@ -946,6 +1163,66 @@ declare class Markdown {
|
|
|
946
1163
|
* contract — but is not a byte-level round-trip of any original source;
|
|
947
1164
|
* surgical editing goes through the offset-splice edit layer instead.
|
|
948
1165
|
*
|
|
1166
|
+
* **The canonical form is a stability commitment, so a test may assert
|
|
1167
|
+
* against these bytes.** There are no options to configure and therefore
|
|
1168
|
+
* nothing to drift, the choices below are pinned by byte-level tests, and
|
|
1169
|
+
* the engine is cross-checked against commonmark.js over the full
|
|
1170
|
+
* CommonMark 0.31.2 corpus. Changing any of them is a **breaking** change
|
|
1171
|
+
* to this package, never a patch. A consumer asserting on rendered
|
|
1172
|
+
* markdown should serialize through here rather than through a third-party
|
|
1173
|
+
* stringifier whose defaults are free to move.
|
|
1174
|
+
*
|
|
1175
|
+
* The canonical choices a byte-level assertion depends on, for a node
|
|
1176
|
+
* carrying no fidelity field:
|
|
1177
|
+
*
|
|
1178
|
+
* | Construct | Canonical form |
|
|
1179
|
+
* | --- | --- |
|
|
1180
|
+
* | Heading | ATX (`## x`), at every depth |
|
|
1181
|
+
* | Thematic break | `***` |
|
|
1182
|
+
* | Bullet list marker | `-` |
|
|
1183
|
+
* | Ordered list delimiter | `.`, flipping to `)` to separate an immediately adjacent sibling list |
|
|
1184
|
+
* | Emphasis / strong | `*` / `**` |
|
|
1185
|
+
* | Code block | fenced when the node carries a `lang` or a `fenceChar`, with the fence grown past any interior backtick run; otherwise indented — **except where indenting would not re-parse as a code block**, which forces a fence (see below) |
|
|
1186
|
+
* | Block separation | exactly one blank line |
|
|
1187
|
+
* | Document | a single trailing newline |
|
|
1188
|
+
*
|
|
1189
|
+
* A node carrying a fidelity field overrides the corresponding row —
|
|
1190
|
+
* `headingStyle: "setext"`, `markerChar`, `fenceChar`, `delimiter` — which
|
|
1191
|
+
* is how a parsed document re-serializes in its author's spelling. The
|
|
1192
|
+
* rows describe a synthesized node, which is the case a test asserting on
|
|
1193
|
+
* generated markdown actually has.
|
|
1194
|
+
*
|
|
1195
|
+
* **Representability wins over the table.** The canonical form never emits
|
|
1196
|
+
* text that would re-parse as something else, so a row yields where the two
|
|
1197
|
+
* conflict. The case that reaches a consumer is the indented code block: an
|
|
1198
|
+
* indented block directly after a list is absorbed as list content, so a
|
|
1199
|
+
* `Code` node with neither `lang` nor `fenceChar` emits **fenced** in that
|
|
1200
|
+
* position and indented everywhere else. A byte-level assertion over
|
|
1201
|
+
* synthesized code blocks therefore depends on the preceding sibling.
|
|
1202
|
+
*
|
|
1203
|
+
* **The posture that makes this a non-issue**, and the one a consumer
|
|
1204
|
+
* building trees for byte-level assertion should adopt: set `fenceChar` on
|
|
1205
|
+
* every `Code` node that carries neither a `lang` nor one already, in a
|
|
1206
|
+
* post-decode walk that reaches nested nodes. The choice then leaves the
|
|
1207
|
+
* emitter entirely and no output depends on a node's neighbours.
|
|
1208
|
+
*
|
|
1209
|
+
* **MDX nodes (constructed trees only — the parser reads no MDX syntax)**
|
|
1210
|
+
* serialize to valid MDX with the mdast-util-mdx defaults, and these
|
|
1211
|
+
* choices are part of the same stability commitment: attribute values
|
|
1212
|
+
* quote with `"` (the quote escaped as `"`), an empty element
|
|
1213
|
+
* self-closes spaced (`<a />`), a fragment is `<></>`, flow children take
|
|
1214
|
+
* block layout indented two spaces per JSX ancestor, attributes move onto
|
|
1215
|
+
* their own lines only when one carries a line ending, expressions emit
|
|
1216
|
+
* `{expr}` with two-space continuation indent, and ESM values emit
|
|
1217
|
+
* verbatim. A tree containing any MDX node additionally escapes `{` in
|
|
1218
|
+
* text — MDX makes it significant — while a tree with none serializes
|
|
1219
|
+
* byte-identically to the table above.
|
|
1220
|
+
*
|
|
1221
|
+
* To *normalize* a document to different choices — a `-` list rewritten to
|
|
1222
|
+
* `*`, setext headings rewritten to ATX — use `MarkdownFormat` with
|
|
1223
|
+
* `MarkdownFormattingOptions`. That is the configurable surface; this one
|
|
1224
|
+
* deliberately is not.
|
|
1225
|
+
*
|
|
949
1226
|
* Failure is rare by design, symmetric with parse: only a hardening-guard
|
|
950
1227
|
* trip on a tree nesting past the depth cap fails, and only synthesized
|
|
951
1228
|
* or decoded trees can nest that far.
|
|
@@ -960,6 +1237,18 @@ declare class Markdown {
|
|
|
960
1237
|
* {@link Markdown.stringifyResult} — synchronous callers can use that
|
|
961
1238
|
* variant directly.
|
|
962
1239
|
*
|
|
1240
|
+
* @remarks
|
|
1241
|
+
* The canonical form is a **stability commitment** and safe to assert
|
|
1242
|
+
* against byte-for-byte; the choices it makes, and the reason changing one
|
|
1243
|
+
* is a breaking change, are documented on
|
|
1244
|
+
* {@link Markdown.stringifyResult}.
|
|
1245
|
+
*
|
|
1246
|
+
* **Fidelity fields must be set on the DECODED tree.** `Mdast.fromMdast`
|
|
1247
|
+
* admits spec mdast and strips everything outside it, so a `fenceChar`,
|
|
1248
|
+
* `headingStyle`, `markerChar` or `delimiter` placed on a plain mdast tree
|
|
1249
|
+
* before admission is silently dropped and the canonical default applies.
|
|
1250
|
+
* Set them on the nodes that come back.
|
|
1251
|
+
*
|
|
963
1252
|
* @param root - The document tree to serialize.
|
|
964
1253
|
* @returns An `Effect` that succeeds with markdown source, or fails with
|
|
965
1254
|
* {@link MarkdownStringifyError}.
|
|
@@ -1903,6 +2192,144 @@ declare class SchemaResolver {
|
|
|
1903
2192
|
static fromRegistry(registrations: Readonly<Record<string, Schema.Top>>): FrontmatterSchemaResolver;
|
|
1904
2193
|
}
|
|
1905
2194
|
//#endregion
|
|
2195
|
+
//#region src/FrontmatterSource.d.ts
|
|
2196
|
+
/**
|
|
2197
|
+
* The three line-terminator spellings a fence line may end with. Recorded by
|
|
2198
|
+
* {@link FrontmatterSource.split} as fidelity — what the source's fence
|
|
2199
|
+
* lines actually used — and consumed by {@link FrontmatterSource.join}.
|
|
2200
|
+
*
|
|
2201
|
+
* @public
|
|
2202
|
+
*/
|
|
2203
|
+
declare const FrontmatterNewline: Schema.Literals<readonly ["\n", "\r\n", "\r"]>;
|
|
2204
|
+
/**
|
|
2205
|
+
* The union of all fence line-terminator literals.
|
|
2206
|
+
*
|
|
2207
|
+
* @public
|
|
2208
|
+
*/
|
|
2209
|
+
type FrontmatterNewline = typeof FrontmatterNewline.Type;
|
|
2210
|
+
declare const FrontmatterSourceBlock_base: Schema.Class<FrontmatterSourceBlock, Schema.Struct<{
|
|
2211
|
+
readonly format: Schema.Literals<readonly ["yaml", "toml", "json"]>;
|
|
2212
|
+
readonly value: Schema.String;
|
|
2213
|
+
readonly newline: Schema.optionalKey<Schema.Literals<readonly ["\n", "\r\n", "\r"]>>;
|
|
2214
|
+
}>, {}>;
|
|
2215
|
+
/**
|
|
2216
|
+
* A frontmatter block at string level: the format its fence declared, the
|
|
2217
|
+
* exact bytes between the fence lines, and the fence lines' terminator.
|
|
2218
|
+
*
|
|
2219
|
+
* @remarks
|
|
2220
|
+
* `value` is the exact source slice strictly between the opening fence line
|
|
2221
|
+
* (its terminator included) and the closing fence line: every value line
|
|
2222
|
+
* WITH its own terminator, verbatim — so a block whose value is one blank
|
|
2223
|
+
* line (`"\n"`) stays distinct from a block with no value lines (`""`), and
|
|
2224
|
+
* interior CRLF terminators survive untouched. This deliberately differs
|
|
2225
|
+
* from the parsed `Frontmatter` NODE's `value`, which drops the final
|
|
2226
|
+
* terminator; the node feeds codecs, this feeds byte-exact reconstruction.
|
|
2227
|
+
* {@link FrontmatterSource.join} accepts a value without a trailing
|
|
2228
|
+
* terminator too, appending `newline` so a hand-built block cannot fuse its
|
|
2229
|
+
* last line into the closing fence.
|
|
2230
|
+
*
|
|
2231
|
+
* `newline` is a fidelity field: `split` always records the terminator
|
|
2232
|
+
* following the opening fence; when absent (a hand-built block), `join`
|
|
2233
|
+
* uses `"\n"`.
|
|
2234
|
+
*
|
|
2235
|
+
* @public
|
|
2236
|
+
*/
|
|
2237
|
+
declare class FrontmatterSourceBlock extends FrontmatterSourceBlock_base {}
|
|
2238
|
+
declare const FrontmatterSourceSplit_base: Schema.Class<FrontmatterSourceSplit, Schema.Struct<{
|
|
2239
|
+
readonly frontmatter: Schema.optionalKey<typeof FrontmatterSourceBlock>;
|
|
2240
|
+
readonly body: Schema.String;
|
|
2241
|
+
readonly bodyOffset: Schema.withConstructorDefault<Schema.Number>;
|
|
2242
|
+
}>, {}>;
|
|
2243
|
+
/**
|
|
2244
|
+
* The result of {@link FrontmatterSource.split}: the frontmatter block when
|
|
2245
|
+
* one exists, the exact body remainder, and the body's byte offset.
|
|
2246
|
+
*
|
|
2247
|
+
* @remarks
|
|
2248
|
+
* `body` is exactly `source.slice(bodyOffset)` — the string and the offset
|
|
2249
|
+
* can never disagree. With no block, `body` is the whole source and
|
|
2250
|
+
* `bodyOffset` is `0`. With a block, `bodyOffset` sits immediately after
|
|
2251
|
+
* the closing fence line and its line terminator (the terminator belongs to
|
|
2252
|
+
* the fence line, as every line's terminator belongs to its line), which is
|
|
2253
|
+
* gray-matter's body boundary; when the closing fence ends the document
|
|
2254
|
+
* there is no terminator and the body is empty.
|
|
2255
|
+
*
|
|
2256
|
+
* `bodyOffset` is informational output of `split`; `join` never reads it,
|
|
2257
|
+
* and it constructor-defaults to `0` so a hand-built value for `join` can
|
|
2258
|
+
* omit it.
|
|
2259
|
+
*
|
|
2260
|
+
* @public
|
|
2261
|
+
*/
|
|
2262
|
+
declare class FrontmatterSourceSplit extends FrontmatterSourceSplit_base {}
|
|
2263
|
+
/**
|
|
2264
|
+
* The string-level frontmatter facade: split raw source at the fence
|
|
2265
|
+
* boundaries and join it back, without parsing anything.
|
|
2266
|
+
*
|
|
2267
|
+
* @public
|
|
2268
|
+
*/
|
|
2269
|
+
declare class FrontmatterSource {
|
|
2270
|
+
private constructor();
|
|
2271
|
+
/**
|
|
2272
|
+
* Split raw source into its frontmatter block and body, at string level.
|
|
2273
|
+
* Total: never fails, never parses — absence of a block (including an
|
|
2274
|
+
* opening fence with no closing fence, which per the grammar is not
|
|
2275
|
+
* frontmatter) is a representable result, not an error.
|
|
2276
|
+
*
|
|
2277
|
+
* @remarks
|
|
2278
|
+
* The grammar is the parser's own offset-0 pre-scan, over raw bytes:
|
|
2279
|
+
* the fence set is closed (`---` yaml, `+++` toml, `---json` json), a
|
|
2280
|
+
* fence line is exactly the fence with no surrounding whitespace, and a
|
|
2281
|
+
* leading BOM means offset 0 is not a fence — strip one before calling
|
|
2282
|
+
* if the source may carry it. Unlike the parse path there is no capture
|
|
2283
|
+
* toggle here, so absence is one fact: the source has no closed block.
|
|
2284
|
+
* (`MarkdownDocument`'s two-reason absence exists because parsing can be
|
|
2285
|
+
* asked not to look; this surface always looks.)
|
|
2286
|
+
*
|
|
2287
|
+
* Byte exactness: `source.slice(0, result.bodyOffset) + result.body`
|
|
2288
|
+
* reassembles `source` exactly, and {@link FrontmatterSource.join}
|
|
2289
|
+
* reproduces the original bytes for an unmodified round-trip — see
|
|
2290
|
+
* `join` for the two normalizations at the contract's edge.
|
|
2291
|
+
*
|
|
2292
|
+
* @example
|
|
2293
|
+
* ```ts
|
|
2294
|
+
* import { FrontmatterSource } from "@effected/markdown";
|
|
2295
|
+
*
|
|
2296
|
+
* const split = FrontmatterSource.split("---\ntitle: hi\n---\n\n# Body\n");
|
|
2297
|
+
* console.log(split.frontmatter?.format); // => "yaml"
|
|
2298
|
+
* console.log(split.frontmatter?.value); // => "title: hi\n"
|
|
2299
|
+
* console.log(split.body); // => "\n# Body\n"
|
|
2300
|
+
* ```
|
|
2301
|
+
*
|
|
2302
|
+
* @param source - The raw document source, body format irrelevant.
|
|
2303
|
+
* @returns A {@link FrontmatterSourceSplit}; `frontmatter` is absent when
|
|
2304
|
+
* the source opens with no closed fence block.
|
|
2305
|
+
*/
|
|
2306
|
+
static split(source: string): FrontmatterSourceSplit;
|
|
2307
|
+
/**
|
|
2308
|
+
* Serialize a split back to one source string. Total and pure.
|
|
2309
|
+
*
|
|
2310
|
+
* @remarks
|
|
2311
|
+
* With no block the body is returned verbatim. With a block the output
|
|
2312
|
+
* is the opening fence, `newline` (default `"\n"`), the value — a
|
|
2313
|
+
* non-empty value missing a final line terminator gets `newline`
|
|
2314
|
+
* appended, so the closing fence always starts its own line — the
|
|
2315
|
+
* closing fence, `newline`, then the body verbatim.
|
|
2316
|
+
*
|
|
2317
|
+
* **Round-trip contract:** `join(split(source)) === source`, byte for
|
|
2318
|
+
* byte, for every source whose closing fence line ends with a line
|
|
2319
|
+
* terminator matching the opening fence's. The two edges where join
|
|
2320
|
+
* normalizes instead: a closing fence at end-of-document gains a final
|
|
2321
|
+
* `newline` (the block's one unterminated spelling), and fence lines
|
|
2322
|
+
* with MISMATCHED terminators (say `---\r\n … ---\n`) re-emit both with
|
|
2323
|
+
* the opening one. Value and body bytes survive verbatim in every case.
|
|
2324
|
+
*
|
|
2325
|
+
* @param split - The parts to serialize, typically from
|
|
2326
|
+
* {@link FrontmatterSource.split} or built with
|
|
2327
|
+
* `FrontmatterSourceSplit.make`.
|
|
2328
|
+
* @returns The combined source string.
|
|
2329
|
+
*/
|
|
2330
|
+
static join(split: FrontmatterSourceSplit): string;
|
|
2331
|
+
}
|
|
2332
|
+
//#endregion
|
|
1906
2333
|
//#region src/JsonFrontmatter.d.ts
|
|
1907
2334
|
/**
|
|
1908
2335
|
* The json frontmatter codec, over `@effected/jsonc`.
|
|
@@ -2344,6 +2771,14 @@ declare class Mdast {
|
|
|
2344
2771
|
* decode into the {@link Frontmatter} capture. Unknown node types fail
|
|
2345
2772
|
* typed.
|
|
2346
2773
|
*
|
|
2774
|
+
* **This package's fidelity fields are among the fields dropped**, because
|
|
2775
|
+
* they are not spec mdast. A `fenceChar`, `headingStyle`, `markerChar` or
|
|
2776
|
+
* `delimiter` set on the tree BEFORE admission is silently discarded, and
|
|
2777
|
+
* the node then serializes with the canonical default — set them on the
|
|
2778
|
+
* decoded nodes this returns instead. The drop is correct (the boundary
|
|
2779
|
+
* admits spec mdast and nothing else) but it is silent, which is why it is
|
|
2780
|
+
* called out here.
|
|
2781
|
+
*
|
|
2347
2782
|
* @param input - A plain mdast tree, typically a `root`.
|
|
2348
2783
|
* @returns A `Result` succeeding with the decoded {@link Root}, or
|
|
2349
2784
|
* failing with {@link MdastDecodeError} carrying the structured issue.
|
|
@@ -2412,5 +2847,5 @@ declare const TomlFrontmatter: FrontmatterCodec;
|
|
|
2412
2847
|
*/
|
|
2413
2848
|
declare const YamlFrontmatter: FrontmatterCodec;
|
|
2414
2849
|
//#endregion
|
|
2415
|
-
export { Blockquote, Break, BreakStyle, BulletChar, Code, CodeBlockStyle, Definition, Delete, type DocumentHeading, type DocumentLink, DocumentSection, Emphasis, EmphasisChar, FenceChar, FlowContent, FootnoteDefinition, FootnoteReference, Frontmatter, type FrontmatterCodec, FrontmatterContent, FrontmatterDecodeError, FrontmatterEncodeError, FrontmatterFormat, FrontmatterFormatMismatchError, FrontmatterMissingError, FrontmatterMissingReason, type FrontmatterResolveError, type FrontmatterSchemaError, type FrontmatterSchemaResolver, FrontmatterValidationError, type FrontmatterWriteError, Heading, HeadingDepth, HeadingStyle, Html, Image, ImageReference, InlineCode, JsonFrontmatter, Link, type LinkBearingNode, LinkReference, List, ListContent, ListDelimiter, ListItem, Markdown, MarkdownDiagnostic, MarkdownDialect, MarkdownDocument, MarkdownEdit, MarkdownFormat, MarkdownFormattingOptions, MarkdownFrontmatter, MarkdownModificationError, MarkdownModificationErrorCode, MarkdownNode, type MarkdownNodeOfType, type MarkdownNodeType, MarkdownParseError, MarkdownParseErrorCode, MarkdownParseOptions, type MarkdownPath, MarkdownRange, type MarkdownRangeLike, type MarkdownSegment, MarkdownStringifyError, MarkdownVisitor, MarkdownVisitorEvent, Mdast, MdastDecodeError, type MdastNode, Paragraph, PhrasingContent, Point, Position, ReferenceType, Root, RowContent, SchemaDeclaration, SchemaDeclarationByName, SchemaDeclarationByPath, SchemaDeclarationByUrl, SchemaDeclarationInline, SchemaDeclarationInvalidError, SchemaDeclarationMissingError, SchemaNameUnknownError, SchemaResolver, SchemaVersionUnresolvableError, type SectionHeadingMatch, type SectionQueryOptions, Strong, Table, TableAlign, TableCell, TableContent, TableRow, Text, ThematicBreak, ThematicBreakChar, TomlFrontmatter, YamlFrontmatter };
|
|
2850
|
+
export { Blockquote, Break, BreakStyle, BulletChar, Code, CodeBlockStyle, Definition, Delete, type DocumentHeading, type DocumentLink, DocumentSection, Emphasis, EmphasisChar, FenceChar, FlowContent, FootnoteDefinition, FootnoteReference, Frontmatter, type FrontmatterCodec, FrontmatterContent, FrontmatterDecodeError, FrontmatterEncodeError, FrontmatterFormat, FrontmatterFormatMismatchError, FrontmatterMissingError, FrontmatterMissingReason, FrontmatterNewline, type FrontmatterResolveError, type FrontmatterSchemaError, type FrontmatterSchemaResolver, FrontmatterSource, FrontmatterSourceBlock, FrontmatterSourceSplit, FrontmatterValidationError, type FrontmatterWriteError, Heading, HeadingDepth, HeadingStyle, Html, Image, ImageReference, InlineCode, JsonFrontmatter, Link, type LinkBearingNode, LinkReference, List, ListContent, ListDelimiter, ListItem, Markdown, MarkdownDiagnostic, MarkdownDialect, MarkdownDocument, MarkdownEdit, MarkdownFormat, MarkdownFormattingOptions, MarkdownFrontmatter, MarkdownModificationError, MarkdownModificationErrorCode, MarkdownNode, type MarkdownNodeOfType, type MarkdownNodeType, MarkdownParseError, MarkdownParseErrorCode, MarkdownParseOptions, type MarkdownPath, MarkdownRange, type MarkdownRangeLike, type MarkdownSegment, MarkdownStringifyError, MarkdownVisitor, MarkdownVisitorEvent, Mdast, MdastDecodeError, type MdastNode, MdxFlowExpression, MdxJsxAttribute, MdxJsxAttributeContent, MdxJsxAttributeValueExpression, MdxJsxExpressionAttribute, MdxJsxFlowElement, MdxJsxTextElement, MdxTextExpression, MdxjsEsm, Paragraph, PhrasingContent, Point, Position, ReferenceType, Root, RowContent, SchemaDeclaration, SchemaDeclarationByName, SchemaDeclarationByPath, SchemaDeclarationByUrl, SchemaDeclarationInline, SchemaDeclarationInvalidError, SchemaDeclarationMissingError, SchemaNameUnknownError, SchemaResolver, SchemaVersionUnresolvableError, type SectionHeadingMatch, type SectionQueryOptions, Strong, Table, TableAlign, TableCell, TableContent, TableRow, Text, ThematicBreak, ThematicBreakChar, TomlFrontmatter, YamlFrontmatter };
|
|
2416
2851
|
//# sourceMappingURL=index.d.ts.map
|
package/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { MarkdownEdit, MarkdownRange } from "./MarkdownEdit.js";
|
|
2
|
-
import { Blockquote, Break, BreakStyle, BulletChar, Code, Definition, Delete, Emphasis, EmphasisChar, FenceChar, FlowContent, FootnoteDefinition, FootnoteReference, Frontmatter, FrontmatterContent, FrontmatterFormat, Heading, HeadingDepth, HeadingStyle, Html, Image, ImageReference, InlineCode, Link, LinkReference, List, ListContent, ListDelimiter, ListItem, MarkdownNode, Paragraph, PhrasingContent, Point, Position, ReferenceType, Root, RowContent, Strong, Table, TableAlign, TableCell, TableContent, TableRow, Text, ThematicBreak, ThematicBreakChar } from "./MarkdownNode.js";
|
|
2
|
+
import { Blockquote, Break, BreakStyle, BulletChar, Code, Definition, Delete, Emphasis, EmphasisChar, FenceChar, FlowContent, FootnoteDefinition, FootnoteReference, Frontmatter, FrontmatterContent, FrontmatterFormat, Heading, HeadingDepth, HeadingStyle, Html, Image, ImageReference, InlineCode, Link, LinkReference, List, ListContent, ListDelimiter, ListItem, MarkdownNode, MdxFlowExpression, MdxJsxAttribute, MdxJsxAttributeContent, MdxJsxAttributeValueExpression, MdxJsxExpressionAttribute, MdxJsxFlowElement, MdxJsxTextElement, MdxTextExpression, MdxjsEsm, Paragraph, PhrasingContent, Point, Position, ReferenceType, Root, RowContent, Strong, Table, TableAlign, TableCell, TableContent, TableRow, Text, ThematicBreak, ThematicBreakChar } from "./MarkdownNode.js";
|
|
3
3
|
import { FrontmatterDecodeError, FrontmatterEncodeError, FrontmatterFormatMismatchError, FrontmatterMissingError, FrontmatterMissingReason, FrontmatterValidationError, MarkdownFrontmatter } from "./Frontmatter.js";
|
|
4
4
|
import { SchemaDeclaration, SchemaDeclarationByName, SchemaDeclarationByPath, SchemaDeclarationByUrl, SchemaDeclarationInline, SchemaDeclarationInvalidError, SchemaDeclarationMissingError, SchemaNameUnknownError, SchemaResolver, SchemaVersionUnresolvableError } from "./FrontmatterResolver.js";
|
|
5
|
+
import { FrontmatterNewline, FrontmatterSource, FrontmatterSourceBlock, FrontmatterSourceSplit } from "./FrontmatterSource.js";
|
|
5
6
|
import { JsonFrontmatter } from "./JsonFrontmatter.js";
|
|
6
7
|
import { MarkdownDiagnostic, MarkdownParseErrorCode } from "./MarkdownDiagnostic.js";
|
|
7
8
|
import { Markdown, MarkdownDialect, MarkdownParseError, MarkdownParseOptions, MarkdownStringifyError } from "./Markdown.js";
|
|
@@ -12,4 +13,4 @@ import { Mdast, MdastDecodeError } from "./Mdast.js";
|
|
|
12
13
|
import { TomlFrontmatter } from "./TomlFrontmatter.js";
|
|
13
14
|
import { YamlFrontmatter } from "./YamlFrontmatter.js";
|
|
14
15
|
|
|
15
|
-
export { Blockquote, Break, BreakStyle, BulletChar, Code, CodeBlockStyle, Definition, Delete, DocumentSection, Emphasis, EmphasisChar, FenceChar, FlowContent, FootnoteDefinition, FootnoteReference, Frontmatter, FrontmatterContent, FrontmatterDecodeError, FrontmatterEncodeError, FrontmatterFormat, FrontmatterFormatMismatchError, FrontmatterMissingError, FrontmatterMissingReason, FrontmatterValidationError, Heading, HeadingDepth, HeadingStyle, Html, Image, ImageReference, InlineCode, JsonFrontmatter, Link, LinkReference, List, ListContent, ListDelimiter, ListItem, Markdown, MarkdownDiagnostic, MarkdownDialect, MarkdownDocument, MarkdownEdit, MarkdownFormat, MarkdownFormattingOptions, MarkdownFrontmatter, MarkdownModificationError, MarkdownModificationErrorCode, MarkdownNode, MarkdownParseError, MarkdownParseErrorCode, MarkdownParseOptions, MarkdownRange, MarkdownStringifyError, MarkdownVisitor, MarkdownVisitorEvent, Mdast, MdastDecodeError, Paragraph, PhrasingContent, Point, Position, ReferenceType, Root, RowContent, SchemaDeclaration, SchemaDeclarationByName, SchemaDeclarationByPath, SchemaDeclarationByUrl, SchemaDeclarationInline, SchemaDeclarationInvalidError, SchemaDeclarationMissingError, SchemaNameUnknownError, SchemaResolver, SchemaVersionUnresolvableError, Strong, Table, TableAlign, TableCell, TableContent, TableRow, Text, ThematicBreak, ThematicBreakChar, TomlFrontmatter, YamlFrontmatter };
|
|
16
|
+
export { Blockquote, Break, BreakStyle, BulletChar, Code, CodeBlockStyle, Definition, Delete, DocumentSection, Emphasis, EmphasisChar, FenceChar, FlowContent, FootnoteDefinition, FootnoteReference, Frontmatter, FrontmatterContent, FrontmatterDecodeError, FrontmatterEncodeError, FrontmatterFormat, FrontmatterFormatMismatchError, FrontmatterMissingError, FrontmatterMissingReason, FrontmatterNewline, FrontmatterSource, FrontmatterSourceBlock, FrontmatterSourceSplit, FrontmatterValidationError, Heading, HeadingDepth, HeadingStyle, Html, Image, ImageReference, InlineCode, JsonFrontmatter, Link, LinkReference, List, ListContent, ListDelimiter, ListItem, Markdown, MarkdownDiagnostic, MarkdownDialect, MarkdownDocument, MarkdownEdit, MarkdownFormat, MarkdownFormattingOptions, MarkdownFrontmatter, MarkdownModificationError, MarkdownModificationErrorCode, MarkdownNode, MarkdownParseError, MarkdownParseErrorCode, MarkdownParseOptions, MarkdownRange, MarkdownStringifyError, MarkdownVisitor, MarkdownVisitorEvent, Mdast, MdastDecodeError, MdxFlowExpression, MdxJsxAttribute, MdxJsxAttributeContent, MdxJsxAttributeValueExpression, MdxJsxExpressionAttribute, MdxJsxFlowElement, MdxJsxTextElement, MdxTextExpression, MdxjsEsm, Paragraph, PhrasingContent, Point, Position, ReferenceType, Root, RowContent, SchemaDeclaration, SchemaDeclarationByName, SchemaDeclarationByPath, SchemaDeclarationByUrl, SchemaDeclarationInline, SchemaDeclarationInvalidError, SchemaDeclarationMissingError, SchemaNameUnknownError, SchemaResolver, SchemaVersionUnresolvableError, Strong, Table, TableAlign, TableCell, TableContent, TableRow, Text, ThematicBreak, ThematicBreakChar, TomlFrontmatter, YamlFrontmatter };
|
package/internal/blockParser.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Frontmatter, Point, Position, Root } from "../MarkdownNode.js";
|
|
2
|
+
import { scanFrontmatter } from "./blocks/frontmatter.js";
|
|
2
3
|
import { makeBlockNode } from "./blockTypes.js";
|
|
3
4
|
import { columnsToNextTabStop, preprocessLines } from "./preprocess.js";
|
|
4
5
|
import { isHtmlBlockEnd } from "./blocks/htmlBlock.js";
|
|
5
6
|
import { blockDialect } from "./blockRegistry.js";
|
|
6
|
-
import { scanFrontmatter } from "./blocks/frontmatter.js";
|
|
7
7
|
import { GuardExceeded } from "./carriers.js";
|
|
8
8
|
import { LineIndex } from "./lineIndex.js";
|
|
9
9
|
import { prepareInline } from "./rawInline.js";
|
|
@@ -51,6 +51,52 @@ const scanFrontmatter = (lines, text) => {
|
|
|
51
51
|
}
|
|
52
52
|
return null;
|
|
53
53
|
};
|
|
54
|
+
/** The terminator starting at `offset`, or null when none does. */
|
|
55
|
+
const terminatorAt = (source, offset) => {
|
|
56
|
+
const code = source.charCodeAt(offset);
|
|
57
|
+
if (code === 10) return "\n";
|
|
58
|
+
if (code === 13) return source.charCodeAt(offset + 1) === 10 ? "\r\n" : "\r";
|
|
59
|
+
return null;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Scan raw source for a frontmatter block — the same closed fence grammar as
|
|
63
|
+
* {@link scanFrontmatter}, over unpreprocessed bytes, returning exact
|
|
64
|
+
* offsets. The two scans agree on every input about WHETHER a block exists
|
|
65
|
+
* (the preprocessor's substitutions are length-preserving and can only break
|
|
66
|
+
* a fence match both scans require); this one exists for the string-level
|
|
67
|
+
* split/join surface, whose contract is byte exactness.
|
|
68
|
+
*
|
|
69
|
+
* Returns `null` when the document has no frontmatter — no fence at offset
|
|
70
|
+
* 0, or an opening fence with no closing fence, which per the grammar is not
|
|
71
|
+
* frontmatter at all.
|
|
72
|
+
*/
|
|
73
|
+
const scanRawFrontmatter = (source) => {
|
|
74
|
+
let index = 0;
|
|
75
|
+
while (index < source.length && terminatorAt(source, index) === null) index += 1;
|
|
76
|
+
const openNewline = index < source.length ? terminatorAt(source, index) : null;
|
|
77
|
+
const rule = FENCES.get(source.slice(0, index));
|
|
78
|
+
if (rule === void 0 || openNewline === null) return null;
|
|
79
|
+
const valueStart = index + openNewline.length;
|
|
80
|
+
let lineStart = valueStart;
|
|
81
|
+
index = valueStart;
|
|
82
|
+
while (index <= source.length) {
|
|
83
|
+
const terminator = index === source.length ? null : terminatorAt(source, index);
|
|
84
|
+
if (terminator === null && index < source.length) {
|
|
85
|
+
index += 1;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (source.slice(lineStart, index) === rule.close) return {
|
|
89
|
+
format: rule.format,
|
|
90
|
+
value: source.slice(valueStart, lineStart),
|
|
91
|
+
newline: openNewline,
|
|
92
|
+
bodyOffset: terminator === null ? index : index + terminator.length
|
|
93
|
+
};
|
|
94
|
+
if (terminator === null) break;
|
|
95
|
+
index += terminator.length;
|
|
96
|
+
lineStart = index;
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
};
|
|
54
100
|
|
|
55
101
|
//#endregion
|
|
56
|
-
export { scanFrontmatter };
|
|
102
|
+
export { scanFrontmatter, scanRawFrontmatter };
|