@dogsbay/serialize-core 0.2.0-beta.116 → 0.2.0-beta.117
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lead.d.ts +64 -0
- package/dist/lead.d.ts.map +1 -0
- package/dist/lead.js +196 -0
- package/dist/lead.js.map +1 -0
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -24,4 +24,5 @@ export { resolvePlugins, composeCapabilities, formatPluginConflicts, type Export
|
|
|
24
24
|
export { realizeIncludes, hasIncludes, type RealizeResult, type RealizeOptions, } from "./includes.js";
|
|
25
25
|
export { realizeChildLinks, hasChildLinks, directoryChildren, navKey, type ChildLinksContext, type ChildLinksResult, } from "./child-links.js";
|
|
26
26
|
export { renderUnknownNode, type UnknownNodePolicy, type UnknownNodeOptions, } from "./unknown.js";
|
|
27
|
+
export { detectLeadingNodes, deriveDescription, extractFirstParagraph, type LeadingNodeInfo, } from "./lead.js";
|
|
27
28
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACL,UAAU,EACV,QAAQ,EACR,SAAS,EACT,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,eAAe,EACf,YAAY,EACZ,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,UAAU,EACV,KAAK,UAAU,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,UAAU,EACV,cAAc,EACd,eAAe,EACf,sBAAsB,EACtB,kBAAkB,EAClB,UAAU,EACV,UAAU,EACV,QAAQ,EACR,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,iCAAiC,EACjC,KAAK,YAAY,EACjB,KAAK,qBAAqB,EAC1B,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,GACtB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,MAAM,EACN,WAAW,EACX,2BAA2B,EAC3B,SAAS,EACT,oBAAoB,EACpB,kBAAkB,EAClB,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,EACb,aAAa,EACb,UAAU,EACV,aAAa,EACb,mBAAmB,EACnB,YAAY,EACZ,UAAU,EACV,gBAAgB,GACjB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,eAAe,EACf,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,MAAM,EACN,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,iBAAiB,EACjB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,GACxB,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACL,UAAU,EACV,QAAQ,EACR,SAAS,EACT,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,eAAe,EACf,YAAY,EACZ,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,UAAU,EACV,KAAK,UAAU,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,UAAU,EACV,cAAc,EACd,eAAe,EACf,sBAAsB,EACtB,kBAAkB,EAClB,UAAU,EACV,UAAU,EACV,QAAQ,EACR,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,iCAAiC,EACjC,KAAK,YAAY,EACjB,KAAK,qBAAqB,EAC1B,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,GACtB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,MAAM,EACN,WAAW,EACX,2BAA2B,EAC3B,SAAS,EACT,oBAAoB,EACpB,kBAAkB,EAClB,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,EACb,aAAa,EACb,UAAU,EACV,aAAa,EACb,mBAAmB,EACnB,YAAY,EACZ,UAAU,EACV,gBAAgB,GACjB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,eAAe,EACf,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,MAAM,EACN,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,iBAAiB,EACjB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,GACxB,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,KAAK,eAAe,GACrB,MAAM,WAAW,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -24,4 +24,6 @@ export { resolvePlugins, composeCapabilities, formatPluginConflicts, } from "./p
|
|
|
24
24
|
export { realizeIncludes, hasIncludes, } from "./includes.js";
|
|
25
25
|
export { realizeChildLinks, hasChildLinks, directoryChildren, navKey, } from "./child-links.js";
|
|
26
26
|
export { renderUnknownNode, } from "./unknown.js";
|
|
27
|
+
// Page-lead reads shared by format-astro and @dogsbay/site-check
|
|
28
|
+
export { detectLeadingNodes, deriveDescription, extractFirstParagraph, } from "./lead.js";
|
|
27
29
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACL,UAAU,EACV,QAAQ,EACR,SAAS,EACT,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,eAAe,EACf,YAAY,EACZ,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,UAAU,GAEX,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,UAAU,EACV,cAAc,EACd,eAAe,EACf,sBAAsB,EACtB,kBAAkB,EAClB,UAAU,EACV,UAAU,EACV,QAAQ,GAIT,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,iCAAiC,GAMlC,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,MAAM,EACN,WAAW,EACX,2BAA2B,EAC3B,SAAS,EACT,oBAAoB,EACpB,kBAAkB,EAClB,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,EACb,aAAa,EACb,UAAU,EACV,aAAa,EACb,mBAAmB,EACnB,YAAY,EACZ,UAAU,EACV,gBAAgB,GACjB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,qBAAqB,GAMtB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,eAAe,EACf,WAAW,GAGZ,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,MAAM,GAGP,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,iBAAiB,GAGlB,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACL,UAAU,EACV,QAAQ,EACR,SAAS,EACT,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,eAAe,EACf,YAAY,EACZ,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,UAAU,GAEX,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,UAAU,EACV,cAAc,EACd,eAAe,EACf,sBAAsB,EACtB,kBAAkB,EAClB,UAAU,EACV,UAAU,EACV,QAAQ,GAIT,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,iCAAiC,GAMlC,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,MAAM,EACN,WAAW,EACX,2BAA2B,EAC3B,SAAS,EACT,oBAAoB,EACpB,kBAAkB,EAClB,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,EACb,aAAa,EACb,UAAU,EACV,aAAa,EACb,mBAAmB,EACnB,YAAY,EACZ,UAAU,EACV,gBAAgB,GACjB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,qBAAqB,GAMtB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,eAAe,EACf,WAAW,GAGZ,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,MAAM,GAGP,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,iBAAiB,GAGlB,MAAM,cAAc,CAAC;AAEtB,iEAAiE;AACjE,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,GAEtB,MAAM,WAAW,CAAC"}
|
package/dist/lead.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect whether a page's body tree already provides a level-1
|
|
3
|
+
* heading and / or a leading paragraph.
|
|
4
|
+
*
|
|
5
|
+
* `format-astro` uses this to decide whether to auto-inject the
|
|
6
|
+
* frontmatter `title` and `description` at the top of `<main>` —
|
|
7
|
+
* we never overwrite writer-authored content, only fill in what
|
|
8
|
+
* the body doesn't already cover.
|
|
9
|
+
*
|
|
10
|
+
* See plans/auto-lede.md.
|
|
11
|
+
*/
|
|
12
|
+
import type { TreeNode } from "@dogsbay/types";
|
|
13
|
+
export interface LeadingNodeInfo {
|
|
14
|
+
/**
|
|
15
|
+
* `true` when `tree[0]` is a level-1 heading. Heading depth
|
|
16
|
+
* lives at either `node.depth` (some importers) or
|
|
17
|
+
* `node.props.level` (others); both shapes are recognized.
|
|
18
|
+
*/
|
|
19
|
+
hasH1: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* `true` when the body's first non-heading node is a paragraph.
|
|
22
|
+
* Used to decide whether the description should be auto-rendered
|
|
23
|
+
* as a lede `<p>` — if the writer already wrote a lede
|
|
24
|
+
* paragraph, we leave it alone.
|
|
25
|
+
*
|
|
26
|
+
* "First non-heading node" means: `tree[1]` when `tree[0]` is a
|
|
27
|
+
* heading; otherwise `tree[0]`. So `# Title\nLede paragraph`
|
|
28
|
+
* yields `{ hasH1: true, hasLede: true }`.
|
|
29
|
+
*/
|
|
30
|
+
hasLede: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Inspect the leading nodes of a page tree.
|
|
34
|
+
*
|
|
35
|
+
* Defensive against empty trees and missing properties — returns
|
|
36
|
+
* `false` for both flags when the tree is empty.
|
|
37
|
+
*/
|
|
38
|
+
export declare function detectLeadingNodes(tree: TreeNode[] | undefined): LeadingNodeInfo;
|
|
39
|
+
/**
|
|
40
|
+
* Derive a `<meta name="description">` from a page body when the
|
|
41
|
+
* frontmatter doesn't supply one: the first prose paragraph,
|
|
42
|
+
* whitespace-collapsed and truncated at a word boundary.
|
|
43
|
+
*
|
|
44
|
+
* Deliberately Minja-unaware. This only runs at build time, on the
|
|
45
|
+
* preprocessed (resolved) tree — `{{ var }}` and `{% include %}` are
|
|
46
|
+
* already gone, so the first paragraph is real prose. (A still-undefined
|
|
47
|
+
* `{{ var }}` survives `preserve` mode, but that's a content bug equally
|
|
48
|
+
* visible in the body and already flagged by the `unresolved-directives`
|
|
49
|
+
* audit — not the description's job to scrub.) The `--no-preprocess` /
|
|
50
|
+
* `dogsbay convert` paths emit unresolved output by design, where a
|
|
51
|
+
* slightly-off description is the least of it.
|
|
52
|
+
*
|
|
53
|
+
* Scans past a leading H1 / heading / code to the first prose paragraph;
|
|
54
|
+
* returns `undefined` when the page has no prose. See
|
|
55
|
+
* plans/auto-meta-description.md.
|
|
56
|
+
*/
|
|
57
|
+
export declare function deriveDescription(tree: TreeNode[] | undefined, maxLen?: number): string | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Extract plain text of the first paragraph in a page tree. Cross-shape
|
|
60
|
+
* tolerant: handles `node.inline` (dogsbay-md parser) and
|
|
61
|
+
* `node.children[{type: "prose", inline}]` (Starlight importer).
|
|
62
|
+
*/
|
|
63
|
+
export declare function extractFirstParagraph(tree: TreeNode[]): string;
|
|
64
|
+
//# sourceMappingURL=lead.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lead.d.ts","sourceRoot":"","sources":["../src/lead.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAc,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE3D,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,KAAK,EAAE,OAAO,CAAC;IACf;;;;;;;;;OASG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,QAAQ,EAAE,GAAG,SAAS,GAC3B,eAAe,CAmCjB;AAmBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,QAAQ,EAAE,GAAG,SAAS,EAC5B,MAAM,SAAM,GACX,MAAM,GAAG,SAAS,CAYpB;AAiCD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,CAO9D"}
|
package/dist/lead.js
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inspect the leading nodes of a page tree.
|
|
3
|
+
*
|
|
4
|
+
* Defensive against empty trees and missing properties — returns
|
|
5
|
+
* `false` for both flags when the tree is empty.
|
|
6
|
+
*/
|
|
7
|
+
export function detectLeadingNodes(tree) {
|
|
8
|
+
if (!tree || tree.length === 0) {
|
|
9
|
+
return { hasH1: false, hasLede: false };
|
|
10
|
+
}
|
|
11
|
+
// H1 detection looks past two things that are not content:
|
|
12
|
+
//
|
|
13
|
+
// - leading raw-HTML CHROME (banners, toolbars — the comparison view
|
|
14
|
+
// injects both). Only tree[0] was inspected before, so a page that
|
|
15
|
+
// opened with a banner "had no H1" and the layout added a second
|
|
16
|
+
// one (external review);
|
|
17
|
+
// - a transparent `group` wrapper, which by definition adds no
|
|
18
|
+
// semantics — it exists only to carry an attribute for a run of
|
|
19
|
+
// blocks (the comparison marks a whole added/removed page with one).
|
|
20
|
+
// A wrapper that hid the page's H1 would resurrect the same bug.
|
|
21
|
+
//
|
|
22
|
+
// LEDE detection deliberately still keys off tree[0]: a paragraph that
|
|
23
|
+
// merely follows an HTML block is not the page's lede, and treating it
|
|
24
|
+
// as one silently suppresses the frontmatter description on any
|
|
25
|
+
// imported page opening with a <figure>/hero block (code review,
|
|
26
|
+
// 2026-07-13). Only an H1 introduces a lede.
|
|
27
|
+
let list = tree;
|
|
28
|
+
for (;;) {
|
|
29
|
+
let i = 0;
|
|
30
|
+
while (i < list.length && list[i]?.type === "html")
|
|
31
|
+
i++;
|
|
32
|
+
const first = list[i];
|
|
33
|
+
if (first?.type === "group" && first.children?.length) {
|
|
34
|
+
list = first.children;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (isH1(first)) {
|
|
38
|
+
return { hasH1: true, hasLede: isParagraph(list[i + 1]) };
|
|
39
|
+
}
|
|
40
|
+
return { hasH1: false, hasLede: isParagraph(tree[0]) };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function isH1(node) {
|
|
44
|
+
if (!node || node.type !== "heading")
|
|
45
|
+
return false;
|
|
46
|
+
// Some importers (dogsbay-md, mkdocs) attach depth as a top-level
|
|
47
|
+
// field; others (Starlight via mdx-jsx) use props.level. Both
|
|
48
|
+
// conventions are valid — check both.
|
|
49
|
+
const depth = node.depth;
|
|
50
|
+
if (typeof depth === "number")
|
|
51
|
+
return depth === 1;
|
|
52
|
+
const level = node.props?.level;
|
|
53
|
+
if (typeof level === "number")
|
|
54
|
+
return level === 1;
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
function isParagraph(node) {
|
|
58
|
+
if (!node)
|
|
59
|
+
return false;
|
|
60
|
+
return node.type === "paragraph";
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Derive a `<meta name="description">` from a page body when the
|
|
64
|
+
* frontmatter doesn't supply one: the first prose paragraph,
|
|
65
|
+
* whitespace-collapsed and truncated at a word boundary.
|
|
66
|
+
*
|
|
67
|
+
* Deliberately Minja-unaware. This only runs at build time, on the
|
|
68
|
+
* preprocessed (resolved) tree — `{{ var }}` and `{% include %}` are
|
|
69
|
+
* already gone, so the first paragraph is real prose. (A still-undefined
|
|
70
|
+
* `{{ var }}` survives `preserve` mode, but that's a content bug equally
|
|
71
|
+
* visible in the body and already flagged by the `unresolved-directives`
|
|
72
|
+
* audit — not the description's job to scrub.) The `--no-preprocess` /
|
|
73
|
+
* `dogsbay convert` paths emit unresolved output by design, where a
|
|
74
|
+
* slightly-off description is the least of it.
|
|
75
|
+
*
|
|
76
|
+
* Scans past a leading H1 / heading / code to the first prose paragraph;
|
|
77
|
+
* returns `undefined` when the page has no prose. See
|
|
78
|
+
* plans/auto-meta-description.md.
|
|
79
|
+
*/
|
|
80
|
+
export function deriveDescription(tree, maxLen = 155) {
|
|
81
|
+
if (!tree || tree.length === 0)
|
|
82
|
+
return undefined;
|
|
83
|
+
// Skip a leading H1 (the page title) so the lede is the node after it.
|
|
84
|
+
let i = isH1(tree[0]) ? 1 : 0;
|
|
85
|
+
for (; i < tree.length; i++) {
|
|
86
|
+
const node = tree[i];
|
|
87
|
+
if (node.type !== "paragraph")
|
|
88
|
+
continue; // skip headings/code/etc.
|
|
89
|
+
const text = paragraphText(node).replace(/\s+/g, " ").trim();
|
|
90
|
+
if (!text)
|
|
91
|
+
continue;
|
|
92
|
+
return truncateAtWord(text, maxLen);
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Flatten a paragraph node's text. Tolerant of the three shapes
|
|
98
|
+
* format-astro already handles: flat `node.inline`, wrapped
|
|
99
|
+
* `node.children[{ inline }]`, and pre-rendered `node.html`.
|
|
100
|
+
*/
|
|
101
|
+
function paragraphText(node) {
|
|
102
|
+
const parts = [];
|
|
103
|
+
const visit = (n) => {
|
|
104
|
+
if (!n || typeof n !== "object")
|
|
105
|
+
return;
|
|
106
|
+
const o = n;
|
|
107
|
+
if (typeof o.text === "string")
|
|
108
|
+
parts.push(o.text);
|
|
109
|
+
if (typeof o.code === "string")
|
|
110
|
+
parts.push(o.code);
|
|
111
|
+
if (Array.isArray(o.inline))
|
|
112
|
+
o.inline.forEach(visit);
|
|
113
|
+
if (Array.isArray(o.children))
|
|
114
|
+
o.children.forEach(visit);
|
|
115
|
+
};
|
|
116
|
+
if (Array.isArray(node.inline))
|
|
117
|
+
node.inline.forEach(visit);
|
|
118
|
+
else if (Array.isArray(node.children))
|
|
119
|
+
node.children.forEach(visit);
|
|
120
|
+
else if (typeof node.html === "string") {
|
|
121
|
+
parts.push(node.html.replace(/<[^>]+>/g, ""));
|
|
122
|
+
}
|
|
123
|
+
return parts.join("");
|
|
124
|
+
}
|
|
125
|
+
function truncateAtWord(s, max) {
|
|
126
|
+
if (s.length <= max)
|
|
127
|
+
return s;
|
|
128
|
+
const cut = s.slice(0, max);
|
|
129
|
+
const lastSpace = cut.lastIndexOf(" ");
|
|
130
|
+
const base = lastSpace > max * 0.6 ? cut.slice(0, lastSpace) : cut;
|
|
131
|
+
return base.replace(/[\s.,;:!?-]+$/, "") + "…";
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Extract plain text of the first paragraph in a page tree. Cross-shape
|
|
135
|
+
* tolerant: handles `node.inline` (dogsbay-md parser) and
|
|
136
|
+
* `node.children[{type: "prose", inline}]` (Starlight importer).
|
|
137
|
+
*/
|
|
138
|
+
export function extractFirstParagraph(tree) {
|
|
139
|
+
for (const node of tree) {
|
|
140
|
+
if (node.type !== "paragraph")
|
|
141
|
+
continue;
|
|
142
|
+
const inline = node.inline ?? findProseInline(node.children);
|
|
143
|
+
if (inline)
|
|
144
|
+
return inlineToPlainText(inline).trim();
|
|
145
|
+
}
|
|
146
|
+
return "";
|
|
147
|
+
}
|
|
148
|
+
function findProseInline(children) {
|
|
149
|
+
if (!children)
|
|
150
|
+
return undefined;
|
|
151
|
+
for (const child of children) {
|
|
152
|
+
if (child.type === "prose" && child.inline)
|
|
153
|
+
return child.inline;
|
|
154
|
+
}
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
function inlineToPlainText(inline) {
|
|
158
|
+
let out = "";
|
|
159
|
+
for (const node of inline) {
|
|
160
|
+
switch (node.type) {
|
|
161
|
+
case "text":
|
|
162
|
+
out += node.text;
|
|
163
|
+
break;
|
|
164
|
+
case "code":
|
|
165
|
+
out += node.text;
|
|
166
|
+
break;
|
|
167
|
+
case "link":
|
|
168
|
+
case "highlight":
|
|
169
|
+
out += inlineToPlainText(node.children);
|
|
170
|
+
break;
|
|
171
|
+
case "kbd":
|
|
172
|
+
out += node.keys.join("+");
|
|
173
|
+
break;
|
|
174
|
+
case "badge":
|
|
175
|
+
out += node.text;
|
|
176
|
+
break;
|
|
177
|
+
case "math":
|
|
178
|
+
out += node.latex;
|
|
179
|
+
break;
|
|
180
|
+
case "image":
|
|
181
|
+
if (node.alt)
|
|
182
|
+
out += node.alt;
|
|
183
|
+
break;
|
|
184
|
+
case "break":
|
|
185
|
+
out += " ";
|
|
186
|
+
break;
|
|
187
|
+
case "html-inline":
|
|
188
|
+
case "footnote-ref":
|
|
189
|
+
case "icon":
|
|
190
|
+
// No useful plain text; skip.
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return out;
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=lead.js.map
|
package/dist/lead.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lead.js","sourceRoot":"","sources":["../src/lead.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dogsbay/serialize-core",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.117",
|
|
4
4
|
"description": "Shared serializer core — shape-tolerant TreeNode reads, a generic inline walker, fence/indent utilities, and the export capability ledger every format exporter builds on",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@dogsbay/types": "0.2.0-beta.
|
|
25
|
+
"@dogsbay/types": "0.2.0-beta.117"
|
|
26
26
|
},
|
|
27
27
|
"repository": {
|
|
28
28
|
"type": "git",
|