snippets.js

⚙️ Extract code snippets from source files


Keywords
generator, javascript, parser, snippets
License
MIT
Install
npm install snippets.js@0.7.0

Documentation

Snippets.js

Snippets.js helps you extract code snippets from source files so you can use them as text in your own projects.

It's particularly useful in documentation projects, where you need to showcase pieces of code but can't either run or lint them to ensure they're correct. Snippets.js integrates in your workflow and returns a collection of parsed snippets.

WARNING: The API is still unstable. Do not use in production yet.

Install

npm install snippets.js

# or

yarn add snippets.js

Getting started

Snippets.js iterates over your source files, generates snippet objects, and exposes them through a readable stream.

const { createSnippets } = require("snippets.js");

const snippets = createSnippets({
  sourceDir: "path/to/snippets/*",
  ignore: ["node_modules/*"]
});

snippets.on("data", snippet => {
  console.log(snippet);
});

snippets.on("end", () => {
  console.log("Finished parsing snippets!");
});

By default, Snippets.js parses the file extension and sets it as the snippet's language. You can change it in the languages setting.

const snippets = createSnippets({
  // ...
  languages: [
    {
      fileType: ["rb"],
      language: "ruby"
    }
  ]
});

You can also transform the raw input code. This is useful when you need to remove a piece of code (think <?php in PHP snippets, for instance).

const snippets = createSnippets({
  // ...
  languages: [
    {
      // ...
      transform: code => code.replace("# frozen_string_literal: true", "")
    }
  ]
});

If you only need to parse a chunk of a longer snippet, you can add special comments to delimit the part you need.

Comments work with // and #.

public class Factorial {
  public static void main(String[] args) {
    int num = 10;
    long factorial = 1;

    // snippets-start
    for(int i = 1; i <= num; ++i)
    {
        factorial *= i;
    }
    // snippets-end

    System.out.printf("Factorial of %d = %d", num, factorial);
  }
}
num = 10
factorial = 1

# snippets-start
for i in range(1,num+1):
    factorial = factorial * i
# snippets-end

print "Factorial of %s = %d" % (num,factorial)

You can create several commented parts in a single snippet to chunk it into several snippet objects.

Additionally, you can name snippets by suffixing the start comment with :<your-name>. Snippet names can include letters, numbers, hyphens and underscores.

Note: Overlapping and nested comments aren't supported.

num = 10
factorial = 1

# snippets-start
for i in range(1,num+1):
    factorial = factorial * i
# snippets-end

# snippets-start:my-snippet
print "Factorial of %s = %d" % (num,factorial)
# snippets-end

API

The library exposes two main modules: createSnippets and createSnippet.

They both let you generate Snippet objects.

createSnippets

Type: (config: { sourceDir?, ignore?, languages? }) => NodeJS.ReadableStream

The createSnippets factory lets you generate a readable stream of Snippet objects from source files.

You can use it to log objects to the console, write them to a file, store them in memory for later usage, anything.

const { createSnippets } = require("snippets.js");

const snippets = createSnippets({
  sourceDir: "path/to/snippets/*",
  ignore: ["node_modules/*"],
  languages: [
    {
      fileType: ["rb"],
      language: "ruby",
      transform: code => code.replace("# frozen_string_literal: true", "")
    }
  ]
});

snippets.on("data", snippet => {
  console.log(snippet);
});

snippets.on("end", () => {
  console.log("Finished parsing snippets!");
});

sourceDir?

Type: string | undefined

The path where to find the source snippets. Supports glob patterns.

module.exports = {
  sourceDir: "path/to/snippets/**/*"
};

ignore?

Type: string[] | undefined

The paths to ignore. Supports glob patterns.

module.exports = {
  ignore: ["node_modules"]
};

languages?

Type: { fileType, language?, transform? }[] | undefined

A collection of rules to handle languages. This lets you apply specific treatment to each snippet based on file type.

module.exports = {
  languages: [
    {
      fileType: ["rb", "erb"],
      language: "ruby",
      transform(code) {
        return code.replace("# frozen_string_literal: true", "");
      }
    },
    {
      // ...
    }
  ]
};
languages.fileType

Type: string[]

The file type(s) on which to apply the rule (based on file extension).

module.exports = {
  languages: [
    {
      fileType: ["rb", "erb"]
    }
  ]
};
languages.language?

Type: string | undefined

The language slug to assign to the snippet. This is used as language for the Markdown fenced blocks.

If not specified, defaults to the file extension.

module.exports = {
  languages: [
    {
      language: "ruby"
    }
  ]
};
languages.transform?

Type: (code: string) => string | undefined

A transform function to apply on the code.

module.exports = {
  languages: [
    {
      transform(code) {
        return code.replace("# frozen_string_literal: true", "");
      }
    }
  ]
};

createSnippet

Type: (options: { language, path?, code, transform? }) => Snippet

The createSnippet factory lets you generate Snippet objects from source input. This is what the library uses internally to generate snippets from your source files.

const { createSnippet } = require("snippets.js");

const phpSnippet = createSnippet({
  language: "php",
  code: '<?php\necho "Hello world!"',
  transform: code => code.replace("<?php", "")
});

You can use createSnippet to manually generate snippets as in the example above, or to build your own snippet factories for specific languages.

const createPhpSnippet = code =>
  createSnippet({
    language: "php",
    code,
    transform: code => code.replace("<?php", "")
  });

const code = '<?php\necho "Hello world!"';

const phpSnippet = createPhpSnippet(code);

If you're using TypeScript, you can implement the SnippetFactory interface.

const createPhpSnippet: SnippetFactory = code =>
  createSnippet({
    language: "php",
    code,
    transform: code => code.replace("<?php", "")
  });

options.language

Type: string

The language of a snippet.

options.path?

Type: string | undefined

The path of a snippet's source file. This is only useful when you're parsing snippets from source files, and can be ommitted if you're building Snippet objects by hand.

options.code

Type: string

The raw code of a snippet.

options.transform?

Type: (code: string) => string | undefined

A function to transform the raw code before returning it.

This is useful when you want to get rid of a piece of code that's necessary in the source file, but that you don't need in the final snippet.

Snippet

A Snippet object contains all the information about a code snippet. This is what the library returns you when you're either using createSnippet manually, or listening for data on snippets.

If you're using TypeScript, you can implement the Snippet interface.

const snippet: Snippet = createSnippet({
  language: "php",
  code: '<?php\necho "Hello world!"',
  transform: code => code.replace("<?php", "")
});

language

Type: string

Get the language of a snippet.

snippet.language; // 'php'

path?

Type: string | undefined

Get the path of a snippet.

This is the original path to the source file. This is only useful when you're parsing snippets from source files, and can be ommitted if you're building Snippet objects by hand.

snippet.path; // 'path/to/original/snippet.php'

code

Type: string

Get the code of a snippet.

snippet.code; // 'echo "Hello world!"'

markdown

Type: string

Get the code of a snippet in Markdown format.

snippet.markdown; // '```php\necho "Hello world!"\n```'

FAQ

Why streams?

Snippets.js was built to work with many snippets, from source files. Reading through a bunch of files and storing lots of objects that potentially contain long chunks of code can become greedy in terms of memory. Streams are an ideal solution to make sure that memory consumption remains under control.

If you don't want to use streams, you can reimplement the iteration logic as you see fit and consume the createSnippet factory exposed by the library.

Can I see a demo?

Sure! This monorepo exposes a fully working example in packages/example/. Check out the code for inspiration, and follow the README to run the demo.

License

Snippets is licensed under MIT.