зеркало из https://github.com/github/docs.git
76 строки
2.2 KiB
JavaScript
76 строки
2.2 KiB
JavaScript
const matter = require('gray-matter')
|
|
const revalidator = require('revalidator')
|
|
const { difference, intersection } = require('lodash')
|
|
|
|
function readFrontmatter (markdown, opts = { validateKeyNames: false, validateKeyOrder: false }) {
|
|
const schema = opts.schema || { properties: {} }
|
|
const filepath = opts.filepath || null
|
|
|
|
let content, data
|
|
let errors = []
|
|
|
|
try {
|
|
({ content, data } = matter(markdown))
|
|
} catch (e) {
|
|
const defaultReason = 'invalid frontmatter entry'
|
|
|
|
const reason = e.reason
|
|
// make this common error message a little easier to understand
|
|
? e.reason.startsWith('can not read a block mapping entry;') ? defaultReason : e.reason
|
|
: defaultReason
|
|
|
|
const error = {
|
|
reason,
|
|
message: 'YML parsing error!'
|
|
}
|
|
|
|
if (filepath) error.filepath = filepath
|
|
errors.push(error)
|
|
return { errors }
|
|
}
|
|
|
|
const allowedKeys = Object.keys(schema.properties)
|
|
const existingKeys = Object.keys(data)
|
|
const expectedKeys = intersection(allowedKeys, existingKeys)
|
|
|
|
;({ errors } = revalidator.validate(data, schema))
|
|
|
|
// add filepath property to each error object
|
|
if (errors.length && filepath) {
|
|
errors = errors.map(error => Object.assign(error, { filepath }))
|
|
}
|
|
|
|
// validate key names
|
|
if (opts.validateKeyNames) {
|
|
const invalidKeys = difference(existingKeys, allowedKeys)
|
|
invalidKeys.forEach(key => {
|
|
const error = {
|
|
property: key,
|
|
message: `not allowed. Allowed properties are: ${allowedKeys.join(', ')}`
|
|
}
|
|
if (filepath) error.filepath = filepath
|
|
errors.push(error)
|
|
})
|
|
}
|
|
|
|
// validate key order
|
|
if (opts.validateKeyOrder && existingKeys.join('') !== expectedKeys.join('')) {
|
|
const error = {
|
|
property: 'keys',
|
|
message: `keys must be in order. Current: ${existingKeys.join(',')}; Expected: ${expectedKeys.join(',')}`
|
|
}
|
|
if (filepath) error.filepath = filepath
|
|
errors.push(error)
|
|
}
|
|
|
|
return { content, data, errors }
|
|
}
|
|
|
|
// Expose gray-matter's underlying stringify method for joining a parsed
|
|
// frontmatter object and a markdown string back into a unified string
|
|
//
|
|
// stringify('some string', {some: 'frontmatter'})
|
|
readFrontmatter.stringify = matter.stringify
|
|
|
|
module.exports = readFrontmatter
|