@mdgate/fb2 0.1.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/README.md +26 -0
- package/dist/fb2.d.ts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/to-markdown.d.ts +6 -0
- package/package.json +42 -0
package/README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# @mdgate/fb2
|
|
2
|
+
|
|
3
|
+
Convert FictionBook (FB2) files to Markdown. Outputs GitHub-Flavored Markdown. Works in Node, Edge,
|
|
4
|
+
and browsers. No native addons.
|
|
5
|
+
|
|
6
|
+
Handles: `.fb2`, `.fb2.zip`
|
|
7
|
+
|
|
8
|
+
## Usage
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { toMarkdown } from '@mdgate/fb2';
|
|
12
|
+
|
|
13
|
+
const markdown = await toMarkdown(bytes);
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Compose with other converters:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { create } from '@mdgate/core';
|
|
20
|
+
import { fb2 } from '@mdgate/fb2';
|
|
21
|
+
|
|
22
|
+
const convert = create([fb2()]);
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Part of [mdgate converters](https://github.com/mdgate/converters); install
|
|
26
|
+
`@mdgate/converters` for every format at once.
|
package/dist/fb2.d.ts
ADDED
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{detectZipDoc as xn,hasOleMagic as R,Package as wn}from"@mdgate/containers";import{ConvertError as l}from"@mdgate/core";import{documentToMarkdown as Cn}from"@mdgate/document";import{fileExtension as Bn}from"@mdgate/utils";import{ns as $,parseXml as q}from"@mdgate/containers";import{ConvertError as W}from"@mdgate/core";import{cellSpanning as G,emptyDocument as K,GridBuilder as Y,heading as J,inlinesAreEmpty as u,inlinesToPlainText as V,MAX_ASSET_TOTAL_BYTES as nn,PLAIN as p,plain as U,resolveHeaderRows as en}from"@mdgate/document";import{cleanText as w,collapseWs as C,isAbsoluteUri as N,trim as B}from"@mdgate/utils";var v={bold:!1,italic:!0,strike:!1,code:!1},tn=new Set(["notes","comments","footnotes"]);function F(n){let e=q(n),i=rn(e);if(i===void 0)throw W.malformed("not a FictionBook document");let t={assets:[],assetTotal:0,byOrigin:new Map};on(i,t);let r=K(),o=sn(i,r,t),s=[];for(let a of k(i,"body")){let f=(a.attrAny("name")??"").toLowerCase();if(tn.has(f)){cn(a,t,s);continue}an(a,r,t,o)}return r.notes=s,r.assets=t.assets,r}function rn(n){if(n.local==="FictionBook")return n;for(let e of n.childElems())if(e.local==="FictionBook")return e;return}function on(n,e){for(let i of n.childElems()){if(i.local!=="binary")continue;let t=i.attrAny("id");if(t===void 0||t.length===0)continue;let r=bn(i.text());if(r===void 0)continue;let o=i.attrAny("content-type")??yn(r);kn(e,t,o,r)}}function sn(n,e,i){let t=g(n,"description"),r=t!==void 0?g(t,"title-info"):void 0;if(r===void 0)return;let o=y(r,"book-title");if(o.length>0)e.blocks.push(J(1,[U(o)]));let s=[];for(let d of k(r,"author")){let h=mn(d);if(h.length>0)s.push(h)}if(s.length>0)e.blocks.push({type:"paragraph",inlines:[U(s.join(", "))]});let a=g(r,"annotation");if(a!==void 0){let d=E(a,i,2);if(d.length>0)e.blocks.push({type:"blockQuote",blocks:d})}let f=g(r,"coverpage");if(f!==void 0)for(let d of k(f,"image")){let h=S(d,i);if(h!==void 0)e.blocks.push({type:"paragraph",inlines:[h]})}return o.length>0?o:void 0}function an(n,e,i,t){let r=g(n,"title");if(r!==void 0){let s=b(r,i),a=B(V(s));if(!u(s)&&!En(a,t))e.blocks.push({type:"heading",level:t!==void 0?2:1,anchor:void 0,content:s})}let o=t!==void 0?2:1;for(let s of n.childElems()){if(s.local==="title")continue;if(s.local==="section")e.blocks.push(...I(s,i,o));else e.blocks.push(...A(s,i,o))}}function cn(n,e,i){for(let t of k(n,"section"))M(t,e,i)}function M(n,e,i){let t=n.attrAny("id");if(t!==void 0&&t.length>0){let r=un(n,e);if(r.length>0)i.push({id:t,kind:"footnote",blocks:r})}for(let r of k(n,"section"))M(r,e,i)}function un(n,e){let i=[];for(let t of n.childElems()){if(t.local==="section")continue;if(t.local==="title"){let r=b(t,e);if(!u(r))i.push({type:"paragraph",inlines:r});continue}i.push(...A(t,e,2))}return i}function I(n,e,i){let t=[],r=n.attrAny("id"),o=g(n,"title");if(o!==void 0){let a=b(o,e);if(!u(a))t.push({type:"heading",level:i,anchor:r,content:a});else if(r!==void 0)t.push({type:"paragraph",inlines:[{type:"anchor",id:r}]})}else if(r!==void 0)t.push({type:"paragraph",inlines:[{type:"anchor",id:r}]});let s=Math.min(i+1,6);for(let a of n.childElems()){if(a.local==="title")continue;if(a.local==="section")t.push(...I(a,e,s));else t.push(...A(a,e,i))}return t}function E(n,e,i){let t=[];for(let r of n.childElems())if(r.local==="section")t.push(...I(r,e,i));else t.push(...A(r,e,i));return t}function A(n,e,i){switch(n.local){case"p":{let t=c(n,e,p);return u(t)?[]:[{type:"paragraph",inlines:t}]}case"subtitle":{let t=c(n,e,p);if(u(t))return[];return[{type:"heading",level:Math.min(i+1,6),anchor:void 0,content:t}]}case"empty-line":return[];case"poem":return ln(n,e,i);case"cite":case"epigraph":case"annotation":{let t=E(n,e,i);return t.length===0?[]:[{type:"blockQuote",blocks:t}]}case"text-author":{let t=c(n,e,v);return u(t)?[]:[{type:"paragraph",inlines:t}]}case"table":{let t=fn(n,e,i);return t===void 0?[]:[t]}case"image":{let t=S(n,e);return t===void 0?[]:[{type:"paragraph",inlines:[t]}]}case"title":{let t=b(n,e);if(u(t))return[];return[{type:"heading",level:i,anchor:void 0,content:t}]}case"stanza":return O(n,e);case"v":{let t=c(n,e,p);return u(t)?[]:[{type:"paragraph",inlines:t}]}case"date":{let t=c(n,e,p);return u(t)?[]:[{type:"paragraph",inlines:t}]}default:return E(n,e,i)}}function ln(n,e,i){let t=[];for(let r of n.childElems())switch(r.local){case"title":{let o=b(r,e);if(!u(o))t.push({type:"heading",level:Math.min(i+1,6),anchor:void 0,content:o});break}case"epigraph":{let o=E(r,e,i);if(o.length>0)t.push({type:"blockQuote",blocks:o});break}case"stanza":t.push(...O(r,e));break;case"text-author":{let o=c(r,e,v);if(!u(o))t.push({type:"paragraph",inlines:o});break}case"date":{let o=c(r,e,p);if(!u(o))t.push({type:"paragraph",inlines:o});break}default:t.push(...A(r,e,i));break}return t.length===0?[]:[{type:"blockQuote",blocks:t}]}function O(n,e){let i=[],t=[];for(let r of n.childElems()){if(r.local==="title"){let o=b(r,e);if(!u(o))t.push({type:"paragraph",inlines:o});continue}if(r.local==="v"){let o=c(r,e,p);if(!u(o))i.push(o)}}if(i.length>0){let r=[];for(let o=0;o<i.length;o+=1){if(o>0)r.push({type:"lineBreak"});r.push(...i[o])}t.push({type:"paragraph",inlines:r})}return t}function fn(n,e,i){let t=k(n,"tr");if(t.length===0)return;let r=new Y,o=0;for(let a=0;a<t.length;a+=1){let f=t[a];r.nextRow();let d=!0,h=!1;for(let m of f.childElems()){if(m.local!=="td"&&m.local!=="th")continue;if(h=!0,m.local!=="th")d=!1;let Z=L(m.attrAny("colspan")),j=L(m.attrAny("rowspan"));r.place(G(E(m,e,i),Z,j))}if(a===o&&d&&h)o+=1}let s=r.finish("data");if(s.grid.length===0)return;return s.headerRows=en(s,o),{type:"table",table:s}}function c(n,e,i){let t=[];for(let r of n.children){if(r.type==="text"){let o=C(w(r.text));if(o.length>0)t.push({type:"text",text:o,style:i});continue}dn(r.elem,e,i,t)}return t}function dn(n,e,i,t){switch(n.local){case"emphasis":t.push(...c(n,e,{...i,italic:!0}));return;case"strong":t.push(...c(n,e,{...i,bold:!0}));return;case"strikethrough":t.push(...c(n,e,{...i,strike:!0}));return;case"code":t.push(...c(n,e,{...i,code:!0}));return;case"a":{let r=D(n),o=(n.attrAny("type")??"").toLowerCase();if(r!==void 0&&(o==="note"||o==="footnote")){let f=r.startsWith("#")?r.slice(1):r;if(f.length>0)t.push({type:"noteRef",id:f});return}let s=c(n,e,i),a=gn(r);if(a!==void 0)t.push({type:"link",content:s,target:a});else t.push(...s);return}case"image":{let r=S(n,e);if(r!==void 0)t.push(r);return}case"style":case"sub":case"sup":t.push(...c(n,e,i));return;default:if(An(n.local)){let r=C(w(n.text()));if(r.length>0)t.push({type:"text",text:r,style:i});return}t.push(...c(n,e,i))}}function S(n,e){let i=D(n),t=B(n.attrAny("alt")??n.attrAny("title")??""),r=pn(i,e),o=t.length>0?t:hn(i);if(r===void 0&&o.length===0)return;return{type:"image",alt:o,source:r??{type:"unavailable"}}}function pn(n,e){if(n===void 0||n.length===0)return;if(N(n)&&!n.startsWith("#"))return{type:"external",url:n};let i=n.startsWith("#")?n.slice(1):n;if(i.length===0)return;let t=e.byOrigin.get(i);if(t===void 0)return{type:"unavailable"};return{type:"asset",id:t}}function hn(n){if(n===void 0||n.length===0)return"";return n.startsWith("#")?n.slice(1):n}function gn(n){if(n===void 0||n.length===0)return;if(n.startsWith("#")){let e=n.slice(1);return e.length>0?{type:"anchor",id:e}:void 0}if(N(n))return{type:"external",url:n};return{type:"relative",url:n}}function b(n,e){let i=[];for(let t of n.childElems()){if(t.local==="empty-line")continue;let r=c(t,e,p);if(u(r))continue;if(i.length>0)i.push({type:"text",text:" ",style:p});i.push(...r)}if(i.length>0)return i;return c(n,e,p)}function mn(n){let e=y(n,"first-name"),i=y(n,"middle-name"),t=y(n,"last-name"),r=y(n,"nickname"),o=[e,i,t].filter((s)=>s.length>0);if(o.length>0)return o.join(" ");return r}function kn(n,e,i,t){let r=n.byOrigin.get(e);if(r!==void 0)return r;if(n.assetTotal+=t.length,n.assetTotal>nn)throw W.resourceLimit("max_asset_total_bytes","embedded assets exceed the retained-bytes cap");let o=n.assets.length;return n.byOrigin.set(e,o),n.assets.push({id:o,mediaType:i,originPart:e,bytes:t.slice()}),o}function bn(n){let e="";for(let i=0;i<n.length;i+=1){let t=n.charCodeAt(i);if(t===9||t===10||t===13||t===32)continue;e+=n[i]}if(e.length===0)return;try{let i=atob(e),t=new Uint8Array(i.length);for(let r=0;r<i.length;r+=1)t[r]=i.charCodeAt(r);return t}catch{return}}function yn(n){if(n.length>=8&&n[0]===137&&n[1]===80&&n[2]===78&&n[3]===71)return"image/png";if(n.length>=3&&n[0]===255&&n[1]===216&&n[2]===255)return"image/jpeg";if(n.length>=3&&n[0]===71&&n[1]===73&&n[2]===70)return"image/gif";return"application/octet-stream"}function D(n){return n.attr($.XLINK,"href")??n.attrAny("href")}function g(n,e){return n.childElems().find((i)=>i.local===e)}function k(n,e){return n.childElems().filter((i)=>i.local===e)}function y(n,e){let i=g(n,e);return i===void 0?"":B(C(w(i.text())))}function En(n,e){if(e===void 0)return!1;return n.toLowerCase()===e.toLowerCase()}function An(n){return n==="p"||n==="poem"||n==="cite"||n==="table"||n==="subtitle"||n==="empty-line"||n==="section"||n==="epigraph"}function L(n){if(n===void 0)return 1;let e=Number.parseInt(n,10);if(!Number.isFinite(e)||e<1)return 1;return Math.min(e,1000)}var In="http://www.gribuser.ru/xml/fictionbook/";function T(){return{id:"fb2",sniff(n,e){if(z(n))return 2;if(e?.path!==void 0&&Un(e.path))return 1;return 0},convert(n){return{markdown:Cn(F(Sn(n)))}}}}function Sn(n){if(H(n))throw l.unsupported("pdf");if(R(n))throw l.unsupported("ole");if(X(n)){let e=xn(n);if(e!==void 0)throw l.unsupported(e);return Tn(n)}return n}function Tn(n){let e;try{e=wn.open(n)}catch(t){if(t instanceof l){if(P(t))throw l.encrypted();throw t}throw l.malformed("not a readable zip archive")}let i;for(let t of e.partNames()){if(t.endsWith("/")||Ln(t))continue;let r=t.toLowerCase();if(!r.endsWith(".fb2")&&!r.endsWith(".xml"))continue;let o;try{o=e.part(t)}catch(s){if(s instanceof l&&s.isFatal())throw s;if(P(s))throw l.encrypted();continue}if(o===void 0)continue;if(r.endsWith(".fb2"))return o;if(i===void 0&&z(o))i=o}if(i!==void 0)return i;throw l.missingPart("*.fb2")}function z(n){if(H(n)||R(n)||X(n))return!1;let e=Q(n);if(e>=n.length||n[e]!==60)return!1;let i=Fn(n),t=Wn(i,0),r=i.slice(t);if(/^<([A-Za-z_][\w.-]*:)?FictionBook\b/i.test(r))return!0;return r.includes(In)}function Un(n){let i=(n.split(/[/\\]/).pop()??"").toLowerCase();return Bn(n)==="fb2"||i.endsWith(".fb2.zip")}function P(n){if(n instanceof l&&n.code==="encrypted")return!0;let e=n instanceof l?n.detail??"":"",t=(n instanceof Error?`${n.message} ${e}`:String(n)).toLowerCase();return t.includes("encrypted")||t.includes("password")}function Ln(n){for(let e of n.split("/"))if(e==="__MACOSX")return!0;return!1}function X(n){return n.length>=4&&n[0]===80&&n[1]===75&&(n[2]===3||n[2]===5||n[2]===7)&&(n[3]===4||n[3]===6||n[3]===8)}function H(n){let e=Q(n);return vn(n,"%PDF-",e)}function Q(n){let e=0;if(n.length>=3&&n[0]===239&&n[1]===187&&n[2]===191)e=3;while(e<n.length){let i=n[e];if(i!==9&&i!==10&&i!==13&&i!==32)break;e+=1}return e}function Wn(n,e){let i=x(n,e);if(n.charCodeAt(i)===65279)i=x(n,i+1);if(_(n,"<?xml",i)){let t=n.indexOf("?>",i);if(t<0)return i;i=x(n,t+2)}for(;;){if(n.startsWith("<!--",i)){let t=n.indexOf("-->",i+4);if(t<0)return i;i=x(n,t+3);continue}if(_(n,"<!doctype",i)){i=Nn(n,i),i=x(n,i);continue}break}return i}function Nn(n,e){let i=0;e+=2;while(e<n.length){let t=n[e];if(t==='"'||t==="'"){let r=t;e+=1;while(e<n.length&&n[e]!==r)e+=1;if(e<n.length)e+=1;continue}if(t==="<")i+=1;else if(t===">"){if(i===0)return e+1;i-=1}e+=1}return e}function x(n,e){while(e<n.length){let i=n.charCodeAt(e);if(i!==9&&i!==10&&i!==13&&i!==32)break;e+=1}return e}function _(n,e,i){if(i+e.length>n.length)return!1;for(let t=0;t<e.length;t+=1){let r=n.charCodeAt(i+t),o=e.charCodeAt(t);if(r===o)continue;let s=r>=65&&r<=90?r+32:r,a=o>=65&&o<=90?o+32:o;if(s!==a)return!1}return!0}function vn(n,e,i){if(i+e.length>n.length)return!1;for(let t=0;t<e.length;t+=1)if(n[i+t]!==e.charCodeAt(t))return!1;return!0}function Fn(n){let e=Math.min(n.length,8192);if(n.length>=2&&n[0]===255&&n[1]===254)return new TextDecoder("utf-16le").decode(n.subarray(0,e));if(n.length>=2&&n[0]===254&&n[1]===255)return new TextDecoder("utf-16be").decode(n.subarray(0,e));let i=0;if(n.length>=3&&n[0]===239&&n[1]===187&&n[2]===191)i=3;return new TextDecoder("utf-8",{fatal:!1}).decode(n.subarray(i,i+8192))}import{create as Mn}from"@mdgate/core";var On=Mn([T()]);function Dn(n,e){return On(n,e)}export{Dn as toMarkdown,T as fb2};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type ConvertHint } from '@mdgate/core';
|
|
2
|
+
/**
|
|
3
|
+
* Convert a single file's bytes to Markdown with the fb2 converter.
|
|
4
|
+
* `hint.path` is only a sniff hint; it is never read from disk.
|
|
5
|
+
*/
|
|
6
|
+
export declare function toMarkdown(bytes: Uint8Array, hint?: ConvertHint): Promise<string>;
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mdgate/fb2",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "mdgate FictionBook (FB2) converter",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist/**/*.js",
|
|
18
|
+
"dist/**/*.d.ts"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "bun ../../scripts/build-package.ts",
|
|
22
|
+
"prepublishOnly": "bun run build"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@mdgate/containers": "0.1.0",
|
|
26
|
+
"@mdgate/core": "0.1.3",
|
|
27
|
+
"@mdgate/document": "0.1.0",
|
|
28
|
+
"@mdgate/utils": "0.1.2"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=20"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"mdgate",
|
|
38
|
+
"markdown",
|
|
39
|
+
"fb2",
|
|
40
|
+
"fictionbook"
|
|
41
|
+
]
|
|
42
|
+
}
|