Observed since 20 Oct, 19:15 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
2md
convert formatted text to markdown
There are lots of packages for turning markdown into html, but this one goes the other way, turning formatted html into markdown.
Say you’re reading an Ars Technica article and want to copy something
into some markdown notes. Just select some content in your browser, copy
it, then run 2md. The heading, list formatting, bold text, and hyperlinks
are all preserved.

You can try it out online at 2md.ca.
A detailed writeup of the internals exists: “Compiling HTML to Markdown with TypeScript: How 2md works”
The easiest way to try out 2md from the command line is with npx, a
tool to automatically download, cache, and run programs; it’s been included
with Node.js since 2017:
npx 2md [--no-quote] [FILE]
You can also install to install the 2md command with yarn:
yarn [global] add 2md
Run
npx 2md [--no-quote] [FILE]
to get markdown.
By default, 2md reads from the clipboard, using osascript, xclip,
or powershell. Otherwise, pass it the name of html file as a command-line
argument.
For easy inserting of stuff into other documents, --quote is on by
default and wraps the markdown in a blockquote:
> # Foo
>
> bar ...
Only a single function is exposed: toMd.
const { toMd } = require('2md');
console.log(toMd('foo <b>bar</b>'));
prints
foo **bar**
Only exported files with public in the path are supported. Everything
else is subject to change without notice. But if there’s some interesting
code here you’d like to reuse, let me know and I can look into publishing
it as a separate package.
Contributions are welcome! There are fairly comprehensive end-to-end and round-trip tests, and TypeScript’s type-checking makes refactoring safer, so don’t be afraid to move code around.
All the original code here is licensed under the Apache License, version
2.0, included in LICENSE.code; except for the contents of the “how it
works” article how-it-works/post.mdx, which is not redistributable.
The current release process, to be automated later, is:
Remove the -pre tag from the version field in core/package.json
version, and from the 2md dependency in website/package.json
Update CHANGELOG.md
Copy README.md and any referenced images such as doc/demo.gif into
the core folder
Commit to git, and git tag vA.B.C
In the core directory, yarn run package and inspect tarball
git push --atomic $REMOTE main vA.B.C
Optional: figure out automation to put CHANGELOG.md excerpt into
auto-created GitHub releases.
npm publish 2md-vA.B.C.tgz
If publishing a pre-release, add npm publish --tag next to set the
correct npm tag.
Bump version and add -pre version suffix in core/package.json;
update the 2md dependency version in website/package.json as well
The yarn workspaces documentation says,
if workspace-b depends on a different version than the one referenced in workspace-a’s package.json, the dependency will be installed from npm rather than linked from your local filesystem. This is because some packages actually need to use the previous versions in order to build the new ones (Babel is one of them).
For the precompiled version, run yarn dist in core and copy
2md.js to ~/bin. It relies on a shell wrapper:
#!/bin/bash
DIR="$(dirname -- "${0}")"
exec node "${DIR}/2md.js" "${@}"
Download counts and popularity will appear here as the collector receives them.
| Package / target | Requirement | Relationship |
|---|---|---|
fs-extraEnvironment{
"local_name": "fs-extra",
"alias": false,
"peer_metadata": null
} | ^8.1.0 | runtime |
grapheme-splitterEnvironment{
"local_name": "grapheme-splitter",
"alias": false,
"peer_metadata": null
} | ^1.0.4 | runtime |
jsdomEnvironment{
"local_name": "jsdom",
"alias": false,
"peer_metadata": null
} | ^15.1.1 | runtime |
lodashEnvironment{
"local_name": "lodash",
"alias": false,
"peer_metadata": null
} | ^4.17.15 | runtime |
regenerator-runtimeEnvironment{
"local_name": "regenerator-runtime",
"alias": false,
"peer_metadata": null
} | ^0.13.3 | runtime |
yargsEnvironment{
"local_name": "yargs",
"alias": false,
"peer_metadata": null
} | ^14.2.0 | runtime |
@babel/cliEnvironment{
"local_name": "@babel/cli",
"alias": false,
"peer_metadata": null
} | ^7.6.4 | development |
@babel/coreEnvironment{
"local_name": "@babel/core",
"alias": false,
"peer_metadata": null
} | ^7.0.0-0 | development |
@babel/plugin-transform-modules-commonjsEnvironment{
"local_name": "@babel/plugin-transform-modules-commonjs",
"alias": false,
"peer_metadata": null
} | ^7.9.0 | development |
@babel/preset-envEnvironment{
"local_name": "@babel/preset-env",
"alias": false,
"peer_metadata": null
} | ^7.9.0 | development |
@babel/preset-typescriptEnvironment{
"local_name": "@babel/preset-typescript",
"alias": false,
"peer_metadata": null
} | ^7.9.0 | development |
@babel/registerEnvironment{
"local_name": "@babel/register",
"alias": false,
"peer_metadata": null
} | ^7.9.0 | development |
@types/chaiEnvironment{
"local_name": "@types/chai",
"alias": false,
"peer_metadata": null
} | ^4.2.11 | development |
@types/fs-extraEnvironment{
"local_name": "@types/fs-extra",
"alias": false,
"peer_metadata": null
} | ^8.1.0 | development |
@types/jsdomEnvironment{
"local_name": "@types/jsdom",
"alias": false,
"peer_metadata": null
} | ^16.1.0 | development |
@types/lodashEnvironment{
"local_name": "@types/lodash",
"alias": false,
"peer_metadata": null
} | ^4.14.144 | development |
@types/mochaEnvironment{
"local_name": "@types/mocha",
"alias": false,
"peer_metadata": null
} | ^7.0.2 | development |
@types/yargsEnvironment{
"local_name": "@types/yargs",
"alias": false,
"peer_metadata": null
} | ^15.0.4 | development |
babel-plugin-transform-class-propertiesEnvironment{
"local_name": "babel-plugin-transform-class-properties",
"alias": false,
"peer_metadata": null
} | ^6.24.1 | development |
chaiEnvironment{
"local_name": "chai",
"alias": false,
"peer_metadata": null
} | ^4.2.0 | development |
mochaEnvironment{
"local_name": "mocha",
"alias": false,
"peer_metadata": null
} | ^7.1.1 | development |
parcelEnvironment{
"local_name": "parcel",
"alias": false,
"peer_metadata": null
} | ^1.12.4 | development |
prettierEnvironment{
"local_name": "prettier",
"alias": false,
"peer_metadata": null
} | ^1.18.2 | development |
remarkEnvironment{
"local_name": "remark",
"alias": false,
"peer_metadata": null
} | ^11.0.1 | development |
remark-htmlEnvironment{
"local_name": "remark-html",
"alias": false,
"peer_metadata": null
} | ^10.0.0 | development |
tslibEnvironment{
"local_name": "tslib",
"alias": false,
"peer_metadata": null
} | ^1.11.1 | development |
typescriptEnvironment{
"local_name": "typescript",
"alias": false,
"peer_metadata": null
} | ^3.8.3 | development |
Source distribution
{
"integrity": "sha512-6ZtDn4fkMM6lGLYbktTzYc5nXJm0qTExJJiNwY6AfKbWqTpsnecsymenpOz3reOgpiqI8EouU/SYyDRS9jkAfg==",
"shasum": "6612fcc57fbdd5852d48ad3e9fb042d24de61d89",
"tarball": "https://registry.npmjs.org/2md/-/2md-0.0.3.tgz",
"fileCount": 21,
"unpackedSize": 48242,
"npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJedk6BCRA9TVsSAnZWagAACEAP/jo6PbCRh/lNrntrjHGz\nwPjc4tn50UKrEOcNx5jxY+bbt7bCBAvFpKkSviUMgY9argT7Pm/YHY8+uqu+\ngD87coD6jnc5I7YvjivRTOIo7kEPtNDLtkOGvIIvyaX/2XlO7F5tO3OB/VOs\naPBiSmtL6dr/AWDrhTSsxXYJ4axSowIKrMsN1sycQZDbZ8wuXnthfcq3DonD\nxS2MU8NHMPa0t1hlIBCDSRrQxckr/MRGjDqoXJCUVeMzOsEEokYrKLE/eKNM\n7dmjkVTEUa4Hc2BcEvNVoqpbDqrVE4qW9OJvzxE67DVOB9e6nnLbjREsYCUr\nZUuw2+es2RNl7cjEgcCHxMD7g3e7+0Nmz1vtM9h0nh1RrgmrEaV5XL9Sxkna\n3OA8XqQjk2zeGfsCboJ/XU4qN9UqmUaj8NGDG0KPZjw0/hEaVCi4fCV9Gehn\nDVEP27UOdzQh4P6LxPLjEVJI0UYNNHAr7/fIwS78PcrEhBx2OLG7IFqiEhc7\nOU9JtJhPVv5ivrafe2URVdJpIZ7UnFMhDhlbGHOmb8TrMlsBFDhZHfj6bzXG\nmw9iQQmMXbns/UUDxFK3k5qhvfUwkNKoj3/dzo+/cvR/DKHpeV50KzILvkdn\nKSemEgkJmT+smajltGt3IICZMj2KkAq6TeGSiitjxF12jlo6upSpjX/nNnMQ\nYmAS\r\n=Tcjy\r\n-----END PGP SIGNATURE-----\r\n",
"signatures": [
{
"keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA",
"sig": "MEYCIQD9RGHOBFphx2XHk8m7DZxWHkz4a+Blcr/gcqotYDvdQwIhANDb4iMR/xT4+9f6iCrCkjxJWGiIniv539qgl9n7J2vi"
}
]
}Shared repository data · GitHub
Public sponsor counts have not been collected. These signals belong to the repository owner.
github · 1 observations shown. Missing days are unknown.
| Date / source period | Value | Observed at |
|---|---|---|
| 2026-10-22 | 0 | 2026-10-22T14:13:51.0065407Z |
Observed since 20 Oct, 19:15 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package_version:acb22723043e23cb4483647c7536ce28d5e9d53d8fac86987d7dda2bdab7bd4a