@effected/markdown 0.3.0 → 0.4.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/Frontmatter.js +33 -11
- package/Markdown.js +11 -5
- package/MarkdownDocument.js +28 -1
- package/MarkdownFormat.js +96 -11
- package/MarkdownNode.js +6 -0
- package/README.md +34 -4
- package/index.d.ts +130 -22
- package/index.js +3 -3
- package/package.json +1 -1
package/Frontmatter.js
CHANGED
|
@@ -69,22 +69,43 @@ var FrontmatterEncodeError = class extends Schema.TaggedErrorClass()("Frontmatte
|
|
|
69
69
|
}
|
|
70
70
|
};
|
|
71
71
|
/**
|
|
72
|
+
* Why a frontmatter decoder found no capture on a document.
|
|
73
|
+
*
|
|
74
|
+
* @remarks
|
|
75
|
+
* `"absent"` — the source genuinely has no frontmatter block.
|
|
76
|
+
* `"captureDisabled"` — the source opens with a well-formed frontmatter
|
|
77
|
+
* block, but the document carries no capture node: it was parsed without
|
|
78
|
+
* `frontmatter: true` (the toggle defaults off), so spec-correct CommonMark
|
|
79
|
+
* read the fences as ordinary content.
|
|
80
|
+
*
|
|
81
|
+
* @public
|
|
82
|
+
*/
|
|
83
|
+
const FrontmatterMissingReason = Schema.Literals(["absent", "captureDisabled"]);
|
|
84
|
+
/**
|
|
72
85
|
* Indicates that a document handed to a frontmatter decoder carries no
|
|
73
86
|
* frontmatter capture.
|
|
74
87
|
*
|
|
75
88
|
* @remarks
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
89
|
+
* `reason` distinguishes the two ways this happens: `"absent"` when the
|
|
90
|
+
* source genuinely has no frontmatter block, `"captureDisabled"` when the
|
|
91
|
+
* source opens with one but the document was parsed with the capture toggle
|
|
92
|
+
* off (`MarkdownParseOptions.frontmatter` defaults to `false`) — the fix
|
|
93
|
+
* there is parsing with `frontmatter: true`, not editing the document. The
|
|
94
|
+
* discriminant is computed from the same structural signal
|
|
95
|
+
* `MarkdownDocument.hasFrontmatterBlock` exposes, so the error and the
|
|
96
|
+
* accessor can never disagree.
|
|
97
|
+
*
|
|
98
|
+
* Cause-free: there is nothing to diagnose beyond the absence itself.
|
|
99
|
+
* Consumers wanting optional semantics can
|
|
100
|
+
* `Effect.catchTag("FrontmatterMissingError", ...)` to a default.
|
|
82
101
|
*
|
|
83
102
|
* @public
|
|
84
103
|
*/
|
|
85
|
-
var FrontmatterMissingError = class extends Schema.TaggedErrorClass()("FrontmatterMissingError", {
|
|
104
|
+
var FrontmatterMissingError = class extends Schema.TaggedErrorClass()("FrontmatterMissingError", {
|
|
105
|
+
/** Why there is no capture: no block at all, or capture left off. */
|
|
106
|
+
reason: FrontmatterMissingReason }) {
|
|
86
107
|
get message() {
|
|
87
|
-
return "the
|
|
108
|
+
return this.reason === "captureDisabled" ? "the source opens with a frontmatter block, but it was not captured; parse with `frontmatter: true`" : "the document has no frontmatter block";
|
|
88
109
|
}
|
|
89
110
|
};
|
|
90
111
|
/**
|
|
@@ -157,7 +178,8 @@ var MarkdownFrontmatter = class MarkdownFrontmatter {
|
|
|
157
178
|
* The decoder reads the document's frontmatter capture (parse with
|
|
158
179
|
* `frontmatter: true` — the toggle defaults off), decodes its raw value
|
|
159
180
|
* through the codec, then validates the data against `schema`. Each stage
|
|
160
|
-
* fails typed: no capture is {@link FrontmatterMissingError}
|
|
181
|
+
* fails typed: no capture is {@link FrontmatterMissingError} (its `reason`
|
|
182
|
+
* says whether the block is genuinely absent or capture was left off), a
|
|
161
183
|
* wrong-format codec is {@link FrontmatterFormatMismatchError}, unparseable
|
|
162
184
|
* content is {@link FrontmatterDecodeError}, and schema-invalid data is
|
|
163
185
|
* {@link FrontmatterValidationError} carrying the structured issue.
|
|
@@ -178,7 +200,7 @@ var MarkdownFrontmatter = class MarkdownFrontmatter {
|
|
|
178
200
|
static schema(schema, codec) {
|
|
179
201
|
return (document) => {
|
|
180
202
|
const node = document.frontmatter;
|
|
181
|
-
return node === void 0 ? Effect.fail(new FrontmatterMissingError()) : codec.decode(node).pipe(Effect.flatMap((data) => Schema.decodeUnknownEffect(schema)(data).pipe(Effect.catchTag("SchemaError", (error) => Effect.fail(new FrontmatterValidationError({ issue: error.issue }))))));
|
|
203
|
+
return node === void 0 ? Effect.fail(new FrontmatterMissingError({ reason: document.hasFrontmatterBlock ? "captureDisabled" : "absent" })) : codec.decode(node).pipe(Effect.flatMap((data) => Schema.decodeUnknownEffect(schema)(data).pipe(Effect.catchTag("SchemaError", (error) => Effect.fail(new FrontmatterValidationError({ issue: error.issue }))))));
|
|
182
204
|
};
|
|
183
205
|
}
|
|
184
206
|
/**
|
|
@@ -269,4 +291,4 @@ var MarkdownFrontmatter = class MarkdownFrontmatter {
|
|
|
269
291
|
};
|
|
270
292
|
|
|
271
293
|
//#endregion
|
|
272
|
-
export { FrontmatterDecodeError, FrontmatterEncodeError, FrontmatterFormatMismatchError, FrontmatterMissingError, FrontmatterValidationError, MarkdownFrontmatter };
|
|
294
|
+
export { FrontmatterDecodeError, FrontmatterEncodeError, FrontmatterFormatMismatchError, FrontmatterMissingError, FrontmatterMissingReason, FrontmatterValidationError, MarkdownFrontmatter };
|
package/Markdown.js
CHANGED
|
@@ -28,7 +28,9 @@ const MarkdownDialect = Schema.Literals(["commonmark", "gfm"]);
|
|
|
28
28
|
* spec-conformant reading must hold unless a consumer opts in. Enabled, the
|
|
29
29
|
* engine captures `---`/`+++`/`---json` blocks at offset 0 into a raw
|
|
30
30
|
* `Frontmatter` head node — decoding it is the frontmatter codec modules'
|
|
31
|
-
* job.
|
|
31
|
+
* job. Parsed with the toggle off, such a document reports no frontmatter —
|
|
32
|
+
* `MarkdownDocument.hasFrontmatterBlock` tells "no block in the source"
|
|
33
|
+
* apart from "parsed with capture off".
|
|
32
34
|
*
|
|
33
35
|
* @public
|
|
34
36
|
*/
|
|
@@ -181,10 +183,14 @@ var Markdown = class Markdown {
|
|
|
181
183
|
* @remarks
|
|
182
184
|
* Canonical serialization: fidelity fields (marker characters, fence
|
|
183
185
|
* style, heading spelling) win when present; documented canonical
|
|
184
|
-
* defaults apply when absent.
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
186
|
+
* defaults apply when absent. One default surprises: a language-less
|
|
187
|
+
* `Code` node with no explicit `fenceChar` serializes as an
|
|
188
|
+
* **indented** code block — set `fenceChar` (or a `lang`) on the node for
|
|
189
|
+
* a fence, or normalize afterward with
|
|
190
|
+
* `MarkdownFormattingOptions.codeBlockStyle: "fenced"`. The output
|
|
191
|
+
* re-parses to a render-equivalent document — the corpus-pinned
|
|
192
|
+
* contract — but is not a byte-level round-trip of any original source;
|
|
193
|
+
* surgical editing goes through the offset-splice edit layer instead.
|
|
188
194
|
*
|
|
189
195
|
* Failure is rare by design, symmetric with parse: only a hardening-guard
|
|
190
196
|
* trip on a tree nesting past the depth cap fails, and only synthesized
|
package/MarkdownDocument.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { MarkdownRange } from "./MarkdownEdit.js";
|
|
2
2
|
import { Definition, Root } from "./MarkdownNode.js";
|
|
3
|
+
import { preprocessLines } from "./internal/preprocess.js";
|
|
3
4
|
import { normalizeLabelText } from "./internal/references.js";
|
|
5
|
+
import { scanFrontmatter } from "./internal/blocks/frontmatter.js";
|
|
4
6
|
import { MarkdownDiagnostic } from "./MarkdownDiagnostic.js";
|
|
5
7
|
import { parsePassResult } from "./Markdown.js";
|
|
6
8
|
import { Effect, Result, Schema } from "effect";
|
|
@@ -164,13 +166,38 @@ var MarkdownDocument = class MarkdownDocument extends Schema.Class("MarkdownDocu
|
|
|
164
166
|
* only ever sit at the head of `root.children` (the capture fires at most
|
|
165
167
|
* once, at offset 0), so the tree is the single source of truth and the
|
|
166
168
|
* accessor can never disagree with it. `undefined` covers both a document
|
|
167
|
-
* with no frontmatter block and one parsed with the capture toggle off
|
|
169
|
+
* with no frontmatter block and one parsed with the capture toggle off —
|
|
170
|
+
* {@link MarkdownDocument.hasFrontmatterBlock} tells the two apart.
|
|
168
171
|
*/
|
|
169
172
|
get frontmatter() {
|
|
170
173
|
const head = this.root.children[0];
|
|
171
174
|
return head !== void 0 && head.type === "frontmatter" ? head : void 0;
|
|
172
175
|
}
|
|
173
176
|
/**
|
|
177
|
+
* Whether the source opens with a well-formed frontmatter block —
|
|
178
|
+
* regardless of how the document was parsed.
|
|
179
|
+
*
|
|
180
|
+
* @remarks
|
|
181
|
+
* The structural signal that disambiguates the `frontmatter` accessor's
|
|
182
|
+
* `undefined`: capture is opt-in (`MarkdownParseOptions.frontmatter`
|
|
183
|
+
* defaults off), so a document whose source visibly starts with `---` can
|
|
184
|
+
* still carry no capture node — spec-correct CommonMark reads the fences as
|
|
185
|
+
* a thematic break plus content. `frontmatter === undefined` with
|
|
186
|
+
* `hasFrontmatterBlock === true` means exactly "parsed with capture off";
|
|
187
|
+
* with `false` it means the source genuinely has no block.
|
|
188
|
+
*
|
|
189
|
+
* Derived, not stored: the getter runs the **same** pre-scan the parser
|
|
190
|
+
* runs when capture is enabled (the closed fence grammar — `---` yaml,
|
|
191
|
+
* `+++` toml, `---json` json; an unclosed fence is not frontmatter), so it
|
|
192
|
+
* is `true` exactly when parsing this source with `frontmatter: true`
|
|
193
|
+
* would produce a capture node, and the two can never drift. Like the
|
|
194
|
+
* other navigation accessors it recomputes per access — bind it once when
|
|
195
|
+
* checking repeatedly.
|
|
196
|
+
*/
|
|
197
|
+
get hasFrontmatterBlock() {
|
|
198
|
+
return scanFrontmatter(preprocessLines(this.source), this.source) !== null;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
174
201
|
* Every heading in the document, in document order, wherever it sits —
|
|
175
202
|
* including headings nested inside blockquotes and list items.
|
|
176
203
|
*
|
package/MarkdownFormat.js
CHANGED
|
@@ -5,6 +5,19 @@ import { Effect, Result, Schema } from "effect";
|
|
|
5
5
|
|
|
6
6
|
//#region src/MarkdownFormat.ts
|
|
7
7
|
/**
|
|
8
|
+
* The two ways CommonMark spells a code block: `fenced` (a backtick or tilde
|
|
9
|
+
* fence) and `indented` (four-space indentation).
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* A formatting target for {@link MarkdownFormattingOptions}, not a node
|
|
13
|
+
* fidelity field: on a {@link Code} node the two spellings are told apart by
|
|
14
|
+
* the presence or absence of `fenceChar`/`fenceLength`, and a language-less
|
|
15
|
+
* node with neither serializes as an **indented** block by default.
|
|
16
|
+
*
|
|
17
|
+
* @public
|
|
18
|
+
*/
|
|
19
|
+
const CodeBlockStyle = Schema.Literals(["fenced", "indented"]);
|
|
20
|
+
/**
|
|
8
21
|
* Options controlling formatting: which concrete-syntax markers to normalize,
|
|
9
22
|
* plus the parse knobs (`dialect`, `frontmatter`) the formatter parses the
|
|
10
23
|
* source with (same defaults as `Markdown.parse`). Every marker option is
|
|
@@ -12,7 +25,25 @@ import { Effect, Result, Schema } from "effect";
|
|
|
12
25
|
*
|
|
13
26
|
* Day-one scope is marker normalization only — heading style, bullet
|
|
14
27
|
* character, emphasis/strong marker, fence character, thematic-break
|
|
15
|
-
* character. Content is never rewritten, rewrapped or
|
|
28
|
+
* character, code-block style. Content is never rewritten, rewrapped or
|
|
29
|
+
* reflowed.
|
|
30
|
+
*
|
|
31
|
+
* @remarks
|
|
32
|
+
* `codeBlockStyle` is the opt-in that converts between the two code-block
|
|
33
|
+
* spellings for **language-less** blocks (a block with a `lang` has no
|
|
34
|
+
* indented spelling and is never touched). It exists because the default
|
|
35
|
+
* surprises: absent this option, a language-less code block keeps its
|
|
36
|
+
* spelling — and a language-less {@link Code} node with no explicit
|
|
37
|
+
* `fenceChar` **serializes as an indented block** through
|
|
38
|
+
* `Markdown.stringify`. `"fenced"` rewrites indented blocks to fences (the
|
|
39
|
+
* fence character follows `fenceChar` when also set, backtick otherwise);
|
|
40
|
+
* `"indented"` rewrites language-less fences to indented form where provably
|
|
41
|
+
* safe. Like every other option, hazardous conversions are skipped, never
|
|
42
|
+
* attempted: both directions apply to root-level, flush-left blocks only,
|
|
43
|
+
* and the `"indented"` direction additionally skips blocks whose indented
|
|
44
|
+
* spelling would lazily continue a paragraph, be absorbed into a preceding
|
|
45
|
+
* list or footnote definition, merge with an adjacent code block, or fail
|
|
46
|
+
* representability (empty, or blank first/last lines).
|
|
16
47
|
*
|
|
17
48
|
* @public
|
|
18
49
|
*/
|
|
@@ -23,7 +54,8 @@ var MarkdownFormattingOptions = class extends Schema.Class("MarkdownFormattingOp
|
|
|
23
54
|
bulletChar: Schema.optionalKey(BulletChar),
|
|
24
55
|
emphasisChar: Schema.optionalKey(EmphasisChar),
|
|
25
56
|
fenceChar: Schema.optionalKey(FenceChar),
|
|
26
|
-
thematicBreakChar: Schema.optionalKey(ThematicBreakChar)
|
|
57
|
+
thematicBreakChar: Schema.optionalKey(ThematicBreakChar),
|
|
58
|
+
codeBlockStyle: Schema.optionalKey(CodeBlockStyle)
|
|
27
59
|
}) {};
|
|
28
60
|
/**
|
|
29
61
|
* Error codes `MarkdownFormat.modify` can fail with.
|
|
@@ -193,6 +225,51 @@ const formatFence = (source, emit, node, target) => {
|
|
|
193
225
|
while (end - closeLength > start + openLength && source[end - closeLength - 1] === fidelity) closeLength++;
|
|
194
226
|
if (closeLength >= 3) emit.push(node, end - closeLength, closeLength, target.repeat(newLength));
|
|
195
227
|
};
|
|
228
|
+
/** A line that is empty or holds only spaces and tabs. */
|
|
229
|
+
const BLANK_LINE = /^[ \t]*$/;
|
|
230
|
+
/** Whether a sibling is a code block with no info string (either spelling). */
|
|
231
|
+
const isLanguagelessCode = (node) => node.type === "code" && node.lang === void 0 && node.meta === void 0;
|
|
232
|
+
/**
|
|
233
|
+
* Convert a language-less code block toward the requested style. Returns
|
|
234
|
+
* whether a whole-block conversion edit was emitted, so the caller can keep
|
|
235
|
+
* `formatFence` off a span this conversion already rewrote.
|
|
236
|
+
*
|
|
237
|
+
* Both directions are whole-block rewrites, so both are restricted to
|
|
238
|
+
* root-level, flush-left blocks — a container's continuation-line prefix
|
|
239
|
+
* (`> `, list indentation) is not reproducible by a single splice. The
|
|
240
|
+
* indented direction carries the re-parse hazards an indented block is
|
|
241
|
+
* subject to and skips each one: it cannot follow a non-blank line (lazy
|
|
242
|
+
* paragraph continuation), a list or footnote definition absorbs it as item
|
|
243
|
+
* continuation, an adjacent language-less code block would merge with it
|
|
244
|
+
* across the blank line, and an empty value or one with blank first/last
|
|
245
|
+
* lines (or interior whitespace-only lines, which blankness would erase) has
|
|
246
|
+
* no indented spelling at all.
|
|
247
|
+
*/
|
|
248
|
+
const formatCodeBlockStyle = (source, emit, node, parent, siblings, index, target, fenceChar) => {
|
|
249
|
+
if (node.lang !== void 0 || node.meta !== void 0) return false;
|
|
250
|
+
if (parent === void 0 || parent.type !== "root") return false;
|
|
251
|
+
const { start, end } = spanOf(node);
|
|
252
|
+
if (lineStartOf(source, start) !== start) return false;
|
|
253
|
+
const value = node.value.endsWith("\n") ? node.value.slice(0, -1) : node.value;
|
|
254
|
+
if (target === "fenced") {
|
|
255
|
+
if (node.fenceChar !== void 0) return false;
|
|
256
|
+
const char = fenceChar ?? "`";
|
|
257
|
+
const fence = char.repeat(Math.max(3, longestRun(value, char) + 1));
|
|
258
|
+
emit.push(node, start, end - start, `${fence}\n${value}\n${fence}`);
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
if (node.fenceChar === void 0) return false;
|
|
262
|
+
const lines = value === "" ? [] : value.split("\n");
|
|
263
|
+
if (lines.length === 0 || BLANK_LINE.test(lines[0]) || BLANK_LINE.test(lines[lines.length - 1])) return false;
|
|
264
|
+
if (lines.some((line) => line !== "" && BLANK_LINE.test(line))) return false;
|
|
265
|
+
if (!previousLineBlank(source, start)) return false;
|
|
266
|
+
const previous = index > 0 ? siblings[index - 1] : void 0;
|
|
267
|
+
const next = index + 1 < siblings.length ? siblings[index + 1] : void 0;
|
|
268
|
+
if (previous !== void 0 && (previous.type === "list" || previous.type === "footnoteDefinition")) return false;
|
|
269
|
+
if (previous !== void 0 && isLanguagelessCode(previous) || next !== void 0 && isLanguagelessCode(next)) return false;
|
|
270
|
+
emit.push(node, start, end - start, lines.map((line) => line === "" ? "" : ` ${line}`).join("\n"));
|
|
271
|
+
return true;
|
|
272
|
+
};
|
|
196
273
|
const FLOW_TYPES = /* @__PURE__ */ new Set([
|
|
197
274
|
"blockquote",
|
|
198
275
|
"code",
|
|
@@ -279,12 +356,18 @@ var MarkdownFormat = class MarkdownFormat {
|
|
|
279
356
|
/**
|
|
280
357
|
* Compute marker-normalization edits per the requested
|
|
281
358
|
* {@link MarkdownFormattingOptions}: heading style, bullet character,
|
|
282
|
-
* emphasis/strong marker, fence character
|
|
283
|
-
* each only where the node's concrete syntax differs
|
|
284
|
-
* the rewrite is provably safe. Content is never
|
|
285
|
-
* restricts edits to the nodes intersecting it (the
|
|
286
|
-
* intersection posture, matching toml). Non-mutating — apply
|
|
287
|
-
* `MarkdownEdit.applyAll` (or use
|
|
359
|
+
* emphasis/strong marker, fence character, thematic-break character and
|
|
360
|
+
* code-block style, each only where the node's concrete syntax differs
|
|
361
|
+
* from the target and the rewrite is provably safe. Content is never
|
|
362
|
+
* touched. `range` restricts edits to the nodes intersecting it (the
|
|
363
|
+
* owning-node intersection posture, matching toml). Non-mutating — apply
|
|
364
|
+
* with `MarkdownEdit.applyAll` (or use
|
|
365
|
+
* {@link MarkdownFormat.formatToString}).
|
|
366
|
+
*
|
|
367
|
+
* Note the code-block default: absent `codeBlockStyle`, a language-less
|
|
368
|
+
* code block keeps whichever spelling it has — `fenceChar` alone
|
|
369
|
+
* normalizes existing fences and deliberately leaves indented blocks
|
|
370
|
+
* indented.
|
|
288
371
|
*/
|
|
289
372
|
static format(text, range, options) {
|
|
290
373
|
const parsed = Markdown.parseResult(text, MarkdownParseOptions.make({
|
|
@@ -293,12 +376,14 @@ var MarkdownFormat = class MarkdownFormat {
|
|
|
293
376
|
}));
|
|
294
377
|
if (Result.isFailure(parsed)) return [];
|
|
295
378
|
const emit = new FormatEmitter(text);
|
|
296
|
-
walk(parsed.success, void 0, [], 0, (node,
|
|
379
|
+
walk(parsed.success, void 0, [], 0, (node, parent, siblings, index) => {
|
|
297
380
|
if (options?.thematicBreakChar !== void 0 && node.type === "thematicBreak") formatThematicBreak(text, emit, node, options.thematicBreakChar);
|
|
298
381
|
if (options?.headingStyle !== void 0 && node.type === "heading") formatHeading(text, emit, node, options.headingStyle);
|
|
299
382
|
if (options?.bulletChar !== void 0 && node.type === "list") formatList(text, emit, node, siblings, index, options.bulletChar);
|
|
300
383
|
if (options?.emphasisChar !== void 0 && isEmphasisLike(node)) formatEmphasis(text, emit, node, siblings, index, options.emphasisChar);
|
|
301
|
-
if (
|
|
384
|
+
if (node.type === "code") {
|
|
385
|
+
if (!(options?.codeBlockStyle !== void 0 && formatCodeBlockStyle(text, emit, node, parent, siblings, index, options.codeBlockStyle, options.fenceChar)) && options?.fenceChar !== void 0) formatFence(text, emit, node, options.fenceChar);
|
|
386
|
+
}
|
|
302
387
|
});
|
|
303
388
|
return (range === void 0 ? emit.edits : emit.edits.filter((edit) => Math.max(edit.nodeStart, range.offset) <= Math.min(edit.nodeEnd, range.offset + range.length))).map((edit) => MarkdownEdit.make({
|
|
304
389
|
offset: edit.offset,
|
|
@@ -377,4 +462,4 @@ var MarkdownFormat = class MarkdownFormat {
|
|
|
377
462
|
};
|
|
378
463
|
|
|
379
464
|
//#endregion
|
|
380
|
-
export { MarkdownFormat, MarkdownFormattingOptions, MarkdownModificationError, MarkdownModificationErrorCode };
|
|
465
|
+
export { CodeBlockStyle, MarkdownFormat, MarkdownFormattingOptions, MarkdownModificationError, MarkdownModificationErrorCode };
|
package/MarkdownNode.js
CHANGED
|
@@ -347,6 +347,12 @@ var ThematicBreak = class extends Schema.Class("ThematicBreak")({
|
|
|
347
347
|
* for fenced blocks and **absent for indented blocks** — their absence is how
|
|
348
348
|
* the two are told apart on the way back out.
|
|
349
349
|
*
|
|
350
|
+
* A consequence worth knowing before it surprises: a language-less `Code`
|
|
351
|
+
* node with no explicit `fenceChar` **serializes as an indented block**
|
|
352
|
+
* through `Markdown.stringify`. To get a fence, set `fenceChar` on the node
|
|
353
|
+
* (or a `lang`, which forces one), or format the emitted source with
|
|
354
|
+
* `MarkdownFormattingOptions.codeBlockStyle: "fenced"`.
|
|
355
|
+
*
|
|
350
356
|
* @public
|
|
351
357
|
*/
|
|
352
358
|
var Code = class extends Schema.Class("Code")({
|
package/README.md
CHANGED
|
@@ -106,7 +106,7 @@ Effect.runPromise(program).then(console.log);
|
|
|
106
106
|
|
|
107
107
|
`find` walks the tree in document pre-order and returns the document's own node, so the match feeds `modify` by identity. Replacements are literal strings or node fragments, and both render through the canonical stringifier, so a modified document re-parses cleanly by construction — you cannot splice in raw markdown that reopens a fence or breaks a table.
|
|
108
108
|
|
|
109
|
-
`MarkdownFormat.format` handles the other half: conservative marker normalization, never content rewriting. It converts heading style, bullet character, emphasis marker, fence character
|
|
109
|
+
`MarkdownFormat.format` handles the other half: conservative marker normalization, never content rewriting. It converts heading style, bullet character, emphasis marker, fence character, thematic-break character and code-block style, and skips any conversion that would not be safe rather than attempting it cleverly:
|
|
110
110
|
|
|
111
111
|
```ts
|
|
112
112
|
import { MarkdownFormat, MarkdownFormattingOptions } from "@effected/markdown";
|
|
@@ -136,6 +136,8 @@ console.log(MarkdownFormat.format(source, undefined, options));
|
|
|
136
136
|
|
|
137
137
|
`format` is pure and total, and the edits are non-mutating data — hand them to `MarkdownEdit.applyAll`, or send them to an editor as a text-edit payload.
|
|
138
138
|
|
|
139
|
+
`codeBlockStyle` is the option to know about before you hit its default: absent it, a language-less code block keeps whichever spelling it already has, and a language-less `Code` node with no `fenceChar` serializes as an *indented* block. `"fenced"` rewrites indented blocks to fences, `"indented"` goes the other way where the result provably re-parses the same, and both directions apply to root-level flush-left blocks only. A block with a language has no indented spelling and is never touched.
|
|
140
|
+
|
|
139
141
|
## Frontmatter
|
|
140
142
|
|
|
141
143
|
Frontmatter capture is opt-in, because enabling it changes how a document opening with `---` parses: CommonMark reads `---\ntitle: x\n---` as a thematic break and a setext heading, and that spec-conformant reading holds unless you ask for something else. Turn it on and compose your schema with a codec for typed gray-matter parity:
|
|
@@ -166,6 +168,8 @@ Effect.runPromise(program).then(console.log);
|
|
|
166
168
|
|
|
167
169
|
Each stage fails typed and separately: no capture is a `FrontmatterMissingError` (catch the tag for optional semantics), a codec handed the wrong fence is a `FrontmatterFormatMismatchError`, unparseable content is a `FrontmatterDecodeError` carrying the format package's own positioned failure structurally, and schema-invalid data is a `FrontmatterValidationError` carrying the structured issue tree rather than a stringified rendering.
|
|
168
170
|
|
|
171
|
+
Because capture is opt-in, "there is no frontmatter" has two meanings, and `FrontmatterMissingError.reason` tells them apart: `"absent"` when the source genuinely has no block, `"captureDisabled"` when it opens with one but was parsed with the toggle off — where the fix is a parse option, not a document edit. `MarkdownDocument.hasFrontmatterBlock` answers the same question directly, by re-running the parser's own pre-scan, so the accessor and the error can never disagree.
|
|
172
|
+
|
|
169
173
|
The three codecs — `YamlFrontmatter` (`---`), `TomlFrontmatter` (`+++`) and `JsonFrontmatter` (`---json`) — are free-standing named exports, one module each, deliberately never collected into a namespace object. Naming one codec is what pulls in its format engine, so a JSON-frontmatter consumer never pays for the yaml parser.
|
|
170
174
|
|
|
171
175
|
Frontmatter blocks can also describe their own schema. `SchemaResolver.classify` sorts a `$schema` value into a tagged union — `ByUrl`, `ByPath`, `Inline` and `ByName` — and `SchemaResolver.fromRegistry` resolves `ByName` declarations like `skill@2.1.0` against schemas you register. URLs, paths and inline documents are carried as data and never fetched: this is a pure package and it performs no IO.
|
|
@@ -192,7 +196,33 @@ Effect.runPromise(program).then(console.log);
|
|
|
192
196
|
// [ "./CHANGELOG.md", "https://example.com/docs" ]
|
|
193
197
|
```
|
|
194
198
|
|
|
195
|
-
`headings` lists every heading wherever it sits, including inside blockquotes and list items. `sections` are delimited by root-level headings only, and each section's range spans its subsections, so the edit layer can splice a whole section out in one edit.
|
|
199
|
+
`headings` lists every heading wherever it sits, including inside blockquotes and list items. `sections` are delimited by root-level headings only, and each section's range spans its subsections, so the edit layer can splice a whole section out in one edit. `firstSection` and `sectionByHeading` find one `DocumentSection` without scanning `sections` yourself — the second matches on an exact trimmed heading string, a `RegExp`, or a predicate, and both accept `{ depth }` to restrict to one heading level:
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
import { MarkdownDocument } from "@effected/markdown";
|
|
203
|
+
import { Effect } from "effect";
|
|
204
|
+
|
|
205
|
+
const source = `# Changelog
|
|
206
|
+
|
|
207
|
+
## 1.2.3
|
|
208
|
+
|
|
209
|
+
Fixed a bug.
|
|
210
|
+
|
|
211
|
+
## 1.2.2
|
|
212
|
+
|
|
213
|
+
Initial release.
|
|
214
|
+
`;
|
|
215
|
+
|
|
216
|
+
const program = Effect.gen(function* () {
|
|
217
|
+
const doc = yield* MarkdownDocument.parse(source);
|
|
218
|
+
return doc.sectionByHeading("1.2.3", { depth: 2 })?.body.trim();
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
Effect.runPromise(program).then(console.log);
|
|
222
|
+
// Fixed a bug.
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
`DocumentSection.body` is the section without its heading, and it is deliberately untrimmed — exactly the bytes `bodyRange` describes — so callers write `.body.trim()` when they want the tidy form.
|
|
196
226
|
|
|
197
227
|
For anything the accessors do not cover, `find` and `findAll` walk the whole tree in document pre-order. A string selector matches the node's `type` and narrows the result — `doc.findAll("heading")` is `ReadonlyArray<Heading>`, `doc.find("table")` is `Table | undefined` — and a type-guard predicate narrows the same way. The nodes come back by identity, so `doc.findAll("heading")[1]` addresses the second heading for `MarkdownFormat.modify` without raw child indexing.
|
|
198
228
|
|
|
@@ -234,13 +264,13 @@ if (Result.isSuccess(parsed)) {
|
|
|
234
264
|
## Features
|
|
235
265
|
|
|
236
266
|
- `Markdown` — `parse`/`stringify` as `Effect`s with typed `MarkdownParseError`/`MarkdownStringifyError` channels, the pure `parseResult`/`stringifyResult` twins for synchronous callers, and the `MarkdownFromString` two-way codec.
|
|
237
|
-
- `MarkdownDocument` — source, tree, diagnostics and the link-definition index, plus the derived `headings`, `sections` and `links` accessors, the `find`/`findAll` tree queries over type-narrowed selectors, and the `frontmatter` capture.
|
|
267
|
+
- `MarkdownDocument` — source, tree, diagnostics and the link-definition index, plus the derived `headings`, `sections` and `links` accessors, the `firstSection`/`sectionByHeading` finders over a `DocumentSection` (heading, depth, range, body), the `find`/`findAll` tree queries over type-narrowed selectors, and the `frontmatter` capture with `hasFrontmatterBlock` to tell an absent block from an uncaptured one.
|
|
238
268
|
- The mdast-shaped node classes — the CommonMark types plus GFM's `delete`, `table`, `tableRow`, `tableCell`, `footnoteDefinition`, `footnoteReference` and task-list `checked`, each carrying unist positions with byte offsets and this package's fidelity fields. `position` defaults to the zero-width synthetic sentinel, so a replacement fragment constructs in one line — `Text.make({ value: "shipped" })`.
|
|
239
269
|
- `MarkdownEdit` / `MarkdownRange` (with `applyAll`) — the non-mutating text-edit vocabulary, field-identical to `@effected/jsonc`'s, `@effected/yaml`'s and `@effected/toml`'s.
|
|
240
270
|
- `MarkdownFormat` — `format`/`formatToString` compute conservative marker-normalization edits; `modify`/`modifyToString` replace a node by identity through the canonical stringifier.
|
|
241
271
|
- `MarkdownVisitor` — walk a parsed tree as a lazy `Stream` of `Enter`/`Exit` events with child-index paths and depth.
|
|
242
272
|
- `Mdast` — `toMdast` projects to plain mdast JSON; `fromMdast`/`fromMdastResult` admit a foreign mdast tree with validation.
|
|
243
|
-
- `MarkdownFrontmatter.schema` plus the `YamlFrontmatter`, `TomlFrontmatter` and `JsonFrontmatter` codecs — typed frontmatter decoding over optional per-format peers, with four separately catchable failure modes.
|
|
273
|
+
- `MarkdownFrontmatter.schema` plus the `YamlFrontmatter`, `TomlFrontmatter` and `JsonFrontmatter` codecs — typed frontmatter decoding over optional per-format peers, with four separately catchable failure modes and a `FrontmatterMissingReason` on the absent one.
|
|
244
274
|
- `SchemaResolver` — classify a frontmatter `$schema` declaration into `ByUrl`/`ByPath`/`Inline`/`ByName` and resolve names against a registry, with no IO and no dependencies.
|
|
245
275
|
- `MarkdownDiagnostic` — the structured diagnostic (`code`, `message`, `offset`, `length`, `line`, `character`) every typed error carries, shaped identically to the sibling packages'.
|
|
246
276
|
|
package/index.d.ts
CHANGED
|
@@ -388,6 +388,12 @@ declare const Code_base: Schema.Class<Code, Schema.Struct<{
|
|
|
388
388
|
* for fenced blocks and **absent for indented blocks** — their absence is how
|
|
389
389
|
* the two are told apart on the way back out.
|
|
390
390
|
*
|
|
391
|
+
* A consequence worth knowing before it surprises: a language-less `Code`
|
|
392
|
+
* node with no explicit `fenceChar` **serializes as an indented block**
|
|
393
|
+
* through `Markdown.stringify`. To get a fence, set `fenceChar` on the node
|
|
394
|
+
* (or a `lang`, which forces one), or format the emitted source with
|
|
395
|
+
* `MarkdownFormattingOptions.codeBlockStyle: "fenced"`.
|
|
396
|
+
*
|
|
391
397
|
* @public
|
|
392
398
|
*/
|
|
393
399
|
declare class Code extends Code_base {}
|
|
@@ -808,7 +814,9 @@ declare const MarkdownParseOptions_base: Schema.Class<MarkdownParseOptions, Sche
|
|
|
808
814
|
* spec-conformant reading must hold unless a consumer opts in. Enabled, the
|
|
809
815
|
* engine captures `---`/`+++`/`---json` blocks at offset 0 into a raw
|
|
810
816
|
* `Frontmatter` head node — decoding it is the frontmatter codec modules'
|
|
811
|
-
* job.
|
|
817
|
+
* job. Parsed with the toggle off, such a document reports no frontmatter —
|
|
818
|
+
* `MarkdownDocument.hasFrontmatterBlock` tells "no block in the source"
|
|
819
|
+
* apart from "parsed with capture off".
|
|
812
820
|
*
|
|
813
821
|
* @public
|
|
814
822
|
*/
|
|
@@ -917,10 +925,14 @@ declare class Markdown {
|
|
|
917
925
|
* @remarks
|
|
918
926
|
* Canonical serialization: fidelity fields (marker characters, fence
|
|
919
927
|
* style, heading spelling) win when present; documented canonical
|
|
920
|
-
* defaults apply when absent.
|
|
921
|
-
*
|
|
922
|
-
*
|
|
923
|
-
*
|
|
928
|
+
* defaults apply when absent. One default surprises: a language-less
|
|
929
|
+
* `Code` node with no explicit `fenceChar` serializes as an
|
|
930
|
+
* **indented** code block — set `fenceChar` (or a `lang`) on the node for
|
|
931
|
+
* a fence, or normalize afterward with
|
|
932
|
+
* `MarkdownFormattingOptions.codeBlockStyle: "fenced"`. The output
|
|
933
|
+
* re-parses to a render-equivalent document — the corpus-pinned
|
|
934
|
+
* contract — but is not a byte-level round-trip of any original source;
|
|
935
|
+
* surgical editing goes through the offset-splice edit layer instead.
|
|
924
936
|
*
|
|
925
937
|
* Failure is rare by design, symmetric with parse: only a hardening-guard
|
|
926
938
|
* trip on a tree nesting past the depth cap fails, and only synthesized
|
|
@@ -1202,9 +1214,32 @@ declare class MarkdownDocument extends MarkdownDocument_base {
|
|
|
1202
1214
|
* only ever sit at the head of `root.children` (the capture fires at most
|
|
1203
1215
|
* once, at offset 0), so the tree is the single source of truth and the
|
|
1204
1216
|
* accessor can never disagree with it. `undefined` covers both a document
|
|
1205
|
-
* with no frontmatter block and one parsed with the capture toggle off
|
|
1217
|
+
* with no frontmatter block and one parsed with the capture toggle off —
|
|
1218
|
+
* {@link MarkdownDocument.hasFrontmatterBlock} tells the two apart.
|
|
1206
1219
|
*/
|
|
1207
1220
|
get frontmatter(): Frontmatter | undefined;
|
|
1221
|
+
/**
|
|
1222
|
+
* Whether the source opens with a well-formed frontmatter block —
|
|
1223
|
+
* regardless of how the document was parsed.
|
|
1224
|
+
*
|
|
1225
|
+
* @remarks
|
|
1226
|
+
* The structural signal that disambiguates the `frontmatter` accessor's
|
|
1227
|
+
* `undefined`: capture is opt-in (`MarkdownParseOptions.frontmatter`
|
|
1228
|
+
* defaults off), so a document whose source visibly starts with `---` can
|
|
1229
|
+
* still carry no capture node — spec-correct CommonMark reads the fences as
|
|
1230
|
+
* a thematic break plus content. `frontmatter === undefined` with
|
|
1231
|
+
* `hasFrontmatterBlock === true` means exactly "parsed with capture off";
|
|
1232
|
+
* with `false` it means the source genuinely has no block.
|
|
1233
|
+
*
|
|
1234
|
+
* Derived, not stored: the getter runs the **same** pre-scan the parser
|
|
1235
|
+
* runs when capture is enabled (the closed fence grammar — `---` yaml,
|
|
1236
|
+
* `+++` toml, `---json` json; an unclosed fence is not frontmatter), so it
|
|
1237
|
+
* is `true` exactly when parsing this source with `frontmatter: true`
|
|
1238
|
+
* would produce a capture node, and the two can never drift. Like the
|
|
1239
|
+
* other navigation accessors it recomputes per access — bind it once when
|
|
1240
|
+
* checking repeatedly.
|
|
1241
|
+
*/
|
|
1242
|
+
get hasFrontmatterBlock(): boolean;
|
|
1208
1243
|
/**
|
|
1209
1244
|
* Every heading in the document, in document order, wherever it sits —
|
|
1210
1245
|
* including headings nested inside blockquotes and list items.
|
|
@@ -1441,18 +1476,46 @@ interface FrontmatterCodec {
|
|
|
1441
1476
|
/** Serialize data into a frontmatter body, without fences. */
|
|
1442
1477
|
readonly encode: (data: unknown) => Effect.Effect<string, FrontmatterEncodeError>;
|
|
1443
1478
|
}
|
|
1444
|
-
|
|
1479
|
+
/**
|
|
1480
|
+
* Why a frontmatter decoder found no capture on a document.
|
|
1481
|
+
*
|
|
1482
|
+
* @remarks
|
|
1483
|
+
* `"absent"` — the source genuinely has no frontmatter block.
|
|
1484
|
+
* `"captureDisabled"` — the source opens with a well-formed frontmatter
|
|
1485
|
+
* block, but the document carries no capture node: it was parsed without
|
|
1486
|
+
* `frontmatter: true` (the toggle defaults off), so spec-correct CommonMark
|
|
1487
|
+
* read the fences as ordinary content.
|
|
1488
|
+
*
|
|
1489
|
+
* @public
|
|
1490
|
+
*/
|
|
1491
|
+
declare const FrontmatterMissingReason: Schema.Literals<readonly ["absent", "captureDisabled"]>;
|
|
1492
|
+
/**
|
|
1493
|
+
* Why a frontmatter decoder found no capture on a document.
|
|
1494
|
+
*
|
|
1495
|
+
* @public
|
|
1496
|
+
*/
|
|
1497
|
+
type FrontmatterMissingReason = typeof FrontmatterMissingReason.Type;
|
|
1498
|
+
declare const FrontmatterMissingError_base: Schema.Class<FrontmatterMissingError, Schema.TaggedStruct<"FrontmatterMissingError", {
|
|
1499
|
+
/** Why there is no capture: no block at all, or capture left off. */
|
|
1500
|
+
readonly reason: Schema.Literals<readonly ["absent", "captureDisabled"]>;
|
|
1501
|
+
}>, import("effect/Cause").YieldableError>;
|
|
1445
1502
|
/**
|
|
1446
1503
|
* Indicates that a document handed to a frontmatter decoder carries no
|
|
1447
1504
|
* frontmatter capture.
|
|
1448
1505
|
*
|
|
1449
1506
|
* @remarks
|
|
1450
|
-
*
|
|
1451
|
-
*
|
|
1452
|
-
*
|
|
1453
|
-
*
|
|
1454
|
-
*
|
|
1455
|
-
*
|
|
1507
|
+
* `reason` distinguishes the two ways this happens: `"absent"` when the
|
|
1508
|
+
* source genuinely has no frontmatter block, `"captureDisabled"` when the
|
|
1509
|
+
* source opens with one but the document was parsed with the capture toggle
|
|
1510
|
+
* off (`MarkdownParseOptions.frontmatter` defaults to `false`) — the fix
|
|
1511
|
+
* there is parsing with `frontmatter: true`, not editing the document. The
|
|
1512
|
+
* discriminant is computed from the same structural signal
|
|
1513
|
+
* `MarkdownDocument.hasFrontmatterBlock` exposes, so the error and the
|
|
1514
|
+
* accessor can never disagree.
|
|
1515
|
+
*
|
|
1516
|
+
* Cause-free: there is nothing to diagnose beyond the absence itself.
|
|
1517
|
+
* Consumers wanting optional semantics can
|
|
1518
|
+
* `Effect.catchTag("FrontmatterMissingError", ...)` to a default.
|
|
1456
1519
|
*
|
|
1457
1520
|
* @public
|
|
1458
1521
|
*/
|
|
@@ -1516,7 +1579,8 @@ declare class MarkdownFrontmatter {
|
|
|
1516
1579
|
* The decoder reads the document's frontmatter capture (parse with
|
|
1517
1580
|
* `frontmatter: true` — the toggle defaults off), decodes its raw value
|
|
1518
1581
|
* through the codec, then validates the data against `schema`. Each stage
|
|
1519
|
-
* fails typed: no capture is {@link FrontmatterMissingError}
|
|
1582
|
+
* fails typed: no capture is {@link FrontmatterMissingError} (its `reason`
|
|
1583
|
+
* says whether the block is genuinely absent or capture was left off), a
|
|
1520
1584
|
* wrong-format codec is {@link FrontmatterFormatMismatchError}, unparseable
|
|
1521
1585
|
* content is {@link FrontmatterDecodeError}, and schema-invalid data is
|
|
1522
1586
|
* {@link FrontmatterValidationError} carrying the structured issue.
|
|
@@ -1866,6 +1930,25 @@ type MarkdownRangeLike = MarkdownRange | {
|
|
|
1866
1930
|
readonly offset: number;
|
|
1867
1931
|
readonly length: number;
|
|
1868
1932
|
};
|
|
1933
|
+
/**
|
|
1934
|
+
* The two ways CommonMark spells a code block: `fenced` (a backtick or tilde
|
|
1935
|
+
* fence) and `indented` (four-space indentation).
|
|
1936
|
+
*
|
|
1937
|
+
* @remarks
|
|
1938
|
+
* A formatting target for {@link MarkdownFormattingOptions}, not a node
|
|
1939
|
+
* fidelity field: on a {@link Code} node the two spellings are told apart by
|
|
1940
|
+
* the presence or absence of `fenceChar`/`fenceLength`, and a language-less
|
|
1941
|
+
* node with neither serializes as an **indented** block by default.
|
|
1942
|
+
*
|
|
1943
|
+
* @public
|
|
1944
|
+
*/
|
|
1945
|
+
declare const CodeBlockStyle: Schema.Literals<readonly ["fenced", "indented"]>;
|
|
1946
|
+
/**
|
|
1947
|
+
* The union of all code-block-style string literals.
|
|
1948
|
+
*
|
|
1949
|
+
* @public
|
|
1950
|
+
*/
|
|
1951
|
+
type CodeBlockStyle = typeof CodeBlockStyle.Type;
|
|
1869
1952
|
declare const MarkdownFormattingOptions_base: Schema.Class<MarkdownFormattingOptions, Schema.Struct<{
|
|
1870
1953
|
readonly dialect: Schema.optionalKey<Schema.Literals<readonly ["commonmark", "gfm"]>>;
|
|
1871
1954
|
readonly frontmatter: Schema.optionalKey<Schema.Boolean>;
|
|
@@ -1874,6 +1957,7 @@ declare const MarkdownFormattingOptions_base: Schema.Class<MarkdownFormattingOpt
|
|
|
1874
1957
|
readonly emphasisChar: Schema.optionalKey<Schema.Literals<readonly ["*", "_"]>>;
|
|
1875
1958
|
readonly fenceChar: Schema.optionalKey<Schema.Literals<readonly ["`", "~"]>>;
|
|
1876
1959
|
readonly thematicBreakChar: Schema.optionalKey<Schema.Literals<readonly ["-", "_", "*"]>>;
|
|
1960
|
+
readonly codeBlockStyle: Schema.optionalKey<Schema.Literals<readonly ["fenced", "indented"]>>;
|
|
1877
1961
|
}>, {}>;
|
|
1878
1962
|
/**
|
|
1879
1963
|
* Options controlling formatting: which concrete-syntax markers to normalize,
|
|
@@ -1883,7 +1967,25 @@ declare const MarkdownFormattingOptions_base: Schema.Class<MarkdownFormattingOpt
|
|
|
1883
1967
|
*
|
|
1884
1968
|
* Day-one scope is marker normalization only — heading style, bullet
|
|
1885
1969
|
* character, emphasis/strong marker, fence character, thematic-break
|
|
1886
|
-
* character. Content is never rewritten, rewrapped or
|
|
1970
|
+
* character, code-block style. Content is never rewritten, rewrapped or
|
|
1971
|
+
* reflowed.
|
|
1972
|
+
*
|
|
1973
|
+
* @remarks
|
|
1974
|
+
* `codeBlockStyle` is the opt-in that converts between the two code-block
|
|
1975
|
+
* spellings for **language-less** blocks (a block with a `lang` has no
|
|
1976
|
+
* indented spelling and is never touched). It exists because the default
|
|
1977
|
+
* surprises: absent this option, a language-less code block keeps its
|
|
1978
|
+
* spelling — and a language-less {@link Code} node with no explicit
|
|
1979
|
+
* `fenceChar` **serializes as an indented block** through
|
|
1980
|
+
* `Markdown.stringify`. `"fenced"` rewrites indented blocks to fences (the
|
|
1981
|
+
* fence character follows `fenceChar` when also set, backtick otherwise);
|
|
1982
|
+
* `"indented"` rewrites language-less fences to indented form where provably
|
|
1983
|
+
* safe. Like every other option, hazardous conversions are skipped, never
|
|
1984
|
+
* attempted: both directions apply to root-level, flush-left blocks only,
|
|
1985
|
+
* and the `"indented"` direction additionally skips blocks whose indented
|
|
1986
|
+
* spelling would lazily continue a paragraph, be absorbed into a preceding
|
|
1987
|
+
* list or footnote definition, merge with an adjacent code block, or fail
|
|
1988
|
+
* representability (empty, or blank first/last lines).
|
|
1887
1989
|
*
|
|
1888
1990
|
* @public
|
|
1889
1991
|
*/
|
|
@@ -1941,12 +2043,18 @@ declare class MarkdownFormat {
|
|
|
1941
2043
|
/**
|
|
1942
2044
|
* Compute marker-normalization edits per the requested
|
|
1943
2045
|
* {@link MarkdownFormattingOptions}: heading style, bullet character,
|
|
1944
|
-
* emphasis/strong marker, fence character
|
|
1945
|
-
* each only where the node's concrete syntax differs
|
|
1946
|
-
* the rewrite is provably safe. Content is never
|
|
1947
|
-
* restricts edits to the nodes intersecting it (the
|
|
1948
|
-
* intersection posture, matching toml). Non-mutating — apply
|
|
1949
|
-
* `MarkdownEdit.applyAll` (or use
|
|
2046
|
+
* emphasis/strong marker, fence character, thematic-break character and
|
|
2047
|
+
* code-block style, each only where the node's concrete syntax differs
|
|
2048
|
+
* from the target and the rewrite is provably safe. Content is never
|
|
2049
|
+
* touched. `range` restricts edits to the nodes intersecting it (the
|
|
2050
|
+
* owning-node intersection posture, matching toml). Non-mutating — apply
|
|
2051
|
+
* with `MarkdownEdit.applyAll` (or use
|
|
2052
|
+
* {@link MarkdownFormat.formatToString}).
|
|
2053
|
+
*
|
|
2054
|
+
* Note the code-block default: absent `codeBlockStyle`, a language-less
|
|
2055
|
+
* code block keeps whichever spelling it has — `fenceChar` alone
|
|
2056
|
+
* normalizes existing fences and deliberately leaves indented blocks
|
|
2057
|
+
* indented.
|
|
1950
2058
|
*/
|
|
1951
2059
|
static format(text: string, range?: MarkdownRangeLike, options?: MarkdownFormattingOptions): ReadonlyArray<MarkdownEdit>;
|
|
1952
2060
|
/**
|
|
@@ -2292,5 +2400,5 @@ declare const TomlFrontmatter: FrontmatterCodec;
|
|
|
2292
2400
|
*/
|
|
2293
2401
|
declare const YamlFrontmatter: FrontmatterCodec;
|
|
2294
2402
|
//#endregion
|
|
2295
|
-
export { Blockquote, Break, BreakStyle, BulletChar, Code, Definition, Delete, type DocumentHeading, type DocumentLink, DocumentSection, Emphasis, EmphasisChar, FenceChar, FlowContent, FootnoteDefinition, FootnoteReference, Frontmatter, type FrontmatterCodec, FrontmatterContent, FrontmatterDecodeError, FrontmatterEncodeError, FrontmatterFormat, FrontmatterFormatMismatchError, FrontmatterMissingError, 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 };
|
|
2403
|
+
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 };
|
|
2296
2404
|
//# sourceMappingURL=index.d.ts.map
|
package/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { MarkdownEdit, MarkdownRange } from "./MarkdownEdit.js";
|
|
2
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";
|
|
3
|
-
import { FrontmatterDecodeError, FrontmatterEncodeError, FrontmatterFormatMismatchError, FrontmatterMissingError, FrontmatterValidationError, MarkdownFrontmatter } from "./Frontmatter.js";
|
|
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
5
|
import { JsonFrontmatter } from "./JsonFrontmatter.js";
|
|
6
6
|
import { MarkdownDiagnostic, MarkdownParseErrorCode } from "./MarkdownDiagnostic.js";
|
|
7
7
|
import { Markdown, MarkdownDialect, MarkdownParseError, MarkdownParseOptions, MarkdownStringifyError } from "./Markdown.js";
|
|
8
8
|
import { DocumentSection, MarkdownDocument } from "./MarkdownDocument.js";
|
|
9
|
-
import { MarkdownFormat, MarkdownFormattingOptions, MarkdownModificationError, MarkdownModificationErrorCode } from "./MarkdownFormat.js";
|
|
9
|
+
import { CodeBlockStyle, MarkdownFormat, MarkdownFormattingOptions, MarkdownModificationError, MarkdownModificationErrorCode } from "./MarkdownFormat.js";
|
|
10
10
|
import { MarkdownVisitor, MarkdownVisitorEvent } from "./MarkdownVisitor.js";
|
|
11
11
|
import { Mdast, MdastDecodeError } from "./Mdast.js";
|
|
12
12
|
import { TomlFrontmatter } from "./TomlFrontmatter.js";
|
|
13
13
|
import { YamlFrontmatter } from "./YamlFrontmatter.js";
|
|
14
14
|
|
|
15
|
-
export { Blockquote, Break, BreakStyle, BulletChar, Code, Definition, Delete, DocumentSection, Emphasis, EmphasisChar, FenceChar, FlowContent, FootnoteDefinition, FootnoteReference, Frontmatter, FrontmatterContent, FrontmatterDecodeError, FrontmatterEncodeError, FrontmatterFormat, FrontmatterFormatMismatchError, FrontmatterMissingError, 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 };
|
|
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 };
|