snippin v0.5.1
Snippin lets you re-use snippets from text files in other contexts.
Like say you're writing some documentation for your code and you want to show some examples of how it behaves. You figure you'll grab the examples from your test suite, because 1. they're already written and 2. they're guaranteed to work --it's so annoying to find bugs in sample code! But there's some boring boilerplate at the top of your test file, and there are some tests that go into too much detail to serve as good examples, so you don't want to just include the whole file in your documentation. With Snippin, you can identify just the specific parts you're interested in:
// test.js
const tap = require('tap')
// #snip "example"
tap.equals(1 + 1, 2)
// #snipNow you can load them with Snippin and use them however you need:
const snippin = new Snippin()
tap.same(snippin.getSnippetsSync('test.js'), {
'example': 'tap.equals(1 + 1, 2)\n'
})Writing snippets
Start a snippet by writing #snip <snippet name> by itself on a line.
The snippet name must be a valid JSON string, e.g.
#snip "example snippet"End a snippet by writing just "#snip" by itself on a line:
#snipYou're allowed as much whitespace as you need before "#snip", and you can also have comment markers on the same line. For example,
// prefixed.js
// #snip "inside a comment"
//
// That "// " at the start of these lines
// won't be part of the snippet
// #sniptap.same(snippin.getSnippetsSync('prefixed.js'), {
'inside a comment': `
That "// " at the start of these lines
won't be part of the snippet
` })Specifically, here are the regex components that match whitespace and comment markers:
- prefix:
/^\s*(?://|\*|/\*)?\s*/ - suffix:
/\s*$/
Snippets can be nested. For example,
// nested.txt
#snip "outer"
Outer snippet
#snip "inner"
Inner snippet
#snip
Still outer snippet
#sniptap.same(snippin.getSnippetsSync('nested.txt'), {
'outer': 'Outer snippet\nInner snippet\nStill outer snippet\n',
'inner': 'Inner snippet\n'
})You can escape "#snip" directives by prefixing them with a "\". And of course if you need a literal "\#snip" you can write "\\#snip":
// escaped.txt
#snip "snippet"
\#snip "literal #snip"
\#snip
// \\#snip "literal backslash"
#sniptap.same(snippin.getSnippetsSync('escaped.txt'), {
'snippet': '#snip "literal #snip"\n#snip\n// \\#snip "literal backslash"\n'
})API
new Snippin([options, streamOptions])
refDirstring The directory relative to which snippets are loaded. Default:'.'.errorLoggerFunction Function to use to log warnings; it will be called with a single argument: an error message string. Default:console.warn.
snippin.getSnippets(file)
filestring The name of the file for which to get snippets.- Returns Promise Resolves to an object containing the snippets found in
file; keys are the snippet names, values are their contents.Gets snippets from the given file. Throws if
filedoesn't exist.
snippin.getSnippetsSync(file)
filestring The name of the file for which to get snippets.- Returns Object The snippets found in
file; keys are the snippet names, values are their contents.Gets snippets from the given file synchronously. Throws Error if
filedoesn't exist.
snippin.setSnippets(file, snippets)
filestring The name of the file for which to set snippets. This can be a path to a real file, or just a name.snippetsObject The snippets to set; properties are snippet names, and their value is the snippet contents.Snippets set this way take precedence over snippets loaded from files. This function operates on the entire set of snippets for a file; it will replace the set of snippets for the given file if it's already been loaded, or prevent it from being loaded if it hasn't yet.
Including snippets
Once you've loaded your snippets, you can include them into your text by using any of the popular templating libraries, or template literals, or whatever.
Snippin also ships with a stream transform that can process "#pin" directives
and render them as the named snippet. Include a snippet by writing #pin file
snippet-name by itself on a line. Both the file and snippet name must be
valid JSON strings.
Continuing the first example above, we can do
const doc = `We all know that one and one make two:
#pin "test.js" "example"`
let output = ''
const pinTx = new PinTx()
pinTx.on('data', chunk => { output += chunk })
pinTx.on('end', () => t.equals(output,
'We all know that one and one make two:\ntap.equals(1 + 1, 2)\n'))
pinTx.end(doc)new PinTx([options, streamOptions])
optionsObject
refDirstring The directory relative to which snippets are loaded. Default:'.'.errorLoggerFunction Function to use to log warnings; it will be called with a single argument: an error message string. Default:console.warn.streamOptionsObject Passed as-is to stream.Transform's constructor. Default:{}.This transform replaces each
#pindirective with the snippet it references.If a
#pindirective is malformed or references a snippet which can't be loaded, a warning is logged, and the directive is output as-is.
Command line
There's a command line interface to the stream transform.
Usage: snippin [-d REFDIR] [-o OUTFILE] [--] [INFILE]
Print standard input (or INFILE) to standard output (or OUTFILE)
with #pins expanded relative to the current working directory
(or INFILE's directory, or REFDIR).
Options:
-d, --refdir=DIRECTORY load snippets relative to DIRECTORY
-o, --outfile=FILE write output to FILE
-h, --help show this usage messageContributing
This project is deliberately left imperfect to encourage you to participate in its development. If you make a Pull Request that
- explains and solves a problem,
- follows standard style, and
- maintains 100% test coverage
it will be merged: this project follows the C4 process.
To make sure your commits follow the style guide and pass all tests, you can add
./.pre-committo your git pre-commit hook.