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

nunjucks-grime

v0.0.4

Published

Some nunjucks extensions for code generators

Downloads

8

Readme

nunjucks-grime

Some nunjucks extensions for code generators

  • allows stitching of existing files
  • ljust/rjust support

Granted, that sounds kind of underwhelming. So what is it?

Stitching sources

The way you normally use nunjucks is this:

template ---> generated output 

This incredible piece of ASCII art means that the default mode of operation is that the template must be a complete description of the output file, where generated content is added in.

But sometimes you are in a situation where you need this:

(existing file + something generated) --> generated output

For example, in my code base I have existing C/C++ code that includes stuff dynamically generated and stuff manually maintained. So I need a solution that

  • allows me to maintain in control of the source code
  • decorate just some lines in it using code generation

This is not a solution nunjucks supports out of the box, so I added a small syntax extension. The elements of the solution are these:

  • the template syntax is extended to defined a 'piece to be stitched into an existing file'.
  • nunjucks Environments already have a set of loaders used to find. So now we have an additional set of loaders that can be used to load 'stitch sources'
  • Bass! Magic!

Stitching Example

Ok, let's assume you have this file stitched.h:

The text you want to modify

#ifndef STITCH_SOURCE_H
#define STITCH_SOURCE_H

... tons of code here that is NOT generated ...

// BEGIN GENERATED FUNCTIONS: DO NOT MANUALLY EDIT, THIS IS GENERATED CODE
// BUT how do I get my generated stuff in here while retaining all the existing bits? 
// END GENERATED FUNCTIONS: DO NOT MANUALLY EDIT, THIS IS GENERATED CODE

... huge megatons of code here that is NOT generated either ...

#endif // STITCH_SOURCE_H

Fear no more, nunjucks-grime is here. You define a special stitch template like this:

The stitch-template dialect

{% stitch %}
// BEGIN GENERATED FUNCTIONS: DO NOT MANUALLY EDIT, THIS IS GENERATED CODE

{%- for item in well_known_client_functions %}
typedef HRESULT (*WINAPI LPFN{{ item }})(LPCTSTR Bassdrum);
{%- endfor %}        

// END GENERATED FUNCTIONS: DO NOT MANUALLY EDIT, THIS IS GENERATED CODE
{% endstitch %}

Some points to notice:

  • The actual code syntax is 100% nunjucks.
  • There are only two exceptions: 0. {% stitch %} indicates that this is the start of a stitch block. The next line will indicate how to recognize the start of that block in the input.
    1. {% endstitch %} tells the code that the previous line terminates the block in the input.

The actual code

If you are familiar with nunjucks (or jinja2 for that matter), this should be pretty readable. Next up: putting it all together

var nunjucks = require('nunjucks-grime');

var env = new nunjucks.Environment(new nunjucks.FileSystemLoader('views'));
env.opts["stitch_source_loaders"] = [new nunjucks.FileSystemLoader('stitch_sources')];
console.log(env.render('stitched.h', data));

This will modify your existing source like this:

#ifndef STITCH_SOURCE_H
#define STITCH_SOURCE_H

... tons of code here that is NOT generated ...

// BEGIN GENERATED FUNCTIONS: DO NOT MANUALLY EDIT, THIS IS GENERATED CODE

typedef HRESULT (*WINAPI LPFNfoo)(LPCTSTR Bassdrum);
typedef HRESULT (*WINAPI LPFNbar)(LPCTSTR Bassdrum);
typedef HRESULT (*WINAPI LPFNblubber)(LPCTSTR Bassdrum);

// END GENERATED FUNCTIONS: DO NOT MANUALLY EDIT, THIS IS GENERATED CODE

... huge megatons of code here that is NOT generated either ...

#endif // STITCH_SOURCE_H

That means you can run that repeatedly, as long as you want: nunjucks-grime will only ever touch the bits enclosed in BEGIN GENERATED FUNCTIONS.. and END GENERATED FUNCTIONS. Not so bad, eh?

OK, now that you are convinced, let's slowly review the code lines I used:

var nunjucks = require('nunjucks-grime');

Note that nunjucks-grime is designed t be used as a drop-in replacement for the original nunjucks.

var env = new nunjucks.Environment(new nunjucks.FileSystemLoader('views'));

That was standard.

env.opts["stitch_source_loaders"] = [new nunjucks.FileSystemLoader('stitch_sources')];

Now this is an extension: you must define how nunjucks-grime should find the original sources to be stitched. You can use any of the existing nunjucks loaders, or write your own standard-conforming loader.

console.log(env.render('stitched.h', data));

Look ma, no new parameters

Minor stuff

Also, because I needed it I have added two helper filters that jinja2 has supported for quite some time:

  • ljust for left-aligning text
  • rjust for right-aligning text

This was probably just an oversight of the nunjucks port: because on the web you don't normally need that kind of thing.

Example

Let's say you have this input:

#ifndef NUNJUCKS_EXTRAS_H
#define NUNJUCKS_EXTRAS_H

// By default, the list will not be aligned:
{%- for item in list_of_items %}
#define {{ item.name }} {{ item.value }}
{%- endfor %}

// but now you can left-align
{%- for item in list_of_items %}
#define {{ item.name|ljust(20) }} {{ item.value }}
{%- endfor %}

// and right-align
{%- for item in list_of_items %}
#define {{ item.name|rjust(20) }} {{ item.value }}
{%- endfor %}

#endif // NUNJUCKS_EXTRAS_H

Note the use of ljust and rjust to specify an alignment. The actual result with nunjucks-grime this:

#ifndef NUNJUCKS_EXTRAS_H
#define NUNJUCKS_EXTRAS_H

// By default, the list will not be aligned:
#define foo 0x10
#define bar 0x1000
#define blubber 0xFFFFFFFE

// but now you can left-align
#define foo                  0x10
#define bar                  0x1000
#define blubber              0xFFFFFFFE

// and right-align
#define                  foo 0x10
#define                  bar 0x1000
#define              blubber 0xFFFFFFFE

#endif // NUNJUCKS_EXTRAS_H

What is up with the name?

I've been hooked on listening to this on volumes that shouldn't be legal.