mdreflink rewrites Markdown files to use reference-style links. It finds all
inline links, such as [text](href)
, and converts them to the shortcut
reference format, [text]
.
A link's definition is placed at the end of the first section in which the link's link text appears. Definitions are collected, de-duplicated, and sorted lexicographically by their link text within their respective sections.
The program is a command-line tool that reads from standard input or a file and writes to standard output or back to the source file.
npm install -g mdreflink
Or run directly without npm installation using npx:
npx mdreflink document.md
This npx approach is beneficial when you want to use mdreflink
occasionally without permanently installing it on your system, or when you
want to ensure you're always using the latest version without managing
updates manually.
The mdreflink
tool operates in several modes.
Read from a file, write to standard output:
Provide a file path as an argument. The formatted content is written to
stdout.
mdreflink document.md > formatted.md
Read from standard input, write to standard output:
If no file path is given, or if the path is -
, the program reads from
stdin.
mdreflink < document.md > formatted.md
Modify a file in-place:
The -w
flag instructs the program to modify the Markdown file directly.
mdreflink -w document.md
Note: The in-place flag is invalid when reading from standard input.
Note that I am not a fluent JavaScript or TypeScript developer, so I am providing this mostly for posterity for myself. This was probably my deepest foray into that ecosystem for a project.
This tool was initially developed through — drum roll — vibe coding the initial project specification and heavily hand iterating on the output. It taught me a lot about a complex and ornate ecosystem that I otherwise knew little about.
This was my first time really vibe coding a project. If you see something curious or suboptimal, please flag it. At this point, will be developing this exclusively by hand.
A Node.js environment is required for development. After cloning the repository, install the project dependencies:
npm install
This command installs libraries necessary for TypeScript compilation, code execution, and testing.
To compile the TypeScript source code into JavaScript, run the build script:
npm run build
This command uses the TypeScript compiler (tsc) to transpile the source
files from src/
into the dist/
directory, as specified in
tsconfig.json
, and then uses esbuild to bundle the sources and transitive
dependencies into a CLI executable.
To run the general test suite:
npm test
To update the test golden files ("snapshots"):
npm run test:update
Smoke testing can be achieved with:
npm test test:e2e
To run tests with coverage reporting:
npm run coverage
For local development, after building, you can link the package to make
the mdreflink
command available globally:
npm link
mdreflink document.md
To uninstall the global link:
npm unlink -g mdreflink
For local development without npm link, you can also run directly:
node dist/index.js document.md > formatted.md
To validate the package configuration before publishing:
npm run lint:package
This runs publint to check for common packaging issues.
To preview what will be published:
npm pack
This creates a tarball showing exactly what files will be included in the published package. Remember to clean up the generated .tgz file afterward.
This project uses automated releases triggered by Git tags. Tags must follow the v{version}
format (e.g., v1.2.3
) to match JavaScript ecosystem conventions.
To create a new release:
-
Update the version in
package.json
:npm version patch # or minor, major
-
Create an annotated tag with release notes:
git tag -a v1.2.3 -m "Release v1.2.3 - Add feature X - Fix bug Y - Update dependencies"
-
Push the tag to trigger automated release:
git push origin v1.2.3
The GitHub Actions workflow will automatically:
- Run all tests (unit and e2e)
- Validate the package
- Publish to npm with provenance
- Create a GitHub release
Note: The tag version (without 'v' prefix) must exactly match the version in package.json
or the release will fail.