npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

markdown_conrefs

v1.2.19

Published

A system for including content references (conrefs) into Markdown files

Downloads

29

Readme

Introduction

I wrote technical documentation in my formative years using the DITA standard. Nowadays, I write documentation in Markdown, but one of the things I really miss is the ability to do content references—or conrefs—from one file to another.

The idea is simple: if you have a term, phrase, or block that you're reusing throughout the documentation, it's best to just define it once, tag it with a unique ID, then refer to that ID whenever you want to pull the content in. Simple, and much more efficient then search and replace.

I wrote a module for this functionality in Node.js, and it would be my dream of dreams if other Markdown packages for other languages implement similar functionality.

Installation

From npm, just do

npm install markdown_conrefs

Syntax

The syntax follows the superior Maruku metadata format for Markdown. IDs are either attached at the block level, or inline. There are a few ways in Maruku to define attributes; this conref system supports all of them (with #blah, with id="blah", with id='blah', or just plain id=blah).

To attach to the block level, just create metadata for the last line of the block, with an id element, like so:

* Item 1
* Item 2
* Item 3
{: #aNiceList}

Here's a great, and final, paragraph.
{: id="myPara"}

To attach conrefs inline, you'll need to wrap the content with brackets ([ ]), and then continue with the same attribute format, like so:

[I don't want to have to rewrite this.]{: .class1 id=aTruth .class2}
[**A RELIEF**]{: key=value id='expression' foo=bar}
[Genesis]{: #newProj} 

Note that this format differs slightly from Maruku. Maruku metadata only applies to Markdown inline elements, like bold, or italic. This system allows you to conref even plain-text. In fact, namp, my Markdown processor written in Node.js, also supports this notation.

Remember: the syntax to define this metadata is curly brace-colon-space! Why is that important? Well...

In order to reference the conref, you'll just use this syntax wherever you want to do an insertion: {:id}. That's curly brace-colon-id-curly brace--nothing else! It's irrelevant if you defined your id with #, id="", or id=''--all you want to do is use the id name. To use the examples above, that'd be:

{:aNiceList}
{:myPara}

{:aTruth}
{:expression}
{:newProj}

Pulling additional attributes

Any other attributes you've defined--class names, language identifiers for fenced code blocks, e.t.c.--get pulled into the resulting document as well, but the ID is stripped.

Why? Consider the following text:

I am working on [Project X]{: #product .secret}. I love being on {:product}. It's more rewarding to be a part of {:product}.

If IDs were kept, the block would resolve as:

I am working on [Project X]{: #product .secret}. I love being on [Project X]{: #product .secret}. It's more rewarding to be a part of [Project X]{: #product .secret}.

That's now three elements in the same document with the same ID, product. Instead, the resolve happens like this:

I am working on [Project X]{: #product .secret}. I love being on [Project X]{: .secret}. It's more rewarding to be a part of [Project X]{: .secret}.

Using

First, add require('markdown_conrefs') to your code. This module only has the following functions:

init(source [, options])

This must always be called first! This creates the id-to-content hash. The parameters are:

  • source is a string of a directory or file name, or, an array of strings for directories and filenames. source can represent the file you want to parse, the files you want to parse, or the highest level directory you want to start searching content references for--this module will recursively find all conref IDs in files to keep track of them.
  • options is a JSON object to path that defines any options for the parser. These are the possible properties:
    • supportsAttributes: set this to true if you know that your Markdown parser supports the Maruku syntax of [ ] / {: } to pass attributes into text. When the conrefs are replaced, these attributes will be preserved; otherwise, they are wiped. Default is false.
    • type: the extension of the files you want to keep. If omitted, all files in source are parsed. You can either include the starting dot (.md) or omit it (md).
    • exclusions: an array of strings, indicating any files or directories you don't want to process when source is a directory.
    • blockPrefixChar: a string, indicating the starting line character in your files. This is used when parsing block conrefs. For example, you may be parsing Javascript comments, in which case blockPrefixChar: "*".
    • blockPrefixCharOptional: a boolean which, if true, means that the blockPrefixChar could, or could not, be there. In other (RegExp) words: options.blockPrefixCharOptional ? "?".

This function has no return value, and is synchronous/blocking.

replaceConref(data)

When you're ready to apply the conrefs, use this function. This function takes one parameter:

  • data, the string containing the markdown text--it's usually the file you're reading.

This function returns data with the conrefs replaced; if no conref IDs are found, just plain old data is returned

getData()

Returns the entire hash list.

Check out the test/ directory for an example; just run cd test && node test/test.js from this directory.

Keep in mind that this module only replaces the references; you'll still need to run a Markdown parser in order to actually generate HTML.

Error Checking

The module automatically halts if:

  • You have more than one ID with the same reference
  • You refer to an ID that doesn't exist

Benchmarks

I tested this module by creating a single file with 10,000 conref IDs, and 10,000 files with a single conref ID. Presumably, lookups would cost the same amount of time, so I made a single call to markdown_conref.init() on each set of files.

On average, the single file took 7ms to complete; the multiple files took 450ms. In other words, they're both damned fast, despite my mediocre programming. For the technical writer, a single file might be easier to manage.