├── .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/) |
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\nHello 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 [](https://www.npmjs.com/package/gray-matter) [](https://npmjs.org/package/gray-matter) [](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/) |
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\nHello 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 [](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 [](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 |
--------------------------------------------------------------------------------