@adobe/helix-md2docx 1.4.26 → 2.0.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/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
# [2.0.0](https://github.com/adobe/helix-md2docx/compare/v1.4.26...v2.0.0) (2022-09-23)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* provide resource loader and converter plugin capability ([#136](https://github.com/adobe/helix-md2docx/issues/136)) ([0a6b703](https://github.com/adobe/helix-md2docx/commit/0a6b7034ca9118016a24197647d49835cddad83d)), closes [#133](https://github.com/adobe/helix-md2docx/issues/133) [#134](https://github.com/adobe/helix-md2docx/issues/134) [#135](https://github.com/adobe/helix-md2docx/issues/135)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### BREAKING CHANGES
|
|
10
|
+
|
|
11
|
+
* svg2png was renamed to a more generic image2png
|
|
12
|
+
|
|
1
13
|
## [1.4.26](https://github.com/adobe/helix-md2docx/compare/v1.4.25...v1.4.26) (2022-09-12)
|
|
2
14
|
|
|
3
15
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/helix-md2docx",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Helix Service that converts markdown to word documents",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -44,13 +44,13 @@
|
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@adobe/eslint-config-helix": "1.3.2",
|
|
47
|
-
"@adobe/helix-mediahandler": "1.2.
|
|
47
|
+
"@adobe/helix-mediahandler": "1.2.4",
|
|
48
48
|
"@semantic-release/changelog": "6.0.1",
|
|
49
49
|
"@semantic-release/exec": "6.0.3",
|
|
50
50
|
"@semantic-release/git": "10.0.1",
|
|
51
51
|
"c8": "7.12.0",
|
|
52
52
|
"dotenv": "16.0.2",
|
|
53
|
-
"eslint": "8.23.
|
|
53
|
+
"eslint": "8.23.1",
|
|
54
54
|
"eslint-import-resolver-exports": "1.0.0-beta.3",
|
|
55
55
|
"eslint-plugin-header": "3.1.1",
|
|
56
56
|
"eslint-plugin-import": "2.26.0",
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
"lint-staged": "13.0.3",
|
|
60
60
|
"mocha": "10.0.0",
|
|
61
61
|
"mocha-multi-reporters": "1.5.1",
|
|
62
|
+
"nock": "13.2.9",
|
|
62
63
|
"semantic-release": "19.0.5",
|
|
63
64
|
"unist-util-inspect": "7.0.1",
|
|
64
65
|
"yauzl": "2.10.0"
|
|
@@ -136,10 +136,10 @@ export default async function image(ctx, node) {
|
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
if (data.
|
|
139
|
+
if (data.originalType === 'image/svg') {
|
|
140
140
|
// create a fake image run for the svg image
|
|
141
141
|
const ir = new ImageRun({
|
|
142
|
-
data: data.
|
|
142
|
+
data: data.originalBuffer,
|
|
143
143
|
transformation: data.dimensions,
|
|
144
144
|
});
|
|
145
145
|
ir.imageData.fileName = data.svgKey;
|
|
@@ -10,14 +10,38 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
import {RequestOptions, Response} from "@adobe/helix-fetch";
|
|
14
|
+
|
|
15
|
+
declare interface ImageToPngOptions {
|
|
16
|
+
/**
|
|
17
|
+
* image data
|
|
18
|
+
*/
|
|
19
|
+
data:Buffer|ArrayBuffer;
|
|
20
|
+
/**
|
|
21
|
+
* informational src information
|
|
22
|
+
*/
|
|
23
|
+
src?:string;
|
|
24
|
+
/**
|
|
25
|
+
* image content type, if available.
|
|
26
|
+
*/
|
|
27
|
+
type?:string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
declare interface ImageToPngResult {
|
|
31
|
+
data:Buffer|ArrayBuffer;
|
|
32
|
+
type?:string;
|
|
33
|
+
width:number;
|
|
34
|
+
height:number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
declare type ImageToPngConverter = (opts:ImageToPngOptions) => Promise<ImageToPngResult>;
|
|
38
|
+
|
|
13
39
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* @function
|
|
17
|
-
* @param {string} svg the input svg
|
|
18
|
-
* @return {string} the base64 encoded png
|
|
40
|
+
* Loader used for loading resources for urls starting with `res:`
|
|
19
41
|
*/
|
|
20
|
-
declare
|
|
42
|
+
declare interface ResourceLoader {
|
|
43
|
+
fetch(url:string, opts:RequestOptions): Promise<Response>
|
|
44
|
+
}
|
|
21
45
|
|
|
22
46
|
declare interface Mdast2DocxOptions {
|
|
23
47
|
/**
|
|
@@ -30,7 +54,15 @@ declare interface Mdast2DocxOptions {
|
|
|
30
54
|
*/
|
|
31
55
|
stylesXML: string;
|
|
32
56
|
|
|
33
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Optional loader for (image) resources
|
|
59
|
+
*/
|
|
60
|
+
resourceLoader?:ResourceLoader;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Optional image2png converter
|
|
64
|
+
*/
|
|
65
|
+
image2png?: ImageToPngConverter
|
|
34
66
|
}
|
|
35
67
|
|
|
36
68
|
/**
|
package/src/mdast2docx/index.js
CHANGED
|
@@ -27,7 +27,8 @@ const { Document, Packer } = docx;
|
|
|
27
27
|
export default async function mdast2docx(mdast, opts = {}) {
|
|
28
28
|
const {
|
|
29
29
|
log = console,
|
|
30
|
-
|
|
30
|
+
resourceLoader,
|
|
31
|
+
image2png,
|
|
31
32
|
} = opts;
|
|
32
33
|
|
|
33
34
|
let {
|
|
@@ -42,7 +43,8 @@ export default async function mdast2docx(mdast, opts = {}) {
|
|
|
42
43
|
listLevel: -1,
|
|
43
44
|
lists: [],
|
|
44
45
|
log,
|
|
45
|
-
|
|
46
|
+
image2png,
|
|
47
|
+
resourceLoader,
|
|
46
48
|
};
|
|
47
49
|
|
|
48
50
|
// eslint-disable-next-line no-param-reassign
|
|
@@ -40,6 +40,7 @@ function hsize(bytes, decimals = 2) {
|
|
|
40
40
|
* @returns {Promise<void>}
|
|
41
41
|
*/
|
|
42
42
|
export default async function downloadImages(ctx, tree) {
|
|
43
|
+
const { log, resourceLoader, image2png } = ctx;
|
|
43
44
|
const context = createFetchContext();
|
|
44
45
|
const { fetch } = context;
|
|
45
46
|
|
|
@@ -63,33 +64,77 @@ export default async function downloadImages(ctx, tree) {
|
|
|
63
64
|
if (node.data) {
|
|
64
65
|
return;
|
|
65
66
|
}
|
|
66
|
-
|
|
67
|
+
const idx = String(count).padStart(2, ' ');
|
|
68
|
+
count += 1;
|
|
67
69
|
let buffer;
|
|
68
70
|
let type;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
let maybeConvert;
|
|
72
|
+
let dimensions = {
|
|
73
|
+
width: 100,
|
|
74
|
+
height: 100,
|
|
75
|
+
};
|
|
76
|
+
if (node.url.startsWith('data:')) {
|
|
77
|
+
const [prefix, data] = node.url.substring(5).split(',');
|
|
78
|
+
const [typ, enc] = prefix.split(';');
|
|
79
|
+
if (enc !== 'base64') {
|
|
80
|
+
log.warn(`[${idx}] Error decoding data url. unknown encoding: ${enc}`);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
buffer = Buffer.from(data, 'base64');
|
|
84
|
+
type = typ;
|
|
72
85
|
} else {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
86
|
+
log.info(`[${idx}] GET ${node.url}`);
|
|
87
|
+
|
|
88
|
+
let doFetch = fetch;
|
|
89
|
+
if (node.url.startsWith('res:')) {
|
|
90
|
+
if (!resourceLoader) {
|
|
91
|
+
log.warn(`[${idx}] Error loading image ${node.url}. resource loader missing.`);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
doFetch = resourceLoader.fetch.bind(resourceLoader);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const ret = await doFetch(node.url);
|
|
77
98
|
if (!ret.ok) {
|
|
78
99
|
const text = await ret.text();
|
|
79
|
-
|
|
100
|
+
log.error(`[${idx}] ${ret.status} ${text}`);
|
|
80
101
|
return;
|
|
81
102
|
}
|
|
82
103
|
buffer = await ret.buffer();
|
|
83
104
|
type = ret.headers.get('content-type');
|
|
84
|
-
|
|
105
|
+
log.info(`[${idx}] ${ret.status} ${hsize(buffer.length).padStart(10)} ${type}`);
|
|
85
106
|
}
|
|
86
|
-
const dimensions = getDimensions(buffer);
|
|
87
107
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
108
|
+
maybeConvert = type !== 'image/png' && type !== 'image/jpg' && type !== 'image/jpeg' && type !== 'image/gif';
|
|
109
|
+
try {
|
|
110
|
+
dimensions = getDimensions(buffer);
|
|
111
|
+
} catch (e) {
|
|
112
|
+
maybeConvert = true;
|
|
113
|
+
log.warn(`[${idx}] Error detecting dimensions: ${e} ${type}`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let originalBuffer;
|
|
117
|
+
let originalType;
|
|
118
|
+
if (maybeConvert && image2png) {
|
|
119
|
+
try {
|
|
120
|
+
const result = await image2png({
|
|
121
|
+
src: node.url,
|
|
122
|
+
data: buffer,
|
|
123
|
+
type,
|
|
124
|
+
});
|
|
125
|
+
if (result) {
|
|
126
|
+
originalBuffer = buffer;
|
|
127
|
+
originalType = type;
|
|
128
|
+
buffer = result.data;
|
|
129
|
+
type = result.type;
|
|
130
|
+
dimensions = {
|
|
131
|
+
width: result.width,
|
|
132
|
+
height: result.height,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
} catch (e) {
|
|
136
|
+
log.warn(`[${idx}] Error to convert to png`, e);
|
|
137
|
+
}
|
|
93
138
|
}
|
|
94
139
|
|
|
95
140
|
const ext = mime.getExtension(type);
|
|
@@ -98,13 +143,14 @@ export default async function downloadImages(ctx, tree) {
|
|
|
98
143
|
ext,
|
|
99
144
|
key: `${ref}.${ext}`,
|
|
100
145
|
buffer,
|
|
101
|
-
|
|
102
|
-
|
|
146
|
+
originalBuffer,
|
|
147
|
+
type,
|
|
148
|
+
originalType,
|
|
103
149
|
dimensions,
|
|
104
150
|
};
|
|
105
151
|
ctx.images[ref] = node.data;
|
|
106
152
|
} catch (error) {
|
|
107
|
-
|
|
153
|
+
log.error(`Cannot download image ${node.url}: ${error.message}`);
|
|
108
154
|
}
|
|
109
155
|
}, 8);
|
|
110
156
|
|