@dogsbay/format-fluidtopics-rest 0.2.0-beta.101
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/README.md +87 -0
- package/dist/assets.d.ts +13 -0
- package/dist/assets.d.ts.map +1 -0
- package/dist/assets.js +53 -0
- package/dist/assets.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +28 -0
- package/dist/cli.js.map +1 -0
- package/dist/frontmatter.d.ts +36 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/frontmatter.js +78 -0
- package/dist/frontmatter.js.map +1 -0
- package/dist/headings.d.ts +13 -0
- package/dist/headings.d.ts.map +1 -0
- package/dist/headings.js +76 -0
- package/dist/headings.js.map +1 -0
- package/dist/html-to-tree.d.ts +17 -0
- package/dist/html-to-tree.d.ts.map +1 -0
- package/dist/html-to-tree.js +309 -0
- package/dist/html-to-tree.js.map +1 -0
- package/dist/importer.d.ts +87 -0
- package/dist/importer.d.ts.map +1 -0
- package/dist/importer.js +354 -0
- package/dist/importer.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/inline-html.d.ts +52 -0
- package/dist/inline-html.d.ts.map +1 -0
- package/dist/inline-html.js +157 -0
- package/dist/inline-html.js.map +1 -0
- package/dist/khub.d.ts +86 -0
- package/dist/khub.d.ts.map +1 -0
- package/dist/khub.js +111 -0
- package/dist/khub.js.map +1 -0
- package/dist/links.d.ts +13 -0
- package/dist/links.d.ts.map +1 -0
- package/dist/links.js +55 -0
- package/dist/links.js.map +1 -0
- package/dist/nav.d.ts +7 -0
- package/dist/nav.d.ts.map +1 -0
- package/dist/nav.js +15 -0
- package/dist/nav.js.map +1 -0
- package/dist/single-page.d.ts +70 -0
- package/dist/single-page.d.ts.map +1 -0
- package/dist/single-page.js +77 -0
- package/dist/single-page.js.map +1 -0
- package/dist/tree.d.ts +2 -0
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +2 -0
- package/dist/tree.js.map +1 -0
- package/package.json +50 -0
package/dist/importer.js
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { parseMeta } from "@dogsbay/types";
|
|
2
|
+
import { KhubClient, KhubAuthError, tocTopics } from "./khub.js";
|
|
3
|
+
import { htmlToTree } from "./html-to-tree.js";
|
|
4
|
+
import { resolveHref, slugFromPrettyUrl, routeFromSlug } from "./links.js";
|
|
5
|
+
import { buildFrontmatter } from "./frontmatter.js";
|
|
6
|
+
import { tocToNav } from "./nav.js";
|
|
7
|
+
import { extractHeadings } from "./headings.js";
|
|
8
|
+
import { parseDataUri, assetPath } from "./assets.js";
|
|
9
|
+
import { buildBookAnchors, bookHeading, shiftHeadings, bookSlugFrom, bookNavItem } from "./single-page.js";
|
|
10
|
+
export async function importFluidTopicsRest(opts) {
|
|
11
|
+
const client = opts.client ??
|
|
12
|
+
new KhubClient(opts.portalBase ?? "", { fetchImpl: opts.fetchImpl, throttleMs: opts.throttleMs });
|
|
13
|
+
const hrefPrefix = opts.hrefPrefix ?? "/docs";
|
|
14
|
+
const log = opts.onProgress ?? (() => { });
|
|
15
|
+
// Map inventory (titles + metadata). Tolerate a portal that 401s the list.
|
|
16
|
+
const listedRaw = await client.listMaps(opts.lang).catch((e) => {
|
|
17
|
+
if (e instanceof KhubAuthError)
|
|
18
|
+
throw e;
|
|
19
|
+
return [];
|
|
20
|
+
});
|
|
21
|
+
// Drop stale duplicate publications (same title + version, older
|
|
22
|
+
// `ft:lastEdition`) unless explicitly told to keep them. See `keepDuplicateMaps`.
|
|
23
|
+
const listed = opts.keepDuplicateMaps ? listedRaw : dedupeMapsByEdition(listedRaw, log);
|
|
24
|
+
const idToMap = new Map(listed.map((m) => [m.id, m]));
|
|
25
|
+
let ids = opts.maps?.length ? opts.maps : listed.map((m) => m.id);
|
|
26
|
+
if (!opts.maps?.length && opts.titleFilter) {
|
|
27
|
+
const needle = opts.titleFilter.toLowerCase();
|
|
28
|
+
ids = listed.filter((m) => (m.title ?? "").toLowerCase().includes(needle)).map((m) => m.id);
|
|
29
|
+
}
|
|
30
|
+
// For requested ids not present in the listing, fetch metadata directly.
|
|
31
|
+
for (const id of ids) {
|
|
32
|
+
if (!idToMap.has(id)) {
|
|
33
|
+
const m = (await client.getMap(id));
|
|
34
|
+
idToMap.set(id, { id, title: m.title ?? id, metadata: m.metadata });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Pre-pass: fetch every selected map's TOC once, and build a tocId → slug
|
|
38
|
+
// index so internal xrefs (hrefless <a data-tocid data-mapid>) can resolve.
|
|
39
|
+
// In single-page mode we additionally pre-compute each book's route + per-node
|
|
40
|
+
// anchors, so xrefs (which may point forward) resolve to `<book>#<anchor>`.
|
|
41
|
+
const tocs = new Map();
|
|
42
|
+
const tocIdToSlug = new Map();
|
|
43
|
+
const bookAnchors = new Map();
|
|
44
|
+
const bookRoutes = new Map();
|
|
45
|
+
const anchorIndex = new Map(); // key: tocId and `${mapId}:${tocId}`
|
|
46
|
+
for (const id of ids) {
|
|
47
|
+
const toc = await client.getToc(id);
|
|
48
|
+
tocs.set(id, toc);
|
|
49
|
+
const walk = (ns) => {
|
|
50
|
+
for (const n of ns) {
|
|
51
|
+
if (n.tocId && n.prettyUrl) {
|
|
52
|
+
const slug = slugFromPrettyUrl(n.prettyUrl);
|
|
53
|
+
if (slug) {
|
|
54
|
+
tocIdToSlug.set(`${id}:${n.tocId}`, slug);
|
|
55
|
+
if (!tocIdToSlug.has(n.tocId))
|
|
56
|
+
tocIdToSlug.set(n.tocId, slug);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (n.children?.length)
|
|
60
|
+
walk(n.children);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
walk(toc);
|
|
64
|
+
if (opts.singlePage) {
|
|
65
|
+
const anchors = buildBookAnchors(toc);
|
|
66
|
+
bookAnchors.set(id, anchors);
|
|
67
|
+
const topicSlugs = tocTopics(toc).map((t) => slugFromPrettyUrl(t.prettyUrl)).filter(Boolean);
|
|
68
|
+
const route = routeFromSlug(bookSlugFrom(topicSlugs, idToMap.get(id)?.title ?? id), hrefPrefix);
|
|
69
|
+
bookRoutes.set(id, route);
|
|
70
|
+
for (const [tocId, anchor] of anchors.byTocId) {
|
|
71
|
+
anchorIndex.set(`${id}:${tocId}`, { anchor, route });
|
|
72
|
+
if (!anchorIndex.has(tocId))
|
|
73
|
+
anchorIndex.set(tocId, { anchor, route });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const resolveTocId = (tocId, mapId) => {
|
|
78
|
+
if (opts.singlePage) {
|
|
79
|
+
const hit = (mapId ? anchorIndex.get(`${mapId}:${tocId}`) : undefined) ?? anchorIndex.get(tocId);
|
|
80
|
+
return hit ? `${hit.route}#${hit.anchor}` : undefined;
|
|
81
|
+
}
|
|
82
|
+
const slug = (mapId ? tocIdToSlug.get(`${mapId}:${tocId}`) : undefined) ?? tocIdToSlug.get(tocId);
|
|
83
|
+
return slug !== undefined ? routeFromSlug(slug, hrefPrefix) : undefined;
|
|
84
|
+
};
|
|
85
|
+
// Extract inline `data:` images to real `_assets` files (deduped by path).
|
|
86
|
+
const assetBytes = new Map();
|
|
87
|
+
const onImage = (img) => {
|
|
88
|
+
if (!img.src.startsWith("data:"))
|
|
89
|
+
return img.src;
|
|
90
|
+
const parsed = parseDataUri(img.src);
|
|
91
|
+
if (!parsed)
|
|
92
|
+
return img.src;
|
|
93
|
+
const path = assetPath(img.resourceId, img.displayName, parsed);
|
|
94
|
+
if (!assetBytes.has(path))
|
|
95
|
+
assetBytes.set(path, parsed.data);
|
|
96
|
+
return `/${path}`;
|
|
97
|
+
};
|
|
98
|
+
const pages = [];
|
|
99
|
+
// Per-map nav nodes paired with the facet path they group under (e.g.
|
|
100
|
+
// ["Reference Guides"]). Flattened or nested by buildGroupedNav at the end.
|
|
101
|
+
const mapNav = [];
|
|
102
|
+
const groupKeys = resolveGroupKeys(opts.groupBy, listed);
|
|
103
|
+
const unresolved = {};
|
|
104
|
+
const seen = new Set();
|
|
105
|
+
let mapsProcessed = 0;
|
|
106
|
+
for (const id of ids) {
|
|
107
|
+
const mapInfo = idToMap.get(id);
|
|
108
|
+
const toc = tocs.get(id);
|
|
109
|
+
const topics = tocTopics(toc);
|
|
110
|
+
log(`map ${mapInfo?.title ?? id}: ${topics.length} topics`);
|
|
111
|
+
// ── single-page (whole book) ───────────────────────────
|
|
112
|
+
if (opts.singlePage) {
|
|
113
|
+
const { ordered } = bookAnchors.get(id);
|
|
114
|
+
const route = bookRoutes.get(id);
|
|
115
|
+
const bookSlug = route.startsWith(hrefPrefix) ? route.slice(hrefPrefix.length).replace(/^\//, "") : route.replace(/^\//, "");
|
|
116
|
+
const combined = [];
|
|
117
|
+
const local = [];
|
|
118
|
+
for (const entry of ordered) {
|
|
119
|
+
const t = entry.node;
|
|
120
|
+
combined.push(bookHeading(entry.level, t.title || labelFromSlug(entry.anchor), entry.anchor));
|
|
121
|
+
if (!t.contentId)
|
|
122
|
+
continue;
|
|
123
|
+
let html;
|
|
124
|
+
try {
|
|
125
|
+
html = await client.getTopicContent(id, t.contentId);
|
|
126
|
+
}
|
|
127
|
+
catch (e) {
|
|
128
|
+
if (e instanceof KhubAuthError)
|
|
129
|
+
throw e;
|
|
130
|
+
log(` ! skip ${entry.anchor}: ${e.message}`);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
const fromSlug = slugFromPrettyUrl(t.prettyUrl) || bookSlug;
|
|
134
|
+
const { tree } = htmlToTree(html, {
|
|
135
|
+
resolveHref: (h) => {
|
|
136
|
+
const r = resolveHref(h, fromSlug, hrefPrefix);
|
|
137
|
+
if (!r.resolved && h)
|
|
138
|
+
local.push(h);
|
|
139
|
+
return r.href;
|
|
140
|
+
},
|
|
141
|
+
resolveTocId,
|
|
142
|
+
onImage,
|
|
143
|
+
});
|
|
144
|
+
shiftHeadings(tree, entry.level - 1);
|
|
145
|
+
combined.push(...tree);
|
|
146
|
+
}
|
|
147
|
+
const title = mapInfo?.title ?? id;
|
|
148
|
+
// Whole-book page: per-topic metadata varies across the rolled-up topics,
|
|
149
|
+
// so the map-level metadata is the representative source — and the book is
|
|
150
|
+
// the right granularity for the technical totals (wordCount/contentSize/…).
|
|
151
|
+
const frontmatter = buildFrontmatter({
|
|
152
|
+
title,
|
|
153
|
+
topicType: "topic",
|
|
154
|
+
mapMeta: mapInfo?.metadata,
|
|
155
|
+
metadataAllow: opts.metadataAllow,
|
|
156
|
+
technical: true,
|
|
157
|
+
});
|
|
158
|
+
const headings = extractHeadings(combined);
|
|
159
|
+
const meta = parseMeta(frontmatter, { slug: bookSlug, taxonomyNames: opts.taxonomyNames });
|
|
160
|
+
pages.push({ slug: bookSlug, title, tree: combined, headings, frontmatter, meta });
|
|
161
|
+
if (local.length)
|
|
162
|
+
unresolved[bookSlug] = local;
|
|
163
|
+
mapNav.push({ item: bookNavItem(title, route), groups: groupPath(mapInfo, groupKeys) });
|
|
164
|
+
mapsProcessed++;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
// ── per-topic (default) ────────────────────────────────
|
|
168
|
+
// Per-topic metadata (subject/audience/author/…) in one request per map;
|
|
169
|
+
// the /content HTML has no <head>, so this is the only source. Best-effort:
|
|
170
|
+
// if the list fails, frontmatter falls back to map-level metadata. When
|
|
171
|
+
// `fullTopicMetadata` is set we instead fetch each topic individually (one
|
|
172
|
+
// request per topic) for its technical numerics + per-topic `updated`.
|
|
173
|
+
const topicMetaById = new Map();
|
|
174
|
+
if (!opts.fullTopicMetadata) {
|
|
175
|
+
try {
|
|
176
|
+
for (const tp of await client.getTopics(id)) {
|
|
177
|
+
if (tp.id && tp.metadata)
|
|
178
|
+
topicMetaById.set(tp.id, tp.metadata);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch (e) {
|
|
182
|
+
if (e instanceof KhubAuthError)
|
|
183
|
+
throw e;
|
|
184
|
+
log(` ! topic metadata unavailable for ${mapInfo?.title ?? id}: ${e.message}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
for (const t of topics) {
|
|
188
|
+
const slug = slugFromPrettyUrl(t.prettyUrl) || `topic/${(t.contentId ?? "").toLowerCase()}`;
|
|
189
|
+
if (seen.has(slug))
|
|
190
|
+
continue;
|
|
191
|
+
seen.add(slug);
|
|
192
|
+
let html;
|
|
193
|
+
try {
|
|
194
|
+
html = await client.getTopicContent(id, t.contentId);
|
|
195
|
+
}
|
|
196
|
+
catch (e) {
|
|
197
|
+
if (e instanceof KhubAuthError)
|
|
198
|
+
throw e; // gated portal — abort
|
|
199
|
+
log(` ! skip ${slug}: ${e.message}`);
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
const local = [];
|
|
203
|
+
const { tree, title, topicType } = htmlToTree(html, {
|
|
204
|
+
resolveHref: (h) => {
|
|
205
|
+
const r = resolveHref(h, slug, hrefPrefix);
|
|
206
|
+
if (!r.resolved && h)
|
|
207
|
+
local.push(h);
|
|
208
|
+
return r.href;
|
|
209
|
+
},
|
|
210
|
+
resolveTocId,
|
|
211
|
+
onImage,
|
|
212
|
+
});
|
|
213
|
+
// Per-topic metadata: full (one call/topic) when opted in, else the
|
|
214
|
+
// cheap per-map list. Technical numerics only emit when we have the full
|
|
215
|
+
// set — otherwise the only values are misleading book totals.
|
|
216
|
+
let topicMeta = t.contentId ? topicMetaById.get(t.contentId) : undefined;
|
|
217
|
+
if (opts.fullTopicMetadata && t.contentId) {
|
|
218
|
+
try {
|
|
219
|
+
topicMeta = (await client.getTopic(id, t.contentId))?.metadata ?? topicMeta;
|
|
220
|
+
}
|
|
221
|
+
catch (e) {
|
|
222
|
+
if (e instanceof KhubAuthError)
|
|
223
|
+
throw e;
|
|
224
|
+
log(` ! full metadata unavailable for ${slug}: ${e.message}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
const finalTitle = title || t.title || labelFromSlug(slug);
|
|
228
|
+
const frontmatter = buildFrontmatter({
|
|
229
|
+
title: finalTitle,
|
|
230
|
+
topicType,
|
|
231
|
+
mapMeta: mapInfo?.metadata,
|
|
232
|
+
topicMeta,
|
|
233
|
+
metadataAllow: opts.metadataAllow,
|
|
234
|
+
technical: !!opts.fullTopicMetadata,
|
|
235
|
+
});
|
|
236
|
+
const headings = extractHeadings(tree);
|
|
237
|
+
const meta = parseMeta(frontmatter, { slug, taxonomyNames: opts.taxonomyNames });
|
|
238
|
+
pages.push({ slug, title: finalTitle, tree, headings, frontmatter, meta });
|
|
239
|
+
if (local.length)
|
|
240
|
+
unresolved[slug] = local;
|
|
241
|
+
}
|
|
242
|
+
const item = { label: mapInfo?.title ?? id, children: tocToNav(toc, hrefPrefix) };
|
|
243
|
+
// Book-type guides get an additive single-page rollup; articles stay
|
|
244
|
+
// per-topic. Driven by the editorialType facet (#single-page-books).
|
|
245
|
+
if (opts.singlePageBooks && metaValue(mapInfo, "ft:editorialType") === "book") {
|
|
246
|
+
item.singlePage = "yes";
|
|
247
|
+
}
|
|
248
|
+
mapNav.push({ item, groups: groupPath(mapInfo, groupKeys) });
|
|
249
|
+
mapsProcessed++;
|
|
250
|
+
}
|
|
251
|
+
if (groupKeys.length) {
|
|
252
|
+
const groupCount = new Set(mapNav.map((m) => m.groups.join(" / "))).size;
|
|
253
|
+
log(`grouped ${mapNav.length} maps into ${groupCount} ${groupKeys.join(" / ")} section(s)`);
|
|
254
|
+
}
|
|
255
|
+
const nav = buildGroupedNav(mapNav);
|
|
256
|
+
const assets = [...assetBytes].map(([path, data]) => ({ path, data }));
|
|
257
|
+
return { pages, nav, unresolved, mapsProcessed, assets };
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Collapse stale duplicate publications. FT khubs commonly list the same guide
|
|
261
|
+
* twice with an identical title + `Version_FT` (often both "Latest"), differing
|
|
262
|
+
* only by `ft:lastEdition` — a leftover older publication alongside the current
|
|
263
|
+
* one. Both produce the same title-derived slug, so their pages overwrite each
|
|
264
|
+
* other (last-wins) but each still contributes a nav entry → the guide appears
|
|
265
|
+
* twice in the nav. Keep only the freshest edition per (title, version); input
|
|
266
|
+
* order is otherwise preserved so grouped-nav output stays stable. `ft:lastEdition`
|
|
267
|
+
* is an ISO date (YYYY-MM-DD), so lexical `>` is chronological.
|
|
268
|
+
*/
|
|
269
|
+
function dedupeMapsByEdition(maps, log) {
|
|
270
|
+
const best = new Map();
|
|
271
|
+
for (const m of maps) {
|
|
272
|
+
// \u0001, not a literal NUL: a NUL byte makes grep classify this whole
|
|
273
|
+
// 430-line file as BINARY and skip it silently, so every plain-text
|
|
274
|
+
// search across it returns nothing. (That is how the single-page
|
|
275
|
+
// module below came to look like dead code.) The separator itself is
|
|
276
|
+
// load-bearing — it keeps a title ending in the version from colliding
|
|
277
|
+
// with the same title carrying that version as a separate field.
|
|
278
|
+
const key = `${m.title ?? m.id}\u0001${metaValue(m, "Version_FT") ?? ""}`;
|
|
279
|
+
const cur = best.get(key);
|
|
280
|
+
if (!cur || (metaValue(m, "ft:lastEdition") ?? "") > (metaValue(cur, "ft:lastEdition") ?? "")) {
|
|
281
|
+
best.set(key, m);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
const keepIds = new Set([...best.values()].map((m) => m.id));
|
|
285
|
+
const kept = maps.filter((m) => keepIds.has(m.id));
|
|
286
|
+
const dropped = maps.length - kept.length;
|
|
287
|
+
if (dropped > 0) {
|
|
288
|
+
log(`deduped ${dropped} stale duplicate map(s) — kept freshest ft:lastEdition per title+version`);
|
|
289
|
+
}
|
|
290
|
+
return kept;
|
|
291
|
+
}
|
|
292
|
+
/** First value of a map's metadata facet, if present. */
|
|
293
|
+
function metaValue(map, key) {
|
|
294
|
+
const v = map?.metadata?.find((m) => m.key === key)?.values?.[0];
|
|
295
|
+
return v && v.trim() ? v.trim() : undefined;
|
|
296
|
+
}
|
|
297
|
+
/** Resolve the grouping facet keys: explicit, forced-flat, or auto-detected. */
|
|
298
|
+
function resolveGroupKeys(groupBy, maps) {
|
|
299
|
+
if (groupBy !== undefined) {
|
|
300
|
+
const g = groupBy.trim().toLowerCase();
|
|
301
|
+
if (g === "" || g === "none" || g === "flat")
|
|
302
|
+
return [];
|
|
303
|
+
return groupBy.split(",").map((s) => s.trim()).filter(Boolean);
|
|
304
|
+
}
|
|
305
|
+
// Auto: prefer Category, then Product — group only when the facet is present on
|
|
306
|
+
// most maps AND has more than one distinct value (else grouping adds nothing).
|
|
307
|
+
for (const key of ["Category", "Product"]) {
|
|
308
|
+
const present = maps.filter((m) => metaValue(m, key)).length;
|
|
309
|
+
const distinct = new Set(maps.map((m) => metaValue(m, key)).filter(Boolean)).size;
|
|
310
|
+
if (distinct > 1 && present / Math.max(1, maps.length) > 0.5)
|
|
311
|
+
return [key];
|
|
312
|
+
}
|
|
313
|
+
return [];
|
|
314
|
+
}
|
|
315
|
+
/** The group path for a map (one label per group key; missing → "Other"). */
|
|
316
|
+
function groupPath(map, keys) {
|
|
317
|
+
return keys.map((k) => metaValue(map, k) ?? "Other");
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Nest per-map nav nodes under their facet group path, creating shared parent
|
|
321
|
+
* group nodes. Group levels (and maps within a group) are sorted by label; a
|
|
322
|
+
* map's own TOC children are left in document order.
|
|
323
|
+
*/
|
|
324
|
+
function buildGroupedNav(items) {
|
|
325
|
+
const roots = [];
|
|
326
|
+
const groupNodes = new Set();
|
|
327
|
+
const findOrAdd = (siblings, label) => {
|
|
328
|
+
let node = siblings.find((s) => s.label === label && groupNodes.has(s));
|
|
329
|
+
if (!node) {
|
|
330
|
+
node = { label, children: [] };
|
|
331
|
+
groupNodes.add(node);
|
|
332
|
+
siblings.push(node);
|
|
333
|
+
}
|
|
334
|
+
return node;
|
|
335
|
+
};
|
|
336
|
+
for (const { item, groups } of items) {
|
|
337
|
+
let level = roots;
|
|
338
|
+
for (const g of groups)
|
|
339
|
+
level = findOrAdd(level, g).children;
|
|
340
|
+
level.push(item);
|
|
341
|
+
}
|
|
342
|
+
const sortGroups = (nodes) => {
|
|
343
|
+
nodes.sort((a, b) => a.label.localeCompare(b.label));
|
|
344
|
+
for (const n of nodes)
|
|
345
|
+
if (groupNodes.has(n) && n.children)
|
|
346
|
+
sortGroups(n.children);
|
|
347
|
+
};
|
|
348
|
+
sortGroups(roots);
|
|
349
|
+
return roots;
|
|
350
|
+
}
|
|
351
|
+
function labelFromSlug(slug) {
|
|
352
|
+
return (slug.split("/").pop() ?? slug).replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
353
|
+
}
|
|
354
|
+
//# sourceMappingURL=importer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"importer.js","sourceRoot":"","sources":["../src/importer.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @dogsbay/format-fluidtopics-rest
|
|
3
|
+
*
|
|
4
|
+
* Importer for a *live* Fluid Topics portal via the public khub REST API. It
|
|
5
|
+
* reverse-engineers each topic's DITA-OT HTML5 (where the DITA element
|
|
6
|
+
* vocabulary survives in `class` names) into the universal TreeNode model —
|
|
7
|
+
* producing ExportPage[] + NavItem[] for any public FT portal (ServiceNow,
|
|
8
|
+
* Johnson Controls, FT's own docs).
|
|
9
|
+
*
|
|
10
|
+
* The sibling `@dogsbay/format-fluidtopics-markdown` does the same job from a
|
|
11
|
+
* Git Markdown export (Option A); this is Option B (live REST / Option B of the
|
|
12
|
+
* A→B→C migration plan).
|
|
13
|
+
*/
|
|
14
|
+
export type { TreeNode, ExportPage, NavItem, Heading } from "@dogsbay/types";
|
|
15
|
+
export { htmlToTree } from "./html-to-tree.js";
|
|
16
|
+
export type { HtmlToTreeResult } from "./html-to-tree.js";
|
|
17
|
+
export { KhubClient, KhubAuthError, normalizeKhubBase, tocTopics } from "./khub.js";
|
|
18
|
+
export type { KhubMap, KhubTocNode, KhubClientOptions } from "./khub.js";
|
|
19
|
+
export { importFluidTopicsRest } from "./importer.js";
|
|
20
|
+
export type { RestImportOptions, RestImportResult } from "./importer.js";
|
|
21
|
+
export { slugFromPrettyUrl, routeFromSlug, resolveHref } from "./links.js";
|
|
22
|
+
export { buildFrontmatter } from "./frontmatter.js";
|
|
23
|
+
export { tocToNav } from "./nav.js";
|
|
24
|
+
export { extractHeadings } from "./headings.js";
|
|
25
|
+
export { inlineFromChildren } from "./inline-html.js";
|
|
26
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAE7E,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACpF,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEzE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { htmlToTree } from "./html-to-tree.js";
|
|
2
|
+
export { KhubClient, KhubAuthError, normalizeKhubBase, tocTopics } from "./khub.js";
|
|
3
|
+
export { importFluidTopicsRest } from "./importer.js";
|
|
4
|
+
export { slugFromPrettyUrl, routeFromSlug, resolveHref } from "./links.js";
|
|
5
|
+
export { buildFrontmatter } from "./frontmatter.js";
|
|
6
|
+
export { tocToNav } from "./nav.js";
|
|
7
|
+
export { extractHeadings } from "./headings.js";
|
|
8
|
+
export { inlineFromChildren } from "./inline-html.js";
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG/C,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGpF,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert DITA-OT HTML5 *inline* content (a cheerio/domhandler node list) into
|
|
3
|
+
* Dogsbay InlineNode[] (flat-annotation / Notion model).
|
|
4
|
+
*
|
|
5
|
+
* DITA-OT emits inline DITA elements as classed spans/anchors:
|
|
6
|
+
* <span class="ph">…</span> → unwrapped (DITA <ph>)
|
|
7
|
+
* <span class="keyword|term|uicontrol">→ unwrapped to text
|
|
8
|
+
* <span class="codeph">…</span> → inline code (monospace domain)
|
|
9
|
+
* <a class="xref|link" href>…</a> → link
|
|
10
|
+
* <strong>/<b>, <em>/<i> → bold / italic annotations
|
|
11
|
+
* <img> → image
|
|
12
|
+
* FT also wraps text in <span class="sentence"> (translation segmentation) and
|
|
13
|
+
* emotion's <span class="css-…">; both are unwrapped.
|
|
14
|
+
*/
|
|
15
|
+
import type { InlineNode } from "@dogsbay/types";
|
|
16
|
+
/** Minimal structural view of a domhandler/cheerio node. */
|
|
17
|
+
export interface DomNode {
|
|
18
|
+
type: string;
|
|
19
|
+
name?: string;
|
|
20
|
+
data?: string;
|
|
21
|
+
attribs?: Record<string, string>;
|
|
22
|
+
children?: DomNode[];
|
|
23
|
+
}
|
|
24
|
+
export interface InlineOptions {
|
|
25
|
+
/** Rewrites an href; defaults to identity. */
|
|
26
|
+
resolveHref?: (href: string) => string;
|
|
27
|
+
/** Rewrites an image src; defaults to identity. */
|
|
28
|
+
resolveSrc?: (src: string) => string;
|
|
29
|
+
/**
|
|
30
|
+
* Rich image hook — receives the FT image metadata (incl. `data:` src,
|
|
31
|
+
* `data-ft-asset-display-name`, `data-ft-resource-id`) and returns the src to
|
|
32
|
+
* use. Lets the importer extract `data:` images to real `_assets` files.
|
|
33
|
+
* Takes precedence over `resolveSrc`.
|
|
34
|
+
*/
|
|
35
|
+
onImage?: (img: {
|
|
36
|
+
src: string;
|
|
37
|
+
alt?: string;
|
|
38
|
+
displayName?: string;
|
|
39
|
+
resourceId?: string;
|
|
40
|
+
}) => string;
|
|
41
|
+
/**
|
|
42
|
+
* Resolve an FT internal cross-reference (`<a class="ft-internal-link"
|
|
43
|
+
* data-tocid=… data-mapid=…>` — hrefless, resolved by FT's client at
|
|
44
|
+
* runtime) to a route. Return undefined to leave it as plain text.
|
|
45
|
+
*/
|
|
46
|
+
resolveTocId?: (tocId: string, mapId?: string) => string | undefined;
|
|
47
|
+
}
|
|
48
|
+
/** Convert a node's children into InlineNode[]. */
|
|
49
|
+
export declare function inlineFromChildren(nodes: DomNode[] | undefined, opts?: InlineOptions): InlineNode[];
|
|
50
|
+
/** Plain text of a node and its descendants (whitespace-collapsed). */
|
|
51
|
+
export declare function textContent(n: DomNode): string;
|
|
52
|
+
//# sourceMappingURL=inline-html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inline-html.d.ts","sourceRoot":"","sources":["../src/inline-html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,gBAAgB,CAAC;AAE7D,4DAA4D;AAC5D,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;CACtB;AAcD,MAAM,WAAW,aAAa;IAC5B,8CAA8C;IAC9C,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACvC,mDAAmD;IACnD,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IACrC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;IACpG;;;;OAIG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;CACtE;AAED,mDAAmD;AACnD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,SAAS,EAAE,IAAI,GAAE,aAAkB,GAAG,UAAU,EAAE,CAIvG;AA0GD,uEAAuE;AACvE,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAU9C"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// Monospace (code) DITA inline domains. NB: `cmd` is deliberately excluded — in
|
|
2
|
+
// a task, <span class="ph cmd"> is the *step command* (an instruction sentence,
|
|
3
|
+
// i.e. prose), not code. `cmdname` (a literal command name) stays; the word
|
|
4
|
+
// boundary means it never matches the `cmd` step class.
|
|
5
|
+
const CODE_CLASSES = /\b(codeph|cmdname|filepath|userinput|systemoutput|parmname|varname|option|kbd|synph)\b/;
|
|
6
|
+
/** Convert a node's children into InlineNode[]. */
|
|
7
|
+
export function inlineFromChildren(nodes, opts = {}) {
|
|
8
|
+
const out = [];
|
|
9
|
+
walk(nodes ?? [], { bold: false, italic: false, strike: false }, out, opts);
|
|
10
|
+
return trimEdges(out);
|
|
11
|
+
}
|
|
12
|
+
function classOf(n) {
|
|
13
|
+
return n.attribs?.class ?? "";
|
|
14
|
+
}
|
|
15
|
+
function walk(nodes, ann, out, opts) {
|
|
16
|
+
for (const n of nodes) {
|
|
17
|
+
if (n.type === "text") {
|
|
18
|
+
const text = (n.data ?? "").replace(/\s+/g, " ");
|
|
19
|
+
if (text)
|
|
20
|
+
out.push(makeText(text, ann));
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (n.type !== "tag")
|
|
24
|
+
continue; // skip comments, etc.
|
|
25
|
+
const name = (n.name ?? "").toLowerCase();
|
|
26
|
+
const cls = classOf(n);
|
|
27
|
+
switch (name) {
|
|
28
|
+
case "strong":
|
|
29
|
+
case "b":
|
|
30
|
+
walk(n.children ?? [], { ...ann, bold: true }, out, opts);
|
|
31
|
+
break;
|
|
32
|
+
case "em":
|
|
33
|
+
case "i":
|
|
34
|
+
walk(n.children ?? [], { ...ann, italic: true }, out, opts);
|
|
35
|
+
break;
|
|
36
|
+
case "s":
|
|
37
|
+
case "del":
|
|
38
|
+
case "strike":
|
|
39
|
+
walk(n.children ?? [], { ...ann, strike: true }, out, opts);
|
|
40
|
+
break;
|
|
41
|
+
case "code":
|
|
42
|
+
out.push({ type: "code", text: textContent(n) });
|
|
43
|
+
break;
|
|
44
|
+
case "a": {
|
|
45
|
+
const rawHref = n.attribs?.href ?? "";
|
|
46
|
+
let href;
|
|
47
|
+
if (rawHref) {
|
|
48
|
+
href = (opts.resolveHref ?? ((h) => h))(rawHref);
|
|
49
|
+
}
|
|
50
|
+
else if (opts.resolveTocId && n.attribs?.["data-tocid"]) {
|
|
51
|
+
// FT internal xref: hrefless <a data-tocid data-mapid>.
|
|
52
|
+
href = opts.resolveTocId(n.attribs["data-tocid"], n.attribs["data-mapid"]);
|
|
53
|
+
}
|
|
54
|
+
const children = [];
|
|
55
|
+
walk(n.children ?? [], ann, children, opts);
|
|
56
|
+
const kids = children.length ? children : [{ type: "text", text: textContent(n) }];
|
|
57
|
+
if (href) {
|
|
58
|
+
out.push({ type: "link", href, children: kids });
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
// Unresolvable / hrefless → emit the text, not a dead empty link.
|
|
62
|
+
out.push(...kids);
|
|
63
|
+
}
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
case "img": {
|
|
67
|
+
const rawSrc = n.attribs?.src ?? "";
|
|
68
|
+
const displayName = n.attribs?.["data-ft-asset-display-name"];
|
|
69
|
+
const resourceId = n.attribs?.["data-ft-resource-id"];
|
|
70
|
+
// alt: explicit alt, else the FT display-name (filename) for a11y.
|
|
71
|
+
const alt = n.attribs?.alt || displayName || undefined;
|
|
72
|
+
let src = rawSrc;
|
|
73
|
+
if (opts.onImage)
|
|
74
|
+
src = opts.onImage({ src: rawSrc, alt, displayName, resourceId });
|
|
75
|
+
else if (opts.resolveSrc)
|
|
76
|
+
src = opts.resolveSrc(rawSrc);
|
|
77
|
+
const img = { type: "image", src };
|
|
78
|
+
if (alt)
|
|
79
|
+
img.alt = alt;
|
|
80
|
+
out.push(img);
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
case "br":
|
|
84
|
+
out.push({ type: "break" });
|
|
85
|
+
break;
|
|
86
|
+
case "span": {
|
|
87
|
+
const tocid = n.attribs?.["data-tocid"];
|
|
88
|
+
if (CODE_CLASSES.test(cls)) {
|
|
89
|
+
out.push({ type: "code", text: textContent(n) });
|
|
90
|
+
}
|
|
91
|
+
else if (tocid && opts.resolveTocId) {
|
|
92
|
+
// FT internal xref rendered as a hrefless span:
|
|
93
|
+
// <span class="xref ft-internal-link" data-tocid data-mapid>text</span>
|
|
94
|
+
const href = opts.resolveTocId(tocid, n.attribs?.["data-mapid"]);
|
|
95
|
+
const children = [];
|
|
96
|
+
walk(n.children ?? [], ann, children, opts);
|
|
97
|
+
const kids = children.length ? children : [{ type: "text", text: textContent(n) }];
|
|
98
|
+
if (href)
|
|
99
|
+
out.push({ type: "link", href, children: kids });
|
|
100
|
+
else
|
|
101
|
+
out.push(...kids);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
// ph / keyword / term / uicontrol / sentence / css-… → unwrap
|
|
105
|
+
walk(n.children ?? [], ann, out, opts);
|
|
106
|
+
}
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
default:
|
|
110
|
+
// sup/sub/wbr/abbr/etc. → unwrap to their inline content
|
|
111
|
+
walk(n.children ?? [], ann, out, opts);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function makeText(text, ann) {
|
|
116
|
+
const span = { type: "text", text };
|
|
117
|
+
if (ann.bold)
|
|
118
|
+
span.bold = true;
|
|
119
|
+
if (ann.italic)
|
|
120
|
+
span.italic = true;
|
|
121
|
+
if (ann.strike)
|
|
122
|
+
span.strikethrough = true;
|
|
123
|
+
return span;
|
|
124
|
+
}
|
|
125
|
+
/** Plain text of a node and its descendants (whitespace-collapsed). */
|
|
126
|
+
export function textContent(n) {
|
|
127
|
+
let s = "";
|
|
128
|
+
const rec = (nodes) => {
|
|
129
|
+
for (const c of nodes) {
|
|
130
|
+
if (c.type === "text")
|
|
131
|
+
s += c.data ?? "";
|
|
132
|
+
else if (c.children)
|
|
133
|
+
rec(c.children);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
rec(n.children ?? []);
|
|
137
|
+
return s.replace(/\s+/g, " ").trim();
|
|
138
|
+
}
|
|
139
|
+
/** Trim leading/trailing whitespace-only text from the inline run. */
|
|
140
|
+
function trimEdges(nodes) {
|
|
141
|
+
const a = [...nodes];
|
|
142
|
+
while (a.length && a[0].type === "text" && a[0].text.trim() === "")
|
|
143
|
+
a.shift();
|
|
144
|
+
while (a.length && a[a.length - 1].type === "text" && a[a.length - 1].text.trim() === "")
|
|
145
|
+
a.pop();
|
|
146
|
+
// Trim the inner edges of the first/last text spans.
|
|
147
|
+
if (a.length) {
|
|
148
|
+
const first = a[0];
|
|
149
|
+
if (first.type === "text")
|
|
150
|
+
first.text = first.text.replace(/^\s+/, "");
|
|
151
|
+
const last = a[a.length - 1];
|
|
152
|
+
if (last.type === "text")
|
|
153
|
+
last.text = last.text.replace(/\s+$/, "");
|
|
154
|
+
}
|
|
155
|
+
return a;
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=inline-html.js.map
|