├── .editorconfig ├── .eslintrc.json ├── .gitattributes ├── .gitignore ├── .nvmrc ├── .travis.yml ├── .verb.md ├── CHANGELOG.md ├── LICENSE ├── README.md ├── benchmark ├── bulk │ ├── code │ │ ├── front-matter.js │ │ └── gray-matter.js │ └── fixtures │ │ └── posts.js ├── code │ ├── 0.5.3.js │ ├── charAt.js │ ├── front-matter.js │ ├── gray-matter.js │ ├── read.js │ ├── regex.js │ ├── split.js │ ├── substr.js │ ├── while.js │ ├── while2.js │ └── while3.js ├── fixtures │ ├── coffee.js │ ├── complex.js │ ├── complex.md │ ├── cson.js │ ├── empty.js │ ├── lang.js │ ├── matter.js │ ├── no-content.js │ ├── no-matter.js │ └── toml.js ├── index.js ├── stats.json └── stats.md ├── bower.json ├── examples ├── coffee.js ├── excerpt-separator.js ├── excerpt-stringify.js ├── excerpt.js ├── fixtures │ ├── coffee-auto.md │ ├── coffee.md │ ├── sections-excerpt.md │ └── sections.md ├── helper.js ├── javascript.js ├── json-stringify.js ├── json.js ├── restore-empty.js ├── sections-excerpt.js ├── sections.js ├── toml.js ├── yaml-stringify.js └── yaml.js ├── gray-matter.d.ts ├── index.js ├── lib ├── defaults.js ├── engine.js ├── engines.js ├── excerpt.js ├── parse.js ├── stringify.js ├── to-file.js └── utils.js ├── package.json └── test ├── fixtures ├── all-dots.yaml ├── all.yaml ├── autodetect-coffee-fn.md ├── autodetect-coffee.md ├── autodetect-coffeescript.md ├── autodetect-cson-fn.md ├── autodetect-cson.md ├── autodetect-javascript.md ├── autodetect-json.md ├── autodetect-no-lang.md ├── autodetect-yaml.md ├── basic.txt ├── complex.md ├── delims-and-lang.md ├── delims-custom.md ├── delims-semi-colons.md ├── empty.md ├── has-matter.md ├── hasnt-matter.md ├── lang-coffee-bad.md ├── lang-coffee-fn.md ├── lang-coffee.md ├── lang-cson-fn.md ├── lang-cson.md ├── lang-javascript-fn.md ├── lang-javascript-object-fn.md ├── lang-json.md ├── lang-yaml.md ├── to-json.md └── to-yaml.md ├── matter-empty.js ├── matter-windows.js ├── matter.excerpt.js ├── matter.js ├── matter.language.js ├── matter.read.js ├── matter.test.js ├── parse-coffee.js ├── parse-cson.js ├── parse-custom.js ├── parse-javascript.js ├── parse-json.js ├── parse-toml.js ├── parse-yaml.js ├── stringify.js └── vinyl-files.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org/ 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [{**/{actual,fixtures,expected,templates}/**,*.md}] 13 | trim_trailing_whitespace = false 14 | insert_final_newline = false 15 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint:recommended", 4 | "./package.json" 5 | ], 6 | 7 | "env": { 8 | "browser": false, 9 | "es6": true, 10 | "node": true, 11 | "mocha": true 12 | }, 13 | 14 | "parserOptions":{ 15 | "ecmaVersion": 9, 16 | "sourceType": "module", 17 | "ecmaFeatures": { 18 | "modules": true, 19 | "experimentalObjectRestSpread": true 20 | } 21 | }, 22 | 23 | "globals": { 24 | "document": false, 25 | "navigator": false, 26 | "window": false 27 | }, 28 | 29 | "rules": { 30 | "accessor-pairs": 2, 31 | "arrow-spacing": [2, { "before": true, "after": true }], 32 | "block-spacing": [2, "always"], 33 | "brace-style": [2, "1tbs", { "allowSingleLine": true }], 34 | "comma-dangle": [2, "never"], 35 | "comma-spacing": [2, { "before": false, "after": true }], 36 | "comma-style": [2, "last"], 37 | "constructor-super": 2, 38 | "curly": [2, "multi-line"], 39 | "dot-location": [2, "property"], 40 | "eol-last": 2, 41 | "eqeqeq": [2, "allow-null"], 42 | "generator-star-spacing": [2, { "before": true, "after": true }], 43 | "handle-callback-err": [2, "^(err|error)$" ], 44 | "indent": [2, 2, { "SwitchCase": 1 }], 45 | "key-spacing": [2, { "beforeColon": false, "afterColon": true }], 46 | "keyword-spacing": [2, { "before": true, "after": true }], 47 | "new-cap": [2, { "newIsCap": true, "capIsNew": false }], 48 | "new-parens": 2, 49 | "no-array-constructor": 2, 50 | "no-caller": 2, 51 | "no-class-assign": 2, 52 | "no-cond-assign": 2, 53 | "no-const-assign": 2, 54 | "no-control-regex": 2, 55 | "no-debugger": 2, 56 | "no-delete-var": 2, 57 | "no-dupe-args": 2, 58 | "no-dupe-class-members": 2, 59 | "no-dupe-keys": 2, 60 | "no-duplicate-case": 2, 61 | "no-empty-character-class": 2, 62 | "no-eval": 2, 63 | "no-ex-assign": 2, 64 | "no-extend-native": 2, 65 | "no-extra-bind": 2, 66 | "no-extra-boolean-cast": 2, 67 | "no-extra-parens": [2, "functions"], 68 | "no-fallthrough": 2, 69 | "no-floating-decimal": 2, 70 | "no-func-assign": 2, 71 | "no-implied-eval": 2, 72 | "no-inner-declarations": [2, "functions"], 73 | "no-invalid-regexp": 2, 74 | "no-irregular-whitespace": 2, 75 | "no-iterator": 2, 76 | "no-label-var": 2, 77 | "no-labels": 2, 78 | "no-lone-blocks": 2, 79 | "no-mixed-spaces-and-tabs": 2, 80 | "no-multi-spaces": 2, 81 | "no-multi-str": 2, 82 | "no-multiple-empty-lines": [2, { "max": 1 }], 83 | "no-native-reassign": 0, 84 | "no-negated-in-lhs": 2, 85 | "no-new": 2, 86 | "no-new-func": 2, 87 | "no-new-object": 2, 88 | "no-new-require": 2, 89 | "no-new-wrappers": 2, 90 | "no-obj-calls": 2, 91 | "no-octal": 2, 92 | "no-octal-escape": 2, 93 | "no-proto": 0, 94 | "no-redeclare": 2, 95 | "no-regex-spaces": 2, 96 | "no-return-assign": 2, 97 | "no-self-compare": 2, 98 | "no-sequences": 2, 99 | "no-shadow-restricted-names": 2, 100 | "no-spaced-func": 2, 101 | "no-sparse-arrays": 2, 102 | "no-this-before-super": 2, 103 | "no-throw-literal": 2, 104 | "no-trailing-spaces": 0, 105 | "no-undef": 2, 106 | "no-undef-init": 2, 107 | "no-unexpected-multiline": 2, 108 | "no-unneeded-ternary": [2, { "defaultAssignment": false }], 109 | "no-unreachable": 2, 110 | "no-unused-vars": [2, { "vars": "all", "args": "none" }], 111 | "no-useless-call": 0, 112 | "no-with": 2, 113 | "one-var": [0, { "initialized": "never" }], 114 | "operator-linebreak": [0, "after", { "overrides": { "?": "before", ":": "before" } }], 115 | "padded-blocks": [0, "never"], 116 | "quotes": [2, "single", "avoid-escape"], 117 | "radix": 2, 118 | "semi": [2, "always"], 119 | "semi-spacing": [2, { "before": false, "after": true }], 120 | "space-before-blocks": [2, "always"], 121 | "space-before-function-paren": [2, "never"], 122 | "space-in-parens": [2, "never"], 123 | "space-infix-ops": 2, 124 | "space-unary-ops": [2, { "words": true, "nonwords": false }], 125 | "spaced-comment": [0, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","] }], 126 | "use-isnan": 2, 127 | "valid-typeof": 2, 128 | "wrap-iife": [2, "any"], 129 | "yoda": [2, "never"] 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Enforce Unix newlines 2 | * text eol=lf 3 | 4 | # binaries 5 | *.ai binary 6 | *.psd binary 7 | *.jpg binary 8 | *.gif binary 9 | *.png binary 10 | *.jpeg binary -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # always ignore files 2 | *.DS_Store 3 | .idea 4 | .vscode 5 | *.sublime-* 6 | 7 | # test related, or directories generated by tests 8 | test/actual 9 | actual 10 | coverage 11 | .nyc* 12 | 13 | # npm 14 | node_modules 15 | npm-debug.log 16 | 17 | # yarn 18 | yarn.lock 19 | yarn-error.log 20 | 21 | # misc 22 | _gh_pages 23 | _draft 24 | _drafts 25 | bower_components 26 | vendor 27 | temp 28 | tmp 29 | TODO.md 30 | package-lock.json -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 14 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | os: 3 | - linux 4 | - osx 5 | language: node_js 6 | node_js: 7 | - node 8 | - '14' 9 | - '12' 10 | - '9' 11 | - '8' 12 | - '7' 13 | - '6' 14 | -------------------------------------------------------------------------------- /.verb.md: -------------------------------------------------------------------------------- 1 | ## Heads up! 2 | 3 | Please see the [changelog](CHANGELOG.md) to learn about breaking changes that were made in v3.0. 4 | 5 |
6 | 7 | # Sponsors 8 | 9 | Thanks to the following companies, organizations, and individuals for supporting the ongoing maintenance and development of {%= name %}! [Become a Sponsor](https://github.com/sponsors/jonschlinkert) to add your logo to this README, or any of [my other projects](https://github.com/jonschlinkert?tab=repositories&q=&type=&language=&sort=stargazers) 10 | 11 | ## Gold Sponsors 12 | 13 | | [https://jaake.tech/](https://jaake.tech/) | 14 | |:---:| 15 | | [https://jaake.tech/](https://jaake.tech/) | 16 | 17 |
18 | 19 | ## What does this do? 20 | 21 |
22 | Run this example 23 | 24 | Add the HTML in the following example to `example.html`, then add the following code to `example.js` and run `$ node example` (without the `$`): 25 | 26 | ```js 27 | const fs = require('fs'); 28 | const matter = require('gray-matter'); 29 | const str = fs.readFileSync('example.html', 'utf8'); 30 | console.log(matter(str)); 31 | ``` 32 | 33 |
34 | 35 | 36 | Converts a string with front-matter, like this: 37 | 38 | ```handlebars 39 | --- 40 | title: Hello 41 | slug: home 42 | --- 43 |

Hello world!

44 | ``` 45 | 46 | Into an object like this: 47 | 48 | ```js 49 | { 50 | content: '

Hello world!

', 51 | data: { 52 | title: 'Hello', 53 | slug: 'home' 54 | } 55 | } 56 | ``` 57 | 58 | ## Why use gray-matter? 59 | 60 | - **simple**: main function takes a string and returns an object 61 | - **accurate**: better at catching and handling edge cases than front-matter parsers that rely on regex for parsing 62 | - **fast**: faster than other front-matter parsers that use regex for parsing 63 | - **flexible**: By default, gray-matter is capable of parsing [YAML][js-yaml], [JSON](http://en.wikipedia.org/wiki/Json) and JavaScript front-matter. But other [engines](#optionsengines) may be added. 64 | - **extensible**: Use [custom delimiters](#optionsdelimiters), or add support for [any language](#optionsengines), like [TOML][], [CoffeeScript][], or [CSON][] 65 | - **battle-tested**: used by [assemble][], [metalsmith][], [phenomic][], [verb][], [generate][], [update][] and many others. 66 | 67 |
68 | Rationale 69 | 70 | **Why did we create gray-matter in the first place?** 71 | 72 | We created gray-matter after trying out other libraries that failed to meet our standards and requirements. 73 | 74 | Some libraries met most of the requirements, but _none met all of them_. 75 | 76 | **Here are the most important**: 77 | 78 | * Be usable, if not simple 79 | * Use a dependable and well-supported library for parsing YAML 80 | * Support other languages besides YAML 81 | * Support stringifying back to YAML or another language 82 | * Don't fail when no content exists 83 | * Don't fail when no front matter exists 84 | * Don't use regex for parsing. This is a relatively simple parsing operation, and regex is the slowest and most error-prone way to do it. 85 | * Have no problem reading YAML files directly 86 | * Have no problem with complex content, including **non-front-matter** fenced code blocks that contain examples of YAML front matter. Other parsers fail on this. 87 | * Support stringifying back to front-matter. This is useful for linting, updating properties, etc. 88 | * Allow custom delimiters, when it's necessary for avoiding delimiter collision. 89 | * Should return an object with at least these three properties: 90 | - `data`: the parsed YAML front matter, as a JSON object 91 | - `content`: the contents as a string, without the front matter 92 | - `orig`: the "original" content (for debugging) 93 | 94 |
95 | 96 | 97 | ## Usage 98 | 99 | Using Node's `require()` system: 100 | 101 | ```js 102 | const matter = require('gray-matter'); 103 | ``` 104 | 105 | Or with [typescript](https://www.typescriptlang.org) 106 | 107 | ```js 108 | import matter = require('gray-matter'); 109 | // OR 110 | import * as matter from 'gray-matter'; 111 | ``` 112 | 113 | Pass a string and [options](#options) to gray-matter: 114 | 115 | ```js 116 | console.log(matter('---\ntitle: Front Matter\n---\nThis is content.')); 117 | ``` 118 | 119 | Returns: 120 | 121 | ```js 122 | { 123 | content: '\nThis is content.', 124 | data: { 125 | title: 'Front Matter' 126 | } 127 | } 128 | ``` 129 | 130 | More about the returned object in the following section. 131 | 132 | *** 133 | 134 | ## Returned object 135 | 136 | gray-matter returns a `file` object with the following properties. 137 | 138 | **Enumerable** 139 | 140 | - `file.data` **{Object}**: the object created by parsing front-matter 141 | - `file.content` **{String}**: the input string, with `matter` stripped 142 | - `file.excerpt` **{String}**: an excerpt, if [defined on the options](#optionsexcerpt) 143 | - `file.empty` **{String}**: when the front-matter is "empty" (either all whitespace, nothing at all, or just comments and no data), the original string is set on this property. See [#65](https://github.com/jonschlinkert/gray-matter/issues/65) for details regarding use case. 144 | - `file.isEmpty` **{Boolean}**: true if front-matter is empty. 145 | 146 | **Non-enumerable** 147 | 148 | In addition, the following non-enumberable properties are added to the object to help with debugging. 149 | 150 | - `file.orig` **{Buffer}**: the original input string (or buffer) 151 | - `file.language` **{String}**: the front-matter language that was parsed. `yaml` is the default 152 | - `file.matter` **{String}**: the _raw_, un-parsed front-matter string 153 | - `file.stringify` **{Function}**: [stringify](#stringify) the file by converting `file.data` to a string in the given language, wrapping it in delimiters and prepending it to `file.content`. 154 | 155 | 156 | ## Run the examples 157 | 158 | If you'd like to test-drive the examples, first clone gray-matter into `my-project` (or wherever you want): 159 | 160 | ```sh 161 | $ git clone https://github.com/jonschlinkert/gray-matter my-project 162 | ``` 163 | 164 | CD into `my-project` and install dependencies: 165 | 166 | ```sh 167 | $ cd my-project && npm install 168 | ``` 169 | 170 | Then run any of the [examples](./examples) to see how gray-matter works: 171 | 172 | ```sh 173 | $ node examples/ 174 | ``` 175 | 176 | **Links to examples** 177 | 178 | {%= examples() %} 179 | 180 | 181 | ## API 182 | {%= apidocs("index.js") %} 183 | 184 | 185 | ## Options 186 | 187 | ### options.excerpt 188 | 189 | **Type**: `Boolean|Function` 190 | 191 | **Default**: `undefined` 192 | 193 | Extract an excerpt that directly follows front-matter, or is the first thing in the string if no front-matter exists. 194 | 195 | If set to `excerpt: true`, it will look for the frontmatter delimiter, `---` by default and grab everything leading up to it. 196 | 197 | **Example** 198 | 199 | ```js 200 | const str = '---\nfoo: bar\n---\nThis is an excerpt.\n---\nThis is content'; 201 | const file = matter(str, { excerpt: true }); 202 | ``` 203 | 204 | Results in: 205 | 206 | ```js 207 | { 208 | content: 'This is an excerpt.\n---\nThis is content', 209 | data: { foo: 'bar' }, 210 | excerpt: 'This is an excerpt.\n' 211 | } 212 | ``` 213 | 214 | You can also set `excerpt` to a function. This function uses the 'file' and 'options' that were initially passed to gray-matter as parameters, so you can control how the excerpt is extracted from the content. 215 | 216 | **Example** 217 | 218 | ```js 219 | // returns the first 4 lines of the contents 220 | function firstFourLines(file, options) { 221 | file.excerpt = file.content.split('\n').slice(0, 4).join(' '); 222 | } 223 | 224 | const file = matter([ 225 | '---', 226 | 'foo: bar', 227 | '---', 228 | 'Only this', 229 | 'will be', 230 | 'in the', 231 | 'excerpt', 232 | 'but not this...' 233 | ].join('\n'), {excerpt: firstFourLines}); 234 | ``` 235 | 236 | Results in: 237 | 238 | ```js 239 | { 240 | content: 'Only this\nwill be\nin the\nexcerpt\nbut not this...', 241 | data: { foo: 'bar' }, 242 | excerpt: 'Only this will be in the excerpt' 243 | } 244 | ``` 245 | 246 | ### options.excerpt_separator 247 | 248 | **Type**: `String` 249 | 250 | **Default**: `undefined` 251 | 252 | Define a custom separator to use for excerpts. 253 | 254 | 255 | ```js 256 | console.log(matter(string, {excerpt_separator: ''})); 257 | ``` 258 | 259 | **Example** 260 | 261 | The following HTML string: 262 | 263 | ```html 264 | --- 265 | title: Blog 266 | --- 267 | My awesome blog. 268 | 269 |

Hello world

270 | ``` 271 | 272 | Results in: 273 | 274 | ```js 275 | { 276 | data: { title: 'Blog'}, 277 | excerpt: 'My awesome blog.', 278 | content: 'My awesome blog.\n\n

Hello world

' 279 | } 280 | ``` 281 | 282 | ### options.engines 283 | 284 | Define custom engines for parsing and/or stringifying front-matter. 285 | 286 | **Type**: `Object` Object of engines 287 | 288 | **Default**: `JSON`, `YAML` and `JavaScript` are already handled by default. 289 | 290 | **Engine format** 291 | 292 | Engines may either be an object with `parse` and (optionally) `stringify` methods, or a function that will be used for parsing only. 293 | 294 | **Examples** 295 | 296 | ```js 297 | const toml = require('toml'); 298 | 299 | /** 300 | * defined as a function 301 | */ 302 | 303 | const file = matter(str, { 304 | engines: { 305 | toml: toml.parse.bind(toml), 306 | } 307 | }); 308 | 309 | /** 310 | * Or as an object 311 | */ 312 | 313 | const file = matter(str, { 314 | engines: { 315 | toml: { 316 | parse: toml.parse.bind(toml), 317 | 318 | // example of throwing an error to let users know stringifying is 319 | // not supported (a TOML stringifier might exist, this is just an example) 320 | stringify: function() { 321 | throw new Error('cannot stringify to TOML'); 322 | } 323 | } 324 | } 325 | }); 326 | 327 | console.log(file); 328 | ``` 329 | 330 | 331 | ### options.language 332 | 333 | **Type**: `String` 334 | 335 | **Default**: `yaml` 336 | 337 | Define the engine to use for parsing front-matter. 338 | 339 | ```js 340 | console.log(matter(string, {language: 'toml'})); 341 | ``` 342 | 343 | **Example** 344 | 345 | The following HTML string: 346 | 347 | ```html 348 | --- 349 | title = "TOML" 350 | description = "Front matter" 351 | categories = "front matter toml" 352 | --- 353 | This is content 354 | ``` 355 | 356 | Results in: 357 | 358 | ```js 359 | { content: 'This is content', 360 | excerpt: '', 361 | data: 362 | { title: 'TOML', 363 | description: 'Front matter', 364 | categories: 'front matter toml' } } 365 | ``` 366 | 367 | **Dynamic language detection** 368 | 369 | Instead of defining the language on the options, gray-matter will automatically detect the language defined after the first delimiter and select the correct engine to use for parsing. 370 | 371 | ```html 372 | ---toml 373 | title = "TOML" 374 | description = "Front matter" 375 | categories = "front matter toml" 376 | --- 377 | This is content 378 | ``` 379 | 380 | 381 | ### options.delimiters 382 | 383 | **Type**: `String` 384 | 385 | **Default**: `---` 386 | 387 | Open and close delimiters can be passed in as an array of strings. 388 | 389 | **Example:** 390 | 391 | ```js 392 | // format delims as a string 393 | matter.read('file.md', {delims: '~~~'}); 394 | // or an array (open/close) 395 | matter.read('file.md', {delims: ['~~~', '~~~']}); 396 | ``` 397 | 398 | would parse: 399 | 400 | ```html 401 | ~~~ 402 | title: Home 403 | ~~~ 404 | This is the {{title}} page. 405 | ``` 406 | 407 | ## Deprecated options 408 | 409 | ### options.lang 410 | 411 | Decrecated, please use [options.language](#optionslanguage) instead. 412 | 413 | ### options.delims 414 | 415 | Decrecated, please use [options.delimiters](#optionsdelimiters) instead. 416 | 417 | ### options.parsers 418 | 419 | Decrecated, please use [options.engines](#optionsengines) instead. 420 | 421 | 422 | [bootstrap-blog]: https://github.com/twbs/bootstrap-blog/tree/gh-pages/_posts 423 | [assemble]: https://github.com/assemble/assemble 424 | [metalsmith]: https://github.com/segmentio/metalsmith 425 | [phenomic]: https://github.com/phenomic/phenomic 426 | [verb]: https://github.com/assemble/verb 427 | [TOML]: http://github.com/mojombo/toml 428 | [CoffeeScript]: http://coffeescript.org 429 | [CSON]: https://github.com/bevry/cson 430 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Release history 2 | 3 | ## 4.0.0 - 2018-04-01 4 | 5 | ### Breaking changes 6 | 7 | - Now requires node v4 or higher. 8 | 9 | 10 | ## 3.0.0 - 2017-06-30 11 | 12 | ### Breaking changes 13 | 14 | - `toml`, `coffee` and `cson` are no longer supported by default. Please see [`options.engines`](README.md#optionsengines) and the [examples](./examples) to learn how to add engines. 15 | 16 | ### Added 17 | 18 | - Support for [excerpts](README.md#optionsexcerpt). 19 | - The returned object now has non-enumerable `matter` and `stringify` properties. 20 | 21 | ### Changed 22 | 23 | - Refactored engines (parsers), so that it's easier to add parsers and stringifiers. 24 | - `options.parsers` was renamed to [`options.engines`](README.md#optionsengines) 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-present, Jon Schlinkert. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gray-matter [![NPM version](https://img.shields.io/npm/v/gray-matter.svg?style=flat)](https://www.npmjs.com/package/gray-matter) [![NPM monthly downloads](https://img.shields.io/npm/dm/gray-matter.svg?style=flat)](https://npmjs.org/package/gray-matter) [![NPM total downloads](https://img.shields.io/npm/dt/gray-matter.svg?style=flat)](https://npmjs.org/package/gray-matter) 2 | 3 | > Parse front-matter from a string or file. Fast, reliable and easy to use. Parses YAML front matter by default, but also has support for YAML, JSON, TOML or Coffee Front-Matter, with options to set custom delimiters. Used by metalsmith, assemble, verb and many other projects. 4 | 5 | Please consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support. 6 | 7 | ## Install 8 | 9 | Install with [npm](https://www.npmjs.com/): 10 | 11 | ```sh 12 | $ npm install --save gray-matter 13 | ``` 14 | 15 | ## Heads up! 16 | 17 | Please see the [changelog](CHANGELOG.md) to learn about breaking changes that were made in v3.0. 18 | 19 |
20 | 21 | # Sponsors 22 | 23 | Thanks to the following companies, organizations, and individuals for supporting the ongoing maintenance and development of gray-matter! [Become a Sponsor](https://github.com/sponsors/jonschlinkert) to add your logo to this README, or any of [my other projects](https://github.com/jonschlinkert?tab=repositories&q=&type=&language=&sort=stargazers) 24 | 25 | ## Gold Sponsors 26 | 27 | | [https://jaake.tech/](https://jaake.tech/) | 28 | |:---:| 29 | | [https://jaake.tech/](https://jaake.tech/) | 30 | 31 |
32 | 33 | ## What does this do? 34 | 35 |
36 | Run this example 37 | 38 | Add the HTML in the following example to `example.html`, then add the following code to `example.js` and run `$ node example` (without the `$`): 39 | 40 | ```js 41 | const fs = require('fs'); 42 | const matter = require('gray-matter'); 43 | const str = fs.readFileSync('example.html', 'utf8'); 44 | console.log(matter(str)); 45 | ``` 46 | 47 |
48 | 49 | Converts a string with front-matter, like this: 50 | 51 | ```handlebars 52 | --- 53 | title: Hello 54 | slug: home 55 | --- 56 |

Hello world!

57 | ``` 58 | 59 | Into an object like this: 60 | 61 | ```js 62 | { 63 | content: '

Hello world!

', 64 | data: { 65 | title: 'Hello', 66 | slug: 'home' 67 | } 68 | } 69 | ``` 70 | 71 | ## Why use gray-matter? 72 | 73 | * **simple**: main function takes a string and returns an object 74 | * **accurate**: better at catching and handling edge cases than front-matter parsers that rely on regex for parsing 75 | * **fast**: faster than other front-matter parsers that use regex for parsing 76 | * **flexible**: By default, gray-matter is capable of parsing [YAML](https://github.com/nodeca/js-yaml), [JSON](http://en.wikipedia.org/wiki/Json) and JavaScript front-matter. But other [engines](#optionsengines) may be added. 77 | * **extensible**: Use [custom delimiters](#optionsdelimiters), or add support for [any language](#optionsengines), like [TOML](http://github.com/mojombo/toml), [CoffeeScript](http://coffeescript.org), or [CSON](https://github.com/bevry/cson) 78 | * **battle-tested**: used by [assemble](https://github.com/assemble/assemble), [metalsmith](https://github.com/segmentio/metalsmith), [phenomic](https://github.com/phenomic/phenomic), [verb](https://github.com/assemble/verb), [generate](https://github.com/generate/generate), [update](https://github.com/update/update) and many others. 79 | 80 |
81 | Rationale 82 | 83 | **Why did we create gray-matter in the first place?** 84 | 85 | We created gray-matter after trying out other libraries that failed to meet our standards and requirements. 86 | 87 | Some libraries met most of the requirements, but _none met all of them_. 88 | 89 | **Here are the most important**: 90 | 91 | * Be usable, if not simple 92 | * Use a dependable and well-supported library for parsing YAML 93 | * Support other languages besides YAML 94 | * Support stringifying back to YAML or another language 95 | * Don't fail when no content exists 96 | * Don't fail when no front matter exists 97 | * Don't use regex for parsing. This is a relatively simple parsing operation, and regex is the slowest and most error-prone way to do it. 98 | * Have no problem reading YAML files directly 99 | * Have no problem with complex content, including **non-front-matter** fenced code blocks that contain examples of YAML front matter. Other parsers fail on this. 100 | * Support stringifying back to front-matter. This is useful for linting, updating properties, etc. 101 | * Allow custom delimiters, when it's necessary for avoiding delimiter collision. 102 | * Should return an object with at least these three properties: 103 | - `data`: the parsed YAML front matter, as a JSON object 104 | - `content`: the contents as a string, without the front matter 105 | - `orig`: the "original" content (for debugging) 106 | 107 |
108 | 109 | ## Usage 110 | 111 | Using Node's `require()` system: 112 | 113 | ```js 114 | const matter = require('gray-matter'); 115 | ``` 116 | 117 | Or with [typescript](https://www.typescriptlang.org) 118 | 119 | ```js 120 | import matter = require('gray-matter'); 121 | // OR 122 | import * as matter from 'gray-matter'; 123 | ``` 124 | 125 | Pass a string and [options](#options) to gray-matter: 126 | 127 | ```js 128 | console.log(matter('---\ntitle: Front Matter\n---\nThis is content.')); 129 | ``` 130 | 131 | Returns: 132 | 133 | ```js 134 | { 135 | content: '\nThis is content.', 136 | data: { 137 | title: 'Front Matter' 138 | } 139 | } 140 | ``` 141 | 142 | More about the returned object in the following section. 143 | 144 | *** 145 | 146 | ## Returned object 147 | 148 | gray-matter returns a `file` object with the following properties. 149 | 150 | **Enumerable** 151 | 152 | * `file.data` **{Object}**: the object created by parsing front-matter 153 | * `file.content` **{String}**: the input string, with `matter` stripped 154 | * `file.excerpt` **{String}**: an excerpt, if [defined on the options](#optionsexcerpt) 155 | * `file.empty` **{String}**: when the front-matter is "empty" (either all whitespace, nothing at all, or just comments and no data), the original string is set on this property. See [#65](https://github.com/jonschlinkert/gray-matter/issues/65) for details regarding use case. 156 | * `file.isEmpty` **{Boolean}**: true if front-matter is empty. 157 | 158 | **Non-enumerable** 159 | 160 | In addition, the following non-enumberable properties are added to the object to help with debugging. 161 | 162 | * `file.orig` **{Buffer}**: the original input string (or buffer) 163 | * `file.language` **{String}**: the front-matter language that was parsed. `yaml` is the default 164 | * `file.matter` **{String}**: the _raw_, un-parsed front-matter string 165 | * `file.stringify` **{Function}**: [stringify](#stringify) the file by converting `file.data` to a string in the given language, wrapping it in delimiters and prepending it to `file.content`. 166 | 167 | ## Run the examples 168 | 169 | If you'd like to test-drive the examples, first clone gray-matter into `my-project` (or wherever you want): 170 | 171 | ```sh 172 | $ git clone https://github.com/jonschlinkert/gray-matter my-project 173 | ``` 174 | 175 | CD into `my-project` and install dependencies: 176 | 177 | ```sh 178 | $ cd my-project && npm install 179 | ``` 180 | 181 | Then run any of the [examples](./examples) to see how gray-matter works: 182 | 183 | ```sh 184 | $ node examples/ 185 | ``` 186 | 187 | **Links to examples** 188 | 189 | * [coffee](examples/coffee.js) 190 | * [excerpt-separator](examples/excerpt-separator.js) 191 | * [excerpt-stringify](examples/excerpt-stringify.js) 192 | * [excerpt](examples/excerpt.js) 193 | * [javascript](examples/javascript.js) 194 | * [json-stringify](examples/json-stringify.js) 195 | * [json](examples/json.js) 196 | * [restore-empty](examples/restore-empty.js) 197 | * [sections-excerpt](examples/sections-excerpt.js) 198 | * [sections](examples/sections.js) 199 | * [toml](examples/toml.js) 200 | * [yaml-stringify](examples/yaml-stringify.js) 201 | * [yaml](examples/yaml.js) 202 | 203 | ## API 204 | 205 | ### [matter](index.js#L29) 206 | 207 | Takes a string or object with `content` property, extracts and parses front-matter from the string, then returns an object with `data`, `content` and other [useful properties](#returned-object). 208 | 209 | **Params** 210 | 211 | * `input` **{Object|String}**: String, or object with `content` string 212 | * `options` **{Object}** 213 | * `returns` **{Object}** 214 | 215 | **Example** 216 | 217 | ```js 218 | const matter = require('gray-matter'); 219 | console.log(matter('---\ntitle: Home\n---\nOther stuff')); 220 | //=> { data: { title: 'Home'}, content: 'Other stuff' } 221 | ``` 222 | 223 | ### [.stringify](index.js#L160) 224 | 225 | Stringify an object to YAML or the specified language, and append it to the given string. By default, only YAML and JSON can be stringified. See the [engines](#engines) section to learn how to stringify other languages. 226 | 227 | **Params** 228 | 229 | * `file` **{String|Object}**: The content string to append to stringified front-matter, or a file object with `file.content` string. 230 | * `data` **{Object}**: Front matter to stringify. 231 | * `options` **{Object}**: [Options](#options) to pass to gray-matter and [js-yaml](https://github.com/nodeca/js-yaml). 232 | * `returns` **{String}**: Returns a string created by wrapping stringified yaml with delimiters, and appending that to the given string. 233 | 234 | **Example** 235 | 236 | ```js 237 | console.log(matter.stringify('foo bar baz', {title: 'Home'})); 238 | // results in: 239 | // --- 240 | // title: Home 241 | // --- 242 | // foo bar baz 243 | ``` 244 | 245 | ### [.read](index.js#L178) 246 | 247 | Synchronously read a file from the file system and parse front matter. Returns the same object as the [main function](#matter). 248 | 249 | **Params** 250 | 251 | * `filepath` **{String}**: file path of the file to read. 252 | * `options` **{Object}**: [Options](#options) to pass to gray-matter. 253 | * `returns` **{Object}**: Returns [an object](#returned-object) with `data` and `content` 254 | 255 | **Example** 256 | 257 | ```js 258 | const file = matter.read('./content/blog-post.md'); 259 | ``` 260 | 261 | ### [.test](index.js#L193) 262 | 263 | Returns true if the given `string` has front matter. 264 | 265 | **Params** 266 | 267 | * `string` **{String}** 268 | * `options` **{Object}** 269 | * `returns` **{Boolean}**: True if front matter exists. 270 | 271 | ## Options 272 | 273 | ### options.excerpt 274 | 275 | **Type**: `Boolean|Function` 276 | 277 | **Default**: `undefined` 278 | 279 | Extract an excerpt that directly follows front-matter, or is the first thing in the string if no front-matter exists. 280 | 281 | If set to `excerpt: true`, it will look for the frontmatter delimiter, `---` by default and grab everything leading up to it. 282 | 283 | **Example** 284 | 285 | ```js 286 | const str = '---\nfoo: bar\n---\nThis is an excerpt.\n---\nThis is content'; 287 | const file = matter(str, { excerpt: true }); 288 | ``` 289 | 290 | Results in: 291 | 292 | ```js 293 | { 294 | content: 'This is an excerpt.\n---\nThis is content', 295 | data: { foo: 'bar' }, 296 | excerpt: 'This is an excerpt.\n' 297 | } 298 | ``` 299 | 300 | You can also set `excerpt` to a function. This function uses the 'file' and 'options' that were initially passed to gray-matter as parameters, so you can control how the excerpt is extracted from the content. 301 | 302 | **Example** 303 | 304 | ```js 305 | // returns the first 4 lines of the contents 306 | function firstFourLines(file, options) { 307 | file.excerpt = file.content.split('\n').slice(0, 4).join(' '); 308 | } 309 | 310 | const file = matter([ 311 | '---', 312 | 'foo: bar', 313 | '---', 314 | 'Only this', 315 | 'will be', 316 | 'in the', 317 | 'excerpt', 318 | 'but not this...' 319 | ].join('\n'), {excerpt: firstFourLines}); 320 | ``` 321 | 322 | Results in: 323 | 324 | ```js 325 | { 326 | content: 'Only this\nwill be\nin the\nexcerpt\nbut not this...', 327 | data: { foo: 'bar' }, 328 | excerpt: 'Only this will be in the excerpt' 329 | } 330 | ``` 331 | 332 | ### options.excerpt_separator 333 | 334 | **Type**: `String` 335 | 336 | **Default**: `undefined` 337 | 338 | Define a custom separator to use for excerpts. 339 | 340 | ```js 341 | console.log(matter(string, {excerpt_separator: ''})); 342 | ``` 343 | 344 | **Example** 345 | 346 | The following HTML string: 347 | 348 | ```html 349 | --- 350 | title: Blog 351 | --- 352 | My awesome blog. 353 | 354 |

Hello world

355 | ``` 356 | 357 | Results in: 358 | 359 | ```js 360 | { 361 | data: { title: 'Blog'}, 362 | excerpt: 'My awesome blog.', 363 | content: 'My awesome blog.\n\n

Hello world

' 364 | } 365 | ``` 366 | 367 | ### options.engines 368 | 369 | Define custom engines for parsing and/or stringifying front-matter. 370 | 371 | **Type**: `Object` Object of engines 372 | 373 | **Default**: `JSON`, `YAML` and `JavaScript` are already handled by default. 374 | 375 | **Engine format** 376 | 377 | Engines may either be an object with `parse` and (optionally) `stringify` methods, or a function that will be used for parsing only. 378 | 379 | **Examples** 380 | 381 | ```js 382 | const toml = require('toml'); 383 | 384 | /** 385 | * defined as a function 386 | */ 387 | 388 | const file = matter(str, { 389 | engines: { 390 | toml: toml.parse.bind(toml), 391 | } 392 | }); 393 | 394 | /** 395 | * Or as an object 396 | */ 397 | 398 | const file = matter(str, { 399 | engines: { 400 | toml: { 401 | parse: toml.parse.bind(toml), 402 | 403 | // example of throwing an error to let users know stringifying is 404 | // not supported (a TOML stringifier might exist, this is just an example) 405 | stringify: function() { 406 | throw new Error('cannot stringify to TOML'); 407 | } 408 | } 409 | } 410 | }); 411 | 412 | console.log(file); 413 | ``` 414 | 415 | ### options.language 416 | 417 | **Type**: `String` 418 | 419 | **Default**: `yaml` 420 | 421 | Define the engine to use for parsing front-matter. 422 | 423 | ```js 424 | console.log(matter(string, {language: 'toml'})); 425 | ``` 426 | 427 | **Example** 428 | 429 | The following HTML string: 430 | 431 | ```html 432 | --- 433 | title = "TOML" 434 | description = "Front matter" 435 | categories = "front matter toml" 436 | --- 437 | This is content 438 | ``` 439 | 440 | Results in: 441 | 442 | ```js 443 | { content: 'This is content', 444 | excerpt: '', 445 | data: 446 | { title: 'TOML', 447 | description: 'Front matter', 448 | categories: 'front matter toml' } } 449 | ``` 450 | 451 | **Dynamic language detection** 452 | 453 | Instead of defining the language on the options, gray-matter will automatically detect the language defined after the first delimiter and select the correct engine to use for parsing. 454 | 455 | ```html 456 | ---toml 457 | title = "TOML" 458 | description = "Front matter" 459 | categories = "front matter toml" 460 | --- 461 | This is content 462 | ``` 463 | 464 | ### options.delimiters 465 | 466 | **Type**: `String` 467 | 468 | **Default**: `---` 469 | 470 | Open and close delimiters can be passed in as an array of strings. 471 | 472 | **Example:** 473 | 474 | ```js 475 | // format delims as a string 476 | matter.read('file.md', {delims: '~~~'}); 477 | // or an array (open/close) 478 | matter.read('file.md', {delims: ['~~~', '~~~']}); 479 | ``` 480 | 481 | would parse: 482 | 483 | ```html 484 | ~~~ 485 | title: Home 486 | ~~~ 487 | This is the {{title}} page. 488 | ``` 489 | 490 | ## Deprecated options 491 | 492 | ### options.lang 493 | 494 | Decrecated, please use [options.language](#optionslanguage) instead. 495 | 496 | ### options.delims 497 | 498 | Decrecated, please use [options.delimiters](#optionsdelimiters) instead. 499 | 500 | ### options.parsers 501 | 502 | Decrecated, please use [options.engines](#optionsengines) instead. 503 | 504 | ## About 505 | 506 |
507 | Contributing 508 | 509 | Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new). 510 | 511 |
512 | 513 |
514 | Running Tests 515 | 516 | Running 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: 517 | 518 | ```sh 519 | $ npm install && npm test 520 | ``` 521 | 522 |
523 | 524 |
525 | Building docs 526 | 527 | _(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.)_ 528 | 529 | To generate the readme, run the following command: 530 | 531 | ```sh 532 | $ npm install -g verbose/verb#dev verb-generate-readme && verb 533 | ``` 534 | 535 |
536 | 537 | ### Related projects 538 | 539 | You might also be interested in these projects: 540 | 541 | * [assemble](https://www.npmjs.com/package/assemble): Get the rocks out of your socks! Assemble makes you fast at creating web projects… [more](https://github.com/assemble/assemble) | [homepage](https://github.com/assemble/assemble "Get the rocks out of your socks! Assemble makes you fast at creating web projects. Assemble is used by thousands of projects for rapid prototyping, creating themes, scaffolds, boilerplates, e-books, UI components, API documentation, blogs, building websit") 542 | * [metalsmith](https://www.npmjs.com/package/metalsmith): An extremely simple, pluggable static site generator. | [homepage](https://metalsmith.io "An extremely simple, pluggable static site generator.") 543 | * [verb](https://www.npmjs.com/package/verb): Documentation generator for GitHub projects. Verb is extremely powerful, easy to use, and is used… [more](https://github.com/verbose/verb) | [homepage](https://github.com/verbose/verb "Documentation generator for GitHub projects. Verb is extremely powerful, easy to use, and is used on hundreds of projects of all sizes to generate everything from API docs to readmes.") 544 | 545 | ### Contributors 546 | 547 | | **Commits** | **Contributor** | 548 | | --- | --- | 549 | | 179 | [jonschlinkert](https://github.com/jonschlinkert) | 550 | | 13 | [robertmassaioli](https://github.com/robertmassaioli) | 551 | | 7 | [RobLoach](https://github.com/RobLoach) | 552 | | 5 | [doowb](https://github.com/doowb) | 553 | | 5 | [heymind](https://github.com/heymind) | 554 | | 3 | [aljopro](https://github.com/aljopro) | 555 | | 3 | [shawnbot](https://github.com/shawnbot) | 556 | | 2 | [reccanti](https://github.com/reccanti) | 557 | | 2 | [onokumus](https://github.com/onokumus) | 558 | | 2 | [moozzyk](https://github.com/moozzyk) | 559 | | 2 | [ajaymathur](https://github.com/ajaymathur) | 560 | | 1 | [Ajedi32](https://github.com/Ajedi32) | 561 | | 1 | [arlair](https://github.com/arlair) | 562 | | 1 | [caesar](https://github.com/caesar) | 563 | | 1 | [ianstormtaylor](https://github.com/ianstormtaylor) | 564 | | 1 | [qm3ster](https://github.com/qm3ster) | 565 | | 1 | [zachwhaley](https://github.com/zachwhaley) | 566 | 567 | ### Author 568 | 569 | **Jon Schlinkert** 570 | 571 | * [GitHub Profile](https://github.com/jonschlinkert) 572 | * [Twitter Profile](https://twitter.com/jonschlinkert) 573 | * [LinkedIn Profile](https://linkedin.com/in/jonschlinkert) 574 | 575 | ### License 576 | 577 | Copyright © 2023, [Jon Schlinkert](https://github.com/jonschlinkert). 578 | Released under the [MIT License](LICENSE). 579 | 580 | *** 581 | 582 | _This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on July 12, 2023._ -------------------------------------------------------------------------------- /benchmark/bulk/code/front-matter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var frontMatter = require('front-matter'); 4 | 5 | module.exports = function(arr) { 6 | var len = arr.length; 7 | var res = []; 8 | while (len--) { 9 | res.push(frontMatter(arr[len])); 10 | } 11 | return res; 12 | }; 13 | -------------------------------------------------------------------------------- /benchmark/bulk/code/gray-matter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var matter = require('../../..'); 4 | 5 | module.exports = function(arr) { 6 | var len = arr.length; 7 | var res = []; 8 | while (len--) { 9 | res.push(matter(arr[len])); 10 | } 11 | return res; 12 | }; 13 | -------------------------------------------------------------------------------- /benchmark/bulk/fixtures/posts.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | var fp = path.join(process.cwd(), 'vendor/bootstrap-blog/_posts'); 7 | if (!fs.existsSync(fp)) { 8 | var msg = [ 9 | ' to run this benchmark you need to pull down the', 10 | ' the bootstrap-blog first. To do so, run:', 11 | ' git clone https://github.com/twbs/bootstrap-blog.git "vendor/bootstrap-blog"', 12 | ].join('\n'); 13 | console.log(msg); 14 | process.exit(0); 15 | } 16 | 17 | module.exports = [lookup(fp)]; 18 | 19 | function lookup(dir) { 20 | var files = fs.readdirSync(dir); 21 | var len = files.length; 22 | var res = []; 23 | 24 | while (len--) { 25 | var fp = path.join(dir, files[len]); 26 | var isFile = fs.statSync(fp).isFile(); 27 | 28 | if (isFile) { 29 | res.push(fs.readFileSync(fp, 'utf8')); 30 | } 31 | } 32 | 33 | // console.log('module.exports = [' + JSON.stringify(res) + '];'); 34 | return res; 35 | } 36 | -------------------------------------------------------------------------------- /benchmark/code/0.5.3.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var delims = require('delimiter-regex'); 4 | var extend = require('extend-shallow'); 5 | var parse = require('../../lib/parse'); 6 | 7 | module.exports = function matter(str, options) { 8 | if (str.length === 0) { 9 | return {orig: '', data: {}, content: ''}; 10 | } 11 | 12 | if (str.charCodeAt(0) === 65279 && str.charCodeAt(1) === 116 && str.charCodeAt(2) === 104) { 13 | str = str.slice(1); 14 | } 15 | 16 | var opts = extend({}, options); 17 | if (str.slice(0, 3) !== '---') { 18 | return {orig: str, data: {}, content: str}; 19 | } 20 | 21 | var delimiters = delims(['---([^\\n]*)', '---\s*([\\s\\S]*)']); 22 | var file = str.match(delimiters); 23 | var res = {orig: str, data: {}, content: str}; 24 | 25 | if (file) { 26 | var lang = (file[1] !== '' ? file[1].trim() : opts.lang) || 'yaml'; 27 | try { 28 | res.data = parse(lang, file[2].trim(), opts); 29 | } catch (err) { 30 | err.origin = __filename; 31 | console.log('Front-matter language not detected by gray-matter', err); 32 | } 33 | res.content = file[3].trim(); 34 | } 35 | 36 | return res; 37 | }; 38 | -------------------------------------------------------------------------------- /benchmark/code/charAt.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var extend = require('extend-shallow'); 4 | var engines = require('../../lib/engines'); 5 | 6 | module.exports = function matter(str, options) { 7 | var res = {orig: str, data: {}, content: ''}; 8 | if (str == '') { 9 | return res; 10 | } 11 | 12 | if (str.charCodeAt(0) === 65279 && str.charCodeAt(1) === 116 && str.charCodeAt(2) === 104) { 13 | str = str.slice(1); 14 | } 15 | 16 | if (str.slice(0, 3) !== '---') { 17 | return res; 18 | } 19 | 20 | var opts = extend({lang: 'yaml', eval: true}, options); 21 | var delim = '---'; 22 | var dlen = delim.length; 23 | var len = str.length - dlen; 24 | var i = dlen; 25 | 26 | var langEnd = false, dataEnd = false; 27 | var data = '', lang = '', next = dlen; 28 | 29 | while (len--) { 30 | var ch = str.charCodeAt(i); 31 | if (langEnd === false && ch == 10 /* '\n' */) { 32 | langEnd = true; 33 | next = i; 34 | } 35 | 36 | if (ch === 45 && str.charCodeAt(i + 1) === 45 && str.charCodeAt(i + 2) === 45) { 37 | dataEnd = true; 38 | next = i + 2; 39 | } 40 | 41 | if (langEnd === false) { 42 | lang += str.charAt(i); 43 | } 44 | 45 | if (langEnd === true && dataEnd === false) { 46 | data += str.charAt(i); 47 | } 48 | 49 | if (dataEnd === true && i > next) { 50 | res.content += str.charAt(i); 51 | } 52 | i++; 53 | } 54 | 55 | lang = (lang && lang.length > 0) 56 | ? lang.trim() 57 | : (opts.lang || 'yaml'); 58 | 59 | data = (data && data.length > 0) 60 | ? data.trim() 61 | : null; 62 | 63 | if (data && data.length > 0) { 64 | var fn = engines[lang]; 65 | if (typeof fn === 'function') { 66 | // The actual data block to parse 67 | res.data = fn(data, opts); 68 | } 69 | } 70 | 71 | if (data == null) { 72 | res.data = {}; 73 | } 74 | 75 | return res; 76 | }; 77 | -------------------------------------------------------------------------------- /benchmark/code/front-matter.js: -------------------------------------------------------------------------------- 1 | module.exports = require('front-matter'); 2 | -------------------------------------------------------------------------------- /benchmark/code/gray-matter.js: -------------------------------------------------------------------------------- 1 | module.exports = require('../..'); 2 | -------------------------------------------------------------------------------- /benchmark/code/read.js: -------------------------------------------------------------------------------- 1 | var extend = require('extend-shallow'); 2 | var engines = require('../../lib/engines'); 3 | 4 | module.exports = function matter(str, options) { 5 | var defaults = {orig: str, data: {}, content: str}; 6 | if (str == '') { 7 | return defaults; 8 | } 9 | 10 | if (str.charCodeAt(0) === 65279 && str.charCodeAt(1) === 116 && str.charCodeAt(2) === 104) { 11 | str = str.slice(1); 12 | } 13 | 14 | // default results 15 | var opts = extend({eval: true}, options); 16 | 17 | // delimiters to use. defaults are `---` 18 | var delim1 = '---'; 19 | var delim2 = '---'; 20 | 21 | // delimiter lengths 22 | var alen = delim1.length; 23 | var blen = delim2.length; 24 | 25 | if (str.slice(0, 3) !== '---') { 26 | return defaults; 27 | } 28 | 29 | // index of the first newline 30 | var nl = str.indexOf('\n'); 31 | 32 | // parser language to use 33 | var lang = str.slice(alen, nl); 34 | var res = defaults; 35 | 36 | // start/end index of the data block to parse 37 | var dataStart = (alen + lang.length); 38 | var dataEnd = str.indexOf(delim2, dataStart); 39 | 40 | // The actual data block to parse 41 | var data = str.slice(dataStart, dataEnd).trim(); 42 | 43 | var fn = opts.parser || parser(lang.trim(), opts); 44 | if (data.length > 0 && typeof fn === 'function') { 45 | try { 46 | res.data = fn(data, opts); 47 | } catch (err) {} 48 | } else if (opts.strict) { 49 | throw new Error('gray-matter cannot find a parser for: ' + str); 50 | } else { 51 | res.data = {}; 52 | } 53 | 54 | res.content = str.slice(blen + dataEnd); 55 | delete res.lang; 56 | return res; 57 | }; 58 | 59 | /** 60 | * Determine the correct the parser to use 61 | * 62 | * @param {String} `lang` Use this if defined and it exists 63 | * @param {Object} `opts` Otherwise, fall back to options.parser or js-yaml 64 | * @return {Function} 65 | */ 66 | 67 | function parser(lang, opts) { 68 | lang = lang || opts.lang; 69 | if (engines.hasOwnProperty(lang)) { 70 | return engines[lang]; 71 | } 72 | return engines.yaml; 73 | } 74 | -------------------------------------------------------------------------------- /benchmark/code/regex.js: -------------------------------------------------------------------------------- 1 | var engines = require('../../lib/engines'); 2 | 3 | module.exports = function matter(str, options) { 4 | if (str.length === 0) { 5 | return {orig: '', data: {}, content: ''}; 6 | } 7 | 8 | if (str.charCodeAt(0) === 65279 && str.charCodeAt(1) === 116 && str.charCodeAt(2) === 104) { 9 | str = str.slice(1); 10 | } 11 | 12 | var match = matchDelims(str); 13 | var lang = match && match[2].trim(); 14 | return !match ? {orig: str, data: {}, content: str} : { 15 | orig: str, 16 | data: lang.length > 0 17 | ? engines[lang in engines ? lang : 'yaml'](lang) 18 | : {}, 19 | content: str.replace(match[0], '') 20 | }; 21 | }; 22 | 23 | function matchDelims(str) { 24 | return /---([^\n]*)([\s\S]*?)\s*---\s*/.exec(str); 25 | } 26 | -------------------------------------------------------------------------------- /benchmark/code/split.js: -------------------------------------------------------------------------------- 1 | var extend = require('extend-shallow'); 2 | var engines = require('../../lib/engines'); 3 | 4 | module.exports = function matter(str, options) { 5 | var defaults = {orig: str, data: {}, content: str}; 6 | if (str == '') { 7 | return defaults; 8 | } 9 | 10 | // strip BOM 11 | if (str.charCodeAt(0) === 65279 && str.charCodeAt(1) === 116 && str.charCodeAt(2) === 104) { 12 | str = str.slice(1); 13 | } 14 | 15 | if (str.slice(0, 3) !== '---') { 16 | return defaults; 17 | } 18 | 19 | var res = {lang: 'yaml', data: {}, content: '', orig: str}; 20 | var opts = extend({}, options); 21 | var delims = opts.delims || ['---', '---']; 22 | 23 | str = str.substr(delims[0].length); 24 | var sections = str.split(delims[0]); 25 | res.data = sections[0]; 26 | 27 | if (res.data[0] !== '\n') { 28 | var n = res.data.indexOf('\n'); 29 | res.lang = res.data.substr(0, n).trim(); 30 | res.data = res.data.substr(n); 31 | } 32 | 33 | if (res.data.length > 0) { 34 | res.data = engines[res.lang](res.data, opts); 35 | } 36 | 37 | // if (typeof res.data === 'string') { 38 | // throw new Error('gray-matter cannot parse: ' + res.data); 39 | // } 40 | 41 | sections.shift(); 42 | res.content = sections.join(delims[0]).trim(); 43 | return res; 44 | }; 45 | -------------------------------------------------------------------------------- /benchmark/code/substr.js: -------------------------------------------------------------------------------- 1 | var extend = require('extend-shallow'); 2 | var engines = require('../../lib/engines'); 3 | 4 | module.exports = function matter(str, options) { 5 | var defaults = {orig: str, data: {}, content: str}; 6 | if (str == '') { 7 | return defaults; 8 | } 9 | 10 | // strip BOM 11 | if (str.charCodeAt(0) === 65279 && str.charCodeAt(1) === 116 && str.charCodeAt(2) === 104) { 12 | str = str.slice(1); 13 | } 14 | 15 | if (str.slice(0, 3) !== '---') { 16 | return defaults; 17 | } 18 | 19 | var res = defaults; 20 | var opts = extend({lang: 'yaml'}, options); 21 | var delims = opts.delims || ['---', '---']; 22 | 23 | var len = delims[0].length; 24 | str = str.substr(len); 25 | 26 | if (str[0] !== '\n') { 27 | var n = str.indexOf('\n'); 28 | res.lang = str.substr(0, n); 29 | str = str.substr(n); 30 | } 31 | 32 | var ii = str.indexOf(delims[1]); 33 | res.lang = (res.lang || opts.lang).trim(); 34 | res.data = str.substr(0, ii); 35 | 36 | if (res.data.length > 0 && engines.hasOwnProperty(res.lang)) { 37 | res.data = engines[res.lang](res.data, opts); 38 | } 39 | 40 | if (typeof res.data === 'string') { 41 | throw new Error('gray-matter cannot parse: ' + res.data); 42 | } 43 | 44 | res.content = str.substr(ii + delims[1].length).trim(); 45 | return res; 46 | }; 47 | -------------------------------------------------------------------------------- /benchmark/code/while.js: -------------------------------------------------------------------------------- 1 | var extend = require('extend-shallow'); 2 | var engines = require('../../lib/engines'); 3 | 4 | module.exports = function matter(str, options) { 5 | if (str.length === 0) { 6 | return {orig: '', data: {}, content: ''}; 7 | } 8 | 9 | if (str.charCodeAt(0) === 65279 && str.charCodeAt(1) === 116 && str.charCodeAt(2) === 104) { 10 | str = str.slice(1); 11 | } 12 | 13 | var o = {data: {}, content: '', orig: str}; 14 | var opts = extend({lang: 'yaml', eval: true}, options); 15 | var delim = opts.delims || ['---', '---']; 16 | 17 | // make sure the starting delim is first thing 18 | if (str.slice(0, delim[0].length) !== delim[0]) { 19 | return {orig: str, data: {}, content: str}; 20 | } 21 | 22 | var len = delim[0].length; 23 | var ch = len; 24 | var language, lang = ''; 25 | 26 | while ((language = str.charAt(ch++)) !== '\n') { 27 | lang += language; 28 | } 29 | 30 | var ll = lang.length; 31 | var to = str.indexOf(delim[0], len); 32 | lang = (lang || opts.lang).trim(); 33 | 34 | var fn = engines[lang]; 35 | var data = str.substr(len + ll, to - ll - len); 36 | if (fn && data.length > 0) { 37 | o.data = fn(data, opts); 38 | } else { 39 | o.data = str.substr(len + ll, to - ll - len); 40 | } 41 | 42 | if (typeof o.data !== 'object') { 43 | throw new Error('gray-matter cannot parse: ' + o.data); 44 | } 45 | 46 | o.content = str.substr(to + len).trim(); 47 | return o; 48 | }; 49 | -------------------------------------------------------------------------------- /benchmark/code/while2.js: -------------------------------------------------------------------------------- 1 | var extend = require('extend-shallow'); 2 | var engines = require('../../lib/engines'); 3 | 4 | module.exports = function matter(str, options) { 5 | if (str === '') { 6 | return {orig: '', data: {}, content: ''}; 7 | } 8 | 9 | if (str.charCodeAt(0) === 65279 && str.charCodeAt(1) === 116 && str.charCodeAt(2) === 104) { 10 | str = str.slice(1); 11 | } 12 | 13 | if (str.slice(0, 3) !== '---') { 14 | return {orig: str, data: {}, content: str}; 15 | } 16 | 17 | var res = {orig: str, data: '', content: ''}; 18 | var opts = extend({lang: 'yaml', eval: true}, options); 19 | 20 | // delimiters to use. defaults are `---` 21 | var delim = '---'; 22 | var lang = ''; 23 | var lines = str.split('\n'); 24 | var len = lines.length; 25 | var dlen = delim.length; 26 | var hasLang = false; 27 | 28 | var limit = 0; 29 | var num = 0; 30 | var i = 0; 31 | var start = 0; 32 | var count = 0; 33 | var end = 0; 34 | 35 | while (len--) { 36 | var line = lines[i++]; 37 | if (line.slice(0, dlen) === delim) { 38 | if (hasLang === false) { 39 | lang = line.slice(dlen).trim(); 40 | hasLang = true; 41 | } 42 | start = i + 1; 43 | count++; 44 | } 45 | 46 | if (i >= start && count === 1) { 47 | res.data += line + '\n'; 48 | } 49 | 50 | if (end !== 0 && i > end) { 51 | res.content += line + '\n'; 52 | } 53 | 54 | if (count === 2) { 55 | end = i; 56 | } 57 | } 58 | 59 | // The actual data block to parse 60 | var data = res.data.trim(); 61 | if (data.length > 0) { 62 | var fn = engines[lang || opts.lang]; 63 | if (typeof fn === 'function') { 64 | res.data = fn(data, opts); 65 | } else { 66 | res.data = {}; 67 | } 68 | } else { 69 | res.data = {}; 70 | } 71 | 72 | return res; 73 | }; 74 | -------------------------------------------------------------------------------- /benchmark/code/while3.js: -------------------------------------------------------------------------------- 1 | var extend = require('extend-shallow'); 2 | var engines = require('../../lib/engines'); 3 | 4 | module.exports = function matter(str, options) { 5 | if (str.length === 0) { 6 | return {orig: '', data: {}, content: ''}; 7 | } 8 | 9 | if (str.charCodeAt(0) === 65279 && str.charCodeAt(1) === 116 && str.charCodeAt(2) === 104) { 10 | str = str.slice(1); 11 | } 12 | 13 | // default results 14 | var opts = extend({lang: 'yaml', eval: true}, options); 15 | var res = {orig: str, data: '', content: ''}; 16 | var delim = opts.delims || ['---', '---']; 17 | 18 | // make sure the starting delim is first thing 19 | if (str.slice(0, delim[0].length) !== delim[0]) { 20 | res.content = str; 21 | res.data = {}; 22 | delete res.lang; 23 | return res; 24 | } 25 | 26 | var len = delim[0].length; 27 | 28 | // index of the first newline 29 | var nl = str.indexOf('\n'); 30 | 31 | // parser language to use 32 | var lang = str.slice(len, nl).trim() || opts.lang; 33 | 34 | // start/end index of the data block to parse 35 | var dataStart = nl + 1; 36 | var dataEnd = str.indexOf(delim[0], dataStart); 37 | 38 | // The actual data block to parse 39 | var data = str.slice(dataStart, dataEnd).trim(); 40 | if (data.length > 0) { 41 | res.data = engines[lang](data, opts); 42 | } 43 | 44 | res.content = str.slice(len + dataEnd).trim(); 45 | delete res.lang; 46 | return res; 47 | }; 48 | -------------------------------------------------------------------------------- /benchmark/fixtures/coffee.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = ['---coffee\ndata =\ntitle: "autodetect-coffee"\nuser: "jonschlinkert"\n---\nContent\n']; 4 | 5 | -------------------------------------------------------------------------------- /benchmark/fixtures/complex.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'); 4 | 5 | module.exports = [fs.readFileSync(__dirname + '/complex.md', 'utf8')]; 6 | 7 | -------------------------------------------------------------------------------- /benchmark/fixtures/complex.md: -------------------------------------------------------------------------------- 1 | --- 2 | # ============================================= 3 | # BUILD CONFIG 4 | # ============================================= 5 | 6 | root: _gh_pages 7 | dest: <%= site.root %> 8 | assets: <%= site.dest %>/assets 9 | date: <%= new Date() %> 10 | 11 | 12 | # Data 13 | data: data 14 | 15 | # Templates 16 | templates: templates 17 | pages: <%= site.templates %> 18 | includes: <%= site.templates %>/includes 19 | layouts: <%= site.templates %>/layouts 20 | layoutext: .hbs 21 | layout: default 22 | 23 | # Styles 24 | styles: styles 25 | components: <%= site.styles %>/components 26 | 27 | 28 | # ============================================= 29 | # EXTENSIONS 30 | # ============================================= 31 | 32 | helpers: <%= site.templates %>/helpers 33 | plugins: 34 | # - assemble-contrib-permalinks 35 | # - assemble-contrib-anchors 36 | # - assemble-contrib-toc 37 | 38 | 39 | # ============================================= 40 | # PROJECT METADATA 41 | # ============================================= 42 | 43 | brand: ASSEMBLE 44 | title: BOILERPLATE 45 | lead: The most awe inspiring static site boilerplate in Northern Kentucky. 46 | 47 | # GitHub 48 | version: <%= pkg.version %> 49 | author: <%= pkg.author.name %> 50 | name: <%= pkg.name %> 51 | description: <%= pkg.description %> 52 | 53 | # URLs 54 | url: 55 | 56 | # Repo 57 | homepage: <%= pkg.homepage %> 58 | repo: <%= pkg.homepage %> 59 | issues: <%= pkg.bugs.url %>?state=open 60 | ghpages: https://<%= site.username %>.github.io/<%= pkg.name %>/ 61 | 62 | # Site 63 | domain: http://assemble.io/ 64 | about: <%= site.url.domain %>/about/ 65 | blog: <%= site.url.domain %>/blog/ 66 | 67 | # Download Links 68 | download: 69 | source: <%= pkg.homepage %>/archive/master.zip 70 | latest: <%= pkg.homepage %>/master/dist/<%= pkg.name %>-<%= pkg.version %>.min.js 71 | 72 | 73 | # ============================================= 74 | # SEO / SEM 75 | # ============================================= 76 | 77 | analytics: 78 | alexa: lpTeh1awA400OE 79 | google: 80 | id: UA-XXXXXXXX-YY 81 | domain: assemble.github.io 82 | siteid: false 83 | tags: FOO-012345 # Google Tags (see: https://www.google.com/tagmanager/) 84 | 85 | 86 | # ============================================= 87 | # SOCIAL / SHARING 88 | # ============================================= 89 | 90 | # Comments 91 | disqus: 92 | enabled: false 93 | shortname: <%= pkg.name %> 94 | 95 | # Social 96 | social: 97 | twitter: 98 | via: jonschlinkert 99 | username: jonschlinkert 100 | related: jonschlinkert:Assemble core team. 101 | facebook: false 102 | linkedin: false 103 | gplus: false 104 | hn: false 105 | google: false 106 | 107 | # Sharing 108 | sharing: 109 | twitter: false 110 | facebook: false 111 | gplus: false 112 | hn: false 113 | google: false 114 | --- 115 | 116 | > Add lots of potentially confusing sytax 117 | 118 | This is an alert 119 | 120 | ## YAML Front Matter 121 | Add YAML front matter to documents to extend the metadata that is supplied to your projects templates. 122 | 123 | ```yaml 124 | --- 125 | username: jonschlinkert 126 | --- 127 | ``` 128 | This is probably most useful when: 129 | 1. You need to use the same or similar templates on a number of different projects 130 | 1. You want to supply data to the templates that wont typically be found in package.json 131 | 132 | 133 | ## Code Comments 134 | Code comments may be used in markdown templates, and they will be stripped from the rendered README as long athey adhere to the following syntax:", 135 | 136 | ```handlebars 137 | [[!-- foo --]] 138 | [[! foo ]] 139 | [[!foo]] 140 | ``` 141 | 142 | ## Escaping 143 | 144 | ### Escaping hashes 145 | This task automatically adjusts heading levels in included templates. For example, `#` is adjusted to `##`, sthat heading levels line up properly after the ", 146 | README is built. 147 | 148 | This can cause problems if youre using hashes for a reason other than headings, such as CSS Ids in codcomments. So to prevent grunt-readme from converting `", 149 | #id {}` to `##id {}`, just add a single backtick before the hash: `#id {}. 150 | 151 | ### Escaping Lo-Dash templates 152 | To prevent Lo-Dash from attempting to evaluat templates that shouldnt be (_as with code examples_), just ussquare brackets instead of curly braces in any ", 153 | templates that have similar patterns to these: `[%= .. %]`, `[%- .. %]`, and `[% .. %]`. The square bracketwill be replaced with curly braces in the rendered output.", 154 | 155 | ~~~ 156 | foo: bar 157 | version: 2 158 | ~~~ 159 | 160 | This is an alert 161 | 162 | # yfm [![NPM version](https://badge.fury.io/js/yfm.png)](http://badge.fury.io/js/yfm) 163 | 164 | > A simple to use YAML Front-Matter parsing and extraction Library. 165 | 166 | **Why another YAML Front Matter library?** 167 | 168 | Because other libraries we tried failed to meet our requirements with [Assemble](http://assemble.io). Some mosof the libraries met most of the ", 169 | requirements, but _none had all of them_. Here are the most important: 170 | 171 | * Be usable, if not simple 172 | * Allow custom delimiters 173 | * Use a dependable and well-supported library for parsing YAML 174 | * Dont fail if YAML front matter exists, but no content 175 | * Dont fail if content exists, but no YAML front matter 176 | * Have no problem reading YAML files directly 177 | * Should return an object that contains the parsed YAML front matter and content, as well as the originacontent.", 178 | 179 | ```bash 180 | npm i yfm --save 181 | ``` 182 | ## Usage 183 | 184 | ```js 185 | var yfm = require(yfm); 186 | yfm(yfm.html); 187 | ``` 188 | ## Options 189 | You may pass an options object as a second parameter. 190 | 191 | #### custom delimiters 192 | Type: `object` 193 | 194 | Default: `{close: ---, open: ---}` 195 | 196 | Open and close delimiters can be a string or an array of strings. If an array of strings is passed for delimiter then all patterns supplied will be used to ", 197 | check for YAML front matter. 198 | 199 | Example: 200 | 201 | ```js 202 | { 203 | close: [---, ~~~], 204 | open: [..., ---] 205 | } 206 | ``` 207 | 208 | Checks for all patterns using these delimiters. 209 | 210 | _Passing multiple delimiters will likely provide unpredictable results, but the option is included for testinpurposes._", 211 | 212 | #### read 213 | Type: `boolean` 214 | 215 | Default: `true` 216 | 217 | Specify whether or not to read a file from the file system. When set to `false` a raw string may be passed tthe function. Example:", 218 | 219 | ```js 220 | yfm(---\nTitle: YFM\n---\nContent., {read: false}) 221 | ``` 222 | 223 | 224 | ## Examples 225 | #### Extract front matter 226 | 227 | Lets say our page, `foo.html` contains 228 | 229 | ```html 230 | --- 231 | title: YAML Front matter 232 | --- 233 |

{{title}}

234 | ``` 235 | 236 | then running the following in the command line: 237 | 238 | ```js 239 | console.log(yfm(foo.html)); 240 | ``` 241 | returns 242 | 243 | ```json 244 | { 245 | context: { 246 | title: YAML Front matter 247 | }, 248 | content:

{{title}}

, 249 | original: ---\ntitle: YAML Front matter\n---\n

{{title}}

250 | } 251 | ``` 252 | and 253 | 254 | ```js 255 | console.log(yfm(foo.html).context); 256 | ``` 257 | returns 258 | 259 | 260 | ```json 261 | {title: YAML Front matter} 262 | ``` 263 | 264 | #### Check for YAML front matter 265 | 266 | ```js 267 | var hasYFM = function (src, options) { 268 | var obj = yfm(src, options).context; 269 | return _.keys(obj).length > 0; 270 | }; 271 | ``` 272 | 273 | ## Authors 274 | 275 | **Jon Schlinkert** 276 | 277 | + [github/jonschlinkert](https://github.com/jonschlinkert) 278 | + [twitter/jonschlinkert](http://twitter.com/jonschlinkert) 279 | 280 | **Brian Woodward** 281 | 282 | + [github/doowb](https://github.com/doowb) 283 | + [twitter/doowb](http://twitter.com/jonschlinkert) 284 | 285 | 286 | ## License 287 | Copyright (c) 2014 Jon Schlinkert, Brian Woodward, contributors. 288 | Released under the MIT license 289 | 290 | *** 291 | 292 | _This file was generated by [grunt-readme](https://github.com/assemble/grunt-readme) on Monday, January 27, 2014._ 293 | 294 | [grunt]: http://gruntjs.com/ 295 | [Getting Started]: https://github.com/gruntjs/grunt/blob/devel/docs/getting_started.md 296 | [package.json]: https://npmjs.org/doc/json.html 297 | -------------------------------------------------------------------------------- /benchmark/fixtures/cson.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = ['---cson\ntitle: "autodetect-CSON"\nuser: "jonschlinkert"\n---\nContent\n']; 4 | 5 | 6 | -------------------------------------------------------------------------------- /benchmark/fixtures/empty.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = ['']; 4 | -------------------------------------------------------------------------------- /benchmark/fixtures/lang.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = ['---yaml\ntitle: autodetect-yaml\nuser: jonschlinkert\n---\nContent\n']; 4 | -------------------------------------------------------------------------------- /benchmark/fixtures/matter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = ['---\ntitle: autodetect-no-lang\nuser: jonschlinkert\n---\nContent\n']; 4 | -------------------------------------------------------------------------------- /benchmark/fixtures/no-content.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = ['---\ntitle: autodetect-no-lang\nuser: jonschlinkert\n---']; 4 | -------------------------------------------------------------------------------- /benchmark/fixtures/no-matter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = ['# No front matter here.']; 4 | -------------------------------------------------------------------------------- /benchmark/fixtures/toml.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = ['--- toml\ntitle = "autodetect-TOML"\n\n[props]\nuser = "jonschlinkert"\n---\nContent\n']; 4 | -------------------------------------------------------------------------------- /benchmark/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const argv = require('minimist')(process.argv.slice(2)); 5 | const suite = require('benchmarked'); 6 | const write = require('write'); 7 | const cwd = path.join.bind(path, argv.cwd || ''); 8 | const dir = path.join.bind(path, __dirname); 9 | const code = argv.c || argv.code || '{gray,front}-matter.js'; 10 | const fixtures = argv.f || argv.fixtures || '{complex*,empty,matter,no-*}.js'; 11 | 12 | suite.run({code: `code/${cwd(code)}`, fixtures: `fixtures/${cwd(fixtures)}`}) 13 | .then(function(stats) { 14 | write.sync(dir('stats.json'), JSON.stringify(stats, null, 2)); 15 | write.sync(dir('stats.md'), suite.render(stats)); 16 | }) 17 | .catch(console.error); 18 | -------------------------------------------------------------------------------- /benchmark/stats.md: -------------------------------------------------------------------------------- 1 | # complex (112 bytes) 2 | gray-matter x 4,766,266 ops/sec ±1.56% (87 runs sampled) 3 | front-matter x 6,061 ops/sec ±2.42% (82 runs sampled) 4 | 5 | fastest is gray-matter (by 78641% avg) 6 | 7 | # empty (38 bytes) 8 | gray-matter x 27,770,032 ops/sec ±1.82% (87 runs sampled) 9 | front-matter x 8,804,363 ops/sec ±1.14% (85 runs sampled) 10 | 11 | fastest is gray-matter (by 315% avg) 12 | 13 | # matter (105 bytes) 14 | gray-matter x 4,480,787 ops/sec ±1.26% (85 runs sampled) 15 | front-matter x 196,492 ops/sec ±1.10% (89 runs sampled) 16 | 17 | fastest is gray-matter (by 2280% avg) 18 | 19 | # no-content (94 bytes) 20 | gray-matter x 4,525,154 ops/sec ±0.92% (89 runs sampled) 21 | front-matter x 199,316 ops/sec ±1.91% (88 runs sampled) 22 | 23 | fastest is gray-matter (by 2270% avg) 24 | 25 | # no-matter (61 bytes) 26 | gray-matter x 4,465,564 ops/sec ±0.81% (91 runs sampled) 27 | front-matter x 5,144,349 ops/sec ±1.16% (86 runs sampled) 28 | 29 | fastest is front-matter (by 115% avg) 30 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gray-matter", 3 | "description": "Parse front-matter from a string or file. Fast, reliable and easy to use. Parses YAML front matter by default, but also has support for YAML, JSON, TOML or Coffee Front-Matter, with options to set custom delimiters. Used by metalsmith, assemble, verb and many other projects.", 4 | "version": "3.1.1", 5 | "homepage": "https://github.com/jonschlinkert/gray-matter", 6 | "authors": [ 7 | "Jon Schlinkert (https://github.com/jonschlinkert)" 8 | ], 9 | "contributors": [ 10 | "(https://github.com/heymind)", 11 | "Andrew Meyer (https://github.com/Ajedi32)", 12 | "Brian Woodward (https://twitter.com/doowb)", 13 | "Caesar Schinas (https://caesarschinas.com)", 14 | "Ian Storm Taylor (http://ianstormtaylor.com)", 15 | "Jon Schlinkert (http://twitter.com/jonschlinkert)", 16 | "Osman Nuri Okumuş (http://onokumus.com)", 17 | "Pawel Kadluczka (http://blog.3d-logic.com)", 18 | "Rob Loach (http://robloach.net)", 19 | "Zach Whaley (http://zachwhaleys.website)" 20 | ], 21 | "repository": "jonschlinkert/gray-matter", 22 | "bugs": { 23 | "url": "https://github.com/jonschlinkert/gray-matter/issues" 24 | }, 25 | "license": "MIT", 26 | "files": [ 27 | "gray-matter.d.ts", 28 | "index.js", 29 | "lib" 30 | ], 31 | "main": [ 32 | "index.js" 33 | ], 34 | "dependencies": { 35 | "define-property": "^2.0.2", 36 | "js-yaml": "^3.11.0", 37 | "kind-of": "^6.0.2", 38 | "section-matter": "^1.0.0", 39 | "strip-bom-string": "^1.0.0" 40 | }, 41 | "devDependencies": { 42 | "ansi-green": "^0.1.1", 43 | "benchmarked": "^2.0.0", 44 | "coffeescript": "^2.2.3", 45 | "delimiter-regex": "^2.0.0", 46 | "extend-shallow": "^3.0.2", 47 | "front-matter": "^2.3.0", 48 | "gulp-format-md": "^1.0.0", 49 | "minimist": "^1.2.0", 50 | "mocha": "^3.5.3", 51 | "toml": "^2.3.3", 52 | "vinyl": "^2.1.0", 53 | "write": "^1.0.3" 54 | }, 55 | "keywords": [ 56 | "assemble", 57 | "coffee", 58 | "coffee-script", 59 | "data", 60 | "docs", 61 | "documentation", 62 | "extract", 63 | "extracting", 64 | "front", 65 | "front-matter", 66 | "frontmatter", 67 | "generate", 68 | "generator", 69 | "gh-pages", 70 | "gray", 71 | "javascript", 72 | "jekyll", 73 | "js", 74 | "JSON", 75 | "markdown", 76 | "matter", 77 | "parse", 78 | "parser", 79 | "parsing", 80 | "site", 81 | "static", 82 | "template", 83 | "toml", 84 | "yaml", 85 | "yfm" 86 | ], 87 | "typings": "gray-matter.d.ts", 88 | "ignore": [ 89 | "actual", 90 | "bower_components", 91 | "fixtures", 92 | "node_modules", 93 | "temp", 94 | "test", 95 | "test.js", 96 | "tmp" 97 | ], 98 | "lintDeps": { 99 | "devDependencies": { 100 | "files": { 101 | "patterns": [ 102 | "concept.js" 103 | ] 104 | } 105 | } 106 | }, 107 | "types": "gray-matter.d.ts", 108 | "browser": { 109 | "fs": false 110 | }, 111 | "eslintConfig": { 112 | "rules": { 113 | "no-console": 0 114 | } 115 | } 116 | } -------------------------------------------------------------------------------- /examples/coffee.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const matter = require('..'); 3 | const coffee = require('coffeescript'); 4 | const green = require('ansi-green'); 5 | const fixture = path.join.bind(path, __dirname, 'fixtures'); 6 | let file; 7 | 8 | const engines = { 9 | coffee: { 10 | parse: function(str, options) { 11 | /* eslint no-eval: 0 */ 12 | return coffee['eval'](str, options); 13 | } 14 | } 15 | }; 16 | 17 | console.log(green('/* coffescript (detected after first delimiter in front-matter) */')); 18 | file = matter.read(fixture('coffee-auto.md'), {engines: engines}); 19 | console.log(file); 20 | console.log(); 21 | 22 | console.log(green('/* coffescript (defined on options) */')); 23 | file = matter.read(fixture('coffee.md'), { 24 | language: 'coffee', 25 | engines: engines 26 | }); 27 | console.log(file); 28 | -------------------------------------------------------------------------------- /examples/excerpt-separator.js: -------------------------------------------------------------------------------- 1 | const matter = require('..'); 2 | const green = require('ansi-green'); 3 | 4 | console.log(green('/* excerpt with custom separator */')); 5 | const file = matter([ 6 | '---', 7 | 'foo: bar', 8 | '---', 9 | 'This is an excerpt.', 10 | '', 11 | 'This is content' 12 | ].join('\n'), {excerpt_separator: ''}); 13 | 14 | console.log(file); 15 | -------------------------------------------------------------------------------- /examples/excerpt-stringify.js: -------------------------------------------------------------------------------- 1 | const matter = require('..'); 2 | const green = require('ansi-green'); 3 | 4 | const file = matter([ 5 | '---', 6 | 'foo: bar', 7 | '---', 8 | 'This is an excerpt.', 9 | '', 10 | 'This is content' 11 | ].join('\n'), {excerpt_separator: ''}); 12 | 13 | console.log(green('/* file object, with excerpt */')); 14 | console.log(file); 15 | 16 | console.log(); 17 | console.log(green('/* stringified, with excerpt */')); 18 | console.log(file.stringify()); 19 | -------------------------------------------------------------------------------- /examples/excerpt.js: -------------------------------------------------------------------------------- 1 | const matter = require('..'); 2 | const green = require('ansi-green'); 3 | 4 | // excerpt as a boolean 5 | const file1 = matter([ 6 | '---', 7 | 'foo: bar', 8 | '---', 9 | 'This is an excerpt.', 10 | '---', 11 | 'This is content' 12 | ].join('\n'), {excerpt: true}); 13 | 14 | console.log(green('/* excerpt: true */')); 15 | console.log(file1); 16 | 17 | // excerpt as a function 18 | 19 | // returns the first 4 lines of the contents 20 | function firstFourLines(file, options) { 21 | file.excerpt = file.content.split('\n').slice(0, 4).join(' '); 22 | } 23 | 24 | const file2 = matter([ 25 | '---', 26 | 'foo: bar', 27 | '---', 28 | 'Only this', 29 | 'will be', 30 | 'in the', 31 | 'excerpt', 32 | 'but not this...' 33 | ].join('\n'), { excerpt: firstFourLines }); 34 | 35 | console.log(green('/* excerpt: function(file, options) { ... } */')); 36 | console.log(file2); 37 | -------------------------------------------------------------------------------- /examples/fixtures/coffee-auto.md: -------------------------------------------------------------------------------- 1 | ---coffee 2 | title: 'coffee functions' 3 | user: 'jonschlinkert' 4 | reverse: (src) -> 5 | src.split('').reverse().join('') 6 | --- 7 | 8 | <%= description %> 9 | <%= reverse(user) %> -------------------------------------------------------------------------------- /examples/fixtures/coffee.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'coffee functions' 3 | user: 'jonschlinkert' 4 | reverse: (src) -> 5 | src.split('').reverse().join('') 6 | --- 7 | 8 | <%= description %> 9 | <%= reverse(user) %> -------------------------------------------------------------------------------- /examples/fixtures/sections-excerpt.md: -------------------------------------------------------------------------------- 1 | ---yaml 2 | title: I'm front matter 3 | --- 4 | 5 | This is an excerpt. 6 | --- 7 | 8 | ---aaa 9 | title: First section 10 | --- 11 | 12 | Section one. 13 | 14 | ---bbb 15 | title: Second section 16 | --- 17 | 18 | Part 1. 19 | 20 | --- 21 | 22 | Part 2. 23 | 24 | --- 25 | 26 | Part 3. 27 | 28 | ---ccc 29 | title: Third section 30 | --- 31 | 32 | Section three. 33 | -------------------------------------------------------------------------------- /examples/fixtures/sections.md: -------------------------------------------------------------------------------- 1 | ---yaml 2 | title: I'm front matter 3 | --- 4 | 5 | This page has front matter that should be parsed before the sections. 6 | 7 | ---aaa 8 | title: First section 9 | --- 10 | 11 | Section one. 12 | 13 | ---bbb 14 | title: Second section 15 | --- 16 | 17 | Part 1. 18 | 19 | --- 20 | 21 | Part 2. 22 | 23 | --- 24 | 25 | Part 3. 26 | 27 | ---ccc 28 | title: Third section 29 | --- 30 | 31 | Section three. 32 | -------------------------------------------------------------------------------- /examples/helper.js: -------------------------------------------------------------------------------- 1 | /** 2 | * this is not an example. this is a helper used to generate 3 | * the list of links to examples in the readme. 4 | */ 5 | 6 | const fs = require('fs'); 7 | const path = require('path'); 8 | 9 | module.exports = function() { 10 | const files = fs.readdirSync(__dirname); 11 | const links = []; 12 | for (let i = 0; i < files.length; i++) { 13 | const name = files[i]; 14 | const ext = path.extname(name); 15 | const stem = path.basename(name, ext); 16 | if (stem !== 'helper' && ext === '.js') { 17 | links.push('- [' + stem + '](examples/' + name + ')'); 18 | } 19 | } 20 | return links.join('\n'); 21 | }; 22 | -------------------------------------------------------------------------------- /examples/javascript.js: -------------------------------------------------------------------------------- 1 | const matter = require('..'); 2 | const green = require('ansi-green'); 3 | 4 | const file = matter([ 5 | '---js', 6 | '{', 7 | ' reverse: function(str) {', 8 | ' return str.split(",").reverse().join(",");', 9 | ' }', 10 | '}', 11 | '---', 12 | 'This is content' 13 | ].join('\n')); 14 | 15 | console.log(green('/* javascript front-matter */')); 16 | console.log(file); 17 | 18 | console.log(); 19 | console.log(green('/* example after calling a function from front-matter */')); 20 | file.data.baz = file.data.reverse('x,y,z'); 21 | console.log(file); 22 | -------------------------------------------------------------------------------- /examples/json-stringify.js: -------------------------------------------------------------------------------- 1 | const matter = require('..'); 2 | const green = require('ansi-green'); 3 | 4 | const file1 = matter([ 5 | '---json', 6 | '{', 7 | ' "name": "gray-matter"', 8 | '}', 9 | '---', 10 | 'This is content' 11 | ].join('\n')); 12 | 13 | console.log(green('/* stringified to YAML, from JSON front-matter */')); 14 | console.log(file1.stringify({}, {language: 'yaml'})); 15 | 16 | const file2 = matter([ 17 | '---', 18 | 'title: Home', 19 | '---', 20 | 'This is content' 21 | ].join('\n')); 22 | 23 | console.log(green('/* stringified JSON, from YAML front-matter */')); 24 | console.log(file2.stringify({}, {language: 'json', spaces: 2})); 25 | -------------------------------------------------------------------------------- /examples/json.js: -------------------------------------------------------------------------------- 1 | const matter = require('..'); 2 | 3 | const file1 = matter([ 4 | '---json', 5 | '{', 6 | ' "name": "gray-matter"', 7 | '}', 8 | '---', 9 | 'This is content' 10 | ].join('\n')); 11 | console.log(file1); 12 | 13 | const file2 = matter([ 14 | '---json', 15 | '{', 16 | ' "name": "gray-matter"', 17 | '}', 18 | '---', 19 | 'This is content' 20 | ].join('\n')); 21 | console.log(file2); 22 | -------------------------------------------------------------------------------- /examples/restore-empty.js: -------------------------------------------------------------------------------- 1 | const matter = require('..'); 2 | 3 | /** 4 | * Parse YAML front-matter 5 | */ 6 | 7 | const str = `--- 8 | --- 9 | This is content`; 10 | const file = matter(str); 11 | 12 | console.log(file); 13 | if (file.isEmpty) { 14 | file.content = str; 15 | } 16 | console.log(file); 17 | -------------------------------------------------------------------------------- /examples/sections-excerpt.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const matter = require('..'); 6 | const str = fs.readFileSync(path.join(__dirname, 'fixtures', 'sections-excerpt.md')); 7 | 8 | const res = matter(str, { excerpt: true, sections: true }); 9 | console.log(JSON.stringify(res, null, 2)); 10 | -------------------------------------------------------------------------------- /examples/sections.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const yaml = require('js-yaml'); 6 | const matter = require('..'); 7 | const str = fs.readFileSync(path.join(__dirname, 'fixtures', 'sections.md')); 8 | 9 | const file = matter(str, { 10 | section: function(section, file) { 11 | if (typeof section.data === 'string' && section.data.trim() !== '') { 12 | section.data = yaml.safeLoad(section.data); 13 | } 14 | section.content = section.content.trim() + '\n'; 15 | } 16 | }); 17 | 18 | console.log(JSON.stringify(file, null, 2)); 19 | -------------------------------------------------------------------------------- /examples/toml.js: -------------------------------------------------------------------------------- 1 | const matter = require('..'); 2 | const toml = require('toml'); 3 | 4 | /** 5 | * Parse TOML front-matter 6 | */ 7 | 8 | const str = [ 9 | '---toml', 10 | 'title = "TOML"', 11 | 'description = "Front matter"', 12 | 'categories = "front matter toml"', 13 | '---', 14 | 'This is content' 15 | ].join('\n'); 16 | 17 | const file = matter(str, { 18 | engines: { 19 | toml: toml.parse.bind(toml) 20 | } 21 | }); 22 | 23 | console.log(file); 24 | -------------------------------------------------------------------------------- /examples/yaml-stringify.js: -------------------------------------------------------------------------------- 1 | const matter = require('..'); 2 | 3 | /** 4 | * Stringify back to YAML 5 | */ 6 | 7 | const file = matter([ 8 | '---', 9 | 'foo: bar', 10 | '---', 11 | 'This is content' 12 | ].join('\n')); 13 | 14 | const str1 = file.stringify(); 15 | console.log(str1); 16 | 17 | /** 18 | * custom data 19 | */ 20 | 21 | const str2 = file.stringify({baz: ['one', 'two', 'three']}); 22 | console.log(str2); 23 | -------------------------------------------------------------------------------- /examples/yaml.js: -------------------------------------------------------------------------------- 1 | const matter = require('..'); 2 | 3 | /** 4 | * Parse YAML front-matter 5 | */ 6 | 7 | const file = matter([ 8 | '---', 9 | 'foo: bar', 10 | '---', 11 | 'This is content' 12 | ].join('\n')); 13 | 14 | console.log(file); 15 | -------------------------------------------------------------------------------- /gray-matter.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Takes a string or object with `content` property, extracts 3 | * and parses front-matter from the string, then returns an object 4 | * with `data`, `content` and other [useful properties](#returned-object). 5 | * 6 | * ```js 7 | * var matter = require('gray-matter'); 8 | * console.log(matter('---\ntitle: Home\n---\nOther stuff')); 9 | * //=> { data: { title: 'Home'}, content: 'Other stuff' } 10 | * ``` 11 | * @param {Object|String} `input` String, or object with `content` string 12 | * @param {Object} `options` 13 | * @return {Object} 14 | * @api public 15 | */ 16 | declare function matter< 17 | I extends matter.Input, 18 | O extends matter.GrayMatterOption 19 | >(input: I | { content: I }, options?: O): matter.GrayMatterFile 20 | 21 | declare namespace matter { 22 | type Input = string | Buffer 23 | interface GrayMatterOption< 24 | I extends Input, 25 | O extends GrayMatterOption 26 | > { 27 | parser?: () => void 28 | eval?: boolean 29 | excerpt?: boolean | ((input: I, options: O) => string) 30 | excerpt_separator?: string 31 | engines?: { 32 | [index: string]: 33 | | ((input: string) => object) 34 | | { parse: (input: string) => object; stringify?: (data: object) => string } 35 | } 36 | language?: string 37 | delimiters?: string | [string, string] 38 | } 39 | interface GrayMatterFile { 40 | data: { [key: string]: any } 41 | content: string 42 | excerpt?: string 43 | orig: Buffer | I 44 | language: string 45 | matter: string 46 | stringify(lang: string): string 47 | } 48 | 49 | /** 50 | * Stringify an object to YAML or the specified language, and 51 | * append it to the given string. By default, only YAML and JSON 52 | * can be stringified. See the [engines](#engines) section to learn 53 | * how to stringify other languages. 54 | * 55 | * ```js 56 | * console.log(matter.stringify('foo bar baz', {title: 'Home'})); 57 | * // results in: 58 | * // --- 59 | * // title: Home 60 | * // --- 61 | * // foo bar baz 62 | * ``` 63 | * @param {String|Object} `file` The content string to append to stringified front-matter, or a file object with `file.content` string. 64 | * @param {Object} `data` Front matter to stringify. 65 | * @param {Object} `options` [Options](#options) to pass to gray-matter and [js-yaml]. 66 | * @return {String} Returns a string created by wrapping stringified yaml with delimiters, and appending that to the given string. 67 | */ 68 | export function stringify>( 69 | file: string | { content: string }, 70 | data: object, 71 | options?: GrayMatterOption 72 | ): string 73 | 74 | /** 75 | * Synchronously read a file from the file system and parse 76 | * front matter. Returns the same object as the [main function](#matter). 77 | * 78 | * ```js 79 | * var file = matter.read('./content/blog-post.md'); 80 | * ``` 81 | * @param {String} `filepath` file path of the file to read. 82 | * @param {Object} `options` [Options](#options) to pass to gray-matter. 83 | * @return {Object} Returns [an object](#returned-object) with `data` and `content` 84 | */ 85 | export function read>( 86 | fp: string, 87 | options?: GrayMatterOption 88 | ): matter.GrayMatterFile 89 | 90 | /** 91 | * Returns true if the given `string` has front matter. 92 | * @param {String} `string` 93 | * @param {Object} `options` 94 | * @return {Boolean} True if front matter exists. 95 | */ 96 | export function test>( 97 | str: string, 98 | options?: GrayMatterOption 99 | ): boolean 100 | 101 | /** 102 | * Detect the language to use, if one is defined after the 103 | * first front-matter delimiter. 104 | * @param {String} `string` 105 | * @param {Object} `options` 106 | * @return {Object} Object with `raw` (actual language string), and `name`, the language with whitespace trimmed 107 | */ 108 | export function language>( 109 | str: string, 110 | options?: GrayMatterOption 111 | ): { name: string; raw: string } 112 | } 113 | 114 | export = matter 115 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const sections = require('section-matter'); 5 | const defaults = require('./lib/defaults'); 6 | const stringify = require('./lib/stringify'); 7 | const excerpt = require('./lib/excerpt'); 8 | const engines = require('./lib/engines'); 9 | const toFile = require('./lib/to-file'); 10 | const parse = require('./lib/parse'); 11 | const utils = require('./lib/utils'); 12 | 13 | /** 14 | * Takes a string or object with `content` property, extracts 15 | * and parses front-matter from the string, then returns an object 16 | * with `data`, `content` and other [useful properties](#returned-object). 17 | * 18 | * ```js 19 | * const matter = require('gray-matter'); 20 | * console.log(matter('---\ntitle: Home\n---\nOther stuff')); 21 | * //=> { data: { title: 'Home'}, content: 'Other stuff' } 22 | * ``` 23 | * @param {Object|String} `input` String, or object with `content` string 24 | * @param {Object} `options` 25 | * @return {Object} 26 | * @api public 27 | */ 28 | 29 | function matter(input, options) { 30 | if (input === '') { 31 | return { data: {}, content: input, excerpt: '', orig: input }; 32 | } 33 | 34 | let file = toFile(input); 35 | const cached = matter.cache[file.content]; 36 | 37 | if (!options) { 38 | if (cached) { 39 | file = Object.assign({}, cached); 40 | file.orig = cached.orig; 41 | return file; 42 | } 43 | 44 | // only cache if there are no options passed. if we cache when options 45 | // are passed, we would need to also cache options values, which would 46 | // negate any performance benefits of caching 47 | matter.cache[file.content] = file; 48 | } 49 | 50 | return parseMatter(file, options); 51 | } 52 | 53 | /** 54 | * Parse front matter 55 | */ 56 | 57 | function parseMatter(file, options) { 58 | const opts = defaults(options); 59 | const open = opts.delimiters[0]; 60 | const close = '\n' + opts.delimiters[1]; 61 | let str = file.content; 62 | 63 | if (opts.language) { 64 | file.language = opts.language; 65 | } 66 | 67 | // get the length of the opening delimiter 68 | const openLen = open.length; 69 | if (!utils.startsWith(str, open, openLen)) { 70 | excerpt(file, opts); 71 | return file; 72 | } 73 | 74 | // if the next character after the opening delimiter is 75 | // a character from the delimiter, then it's not a front- 76 | // matter delimiter 77 | if (str.charAt(openLen) === open.slice(-1)) { 78 | return file; 79 | } 80 | 81 | // strip the opening delimiter 82 | str = str.slice(openLen); 83 | const len = str.length; 84 | 85 | // use the language defined after first delimiter, if it exists 86 | const language = matter.language(str, opts); 87 | if (language.name) { 88 | file.language = language.name; 89 | str = str.slice(language.raw.length); 90 | } 91 | 92 | // get the index of the closing delimiter 93 | let closeIndex = str.indexOf(close); 94 | if (closeIndex === -1) { 95 | closeIndex = len; 96 | } 97 | 98 | // get the raw front-matter block 99 | file.matter = str.slice(0, closeIndex); 100 | 101 | const block = file.matter.replace(/^\s*#[^\n]+/gm, '').trim(); 102 | if (block === '') { 103 | file.isEmpty = true; 104 | file.empty = file.content; 105 | file.data = {}; 106 | } else { 107 | 108 | // create file.data by parsing the raw file.matter block 109 | file.data = parse(file.language, file.matter, opts); 110 | } 111 | 112 | // update file.content 113 | if (closeIndex === len) { 114 | file.content = ''; 115 | } else { 116 | file.content = str.slice(closeIndex + close.length); 117 | if (file.content[0] === '\r') { 118 | file.content = file.content.slice(1); 119 | } 120 | if (file.content[0] === '\n') { 121 | file.content = file.content.slice(1); 122 | } 123 | } 124 | 125 | excerpt(file, opts); 126 | 127 | if (opts.sections === true || typeof opts.section === 'function') { 128 | sections(file, opts.section); 129 | } 130 | return file; 131 | } 132 | 133 | /** 134 | * Expose engines 135 | */ 136 | 137 | matter.engines = engines; 138 | 139 | /** 140 | * Stringify an object to YAML or the specified language, and 141 | * append it to the given string. By default, only YAML and JSON 142 | * can be stringified. See the [engines](#engines) section to learn 143 | * how to stringify other languages. 144 | * 145 | * ```js 146 | * console.log(matter.stringify('foo bar baz', {title: 'Home'})); 147 | * // results in: 148 | * // --- 149 | * // title: Home 150 | * // --- 151 | * // foo bar baz 152 | * ``` 153 | * @param {String|Object} `file` The content string to append to stringified front-matter, or a file object with `file.content` string. 154 | * @param {Object} `data` Front matter to stringify. 155 | * @param {Object} `options` [Options](#options) to pass to gray-matter and [js-yaml]. 156 | * @return {String} Returns a string created by wrapping stringified yaml with delimiters, and appending that to the given string. 157 | * @api public 158 | */ 159 | 160 | matter.stringify = function(file, data, options) { 161 | if (typeof file === 'string') file = matter(file, options); 162 | return stringify(file, data, options); 163 | }; 164 | 165 | /** 166 | * Synchronously read a file from the file system and parse 167 | * front matter. Returns the same object as the [main function](#matter). 168 | * 169 | * ```js 170 | * const file = matter.read('./content/blog-post.md'); 171 | * ``` 172 | * @param {String} `filepath` file path of the file to read. 173 | * @param {Object} `options` [Options](#options) to pass to gray-matter. 174 | * @return {Object} Returns [an object](#returned-object) with `data` and `content` 175 | * @api public 176 | */ 177 | 178 | matter.read = function(filepath, options) { 179 | const str = fs.readFileSync(filepath, 'utf8'); 180 | const file = matter(str, options); 181 | file.path = filepath; 182 | return file; 183 | }; 184 | 185 | /** 186 | * Returns true if the given `string` has front matter. 187 | * @param {String} `string` 188 | * @param {Object} `options` 189 | * @return {Boolean} True if front matter exists. 190 | * @api public 191 | */ 192 | 193 | matter.test = function(str, options) { 194 | return utils.startsWith(str, defaults(options).delimiters[0]); 195 | }; 196 | 197 | /** 198 | * Detect the language to use, if one is defined after the 199 | * first front-matter delimiter. 200 | * @param {String} `string` 201 | * @param {Object} `options` 202 | * @return {Object} Object with `raw` (actual language string), and `name`, the language with whitespace trimmed 203 | */ 204 | 205 | matter.language = function(str, options) { 206 | const opts = defaults(options); 207 | const open = opts.delimiters[0]; 208 | 209 | if (matter.test(str)) { 210 | str = str.slice(open.length); 211 | } 212 | 213 | const language = str.slice(0, str.search(/\r?\n/)); 214 | return { 215 | raw: language, 216 | name: language ? language.trim() : '' 217 | }; 218 | }; 219 | 220 | /** 221 | * Expose `matter` 222 | */ 223 | 224 | matter.cache = {}; 225 | matter.clearCache = function() { 226 | matter.cache = {}; 227 | }; 228 | module.exports = matter; 229 | -------------------------------------------------------------------------------- /lib/defaults.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const engines = require('./engines'); 4 | const utils = require('./utils'); 5 | 6 | module.exports = function(options) { 7 | const opts = Object.assign({}, options); 8 | 9 | // ensure that delimiters are an array 10 | opts.delimiters = utils.arrayify(opts.delims || opts.delimiters || '---'); 11 | if (opts.delimiters.length === 1) { 12 | opts.delimiters.push(opts.delimiters[0]); 13 | } 14 | 15 | opts.language = (opts.language || opts.lang || 'yaml').toLowerCase(); 16 | opts.engines = Object.assign({}, engines, opts.parsers, opts.engines); 17 | return opts; 18 | }; 19 | -------------------------------------------------------------------------------- /lib/engine.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(name, options) { 4 | let engine = options.engines[name] || options.engines[aliase(name)]; 5 | if (typeof engine === 'undefined') { 6 | throw new Error('gray-matter engine "' + name + '" is not registered'); 7 | } 8 | if (typeof engine === 'function') { 9 | engine = { parse: engine }; 10 | } 11 | return engine; 12 | }; 13 | 14 | function aliase(name) { 15 | switch (name.toLowerCase()) { 16 | case 'js': 17 | case 'javascript': 18 | return 'javascript'; 19 | case 'coffee': 20 | case 'coffeescript': 21 | case 'cson': 22 | return 'coffee'; 23 | case 'yaml': 24 | case 'yml': 25 | return 'yaml'; 26 | default: { 27 | return name; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/engines.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const yaml = require('js-yaml'); 4 | 5 | /** 6 | * Default engines 7 | */ 8 | 9 | const engines = exports = module.exports; 10 | 11 | /** 12 | * YAML 13 | */ 14 | 15 | engines.yaml = { 16 | parse: yaml.safeLoad.bind(yaml), 17 | stringify: yaml.safeDump.bind(yaml) 18 | }; 19 | 20 | /** 21 | * JSON 22 | */ 23 | 24 | engines.json = { 25 | parse: JSON.parse.bind(JSON), 26 | stringify: function(obj, options) { 27 | const opts = Object.assign({replacer: null, space: 2}, options); 28 | return JSON.stringify(obj, opts.replacer, opts.space); 29 | } 30 | }; 31 | 32 | /** 33 | * JavaScript 34 | */ 35 | 36 | engines.javascript = { 37 | parse: function parse(str, options, wrap) { 38 | /* eslint no-eval: 0 */ 39 | try { 40 | if (wrap !== false) { 41 | str = '(function() {\nreturn ' + str.trim() + ';\n}());'; 42 | } 43 | return eval(str) || {}; 44 | } catch (err) { 45 | if (wrap !== false && /(unexpected|identifier)/i.test(err.message)) { 46 | return parse(str, options, false); 47 | } 48 | throw new SyntaxError(err); 49 | } 50 | }, 51 | stringify: function() { 52 | throw new Error('stringifying JavaScript is not supported'); 53 | } 54 | }; 55 | -------------------------------------------------------------------------------- /lib/excerpt.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const defaults = require('./defaults'); 4 | 5 | module.exports = function(file, options) { 6 | const opts = defaults(options); 7 | 8 | if (file.data == null) { 9 | file.data = {}; 10 | } 11 | 12 | if (typeof opts.excerpt === 'function') { 13 | return opts.excerpt(file, opts); 14 | } 15 | 16 | const sep = file.data.excerpt_separator || opts.excerpt_separator; 17 | if (sep == null && (opts.excerpt === false || opts.excerpt == null)) { 18 | return file; 19 | } 20 | 21 | const delimiter = typeof opts.excerpt === 'string' 22 | ? opts.excerpt 23 | : (sep || opts.delimiters[0]); 24 | 25 | // if enabled, get the excerpt defined after front-matter 26 | const idx = file.content.indexOf(delimiter); 27 | if (idx !== -1) { 28 | file.excerpt = file.content.slice(0, idx); 29 | } 30 | 31 | return file; 32 | }; 33 | -------------------------------------------------------------------------------- /lib/parse.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const getEngine = require('./engine'); 4 | const defaults = require('./defaults'); 5 | 6 | module.exports = function(language, str, options) { 7 | const opts = defaults(options); 8 | const engine = getEngine(language, opts); 9 | if (typeof engine.parse !== 'function') { 10 | throw new TypeError('expected "' + language + '.parse" to be a function'); 11 | } 12 | return engine.parse(str, opts); 13 | }; 14 | -------------------------------------------------------------------------------- /lib/stringify.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const typeOf = require('kind-of'); 4 | const getEngine = require('./engine'); 5 | const defaults = require('./defaults'); 6 | 7 | module.exports = function(file, data, options) { 8 | if (data == null && options == null) { 9 | switch (typeOf(file)) { 10 | case 'object': 11 | data = file.data; 12 | options = {}; 13 | break; 14 | case 'string': 15 | return file; 16 | default: { 17 | throw new TypeError('expected file to be a string or object'); 18 | } 19 | } 20 | } 21 | 22 | const str = file.content; 23 | const opts = defaults(options); 24 | if (data == null) { 25 | if (!opts.data) return file; 26 | data = opts.data; 27 | } 28 | 29 | const language = file.language || opts.language; 30 | const engine = getEngine(language, opts); 31 | if (typeof engine.stringify !== 'function') { 32 | throw new TypeError('expected "' + language + '.stringify" to be a function'); 33 | } 34 | 35 | data = Object.assign({}, file.data, data); 36 | const open = opts.delimiters[0]; 37 | const close = opts.delimiters[1]; 38 | const matter = engine.stringify(data, options).trim(); 39 | let buf = ''; 40 | 41 | if (matter !== '{}') { 42 | buf = newline(open) + newline(matter) + newline(close); 43 | } 44 | 45 | if (typeof file.excerpt === 'string' && file.excerpt !== '') { 46 | if (str.indexOf(file.excerpt.trim()) === -1) { 47 | buf += newline(file.excerpt) + newline(close); 48 | } 49 | } 50 | 51 | return buf + newline(str); 52 | }; 53 | 54 | function newline(str) { 55 | return str.slice(-1) !== '\n' ? str + '\n' : str; 56 | } 57 | -------------------------------------------------------------------------------- /lib/to-file.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const typeOf = require('kind-of'); 4 | const stringify = require('./stringify'); 5 | const utils = require('./utils'); 6 | 7 | /** 8 | * Normalize the given value to ensure an object is returned 9 | * with the expected properties. 10 | */ 11 | 12 | module.exports = function(file) { 13 | if (typeOf(file) !== 'object') { 14 | file = { content: file }; 15 | } 16 | 17 | if (typeOf(file.data) !== 'object') { 18 | file.data = {}; 19 | } 20 | 21 | // if file was passed as an object, ensure that 22 | // "file.content" is set 23 | if (file.contents && file.content == null) { 24 | file.content = file.contents; 25 | } 26 | 27 | // set non-enumerable properties on the file object 28 | utils.define(file, 'orig', utils.toBuffer(file.content)); 29 | utils.define(file, 'language', file.language || ''); 30 | utils.define(file, 'matter', file.matter || ''); 31 | utils.define(file, 'stringify', function(data, options) { 32 | if (options && options.language) { 33 | file.language = options.language; 34 | } 35 | return stringify(file, data, options); 36 | }); 37 | 38 | // strip BOM and ensure that "file.content" is a string 39 | file.content = utils.toString(file.content); 40 | file.isEmpty = false; 41 | file.excerpt = ''; 42 | return file; 43 | }; 44 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const stripBom = require('strip-bom-string'); 4 | const typeOf = require('kind-of'); 5 | 6 | exports.define = function(obj, key, val) { 7 | Reflect.defineProperty(obj, key, { 8 | enumerable: false, 9 | configurable: true, 10 | writable: true, 11 | value: val 12 | }); 13 | }; 14 | 15 | /** 16 | * Returns true if `val` is a buffer 17 | */ 18 | 19 | exports.isBuffer = function(val) { 20 | return typeOf(val) === 'buffer'; 21 | }; 22 | 23 | /** 24 | * Returns true if `val` is an object 25 | */ 26 | 27 | exports.isObject = function(val) { 28 | return typeOf(val) === 'object'; 29 | }; 30 | 31 | /** 32 | * Cast `input` to a buffer 33 | */ 34 | 35 | exports.toBuffer = function(input) { 36 | return typeof input === 'string' ? Buffer.from(input) : input; 37 | }; 38 | 39 | /** 40 | * Cast `val` to a string. 41 | */ 42 | 43 | exports.toString = function(input) { 44 | if (exports.isBuffer(input)) return stripBom(String(input)); 45 | if (typeof input !== 'string') { 46 | throw new TypeError('expected input to be a string or buffer'); 47 | } 48 | return stripBom(input); 49 | }; 50 | 51 | /** 52 | * Cast `val` to an array. 53 | */ 54 | 55 | exports.arrayify = function(val) { 56 | return val ? (Array.isArray(val) ? val : [val]) : []; 57 | }; 58 | 59 | /** 60 | * Returns true if `str` starts with `substr`. 61 | */ 62 | 63 | exports.startsWith = function(str, substr, len) { 64 | if (typeof len !== 'number') len = substr.length; 65 | return str.slice(0, len) === substr; 66 | }; 67 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gray-matter", 3 | "description": "Parse front-matter from a string or file. Fast, reliable and easy to use. Parses YAML front matter by default, but also has support for YAML, JSON, TOML or Coffee Front-Matter, with options to set custom delimiters. Used by metalsmith, assemble, verb and many other projects.", 4 | "version": "4.0.3", 5 | "homepage": "https://github.com/jonschlinkert/gray-matter", 6 | "author": "Jon Schlinkert (https://github.com/jonschlinkert)", 7 | "contributors": [ 8 | "Andrew Meyer (https://github.com/Ajedi32)", 9 | "Brian Woodward (https://twitter.com/doowb)", 10 | "Caesar Schinas (https://caesarschinas.com)", 11 | "Ian Storm Taylor (http://ianstormtaylor.com)", 12 | "Jon Schlinkert (http://twitter.com/jonschlinkert)", 13 | "Osman Nuri Okumuş (http://onokumus.com)", 14 | "Pawel Kadluczka (http://blog.3d-logic.com)", 15 | "Rob Loach (http://robloach.net)", 16 | "(https://github.com/heymind)", 17 | "Zach Whaley (http://zachwhaleys.website)" 18 | ], 19 | "repository": "jonschlinkert/gray-matter", 20 | "bugs": { 21 | "url": "https://github.com/jonschlinkert/gray-matter/issues" 22 | }, 23 | "license": "MIT", 24 | "files": [ 25 | "gray-matter.d.ts", 26 | "index.js", 27 | "lib" 28 | ], 29 | "main": "index.js", 30 | "engines": { 31 | "node": ">=6.0" 32 | }, 33 | "scripts": { 34 | "test": "mocha" 35 | }, 36 | "dependencies": { 37 | "js-yaml": "^3.13.1", 38 | "kind-of": "^6.0.2", 39 | "section-matter": "^1.0.0", 40 | "strip-bom-string": "^1.0.0" 41 | }, 42 | "devDependencies": { 43 | "ansi-green": "^0.1.1", 44 | "benchmarked": "^2.0.0", 45 | "coffeescript": "^2.2.3", 46 | "delimiter-regex": "^2.0.0", 47 | "extend-shallow": "^3.0.2", 48 | "front-matter": "^2.3.0", 49 | "gulp-format-md": "^2.0.0", 50 | "minimist": "^1.2.0", 51 | "mocha": "^10.2.0", 52 | "toml": "^2.3.3", 53 | "vinyl": "^2.1.0", 54 | "write": "^1.0.3" 55 | }, 56 | "keywords": [ 57 | "assemble", 58 | "coffee", 59 | "coffee-script", 60 | "data", 61 | "docs", 62 | "documentation", 63 | "extract", 64 | "extracting", 65 | "front", 66 | "front-matter", 67 | "frontmatter", 68 | "generate", 69 | "generator", 70 | "gh-pages", 71 | "gray", 72 | "javascript", 73 | "jekyll", 74 | "js", 75 | "JSON", 76 | "markdown", 77 | "matter", 78 | "parse", 79 | "parser", 80 | "parsing", 81 | "site", 82 | "static", 83 | "template", 84 | "toml", 85 | "yaml", 86 | "yfm" 87 | ], 88 | "browser": { 89 | "fs": false 90 | }, 91 | "typings": "gray-matter.d.ts", 92 | "eslintConfig": { 93 | "rules": { 94 | "no-console": 0 95 | } 96 | }, 97 | "verb": { 98 | "toc": false, 99 | "layout": "default", 100 | "tasks": [ 101 | "readme" 102 | ], 103 | "plugins": [ 104 | "gulp-format-md" 105 | ], 106 | "helpers": { 107 | "examples": "./examples/helper.js" 108 | }, 109 | "lint": { 110 | "reflinks": true 111 | }, 112 | "related": { 113 | "list": [ 114 | "assemble", 115 | "metalsmith", 116 | "verb" 117 | ] 118 | }, 119 | "reflinks": [ 120 | "coffe-script", 121 | "generate", 122 | "js-yaml", 123 | "toml", 124 | "update" 125 | ] 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /test/fixtures/all-dots.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | one: foo 3 | two: bar 4 | three: baz 5 | ... 6 | -------------------------------------------------------------------------------- /test/fixtures/all.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | one: foo 3 | two: bar 4 | three: baz 5 | -------------------------------------------------------------------------------- /test/fixtures/autodetect-coffee-fn.md: -------------------------------------------------------------------------------- 1 | ---coffee 2 | title: 'coffee functions' 3 | user: 'jonschlinkert' 4 | fn: 5 | reverse = (src) -> 6 | src.split('').reverse().join('') 7 | --- 8 | {%= description %} 9 | {%= reverse(user) %} -------------------------------------------------------------------------------- /test/fixtures/autodetect-coffee.md: -------------------------------------------------------------------------------- 1 | --- coffee 2 | data = 3 | title: 'autodetect-coffee' 4 | user: 'jonschlinkert' 5 | --- 6 | Content -------------------------------------------------------------------------------- /test/fixtures/autodetect-coffeescript.md: -------------------------------------------------------------------------------- 1 | ---coffeescript 2 | data = 3 | title: 'autodetect-coffeescript' 4 | user: 'jonschlinkert' 5 | --- 6 | Content -------------------------------------------------------------------------------- /test/fixtures/autodetect-cson-fn.md: -------------------------------------------------------------------------------- 1 | ---cson 2 | title: 'CSON functions' 3 | user: 'jonschlinkert' 4 | fn: 5 | reverse = (src) -> 6 | src.split('').reverse().join('') 7 | --- 8 | {%= description %} 9 | {%= reverse(user) %} -------------------------------------------------------------------------------- /test/fixtures/autodetect-cson.md: -------------------------------------------------------------------------------- 1 | ---cson 2 | title: 'autodetect-CSON' 3 | user: 'jonschlinkert' 4 | --- 5 | Content -------------------------------------------------------------------------------- /test/fixtures/autodetect-javascript.md: -------------------------------------------------------------------------------- 1 | ---javascript 2 | { 3 | title: 'autodetect-javascript', 4 | user: 'jonschlinkert', 5 | fn: { 6 | reverse: function(str) { 7 | return str.split('').reverse().join(''); 8 | } 9 | } 10 | } 11 | --- 12 | 13 | {%= description %} 14 | {%= reverse(user) %} 15 | 16 | 17 | ## Code fence 18 | 19 | ```js 20 | var foo = 'bar'; 21 | ``` 22 | -------------------------------------------------------------------------------- /test/fixtures/autodetect-json.md: -------------------------------------------------------------------------------- 1 | ---json 2 | { 3 | "title": "autodetect-JSON", 4 | "description": "Front Matter" 5 | } 6 | --- 7 | 8 | # This page has JSON front matter! -------------------------------------------------------------------------------- /test/fixtures/autodetect-no-lang.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: autodetect-no-lang 3 | user: jonschlinkert 4 | --- 5 | Content -------------------------------------------------------------------------------- /test/fixtures/autodetect-yaml.md: -------------------------------------------------------------------------------- 1 | ---yaml 2 | title: autodetect-yaml 3 | user: jonschlinkert 4 | --- 5 | Content -------------------------------------------------------------------------------- /test/fixtures/basic.txt: -------------------------------------------------------------------------------- 1 | --- 2 | title: Basic 3 | --- 4 | this is content. -------------------------------------------------------------------------------- /test/fixtures/complex.md: -------------------------------------------------------------------------------- 1 | --- 2 | # ============================================= 3 | # BUILD CONFIG 4 | # ============================================= 5 | 6 | root: _gh_pages 7 | dest: <%= site.root %> 8 | assets: <%= site.dest %>/assets 9 | date: <%= new Date() %> 10 | 11 | 12 | # Data 13 | data: data 14 | 15 | # Templates 16 | templates: templates 17 | pages: <%= site.templates %> 18 | includes: <%= site.templates %>/includes 19 | layouts: <%= site.templates %>/layouts 20 | layoutext: .hbs 21 | layout: default 22 | 23 | # Styles 24 | styles: styles 25 | components: <%= site.styles %>/components 26 | 27 | 28 | # ============================================= 29 | # EXTENSIONS 30 | # ============================================= 31 | 32 | helpers: <%= site.templates %>/helpers 33 | plugins: 34 | # - assemble-contrib-permalinks 35 | # - assemble-contrib-anchors 36 | # - assemble-contrib-toc 37 | 38 | 39 | # ============================================= 40 | # PROJECT METADATA 41 | # ============================================= 42 | 43 | brand: ASSEMBLE 44 | title: BOILERPLATE 45 | lead: The most awe inspiring static site boilerplate in Northern Kentucky. 46 | 47 | # GitHub 48 | version: <%= pkg.version %> 49 | author: <%= pkg.author.name %> 50 | name: <%= pkg.name %> 51 | description: <%= pkg.description %> 52 | 53 | # URLs 54 | url: 55 | 56 | # Repo 57 | homepage: <%= pkg.homepage %> 58 | repo: <%= pkg.homepage %> 59 | issues: <%= pkg.bugs.url %>?state=open 60 | ghpages: https://<%= site.username %>.github.io/<%= pkg.name %>/ 61 | 62 | # Site 63 | domain: http://assemble.io/ 64 | about: <%= site.url.domain %>/about/ 65 | blog: <%= site.url.domain %>/blog/ 66 | 67 | # Download Links 68 | download: 69 | source: <%= pkg.homepage %>/archive/master.zip 70 | latest: <%= pkg.homepage %>/master/dist/<%= pkg.name %>-<%= pkg.version %>.min.js 71 | 72 | 73 | # ============================================= 74 | # SEO / SEM 75 | # ============================================= 76 | 77 | analytics: 78 | alexa: lpTeh1awA400OE 79 | google: 80 | id: UA-XXXXXXXX-YY 81 | domain: assemble.github.io 82 | siteid: false 83 | tags: FOO-012345 # Google Tags (see: https://www.google.com/tagmanager/) 84 | 85 | 86 | # ============================================= 87 | # SOCIAL / SHARING 88 | # ============================================= 89 | 90 | # Comments 91 | disqus: 92 | enabled: false 93 | shortname: <%= pkg.name %> 94 | 95 | # Social 96 | social: 97 | twitter: 98 | via: jonschlinkert 99 | username: jonschlinkert 100 | related: jonschlinkert:Assemble core team. 101 | facebook: false 102 | linkedin: false 103 | gplus: false 104 | hn: false 105 | google: false 106 | 107 | # Sharing 108 | sharing: 109 | twitter: false 110 | facebook: false 111 | gplus: false 112 | hn: false 113 | google: false 114 | --- 115 | 116 | This is an alert 117 | 118 | ## YAML Front Matter 119 | Add YAML front matter to documents to extend the metadata that is supplied to your project's templates. 120 | 121 | ```yaml 122 | --- 123 | username: jonschlinkert 124 | --- 125 | ``` 126 | This is probably most useful when: 127 | 1. You need to use the same or similar templates on a number of different projects 128 | 1. You want to supply data to the templates that won't typically be found in package.json 129 | 130 | 131 | ## Code Comments 132 | Code comments may be used in markdown templates, and they will be stripped from the rendered README as long as they adhere to the following syntax: 133 | 134 | ```handlebars 135 | [[!-- foo --]] 136 | [[! foo ]] 137 | [[!foo]] 138 | ``` 139 | 140 | ## Escaping 141 | 142 | ### Escaping hashes 143 | This task automatically adjusts heading levels in included templates. For example, `#` is adjusted to `##`, so that heading levels "line up" properly after the README is built. 144 | 145 | This can cause problems if you're using hashes for a reason other than headings, such as CSS Id's in code comments. So to prevent grunt-readme from converting `#id {}` to `##id {}`, just add a single backtick before the hash: `#id {}. 146 | 147 | ### Escaping Lo-Dash templates 148 | To prevent Lo-Dash from attempting to evaluat templates that shouldn't be (_as with code examples_), just use square brackets instead of curly braces in any templates that have similar patterns to these: `[%= .. %]`, `[%- .. %]`, and `[% .. %]`. The square brackets will be replaced with curly braces in the rendered output. 149 | 150 | 151 | ~~~ 152 | foo: bar 153 | version: 2 154 | ~~~ 155 | 156 | This is an alert 157 | 158 | # yfm [![NPM version](https://badge.fury.io/js/yfm.png)](http://badge.fury.io/js/yfm) 159 | 160 | > A simple to use YAML Front-Matter parsing and extraction Library. 161 | 162 | **Why another YAML Front Matter library?** 163 | 164 | Because other libraries we tried failed to meet our requirements with [Assemble](http://assemble.io). Some most of the libraries met most of the requirements, but _none had all of them_. Here are the most important: 165 | 166 | * Be usable, if not simple 167 | * Allow custom delimiters 168 | * Use a dependable and well-supported library for parsing YAML 169 | * Don't fail if YAML front matter exists, but no content 170 | * Don't fail if content exists, but no YAML front matter 171 | * Have no problem reading YAML files directly 172 | * Should return an object that contains the parsed YAML front matter and content, as well as the "original" content. 173 | 174 | ```bash 175 | npm i yfm --save 176 | ``` 177 | ## Usage 178 | 179 | ```js 180 | var yfm = require('yfm'); 181 | yfm('yfm.html'); 182 | ``` 183 | ## Options 184 | You may pass an options object as a second parameter. 185 | 186 | #### custom delimiters 187 | Type: `object` 188 | 189 | Default: `{close: '---', open: '---'}` 190 | 191 | Open and close delimiters can be a string or an array of strings. If an array of strings is passed for a delimiter then all patterns supplied will be used to check for YAML front matter. 192 | 193 | Example: 194 | 195 | ```js 196 | { 197 | close: ['---', '~~~'], 198 | open: ['...', '---'] 199 | } 200 | ``` 201 | 202 | Checks for all patterns using these delimiters. 203 | 204 | _Passing multiple delimiters will likely provide unpredictable results, but the option is included for testing purposes._ 205 | 206 | #### read 207 | Type: `boolean` 208 | 209 | Default: `true` 210 | 211 | Specify whether or not to read a file from the file system. When set to `false` a raw string may be passed to the function. Example: 212 | 213 | ```js 214 | yfm('---\nTitle: YFM\n---\nContent.', {read: false}) 215 | ``` 216 | 217 | 218 | ## Examples 219 | #### Extract front matter 220 | 221 | Let's say our page, `foo.html` contains 222 | 223 | ```html 224 | --- 225 | title: YAML Front matter 226 | --- 227 |

{{title}}

228 | ``` 229 | 230 | then running the following in the command line: 231 | 232 | ```js 233 | console.log(yfm('foo.html')); 234 | ``` 235 | returns 236 | 237 | ```json 238 | { 239 | "context": { 240 | "title": "YAML Front matter" 241 | }, 242 | "content": "

{{title}}

", 243 | "original": "---\ntitle: YAML Front matter\n---\n

{{title}}

" 244 | } 245 | ``` 246 | and 247 | 248 | ```js 249 | console.log(yfm('foo.html').context); 250 | ``` 251 | returns 252 | 253 | 254 | ```json 255 | {"title": "YAML Front matter"} 256 | ``` 257 | 258 | #### Check for YAML front matter 259 | 260 | ```js 261 | var hasYFM = function (src, options) { 262 | var obj = yfm(src, options).context; 263 | return _.keys(obj).length > 0; 264 | }; 265 | ``` 266 | 267 | 268 | ## Authors 269 | 270 | **Jon Schlinkert** 271 | 272 | + [github/jonschlinkert](https://github.com/jonschlinkert) 273 | + [twitter/jonschlinkert](http://twitter.com/jonschlinkert) 274 | 275 | **Brian Woodward** 276 | 277 | + [github/doowb](https://github.com/doowb) 278 | + [twitter/doowb](http://twitter.com/jonschlinkert) 279 | 280 | 281 | ## License 282 | Copyright (c) 2014 Jon Schlinkert, Brian Woodward, contributors. 283 | Released under the MIT license 284 | 285 | *** 286 | 287 | _This file was generated by [grunt-readme](https://github.com/assemble/grunt-readme) on Monday, January 27, 2014._ 288 | 289 | [grunt]: http://gruntjs.com/ 290 | [Getting Started]: https://github.com/gruntjs/grunt/blob/devel/docs/getting_started.md 291 | [package.json]: https://npmjs.org/doc/json.html 292 | -------------------------------------------------------------------------------- /test/fixtures/delims-and-lang.md: -------------------------------------------------------------------------------- 1 | ;;; json 2 | { 3 | "title": "JSON", 4 | "description": "Front Matter" 5 | } 6 | ;;; 7 | 8 | # This page has JSON front matter! -------------------------------------------------------------------------------- /test/fixtures/delims-custom.md: -------------------------------------------------------------------------------- 1 | ~~~ 2 | title: custom-delims 3 | foo: bar 4 | version: 2 5 | ~~~ 6 | 7 | This is an alert 8 | -------------------------------------------------------------------------------- /test/fixtures/delims-semi-colons.md: -------------------------------------------------------------------------------- 1 | ;;; 2 | { 3 | "title": "delims-semi-colons JSON", 4 | "description": "Front Matter" 5 | } 6 | ;;; 7 | 8 | # This page has JSON front matter! -------------------------------------------------------------------------------- /test/fixtures/empty.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonschlinkert/gray-matter/ce67a86dba419381db0dd01cc84e2d30a1d1e6a5/test/fixtures/empty.md -------------------------------------------------------------------------------- /test/fixtures/has-matter.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Has Matter! 3 | --- 4 | Boom. -------------------------------------------------------------------------------- /test/fixtures/hasnt-matter.md: -------------------------------------------------------------------------------- 1 | # This file doesn't have matter! -------------------------------------------------------------------------------- /test/fixtures/lang-coffee-bad.md: -------------------------------------------------------------------------------- 1 | --- coffee 2 | data 3 | title: 'autodetect-coffee' 4 | user: 'jonschlinkert' 5 | --- 6 | Content -------------------------------------------------------------------------------- /test/fixtures/lang-coffee-fn.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'coffee functions' 3 | user: 'jonschlinkert' 4 | fn: 5 | reverse = (src) -> 6 | src.split('').reverse().join('') 7 | --- 8 | {%= description %} 9 | {%= reverse(user) %} -------------------------------------------------------------------------------- /test/fixtures/lang-coffee.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'coffee' 3 | description: ''' 4 | Front matter 5 | ''' 6 | categories: ''' 7 | front matter coffee coffee-script 8 | ''' 9 | --- 10 | 11 | # This page has coffee front matter! -------------------------------------------------------------------------------- /test/fixtures/lang-cson-fn.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'CSON functions' 3 | user: 'jonschlinkert' 4 | fn: 5 | reverse = (src) -> 6 | src.split('').reverse().join('') 7 | --- 8 | {%= description %} 9 | {%= reverse(user) %} -------------------------------------------------------------------------------- /test/fixtures/lang-cson.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'CSON' 3 | description: ''' 4 | Front matter 5 | ''' 6 | categories: ''' 7 | front matter cson 8 | ''' 9 | --- 10 | 11 | # This page has cson front matter! -------------------------------------------------------------------------------- /test/fixtures/lang-javascript-fn.md: -------------------------------------------------------------------------------- 1 | --- 2 | function reverse(str) { 3 | return str.split('').reverse().join(''); 4 | } 5 | --- 6 | 7 | {%= description %} 8 | {%= reverse(user) %} 9 | 10 | 11 | ## Code fence 12 | 13 | ```js 14 | var foo = 'bar'; 15 | ``` 16 | -------------------------------------------------------------------------------- /test/fixtures/lang-javascript-object-fn.md: -------------------------------------------------------------------------------- 1 | --- 2 | { 3 | title: 'javascript front matter', 4 | user: 'jonschlinkert', 5 | fn: { 6 | reverse: function(str) { 7 | return str.split('').reverse().join(''); 8 | } 9 | } 10 | } 11 | --- 12 | 13 | {%= description %} 14 | {%= reverse(user) %} 15 | 16 | 17 | ## Code fence 18 | 19 | ```js 20 | var foo = 'bar'; 21 | ``` 22 | -------------------------------------------------------------------------------- /test/fixtures/lang-json.md: -------------------------------------------------------------------------------- 1 | --- 2 | { 3 | "title": "JSON", 4 | "description": "Front Matter" 5 | } 6 | --- 7 | 8 | # This page has JSON front matter! -------------------------------------------------------------------------------- /test/fixtures/lang-yaml.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: YAML 3 | --- 4 | 5 | # This page has YAML front matter! 6 | -------------------------------------------------------------------------------- /test/fixtures/to-json.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: to JSON 3 | --- -------------------------------------------------------------------------------- /test/fixtures/to-yaml.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: to YAML 3 | --- -------------------------------------------------------------------------------- /test/matter-empty.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('mocha'); 4 | var assert = require('assert'); 5 | var utils = require('../lib/utils'); 6 | var matter = require('..'); 7 | 8 | describe('gray-matter', function() { 9 | it('should work with empty front-matter', function() { 10 | var file1 = matter('---\n---\nThis is content'); 11 | assert.equal(file1.content, 'This is content'); 12 | assert.deepEqual(file1.data, {}); 13 | 14 | var file2 = matter('---\n\n---\nThis is content'); 15 | assert.equal(file2.content, 'This is content'); 16 | assert.deepEqual(file2.data, {}); 17 | 18 | var file3 = matter('---\n\n\n\n\n\n---\nThis is content'); 19 | assert.equal(file3.content, 'This is content'); 20 | assert.deepEqual(file3.data, {}); 21 | }); 22 | 23 | it('should add content with empty front matter to file.empty', function() { 24 | assert.deepEqual(matter('---\n---').empty, '---\n---'); 25 | }); 26 | 27 | it('should update file.isEmpty to true', function() { 28 | assert.deepEqual(matter('---\n---').isEmpty, true); 29 | }); 30 | 31 | it('should work when front-matter has comments', function() { 32 | const fixture = '---\n # this is a comment\n# another one\n---'; 33 | assert.deepEqual(matter(fixture).empty, fixture); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /test/matter-windows.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('mocha'); 4 | var assert = require('assert'); 5 | var utils = require('../lib/utils'); 6 | var matter = require('..'); 7 | 8 | describe('gray-matter (windows carriage returns)', function() { 9 | it('should extract YAML front matter', function() { 10 | var actual = matter('---\r\nabc: xyz\r\n---'); 11 | assert(actual.hasOwnProperty('data')); 12 | assert(actual.hasOwnProperty('content')); 13 | assert(actual.hasOwnProperty('orig')); 14 | assert.deepEqual(actual.data.abc, 'xyz'); 15 | }); 16 | 17 | it('should cache orig string as a buffer on the "orig property"', function() { 18 | var fixture = '---\r\nabc: xyz\r\n---'; 19 | var actual = matter(fixture); 20 | assert(utils.isBuffer(actual.orig)); 21 | assert.equal(actual.orig.toString(), fixture); 22 | }); 23 | 24 | it('should throw parsing errors', function() { 25 | assert.throws(function() { 26 | matter('---whatever\r\nabc: xyz\r\n---'); 27 | }); 28 | }); 29 | 30 | it('should throw an error when a string is not passed:', function() { 31 | assert.throws(function() { 32 | matter(); 33 | }); 34 | }); 35 | 36 | it('should return an object when the string is 0 length:', function() { 37 | assert(utils.isObject(matter(''))); 38 | }); 39 | 40 | it('should extract YAML front matter and content', function() { 41 | var fixture = '---\r\nabc: xyz\r\nversion: 2\r\n---\r\n\r\nThis is an alert\r\n'; 42 | var actual = matter(fixture); 43 | assert.deepEqual(actual.data, {abc: 'xyz', version: 2}); 44 | assert.equal(actual.content, '\r\nThis is an alert\r\n'); 45 | assert.equal(actual.orig.toString(), fixture); 46 | }); 47 | 48 | it('should use a custom delimiter as a string.', function() { 49 | var fixture = '~~~\r\nabc: xyz\r\nversion: 2\r\n~~~\r\n\r\nThis is an alert\r\n'; 50 | var actual = matter(fixture, {delims: '~~~'}); 51 | assert.deepEqual(actual.data, {abc: 'xyz', version: 2}); 52 | assert.equal(actual.content, '\r\nThis is an alert\r\n'); 53 | assert.equal(actual.orig.toString(), fixture); 54 | }); 55 | 56 | it('should use custom delimiters as an array.', function() { 57 | var fixture = '~~~\r\nabc: xyz\r\nversion: 2\r\n~~~\r\n\r\nThis is an alert\r\n'; 58 | var actual = matter(fixture, {delims: ['~~~']}); 59 | assert.deepEqual(actual.data, {abc: 'xyz', version: 2}); 60 | assert.equal(actual.content, '\r\nThis is an alert\r\n'); 61 | assert.equal(actual.orig.toString(), fixture); 62 | }); 63 | 64 | it('should correctly identify delimiters and ignore strings that look like delimiters.', function() { 65 | var fixture = '---\r\nname: "troublesome --- value"\r\n---\r\nhere is some content\r\n'; 66 | var actual = matter(fixture); 67 | assert.deepEqual(actual.data, {name: 'troublesome --- value'}); 68 | assert.equal(actual.content, 'here is some content\r\n'); 69 | assert.equal(String(actual.orig), '---\r\nname: "troublesome --- value"\r\n---\r\nhere is some content\r\n'); 70 | }); 71 | 72 | it('should correctly parse a string that only has an opening delimiter', function() { 73 | var fixture = '---\r\nname: "troublesome --- value"\r\n'; 74 | var actual = matter(fixture); 75 | assert.deepEqual(actual.data, {name: 'troublesome --- value'}); 76 | assert.equal(actual.content, ''); 77 | assert.equal(String(actual.orig), '---\r\nname: "troublesome --- value"\r\n'); 78 | }); 79 | 80 | it('should not try to parse a string has content that looks like front-matter.', function() { 81 | var fixture = '-----------name--------------value\r\nfoo'; 82 | var actual = matter(fixture); 83 | assert.deepEqual(actual.data, {}); 84 | assert.equal(actual.content, '-----------name--------------value\r\nfoo'); 85 | assert.equal(String(actual.orig), '-----------name--------------value\r\nfoo'); 86 | }); 87 | }); 88 | -------------------------------------------------------------------------------- /test/matter.excerpt.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * gray-matter 3 | * 4 | * Copyright (c) 2014-2017, Jon Schlinkert. 5 | * Released under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | require('mocha'); 11 | var assert = require('assert'); 12 | var matter = require('..'); 13 | 14 | describe('.excerpt', function() { 15 | it('should get an excerpt after front matter', function() { 16 | var file = matter('---\nabc: xyz\n---\nfoo\nbar\nbaz\n---\ncontent', {excerpt: true}); 17 | 18 | assert.equal(file.matter, '\nabc: xyz'); 19 | assert.equal(file.content, 'foo\nbar\nbaz\n---\ncontent'); 20 | assert.equal(file.excerpt, 'foo\nbar\nbaz\n'); 21 | assert.deepEqual(file.data.abc, 'xyz'); 22 | }); 23 | 24 | it('should not get excerpt when disabled', function() { 25 | var file = matter('---\nabc: xyz\n---\nfoo\nbar\nbaz\n---\ncontent'); 26 | 27 | assert.equal(file.matter, '\nabc: xyz'); 28 | assert.equal(file.content, 'foo\nbar\nbaz\n---\ncontent'); 29 | assert.equal(file.excerpt, ''); 30 | assert.deepEqual(file.data.abc, 'xyz'); 31 | }); 32 | 33 | it('should use a custom separator', function() { 34 | var file = matter('---\nabc: xyz\n---\nfoo\nbar\nbaz\n\ncontent', { 35 | excerpt_separator: '' 36 | }); 37 | 38 | assert.equal(file.matter, '\nabc: xyz'); 39 | assert.equal(file.content, 'foo\nbar\nbaz\n\ncontent'); 40 | assert.equal(file.excerpt, 'foo\nbar\nbaz\n'); 41 | assert.deepEqual(file.data.abc, 'xyz'); 42 | }); 43 | 44 | it('should use a custom separator when no front-matter exists', function() { 45 | var file = matter('foo\nbar\nbaz\n\ncontent', { 46 | excerpt_separator: '' 47 | }); 48 | 49 | assert.equal(file.matter, ''); 50 | assert.equal(file.content, 'foo\nbar\nbaz\n\ncontent'); 51 | assert.equal(file.excerpt, 'foo\nbar\nbaz\n'); 52 | assert.deepEqual(file.data, {}); 53 | }); 54 | 55 | it('should use a custom function to get excerpt', function() { 56 | var file = matter('---\nabc: xyz\n---\nfoo\nbar\nbaz\n---\ncontent', { 57 | excerpt: function(file) { 58 | file.excerpt = 'custom'; 59 | } 60 | }); 61 | 62 | assert.equal(file.matter, '\nabc: xyz'); 63 | assert.equal(file.content, 'foo\nbar\nbaz\n---\ncontent'); 64 | assert.equal(file.excerpt, 'custom'); 65 | assert.deepEqual(file.data.abc, 'xyz'); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /test/matter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('mocha'); 4 | var assert = require('assert'); 5 | var utils = require('../lib/utils'); 6 | var matter = require('..'); 7 | 8 | describe('gray-matter', function() { 9 | it('should extract YAML front matter', function() { 10 | var actual = matter('---\nabc: xyz\n---'); 11 | assert(actual.hasOwnProperty('data')); 12 | assert(actual.hasOwnProperty('content')); 13 | assert(actual.hasOwnProperty('orig')); 14 | assert.deepEqual(actual.data.abc, 'xyz'); 15 | }); 16 | 17 | it('should cache original string as a buffer on the "orig property"', function() { 18 | var fixture = '---\nabc: xyz\n---'; 19 | var actual = matter(fixture); 20 | assert(utils.isBuffer(actual.orig)); 21 | assert.equal(actual.orig.toString(), fixture); 22 | }); 23 | 24 | it('extra characters should throw parsing errors', function() { 25 | assert.throws(function() { 26 | matter('---whatever\nabc: xyz\n---'); 27 | }); 28 | }); 29 | 30 | it('boolean yaml types should still return the empty object', function() { 31 | var actual = matter('--- true\n---'); 32 | assert.deepEqual(actual.data, {}); 33 | }); 34 | 35 | it('string yaml types should still return the empty object', function() { 36 | var actual = matter('--- true\n---'); 37 | assert.deepEqual(actual.data, {}); 38 | }); 39 | 40 | it('number yaml types should still return the empty object', function() { 41 | var actual = matter('--- 42\n---'); 42 | assert.deepEqual(actual.data, {}); 43 | }); 44 | 45 | it('should throw an error when a string is not passed:', function() { 46 | assert.throws(function() { 47 | matter(); 48 | }); 49 | }); 50 | 51 | it('should return an object when the string is 0 length:', function() { 52 | assert(utils.isObject(matter(''))); 53 | }); 54 | 55 | it('should extract YAML front matter and content', function() { 56 | var fixture = '---\nabc: xyz\nversion: 2\n---\n\nThis is an alert\n'; 57 | var actual = matter(fixture); 58 | assert.deepEqual(actual.data, {abc: 'xyz', version: 2}); 59 | assert.equal(actual.content, '\nThis is an alert\n'); 60 | assert.equal(actual.orig.toString(), fixture); 61 | }); 62 | 63 | it('should use a custom delimiter as a string.', function() { 64 | var fixture = '~~~\nabc: xyz\nversion: 2\n~~~\n\nThis is an alert\n'; 65 | var actual = matter(fixture, {delims: '~~~'}); 66 | assert.deepEqual(actual.data, {abc: 'xyz', version: 2}); 67 | assert.equal(actual.content, '\nThis is an alert\n'); 68 | assert.equal(actual.orig.toString(), fixture); 69 | }); 70 | 71 | it('should use custom delimiters as an array.', function() { 72 | var fixture = '~~~\nabc: xyz\nversion: 2\n~~~\n\nThis is an alert\n'; 73 | var actual = matter(fixture, {delims: ['~~~']}); 74 | assert.deepEqual(actual.data, {abc: 'xyz', version: 2}); 75 | assert.equal(actual.content, '\nThis is an alert\n'); 76 | assert.equal(actual.orig.toString(), fixture); 77 | }); 78 | 79 | it('should correctly identify delimiters and ignore strings that look like delimiters.', function() { 80 | var fixture = '---\nname: "troublesome --- value"\n---\nhere is some content\n'; 81 | var actual = matter(fixture); 82 | assert.deepEqual(actual.data, {name: 'troublesome --- value'}); 83 | assert.equal(actual.content, 'here is some content\n'); 84 | assert.equal(String(actual.orig), '---\nname: "troublesome --- value"\n---\nhere is some content\n'); 85 | }); 86 | 87 | it('should correctly parse a string that only has an opening delimiter', function() { 88 | var fixture = '---\nname: "troublesome --- value"\n'; 89 | var actual = matter(fixture); 90 | assert.deepEqual(actual.data, {name: 'troublesome --- value'}); 91 | assert.equal(actual.content, ''); 92 | assert.equal(String(actual.orig), '---\nname: "troublesome --- value"\n'); 93 | }); 94 | 95 | it('should not try to parse a string has content that looks like front-matter.', function() { 96 | var fixture = '-----------name--------------value\nfoo'; 97 | var actual = matter(fixture); 98 | assert.deepEqual(actual.data, {}); 99 | assert.equal(actual.content, '-----------name--------------value\nfoo'); 100 | assert.equal(String(actual.orig), '-----------name--------------value\nfoo'); 101 | }); 102 | }); 103 | -------------------------------------------------------------------------------- /test/matter.language.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * gray-matter 3 | * 4 | * Copyright (c) 2014-2017, Jon Schlinkert. 5 | * Released under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var assert = require('assert'); 11 | var matter = require('..'); 12 | 13 | describe('.language', function() { 14 | it('should detect the name of the language to parse', function() { 15 | assert.deepEqual(matter.language('---\nfoo: bar\n---'), { 16 | raw: '', 17 | name: '' 18 | }); 19 | assert.deepEqual(matter.language('---js\nfoo: bar\n---'), { 20 | raw: 'js', 21 | name: 'js' 22 | }); 23 | assert.deepEqual(matter.language('---coffee\nfoo: bar\n---'), { 24 | raw: 'coffee', 25 | name: 'coffee' 26 | }); 27 | }); 28 | 29 | it('should work around whitespace', function() { 30 | assert.deepEqual(matter.language('--- \nfoo: bar\n---'), { 31 | raw: ' ', 32 | name: '' 33 | }); 34 | assert.deepEqual(matter.language('--- js \nfoo: bar\n---'), { 35 | raw: ' js ', 36 | name: 'js' 37 | }); 38 | assert.deepEqual(matter.language('--- coffee \nfoo: bar\n---'), { 39 | raw: ' coffee ', 40 | name: 'coffee' 41 | }); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /test/matter.read.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * gray-matter 3 | * 4 | * Copyright (c) 2014-2017, Jon Schlinkert. 5 | * Released under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var path = require('path'); 11 | var assert = require('assert'); 12 | var matter = require('..'); 13 | var fixture = path.join.bind(path, __dirname, 'fixtures'); 14 | 15 | describe('.read', function() { 16 | it('should extract YAML front matter from files with content.', function() { 17 | var file = matter.read(fixture('basic.txt')); 18 | 19 | assert(file.hasOwnProperty('path')); 20 | assert(file.hasOwnProperty('data', {title: 'Basic'})); 21 | assert.equal(file.content, 'this is content.'); 22 | }); 23 | 24 | it('should parse complex YAML front matter.', function() { 25 | var file = matter.read(fixture('complex.md')); 26 | 27 | assert(file.hasOwnProperty('data')); 28 | assert.equal(file.data.root, '_gh_pages'); 29 | 30 | assert(file.hasOwnProperty('path')); 31 | assert(file.hasOwnProperty('content')); 32 | assert(file.hasOwnProperty('orig')); 33 | assert(file.data.hasOwnProperty('root')); 34 | }); 35 | 36 | it('should return an object when a file is empty.', function() { 37 | var file = matter.read(fixture('empty.md')); 38 | assert(file.hasOwnProperty('path')); 39 | assert(file.hasOwnProperty('data')); 40 | assert(file.hasOwnProperty('content')); 41 | assert(file.hasOwnProperty('orig')); 42 | }); 43 | 44 | it('should return an object when no front matter exists.', function() { 45 | var file = matter.read(fixture('hasnt-matter.md')); 46 | assert(file.hasOwnProperty('path')); 47 | assert(file.hasOwnProperty('data')); 48 | assert(file.hasOwnProperty('content')); 49 | assert(file.hasOwnProperty('orig')); 50 | }); 51 | 52 | it('should parse YAML files directly', function() { 53 | var file = matter.read(fixture('all.yaml')); 54 | assert(file.hasOwnProperty('path')); 55 | assert(file.hasOwnProperty('data')); 56 | assert(file.hasOwnProperty('content')); 57 | assert(file.hasOwnProperty('orig')); 58 | assert.deepEqual(file.data, { 59 | one: 'foo', 60 | two: 'bar', 61 | three: 'baz' 62 | }); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /test/matter.test.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * gray-matter 3 | * 4 | * Copyright (c) 2014-2017, Jon Schlinkert. 5 | * Released under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var assert = require('assert'); 11 | var matter = require('..'); 12 | 13 | describe('.test', function() { 14 | it('should return `true` if the string has front-matter:', function() { 15 | assert(matter.test('---\nabc: xyz\n---')); 16 | assert(!matter.test('---\nabc: xyz\n---', {delims: '~~~'})); 17 | assert(matter.test('~~~\nabc: xyz\n~~~', {delims: '~~~'})); 18 | assert(!matter.test('\nabc: xyz\n---')); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /test/parse-coffee.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * gray-matter 3 | * 4 | * Copyright (c) 2014-2017, Jon Schlinkert. 5 | * Released under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var path = require('path'); 11 | var assert = require('assert'); 12 | var extend = require('extend-shallow'); 13 | var matter = require('../'); 14 | var fixture = path.join.bind(path, __dirname, 'fixtures'); 15 | var coffee = require('coffeescript'); 16 | var defaults = { 17 | engines: { 18 | coffee: { 19 | parse: function(str, options) { 20 | /* eslint no-eval: 0 */ 21 | return coffee['eval'](str, options); 22 | } 23 | } 24 | } 25 | }; 26 | 27 | function parse(name, options) { 28 | return matter.read(fixture(name), extend({}, defaults, options)); 29 | } 30 | 31 | describe('parse coffee', function() { 32 | it('should throw an error when coffee cannot be parsed', function() { 33 | assert.throws(function() { 34 | parse('lang-coffee-bad.md', {lang: 'coffee'}); 35 | }); 36 | }); 37 | 38 | it('should parse coffee front matter', function() { 39 | var file = parse('lang-coffee.md', {lang: 'coffee'}); 40 | assert.equal(file.data.title, 'coffee'); 41 | assert(file.hasOwnProperty('data')); 42 | assert(file.hasOwnProperty('content')); 43 | assert(file.hasOwnProperty('orig')); 44 | }); 45 | 46 | it('should eval functions in coffee front matter', function() { 47 | var file = parse('lang-coffee-fn.md', {lang: 'coffee'}); 48 | 49 | assert.equal(typeof file.data.fn, 'function'); 50 | assert.equal(file.data.title, 'coffee functions'); 51 | assert(file.hasOwnProperty('data')); 52 | assert(file.hasOwnProperty('content')); 53 | assert(file.hasOwnProperty('orig')); 54 | }); 55 | 56 | it('should eval functions in auto-detected coffee front matter', function() { 57 | var file = parse('autodetect-coffee-fn.md'); 58 | assert.equal(typeof file.data.fn, 'function'); 59 | assert.equal(file.data.title, 'coffee functions'); 60 | assert(file.hasOwnProperty('data')); 61 | assert(file.hasOwnProperty('content')); 62 | assert(file.hasOwnProperty('orig')); 63 | }); 64 | 65 | it('should detect "coffee" as the language', function() { 66 | var file = parse('autodetect-coffee.md'); 67 | assert.equal(file.data.title, 'autodetect-coffee'); 68 | assert(file.hasOwnProperty('data')); 69 | assert(file.hasOwnProperty('content')); 70 | assert(file.hasOwnProperty('orig')); 71 | }); 72 | 73 | it('should detect "coffeescript" as the language', function() { 74 | var file = parse('autodetect-coffeescript.md'); 75 | assert.equal(file.data.title, 'autodetect-coffeescript'); 76 | assert(file.hasOwnProperty('data')); 77 | assert(file.hasOwnProperty('content')); 78 | assert(file.hasOwnProperty('orig')); 79 | }); 80 | }); 81 | -------------------------------------------------------------------------------- /test/parse-cson.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * gray-matter 3 | * 4 | * Copyright (c) 2014-2017, Jon Schlinkert. 5 | * Released under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var path = require('path'); 11 | var assert = require('assert'); 12 | var matter = require('..'); 13 | var extend = require('extend-shallow'); 14 | var coffee = require('coffeescript'); 15 | var fixture = path.join.bind(path, __dirname, 'fixtures'); 16 | var defaults = { 17 | engines: { 18 | coffee: { 19 | parse: function(str, options) { 20 | /* eslint no-eval: 0 */ 21 | return coffee['eval'](str, options); 22 | } 23 | } 24 | } 25 | }; 26 | 27 | function parse(name, options) { 28 | return matter.read(fixture(name), extend({}, defaults, options)); 29 | } 30 | 31 | describe('parse cson:', function() { 32 | it('should parse CSON front matter.', function() { 33 | var actual = parse('lang-cson.md', { 34 | language: 'cson' 35 | }); 36 | 37 | assert.equal(actual.data.title, 'CSON'); 38 | assert(actual.hasOwnProperty('data')); 39 | assert(actual.hasOwnProperty('content')); 40 | assert(actual.hasOwnProperty('orig')); 41 | }); 42 | 43 | it('should evaluate functions in CSON front matter.', function() { 44 | var actual = parse('lang-cson-fn.md', { 45 | language: 'cson' 46 | }); 47 | 48 | assert.equal(typeof actual.data.fn, 'function'); 49 | assert.equal(actual.data.title, 'CSON functions'); 50 | assert(actual.hasOwnProperty('data')); 51 | assert(actual.hasOwnProperty('content')); 52 | assert(actual.hasOwnProperty('orig')); 53 | }); 54 | 55 | it('should evaluate functions in auto-detected CSON front matter.', function() { 56 | var actual = parse('autodetect-cson-fn.md'); 57 | assert.equal(typeof actual.data.fn, 'function'); 58 | assert.equal(actual.data.title, 'CSON functions'); 59 | assert(actual.hasOwnProperty('data')); 60 | assert(actual.hasOwnProperty('content')); 61 | assert(actual.hasOwnProperty('orig')); 62 | }); 63 | 64 | it('should auto-detect cson as the language.', function() { 65 | var actual = parse('autodetect-cson.md'); 66 | 67 | assert.equal(actual.data.title, 'autodetect-CSON'); 68 | assert(actual.hasOwnProperty('data')); 69 | assert(actual.hasOwnProperty('content')); 70 | assert(actual.hasOwnProperty('orig')); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /test/parse-custom.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * gray-matter 3 | * 4 | * Copyright (c) 2014-2017, Jon Schlinkert. 5 | * Released under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var assert = require('assert'); 11 | var YAML = require('js-yaml'); 12 | var matter = require('..'); 13 | 14 | describe('custom parser:', function() { 15 | it('should allow a custom parser to be registered:', function() { 16 | var actual = matter.read('./test/fixtures/lang-yaml.md', { 17 | parser: function customParser(str, opts) { 18 | try { 19 | return YAML.safeLoad(str, opts); 20 | } catch (err) { 21 | throw new SyntaxError(err); 22 | } 23 | } 24 | }); 25 | 26 | assert.equal(actual.data.title, 'YAML'); 27 | assert(actual.hasOwnProperty('data')); 28 | assert(actual.hasOwnProperty('content')); 29 | assert(actual.hasOwnProperty('orig')); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /test/parse-javascript.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * gray-matter 3 | * 4 | * Copyright (c) 2014-2017, Jon Schlinkert. 5 | * Released under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var assert = require('assert'); 11 | var matter = require('../'); 12 | 13 | describe('parse javascript:', function() { 14 | it('should parse front matter when options.lang is javascript', function() { 15 | var file = matter.read('./test/fixtures/lang-javascript-object-fn.md', { 16 | lang: 'javascript' 17 | }); 18 | 19 | assert.equal(file.data.title, 'javascript front matter'); 20 | assert(file.hasOwnProperty('data')); 21 | assert(file.hasOwnProperty('content')); 22 | assert(file.hasOwnProperty('orig')); 23 | assert.equal(typeof file.data.fn.reverse, 'function'); 24 | }); 25 | 26 | it('should parse front matter when options.language is js', function() { 27 | var file = matter.read('./test/fixtures/lang-javascript-object-fn.md', { 28 | language: 'js' 29 | }); 30 | 31 | assert.equal(file.data.title, 'javascript front matter'); 32 | assert(file.hasOwnProperty('data')); 33 | assert(file.hasOwnProperty('content')); 34 | assert(file.hasOwnProperty('orig')); 35 | assert.equal(typeof file.data.fn.reverse, 'function'); 36 | }); 37 | 38 | it('should eval functions', function() { 39 | var file = matter.read('./test/fixtures/lang-javascript-fn.md', {language: 'js'}); 40 | assert.equal(typeof file.data, 'function'); 41 | }); 42 | 43 | it('should detect "javascript" after the first delimiter', function() { 44 | var file = matter.read('./test/fixtures/autodetect-javascript.md'); 45 | assert.equal(file.data.title, 'autodetect-javascript'); 46 | assert.equal(file.data.title, 'autodetect-javascript'); 47 | assert(file.hasOwnProperty('data')); 48 | assert(file.hasOwnProperty('content')); 49 | assert(file.hasOwnProperty('orig')); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /test/parse-json.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * gray-matter 3 | * 4 | * Copyright (c) 2014-2017, Jon Schlinkert. 5 | * Released under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var assert = require('assert'); 11 | var matter = require('..'); 12 | 13 | describe('parse json:', function() { 14 | it('should parse JSON front matter.', function() { 15 | var actual = matter.read('./test/fixtures/lang-json.md', { 16 | lang: 'json' 17 | }); 18 | 19 | assert.equal(actual.data.title, 'JSON'); 20 | assert(actual.hasOwnProperty('data')); 21 | assert(actual.hasOwnProperty('content')); 22 | assert(actual.hasOwnProperty('orig')); 23 | }); 24 | 25 | it('should auto-detect JSON as the language.', function() { 26 | var actual = matter.read('./test/fixtures/autodetect-json.md'); 27 | 28 | assert.equal(actual.data.title, 'autodetect-JSON'); 29 | assert(actual.hasOwnProperty('data')); 30 | assert(actual.hasOwnProperty('content')); 31 | assert(actual.hasOwnProperty('orig')); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /test/parse-toml.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * gray-matter 3 | * 4 | * Copyright (c) 2014-2017, Jon Schlinkert. 5 | * Released under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var assert = require('assert'); 11 | var matter = require('..'); 12 | var extend = require('extend-shallow'); 13 | var toml = require('toml'); 14 | var defaults = { 15 | engines: { 16 | toml: toml.parse.bind(toml) 17 | } 18 | }; 19 | 20 | function parse(str, options) { 21 | return matter(str, extend({}, defaults, options)); 22 | } 23 | 24 | describe('parse TOML:', function() { 25 | it('should parse toml front matter.', function() { 26 | var actual = parse('---\ntitle = "TOML"\ndescription = "Front matter"\ncategories = "front matter toml"\n---\n\n# This file has toml front matter!\n', { 27 | lang: 'toml' 28 | }); 29 | assert.equal(actual.data.title, 'TOML'); 30 | assert(actual.hasOwnProperty('data')); 31 | assert(actual.hasOwnProperty('content')); 32 | assert(actual.hasOwnProperty('orig')); 33 | }); 34 | 35 | it('should auto-detect TOML as the language.', function() { 36 | var actual = parse('---toml\ntitle = "autodetect-TOML"\n[props]\nuser = "jonschlinkert"\n---\nContent\n'); 37 | assert.equal(actual.data.title, 'autodetect-TOML'); 38 | assert(actual.hasOwnProperty('data')); 39 | assert(actual.hasOwnProperty('content')); 40 | assert(actual.hasOwnProperty('orig')); 41 | }); 42 | 43 | it('should throw on TOML syntax errors', function() { 44 | assert.throws(function() { 45 | matter('---toml\n[props\nuser = "jonschlinkert"\n---\nContent\n'); 46 | }); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /test/parse-yaml.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * gray-matter 3 | * 4 | * Copyright (c) 2014-2017, Jon Schlinkert. 5 | * Released under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var assert = require('assert'); 11 | var matter = require('..'); 12 | 13 | describe('parse YAML:', function() { 14 | it('should parse YAML', function() { 15 | var file = matter.read('./test/fixtures/all.yaml'); 16 | assert.deepEqual(file.data, { 17 | one: 'foo', 18 | two: 'bar', 19 | three: 'baz' 20 | }); 21 | }); 22 | 23 | it('should parse YAML with closing ...', function() { 24 | var file = matter.read('./test/fixtures/all-dots.yaml'); 25 | assert.deepEqual(file.data, { 26 | one: 'foo', 27 | two: 'bar', 28 | three: 'baz' 29 | }); 30 | }); 31 | 32 | it('should parse YAML front matter', function() { 33 | var actual = matter.read('./test/fixtures/lang-yaml.md'); 34 | assert.equal(actual.data.title, 'YAML'); 35 | assert(actual.hasOwnProperty('data')); 36 | assert(actual.hasOwnProperty('content')); 37 | assert(actual.hasOwnProperty('orig')); 38 | }); 39 | 40 | it('should detect YAML as the language with no language defined after the first fence', function() { 41 | var actual = matter.read('./test/fixtures/autodetect-no-lang.md'); 42 | assert.equal(actual.data.title, 'autodetect-no-lang'); 43 | assert(actual.hasOwnProperty('data')); 44 | assert(actual.hasOwnProperty('content')); 45 | assert(actual.hasOwnProperty('orig')); 46 | }); 47 | 48 | it('should detect YAML as the language', function() { 49 | var actual = matter.read('./test/fixtures/autodetect-yaml.md'); 50 | assert.equal(actual.data.title, 'autodetect-yaml'); 51 | assert(actual.hasOwnProperty('data')); 52 | assert(actual.hasOwnProperty('content')); 53 | assert(actual.hasOwnProperty('orig')); 54 | }); 55 | 56 | it('should use safeLoad when specified', function() { 57 | var fixture = '---\nabc: xyz\nversion: 2\n---\n\nThis is an alert\n'; 58 | var actual = matter(fixture, {safeLoad: true}); 59 | assert.deepEqual(actual.data, {abc: 'xyz', version: 2}); 60 | assert.equal(actual.content, '\nThis is an alert\n'); 61 | assert(actual.hasOwnProperty('orig')); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /test/stringify.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * gray-matter 3 | * 4 | * Copyright (c) 2014-2017, Jon Schlinkert. 5 | * Released under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var assert = require('assert'); 11 | var matter = require('../'); 12 | 13 | describe('.stringify', function() { 14 | it('should stringify front-matter from a file object', function() { 15 | var file = { 16 | content: 'Name: {{name}}\n', 17 | data: {name: 'gray-matter'} 18 | }; 19 | 20 | assert.equal(matter.stringify(file), [ 21 | '---', 22 | 'name: gray-matter', 23 | '---', 24 | 'Name: {{name}}\n' 25 | ].join('\n')); 26 | }); 27 | 28 | it('should stringify from a string', function() { 29 | assert.equal(matter.stringify('Name: {{name}}\n'), 'Name: {{name}}\n'); 30 | }); 31 | 32 | it('should use custom delimiters to stringify', function() { 33 | var data = {name: 'gray-matter'}; 34 | var actual = matter.stringify('Name: {{name}}', data, {delims: '~~~'}); 35 | assert.equal(actual, [ 36 | '~~~', 37 | 'name: gray-matter', 38 | '~~~', 39 | 'Name: {{name}}\n' 40 | ].join('\n')); 41 | }); 42 | 43 | it('should stringify a file object', function() { 44 | var file = { content: 'Name: {{name}}', data: {name: 'gray-matter'} }; 45 | var actual = matter.stringify(file); 46 | assert.equal(actual, [ 47 | '---', 48 | 'name: gray-matter', 49 | '---', 50 | 'Name: {{name}}\n' 51 | ].join('\n')); 52 | }); 53 | 54 | it('should stringify an excerpt', function() { 55 | var file = { content: 'Name: {{name}}', data: {name: 'gray-matter'} }; 56 | file.excerpt = 'This is an excerpt.'; 57 | 58 | assert.equal(matter.stringify(file), [ 59 | '---', 60 | 'name: gray-matter', 61 | '---', 62 | 'This is an excerpt.', 63 | '---', 64 | 'Name: {{name}}\n' 65 | ].join('\n')); 66 | }); 67 | 68 | it('should not add an excerpt if it already exists', function() { 69 | var file = { content: 'Name: {{name}}\n\nThis is an excerpt.', data: {name: 'gray-matter'} }; 70 | file.excerpt = 'This is an excerpt.'; 71 | 72 | assert.equal(matter.stringify(file), [ 73 | '---', 74 | 'name: gray-matter', 75 | '---', 76 | 'Name: {{name}}\n\nThis is an excerpt.\n' 77 | ].join('\n')); 78 | }); 79 | }); 80 | -------------------------------------------------------------------------------- /test/vinyl-files.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * gray-matter 3 | * 4 | * Copyright (c) 2014-2017, Jon Schlinkert. 5 | * Released under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var assert = require('assert'); 11 | var File = require('vinyl'); 12 | var matter = require('..'); 13 | 14 | describe('vinyl files', function() { 15 | it('should take a vinyl file', function() { 16 | var file = new File({path: 'foo', contents: Buffer.from('---\none: two\n---\nbar')}); 17 | 18 | var actual = matter(file); 19 | assert.equal(actual.path, 'foo'); 20 | assert.deepEqual(actual.data, {one: 'two'}); 21 | assert.deepEqual(actual.content, 'bar'); 22 | assert.deepEqual(actual.contents, Buffer.from('---\none: two\n---\nbar')); 23 | }); 24 | }); 25 | --------------------------------------------------------------------------------