├── .gitignore ├── tests ├── templates │ ├── missing_boundary_header.mhtml │ ├── missing_boundary.mhtml │ ├── unexpected_eof.mhtml │ └── missing_headers.mhtml └── mhtml2html.test.js ├── .eslintrc ├── karma.conf.js ├── webpack.config.js ├── LICENSE.txt ├── .circleci └── config.yml ├── package.json ├── index.js ├── README.md └── src └── mhtml2html.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Node Modules 2 | node_modules 3 | 4 | # MHTML and HTML 5 | .mhtml 6 | .html 7 | 8 | # Build 9 | dist 10 | -------------------------------------------------------------------------------- /tests/templates/missing_boundary_header.mhtml: -------------------------------------------------------------------------------- 1 | From: 2 | Subject: Max Sindwani 3 | Date: Tue, 5 Sep 2016 22:30:04 -0000 4 | MIME-Version: 1.0 5 | Content-Type: multipart/related; 6 | type="text/html"; 7 | 8 | ------MultipartBoundary--13Auk8ODqvYITpKWs1cqVnvH965JWLgToStNEOgxaj---- 9 | Content-Type: text/html 10 | Content-Transfer-Encoding: quoted-printable 11 | 12 | 2 | Subject: Max Sindwani 3 | Date: Tue, 5 Sep 2016 22:30:04 -0000 4 | MIME-Version: 1.0 5 | Content-Type: multipart/related; 6 | type="text/html"; 7 | boundary="----MultipartBoundary--13Auk8ODqvYITpKWs1cqVnvH965JWLgToStNEOgxaj----" 8 | 9 | 10 | Content-Type: text/html 11 | Content-ID: 12 | Content-Transfer-Encoding: quoted-printable 13 | Content-Location: http://msindwan.bitbucket.org/ 14 | 15 | 2 | Subject: Max Sindwani 3 | Date: Tue, 5 Sep 2016 22:30:04 -0000 4 | MIME-Version: 1.0 5 | Content-Type: multipart/related; 6 | type="text/html"; 7 | boundary="----MultipartBoundary--13Auk8ODqvYITpKWs1cqVnvH965JWLgToStNEOgxaj----" 8 | 9 | ------MultipartBoundary--13Auk8ODqvYITpKWs1cqVnvH965JWLgToStNEOgxaj---- 10 | Content-Type: text/html 11 | Content-ID: 12 | Content-Transfer-Encoding: quoted-printable 13 | Content-Location: http://msindwan.bitbucket.org/ 14 | 15 | 2 | Subject: Max Sindwani 3 | Date: Tue, 5 Sep 2016 22:30:04 -0000 4 | MIME-Version: 1.0 5 | Content-Type: multipart/related; 6 | type="text/html"; 7 | boundary="----MultipartBoundary--13Auk8ODqvYITpKWs1cqVnvH965JWLgToStNEOgxaj----" 8 | 9 | ------MultipartBoundary--13Auk8ODqvYITpKWs1cqVnvH965JWLgToStNEOgxaj---- 10 | Content-Type: text/html 11 | Content-ID: 12 | Content-Transfer-Encoding: quoted-printable 13 | Content-Location: http://msindwan.bitbucket.org/ 14 | 15 | 18 | =20 19 | 20 | 22 | 23 | ------MultipartBoundary--13Auk8ODqvYITpKWs1cqVnvH965JWLgToStNEOgxaj---- 24 | Content-Type: text/html 25 | Content-Transfer-Encoding: quoted-printable 26 | 27 | ~/mhtml2html/.npmrc 36 | - run: 37 | name: Publish package 38 | command: npm publish 39 | 40 | workflows: 41 | version: 2 42 | build-deploy: 43 | jobs: 44 | - build: 45 | filters: 46 | tags: 47 | only: /^v.*/ 48 | - deploy: 49 | requires: 50 | - build 51 | filters: 52 | tags: 53 | only: /^v.*/ 54 | branches: 55 | ignore: /.*/ 56 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mhtml2html", 3 | "version": "3.0.0", 4 | "description": "Converts an mhtml document to a single html document", 5 | "author": "Mayank Sindwani", 6 | "license": "MIT", 7 | "homepage": "https://github.com/msindwan/mhtml2html#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/msindwan/mhtml2html.git" 11 | }, 12 | "files": [ 13 | "dist/", 14 | "index.js", 15 | "LICENSE.txt", 16 | "README.md" 17 | ], 18 | "main": "dist/mhtml2html.js", 19 | "bin": { 20 | "mhtml2html": "./index.js" 21 | }, 22 | "scripts": { 23 | "lint": "eslint src", 24 | "prebuild": "yarn lint", 25 | "build": "webpack --mode=production", 26 | "pretest": "yarn build", 27 | "test": "yarn mocha tests/ && karma start --single-run" 28 | }, 29 | "engines": { 30 | "node": ">=10" 31 | }, 32 | "dependencies": { 33 | "base-64": "^0.1.0", 34 | "jsdom": "^15.1.1", 35 | "quoted-printable": "^1.0.1", 36 | "yargs": "^15.1.0" 37 | }, 38 | "devDependencies": { 39 | "@babel/core": "^7.6.0", 40 | "babel-loader": "^8.0.6", 41 | "chai": "^4.2.0", 42 | "eslint": "^6.3.0", 43 | "karma": "^4.3.0", 44 | "karma-chai": "^0.1.0", 45 | "karma-chrome-launcher": "^3.1.0", 46 | "karma-cli": "^2.0.0", 47 | "karma-mocha": "^1.3.0", 48 | "mocha": "^6.2.0", 49 | "webpack": "^4.39.3", 50 | "webpack-cli": "^3.3.8" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * index.js 5 | * 6 | * @Author : Mayank Sindwani 7 | * @Date : 2016-09-05 8 | * @Description : CLI for mhtml2html. 9 | * 10 | * The MIT License(MIT) 11 | * Copyright(c) 2016 Mayank Sindwani 12 | **/ 13 | 14 | const mhtml2html = require('./dist/mhtml2html'); 15 | const { JSDOM } = require('jsdom'); 16 | const yargs = require('yargs'); 17 | const fs = require('fs'); 18 | 19 | yargs 20 | .command('$0 ', 'Converts an mhtml file to a single html file', (yargs) => { 21 | yargs.positional('input', { 22 | describe: 'The path to the input mhtml file', 23 | type: 'string', 24 | }).positional('output', { 25 | describe: 'The path to the output html file', 26 | type: 'string' 27 | }) 28 | }, (argv) => { 29 | fs.readFile(argv.input, 'utf8', (err, data) => { 30 | if (err) { 31 | throw err; 32 | } 33 | 34 | const doc = mhtml2html.convert(data, { convertIframes: argv.convertIframes, parseDOM: (html) => new JSDOM(html) }); 35 | fs.writeFile(argv.output, doc.serialize(), err => { 36 | if (err) { 37 | return console.log(err); 38 | } 39 | }); 40 | }); 41 | }) 42 | .option('convertIframes', { 43 | alias: 'i', 44 | type: 'boolean', 45 | description: 'Include iframes in the converted output' 46 | }) 47 | .argv 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mhtml2html.js 2 | 3 | [![npm version](https://badge.fury.io/js/mhtml2html.svg)](https://badge.fury.io/js/mhtml2html) [![circleci](https://circleci.com/gh/msindwan/mhtml2html.svg?style=shield&circle-token=:circle-token)](https://circleci.com/gh/msindwan/mhtml2html) 4 | 5 | `mhtml2html` converts `MHTML` files to a single `HTML` file using javascript. 6 | 7 | [Usage](#usage) | [API](#api) | [Development](#development) 8 | 9 | ## Usage 10 | 11 | `mhtml2html` is compatible with Node >= v10. 12 | 13 | **It has only been tested with MHTML files built and used with the latest versions of Chrome** 14 | 15 | ### Node.js Example 16 | 17 | mhtml2html can be used via the command line (use the `--help` flag to view all options): 18 | 19 | ```sh 20 | $ mhtml2html 21 | ``` 22 | 23 | For programmatic usage, mhtml2html can be used provided a WHATWG DOM parser implementation (e.g [jsdom](https://github.com/jsdom/jsdom)): 24 | 25 | ```js 26 | const mhtml2html = require('mhtml2html'); 27 | const { JSDOM } = require('jsdom'); 28 | 29 | const mhtml = ''; 30 | const htmlDoc = mhtml2html.convert(mhtml, { parseDOM: (html) => new JSDOM(html) }); 31 | console.log(htmlDoc); 32 | ``` 33 | 34 | ### Browser Example 35 | 36 | To get started, import mhtml2html: 37 | 38 | ```js 39 | import mhtml2html from 'mhtml2html'; 40 | ``` 41 | 42 | Or include it as a script in your webpage: 43 | 44 | ```html 45 |