{"id":13527763,"url":"https://github.com/here-be/snapdragon","last_synced_at":"2025-05-15T16:05:19.290Z","repository":{"id":31832884,"uuid":"35399815","full_name":"here-be/snapdragon","owner":"here-be","description":"snapdragon is an extremely pluggable, powerful and easy-to-use parser-renderer factory.","archived":false,"fork":false,"pushed_at":"2023-03-14T09:12:47.000Z","size":212,"stargazers_count":226,"open_issues_count":8,"forks_count":25,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-07T21:13:29.707Z","etag":null,"topics":["ast","compile","compiler","javascript","lex","lexer","node","nodejs","parse","parser","render","source-map","token","tokenize"],"latest_commit_sha":null,"homepage":"https://github.com/here-be","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/here-be.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2015-05-11T03:22:26.000Z","updated_at":"2025-03-05T09:39:23.000Z","dependencies_parsed_at":"2022-09-13T21:11:21.374Z","dependency_job_id":"5abc15e0-74cd-4853-8ffa-c3f84a3a3ca5","html_url":"https://github.com/here-be/snapdragon","commit_stats":{"total_commits":167,"total_committers":7,"mean_commits":"23.857142857142858","dds":0.07185628742514971,"last_synced_commit":"fb340c536871669c83601ce6f6cb49d9ff730fac"},"previous_names":["jonschlinkert/snapdragon"],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/here-be%2Fsnapdragon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/here-be%2Fsnapdragon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/here-be%2Fsnapdragon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/here-be%2Fsnapdragon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/here-be","download_url":"https://codeload.github.com/here-be/snapdragon/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248943458,"owners_count":21186958,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ast","compile","compiler","javascript","lex","lexer","node","nodejs","parse","parser","render","source-map","token","tokenize"],"created_at":"2024-08-01T06:02:00.508Z","updated_at":"2025-05-15T16:05:19.274Z","avatar_url":"https://github.com/here-be.png","language":"JavaScript","readme":"# snapdragon [![NPM version](https://img.shields.io/npm/v/snapdragon.svg?style=flat)](https://www.npmjs.com/package/snapdragon) [![NPM monthly downloads](https://img.shields.io/npm/dm/snapdragon.svg?style=flat)](https://npmjs.org/package/snapdragon) [![NPM total downloads](https://img.shields.io/npm/dt/snapdragon.svg?style=flat)](https://npmjs.org/package/snapdragon) [![Linux Build Status](https://img.shields.io/travis/here-be/snapdragon.svg?style=flat\u0026label=Travis)](https://travis-ci.org/here-be/snapdragon)\n\n\u003e Easy-to-use plugin system for creating powerful, fast and versatile parsers and compilers, with built-in source-map support.\n\nPlease consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support.\n\n## Table of Contents\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eDetails\u003c/strong\u003e\u003c/summary\u003e\n\n- [Install](#install)\n- [Quickstart example](#quickstart-example)\n- [Parsing](#parsing)\n- [Compiling](#compiling)\n- [All together](#all-together)\n- [API](#api)\n  * [Parse](#parse)\n  * [Compile](#compile)\n- [Snapdragon in the wild](#snapdragon-in-the-wild)\n- [History](#history)\n  * [v0.9.0](#v090)\n  * [v0.5.0](#v050)\n- [About](#about)\n\n\u003c/details\u003e\n\n## Install\n\nInstall with [npm](https://www.npmjs.com/):\n\n```sh\n$ npm install --save snapdragon\n```\n\nCreated by [jonschlinkert](https://github.com/jonschlinkert) and [doowb](https://github.com/doowb).\n\n**Features**\n\n* Bootstrap your own parser, get sourcemap support for free\n* All parsing and compiling is handled by simple, reusable middleware functions\n* Inspired by the parsers in [pug](https://pugjs.org/) and [css](https://github.com/reworkcss/css).\n\n## Quickstart example\n\nAll of the examples in this document assume the following two lines of setup code exist first:\n\n```js\nvar Snapdragon = require('snapdragon');\nvar snapdragon = new Snapdragon();\n```\n\n**Parse a string**\n\n```js\nvar ast = snapdragon.parser\n  // parser handlers (essentially middleware)\n  // used for parsing substrings to create tokens\n  .set('foo', function () {})\n  .set('bar', function () {})\n  .parse('some string', options);\n```\n\n**Compile an AST returned from `.parse()`**\n\n```js\nvar result = snapdragon.compiler\n  // compiler handlers (essentially middleware), \n  // called on a node when the `node.type` matches\n  // the name of the handler\n  .set('foo', function () {})\n  .set('bar', function () {})\n  // pass the `ast` from the parse method\n  .compile(ast)\n\n// the compiled string\nconsole.log(result.output);\n```\n\nSee the [examples](./examples/).\n\n## Parsing\n\n**Parser handlers**\n\nParser handlers are middleware functions responsible for matching substrings to create tokens:\n\n**Example handler**\n\n```js\nvar ast = snapdragon.parser\n  .set('dot', function() {\n    var pos = this.position();\n    var m = this.match(/^\\./);\n    if (!m) return;\n    return pos({\n      // the \"type\" will be used by the compiler later on,\n      // we'll go over this in the compiler docs\n      type: 'dot',\n      // \"val\" is the string captured by \".match\",\n      // in this case that would be '.'\n      val: m[0]\n    });\n  })\n  .parse('.'[, options])\n```\n\n_As a side node, it's not scrictly required to set the `type` on the token, since the parser will add it to the token if it's undefined, based on the name of the handler. But it's good practice since tokens aren't always returned._\n\n**Example token**\n\nAnd the resulting tokens look something like this:\n\n```js\n{ \n  type: 'dot',\n  val: '.' \n}\n```\n\n**Position**\n\nNext, `pos()` is called on the token as it's returned, which patches the token with the `position` of the string that was captured:\n\n```js\n{ type: 'dot',\n  val: '.',\n  position:\n   { start: { lineno: 1, column: 1 },\n     end: { lineno: 1, column: 2 } }}\n```\n\n**Life as an AST node**\n\nWhen the token is returned, the parser pushes it onto the `nodes` array of the \"previous\" node (since we're in a tree, the \"previous\" node might be literally the last node that was created, or it might be the \"parent\" node inside a nested context, like when parsing brackets or something with an open or close), at which point the token begins its life as an AST node.\n\n**Wrapping up**\n\nIn the parser calls all handlers and cannot find a match for a substring, an error is thrown.\n\nAssuming the parser finished parsing the entire string, an AST is returned.\n\n## Compiling\n\nThe compiler's job is to take the AST created by the [parser](#parsing) and convert it to a new string. It does this by iterating over each node on the AST and calling a function on the node based on its `type`.\n\nThis function is called a \"handler\".\n\n**Compiler handlers**\n\nHandlers are _named_ middleware functions that are called on a node when `node.type` matches the name of a registered handler.\n\n```js\nvar result = snapdragon.compiler\n  .set('dot', function (node) {\n    console.log(node.val)\n    //=\u003e '.'\n    return this.emit(node.val);\n  })\n```\n\nIf `node.type` does not match a registered handler, an error is thrown.\n\n**Source maps**\n\nIf you want source map support, make sure to emit the entire node as the second argument as well (this allows the compiler to get the `node.position`).\n\n```js\nvar res = snapdragon.compiler\n  .set('dot', function (node) {\n    return this.emit(node.val, node);\n  })\n```\n\n## All together\n\nThis is a very basic example, but it shows how to parse a dot, then compile it as an escaped dot.\n\n```js\nvar Snapdragon = require('..');\nvar snapdragon = new Snapdragon();\n\nvar ast = snapdragon.parser\n  .set('dot', function () {\n    var pos = this.position();\n    var m = this.match(/^\\./);\n    if (!m) return;\n    return pos({\n      type: 'dot',\n      val: m[0]\n    })\n  })\n  .parse('.')\n\nvar result = snapdragon.compiler\n  .set('dot', function (node) {\n    return this.emit('\\\\' + node.val);\n  })\n  .compile(ast)\n\nconsole.log(result.output);\n//=\u003e '\\.'\n```\n\n## API\n\n### [Parser](lib/parser.js#L27)\n\nCreate a new `Parser` with the given `input` and `options`.\n\n**Params**\n\n* `input` **{String}**\n* `options` **{Object}**\n\n**Example**\n\n```js\nvar Snapdragon = require('snapdragon');\nvar Parser = Snapdragon.Parser;\nvar parser = new Parser();\n```\n\n### [.error](lib/parser.js#L97)\n\nThrow a formatted error message with details including the cursor position.\n\n**Params**\n\n* `msg` **{String}**: Message to use in the Error.\n* `node` **{Object}**\n* `returns` **{undefined}**\n\n**Example**\n\n```js\nparser.set('foo', function(node) {\n  if (node.val !== 'foo') {\n    throw this.error('expected node.val to be \"foo\"', node);\n  }\n});\n```\n\n### [.define](lib/parser.js#L115)\n\nDefine a non-enumberable property on the `Parser` instance. This is useful in plugins, for exposing methods inside handlers.\n\n**Params**\n\n* `key` **{String}**: propery name\n* `val` **{any}**: property value\n* `returns` **{Object}**: Returns the Parser instance for chaining.\n\n**Example**\n\n```js\nparser.define('foo', 'bar');\n```\n\n### [.node](lib/parser.js#L133)\n\nCreate a new [Node](#node) with the given `val` and `type`.\n\n**Params**\n\n* `val` **{Object}**\n* `type` **{String}**\n* `returns` **{Object}**: returns the [Node](#node) instance.\n\n**Example**\n\n```js\nparser.node('/', 'slash');\n```\n\n### [.position](lib/parser.js#L155)\n\nMark position and patch `node.position`.\n\n* `returns` **{Function}**: Returns a function that takes a `node`\n\n**Example**\n\n```js\nparser.set('foo', function(node) {\n  var pos = this.position();\n  var match = this.match(/foo/);\n  if (match) {\n    // call `pos` with the node\n    return pos(this.node(match[0]));\n  }\n});\n```\n\n### [.set](lib/parser.js#L187)\n\nAdd parser `type` with the given visitor `fn`.\n\n**Params**\n\n* `type` **{String}**\n* `fn` **{Function}**\n\n**Example**\n\n```js\n parser.set('all', function() {\n   var match = this.match(/^./);\n   if (match) {\n     return this.node(match[0]);\n   }\n });\n```\n\n### [.get](lib/parser.js#L206)\n\nGet parser `type`.\n\n**Params**\n\n* `type` **{String}**\n\n**Example**\n\n```js\nvar fn = parser.get('slash');\n```\n\n### [.push](lib/parser.js#L229)\n\nPush a node onto the stack for the given `type`.\n\n**Params**\n\n* `type` **{String}**\n* `returns` **{Object}** `token`\n\n**Example**\n\n```js\nparser.set('all', function() {\n  var match = this.match(/^./);\n  if (match) {\n    var node = this.node(match[0]);\n    this.push(node);\n    return node;\n  }\n});\n```\n\n### [.pop](lib/parser.js#L261)\n\nPop a token off of the stack of the given `type`.\n\n**Params**\n\n* `type` **{String}**\n* `returns` **{Object}**: Returns a token\n\n**Example**\n\n```js\nparser.set('close', function() {\n  var match = this.match(/^\\}/);\n  if (match) {\n    var node = this.node({\n      type: 'close',\n      val: match[0]\n    });\n\n    this.pop(node.type);\n    return node;\n  }\n});\n```\n\n### [.isInside](lib/parser.js#L294)\n\nReturn true if inside a \"set\" of the given `type`. Sets are created manually by adding a type to `parser.sets`. A node is \"inside\" a set when an `*.open` node for the given `type` was previously pushed onto the set. The type is removed from the set by popping it off when the `*.close` node for the given type is reached.\n\n**Params**\n\n* `type` **{String}**\n* `returns` **{Boolean}**\n\n**Example**\n\n```js\nparser.set('close', function() {\n  var pos = this.position();\n  var m = this.match(/^\\}/);\n  if (!m) return;\n  if (!this.isInside('bracket')) {\n    throw new Error('missing opening bracket');\n  }\n});\n```\n\n### [.isType](lib/parser.js#L324)\n\nReturn true if `node` is the given `type`.\n\n**Params**\n\n* `node` **{Object}**\n* `type` **{String}**\n* `returns` **{Boolean}**\n\n**Example**\n\n```js\nparser.isType(node, 'brace');\n```\n\n### [.prev](lib/parser.js#L340)\n\nGet the previous AST node from the `parser.stack` (when inside a nested context) or `parser.nodes`.\n\n* `returns` **{Object}**\n\n**Example**\n\n```js\nvar prev = this.prev();\n```\n\n### [.prev](lib/parser.js#L394)\n\nMatch `regex`, return captures, and update the cursor position by `match[0]` length.\n\n**Params**\n\n* `regex` **{RegExp}**\n* `returns` **{Object}**\n\n**Example**\n\n```js\n// make sure to use the starting regex boundary: \"^\"\nvar match = this.match(/^\\./);\n```\n\n**Params**\n\n* `input` **{String}**\n* `returns` **{Object}**: Returns an AST with `ast.nodes`\n\n**Example**\n\n```js\nvar ast = parser.parse('foo/bar');\n```\n\n### [Compiler](lib/compiler.js#L24)\n\nCreate a new `Compiler` with the given `options`.\n\n**Params**\n\n* `options` **{Object}**\n* `state` **{Object}**: Optionally pass a \"state\" object to use inside visitor functions.\n\n**Example**\n\n```js\nvar Snapdragon = require('snapdragon');\nvar Compiler = Snapdragon.Compiler;\nvar compiler = new Compiler();\n```\n\n### [.error](lib/compiler.js#L67)\n\nThrow a formatted error message with details including the cursor position.\n\n**Params**\n\n* `msg` **{String}**: Message to use in the Error.\n* `node` **{Object}**\n* `returns` **{undefined}**\n\n**Example**\n\n```js\ncompiler.set('foo', function(node) {\n  if (node.val !== 'foo') {\n    throw this.error('expected node.val to be \"foo\"', node);\n  }\n});\n```\n\n### [.emit](lib/compiler.js#L86)\n\nConcat the given string to `compiler.output`.\n\n**Params**\n\n* `string` **{String}**\n* `node` **{Object}**: Optionally pass the node to use for position if source maps are enabled.\n* `returns` **{String}**: returns the string\n\n**Example**\n\n```js\ncompiler.set('foo', function(node) {\n  this.emit(node.val, node);\n});\n```\n\n### [.noop](lib/compiler.js#L104)\n\nEmit an empty string to effectively \"skip\" the string for the given `node`, but still emit the position and node type.\n\n**Params**\n\n* **{Object}**: node\n\n**Example**\n\n```js\n// example: do nothing for beginning-of-string\nsnapdragon.compiler.set('bos', compiler.noop);\n```\n\n### [.define](lib/compiler.js#L124)\n\nDefine a non-enumberable property on the `Compiler` instance. This is useful in plugins, for exposing methods inside handlers.\n\n**Params**\n\n* `key` **{String}**: propery name\n* `val` **{any}**: property value\n* `returns` **{Object}**: Returns the Compiler instance for chaining.\n\n**Example**\n\n```js\ncompiler.define('customMethod', function() {\n  // do stuff\n});\n```\n\n### [.set](lib/compiler.js#L152)\n\nAdd a compiler `fn` for the given `type`. Compilers are called when the `.compile` method encounters a node of the given type to generate the output string.\n\n**Params**\n\n* `type` **{String}**\n* `fn` **{Function}**\n\n**Example**\n\n```js\ncompiler\n  .set('comma', function(node) {\n    this.emit(',');\n  })\n  .set('dot', function(node) {\n    this.emit('.');\n  })\n  .set('slash', function(node) {\n    this.emit('/');\n  });\n```\n\n### [.get](lib/compiler.js#L168)\n\nGet the compiler of the given `type`.\n\n**Params**\n\n* `type` **{String}**\n\n**Example**\n\n```js\nvar fn = compiler.get('slash');\n```\n\n### [.visit](lib/compiler.js#L188)\n\nVisit `node` using the registered compiler function associated with the `node.type`.\n\n**Params**\n\n* `node` **{Object}**\n* `returns` **{Object}**: returns the node\n\n**Example**\n\n```js\ncompiler\n  .set('i', function(node) {\n    this.visit(node);\n  })\n```\n\n### [.mapVisit](lib/compiler.js#L226)\n\nIterate over `node.nodes`, calling [visit](#visit) on each node.\n\n**Params**\n\n* `node` **{Object}**\n* `returns` **{Object}**: returns the node\n\n**Example**\n\n```js\ncompiler\n  .set('i', function(node) {\n    utils.mapVisit(node);\n  })\n```\n\n### [.compile](lib/compiler.js#L250)\n\nCompile the given `AST` and return a string. Iterates over `ast.nodes` with [mapVisit](#mapVisit).\n\n**Params**\n\n* `ast` **{Object}**\n* `options` **{Object}**: Compiler options\n* `returns` **{Object}**: returns the node\n\n**Example**\n\n```js\nvar ast = parser.parse('foo');\nvar str = compiler.compile(ast);\n```\n\n## Snapdragon in the wild\n\nA few of the libraries that use snapdragon:\n\n* [braces](https://www.npmjs.com/package/braces): Bash-like brace expansion, implemented in JavaScript. Safer than other brace expansion libs, with complete support… [more](https://github.com/micromatch/braces) | [homepage](https://github.com/micromatch/braces \"Bash-like brace expansion, implemented in JavaScript. Safer than other brace expansion libs, with complete support for the Bash 4.3 braces specification, without sacrificing speed.\")\n* [breakdance](https://www.npmjs.com/package/breakdance): Breakdance is a node.js library for converting HTML to markdown. Highly pluggable, flexible and easy… [more](http://breakdance.io) | [homepage](http://breakdance.io \"Breakdance is a node.js library for converting HTML to markdown. Highly pluggable, flexible and easy to use. It's time for your markup to get down.\")\n* [expand-brackets](https://www.npmjs.com/package/expand-brackets): Expand POSIX bracket expressions (character classes) in glob patterns. | [homepage](https://github.com/jonschlinkert/expand-brackets \"Expand POSIX bracket expressions (character classes) in glob patterns.\")\n* [extglob](https://www.npmjs.com/package/extglob): Extended glob support for JavaScript. Adds (almost) the expressive power of regular expressions to glob… [more](https://github.com/micromatch/extglob) | [homepage](https://github.com/micromatch/extglob \"Extended glob support for JavaScript. Adds (almost) the expressive power of regular expressions to glob patterns.\")\n* [micromatch](https://www.npmjs.com/package/micromatch): Glob matching for javascript/node.js. A drop-in replacement and faster alternative to minimatch and multimatch. | [homepage](https://github.com/micromatch/micromatch \"Glob matching for javascript/node.js. A drop-in replacement and faster alternative to minimatch and multimatch.\")\n* [nanomatch](https://www.npmjs.com/package/nanomatch): Fast, minimal glob matcher for node.js. Similar to micromatch, minimatch and multimatch, but complete Bash… [more](https://github.com/micromatch/nanomatch) | [homepage](https://github.com/micromatch/nanomatch \"Fast, minimal glob matcher for node.js. Similar to micromatch, minimatch and multimatch, but complete Bash 4.3 wildcard support only (no support for exglobs, posix brackets or braces)\")\n\n## History\n\n### v0.9.0\n\n**Breaking changes!**\n\nIn an attempt to make snapdragon lighter, more versatile, and more pluggable, some major changes were made in this release.\n\n* `parser.capture` was externalized to [snapdragon-capture](https://github.com/jonschlinkert/snapdragon-capture)\n* `parser.capturePair` was externalized to [snapdragon-capture-set](https://github.com/jonschlinkert/snapdragon-capture-set)\n* Nodes are now an instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)\n\n### v0.5.0\n\n**Breaking changes!**\n\nSubstantial breaking changes were made in v0.5.0! Most of these changes are part of a larger refactor that will be finished in 0.6.0, including the introduction of a `Lexer` class.\n\n* Renderer was renamed to `Compiler`\n* the `.render` method was renamed to `.compile`\n\n## About\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eContributing\u003c/strong\u003e\u003c/summary\u003e\n\nPull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eRunning Tests\u003c/strong\u003e\u003c/summary\u003e\n\nRunning and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:\n\n```sh\n$ npm install \u0026\u0026 npm test\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eBuilding docs\u003c/strong\u003e\u003c/summary\u003e\n\n_(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_\n\nTo generate the readme, run the following command:\n\n```sh\n$ npm install -g verbose/verb#dev verb-generate-readme \u0026\u0026 verb\n```\n\n\u003c/details\u003e\n\n### Related projects\n\nA few of the libraries that use snapdragon:\n\n* [snapdragon-capture-set](https://www.npmjs.com/package/snapdragon-capture-set): Plugin that adds a `.captureSet()` method to snapdragon, for matching and capturing substrings that have… [more](https://github.com/jonschlinkert/snapdragon-capture-set) | [homepage](https://github.com/jonschlinkert/snapdragon-capture-set \"Plugin that adds a `.captureSet()` method to snapdragon, for matching and capturing substrings that have an `open` and `close`, like braces, brackets, etc\")\n* [snapdragon-capture](https://www.npmjs.com/package/snapdragon-capture): Snapdragon plugin that adds a capture method to the parser instance. | [homepage](https://github.com/jonschlinkert/snapdragon-capture \"Snapdragon plugin that adds a capture method to the parser instance.\")\n* [snapdragon-node](https://www.npmjs.com/package/snapdragon-node): Snapdragon utility for creating a new AST node in custom code, such as plugins. | [homepage](https://github.com/jonschlinkert/snapdragon-node \"Snapdragon utility for creating a new AST node in custom code, such as plugins.\")\n* [snapdragon-util](https://www.npmjs.com/package/snapdragon-util): Utilities for the snapdragon parser/compiler. | [homepage](https://github.com/here-be/snapdragon-util \"Utilities for the snapdragon parser/compiler.\")\n\n### Contributors\n\n| **Commits** | **Contributor** | \n| --- | --- |\n| 156 | [jonschlinkert](https://github.com/jonschlinkert) |\n| 3 | [doowb](https://github.com/doowb) |\n| 2 | [danez](https://github.com/danez) |\n| 1 | [EdwardBetts](https://github.com/EdwardBetts) |\n\n### Author\n\n**Jon Schlinkert**\n\n* [LinkedIn Profile](https://linkedin.com/in/jonschlinkert)\n* [GitHub Profile](https://github.com/jonschlinkert)\n* [Twitter Profile](https://twitter.com/jonschlinkert)\n\n### License\n\nCopyright © 2018, [Jon Schlinkert](https://github.com/jonschlinkert).\nReleased under the [MIT License](LICENSE).\n\n***\n\n_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on March 20, 2018._","funding_links":[],"categories":["Github Repositories","JavaScript"],"sub_categories":["HTML stuff"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhere-be%2Fsnapdragon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhere-be%2Fsnapdragon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhere-be%2Fsnapdragon/lists"}