-
-
Notifications
You must be signed in to change notification settings - Fork 28
/
Copy pathvalidate.js
113 lines (107 loc) · 3.79 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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import { isEntityId, isPropertyId, isGuid, isItemId } from 'wikibase-sdk'
import { hasSpecialSnaktype } from './claim/special_snaktype.js'
import * as datatypeTests from './datatype_tests.js'
import error_ from './error.js'
import { inviteToOpenAFeatureRequest } from './issues.js'
import datatypesToBuilderDatatypes from './properties/datatypes_to_builder_datatypes.js'
import { isPlainObject, isNonEmptyString, forceArray, isArray } from './utils.js'
// For a list of valid languages
// see https://www.wikidata.org/w/api.php?action=help&modules=wbgetentities
const langRegex = /^\w{2,3}(-[\w-]{2,10})?$/
const siteRegex = /^[a-z_]{2,20}$/
const possibleRanks = [ 'normal', 'preferred', 'deprecated' ]
const validateStringValue = (name, str) => {
if (str === null) return
if (isPlainObject(str)) {
if (str.remove === true) return
// Required by entity/edit.js validation:
// values can be passed as objects to allow for flags (ex: 'remove=true')
if (str.value != null) str = str.value
// title is the API key for sitelinks
if (str.title != null) str = str.title
}
if (!(isNonEmptyString(str))) {
throw error_.new(`invalid ${name}`, { str })
}
}
export const entity = entity => {
if (!isEntityId(entity)) {
throw error_.new('invalid entity', { entity })
}
}
export const property = property => {
if (!isNonEmptyString(property)) {
throw error_.new('missing property', { property })
}
if (!isPropertyId(property)) {
throw error_.new('invalid property', { property })
}
}
export const language = language => {
if (!(isNonEmptyString(language) && langRegex.test(language))) {
throw error_.new('invalid language', { language })
}
}
export const labelOrDescription = validateStringValue
export const aliases = (value, options = {}) => {
const { allowEmptyArray = false } = options
value = forceArray(value)
if (!allowEmptyArray && value.length === 0) throw error_.new('empty alias array', { value })
// Yes, it's not an label or a description, but it works the same
value.forEach(validateStringValue.bind(null, 'alias'))
}
export const snakValue = (property, datatype, value) => {
if (hasSpecialSnaktype(value)) return
if (value == null) {
throw error_.new('missing snak value', { property, value })
}
if (value.value) value = value.value
const builderDatatype = datatypesToBuilderDatatypes(datatype)
if (datatypeTests[builderDatatype] == null) {
const context = { property, value, datatype, builderDatatype }
const featureRequestMessage = inviteToOpenAFeatureRequest({
title: `add support for ${datatype} datatype`,
context,
})
throw error_.new(`unsupported datatype: ${datatype}\n${featureRequestMessage}`, context)
}
if (!datatypeTests[builderDatatype](value)) {
throw error_.new(`invalid ${builderDatatype} value`, { property, value })
}
}
export const site = site => {
if (!(isNonEmptyString(site) && siteRegex.test(site))) {
throw error_.new('invalid site', { site })
}
}
export const siteTitle = validateStringValue.bind(null, 'title')
export const badges = badges => {
if (!isArray(badges)) {
throw error_.new('invalid badges', { badges })
}
for (const badge of badges) {
if (!isItemId(badge)) {
throw error_.new('invalid badge', { invalidBadge: badge, badges })
}
}
}
export const guid = guid => {
if (!isNonEmptyString(guid)) {
throw error_.new('missing guid', { guid })
}
if (!isGuid(guid)) {
throw error_.new('invalid guid', { guid })
}
}
export const hash = hash => {
// Couldn't find the hash length range
// but it looks to be somewhere around 40 characters
if (!/^[0-9a-f]{20,80}$/.test(hash)) {
throw error_.new('invalid hash', { hash })
}
}
export const rank = rank => {
if (possibleRanks.indexOf(rank) === -1) {
throw error_.new('invalid rank', { rank })
}
}