-
Notifications
You must be signed in to change notification settings - Fork 54
/
validate.js
96 lines (73 loc) · 2.63 KB
/
validate.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
const isPlainObj = require('is-plain-obj')
const { LIFECYCLE, LEGACY_LIFECYCLE } = require('@netlify/config')
const { serializeList } = require('../../utils/list')
const { validateConfigSchema } = require('../config/validate_config')
const { API_METHODS } = require('./api')
// Validate the shape of a plugin return value
// TODO: validate allowed characters in `logic` properties
const validatePlugin = function(logic) {
if (!isPlainObj(logic)) {
throw new Error(`Plugin must be an object or a function`)
}
validateRequiredProperties(logic)
Object.entries(logic).forEach(([propName, value]) => validateProperty(value, propName))
}
// Validate `plugin.*` required properties
const validateRequiredProperties = function(logic) {
REQUIRED_PROPERTIES.forEach(propName => validateRequiredProperty(logic, propName))
}
const REQUIRED_PROPERTIES = ['name']
const validateRequiredProperty = function(logic, propName) {
if (logic[propName] === undefined) {
throw new Error(`Missing required property '${propName}'`)
}
}
const validateProperty = function(value, propName) {
if (typeof value === 'function') {
validateMethod(propName)
return
}
validateNonMethod(value, propName)
}
// Validate `plugin.*` event handlers
const validateMethod = function(propName) {
const propNameA = propName.replace(OVERRIDE_REGEXP, '')
if (!LIFECYCLE.includes(propNameA) && LEGACY_LIFECYCLE[propNameA] === undefined) {
throw new Error(`Invalid event '${propNameA}'.
Please use a valid event name. One of:
${serializeList(LIFECYCLE)}`)
}
}
// Event handlers can start with `pluginName:` to override another plugin
const OVERRIDE_REGEXP = /^[^:]+:/
const validateNonMethod = function(value, propName) {
const validator = VALIDATORS[propName]
if (validator === undefined) {
throw new Error(`Invalid property '${propName}'.
Please use a property name. One of:
${serializeList(Object.keys(VALIDATORS))}`)
}
validator(value)
}
// Validate `plugin.name`
const validateName = function(name) {
if (typeof name !== 'string') {
throw new Error(`Property 'name' must be a string`)
}
}
// Validate `plugin.scopes`
const validateScopes = function(scopes) {
const wrongScope = scopes.find(scope => !isValidScope(scope))
if (wrongScope === undefined) {
return
}
throw new Error(`Invalid scope "${wrongScope}"
Please use a valid scope. One of:
${serializeList(ALLOWED_SCOPES)}`)
}
const isValidScope = function(scope) {
return ALLOWED_SCOPES.includes(scope)
}
const ALLOWED_SCOPES = ['*', ...API_METHODS]
const VALIDATORS = { name: validateName, scopes: validateScopes, config: validateConfigSchema }
module.exports = { validatePlugin }