wikibase-edit
Version:
Edit Wikibase from NodeJS
115 lines • 4.4 kB
JavaScript
import { isEntityId, isPropertyId, isGuid, isItemId, wikimediaLanguageCodes, ranks } from 'wikibase-sdk';
import { hasSpecialSnaktype } from './claim/special_snaktype.js';
import * as datatypeTests from './datatype_tests.js';
import { newError } from './error.js';
import { inviteToOpenAFeatureRequest } from './issues.js';
import { normalizeDatatype } from './properties/datatypes_to_builder_datatypes.js';
import { isNonEmptyString, forceArray, isArray, setHas, arrayIncludes } from './utils.js';
const siteRegex = /^[a-z_]{2,20}$/;
const wikimediaLanguageCodesSet = new Set(wikimediaLanguageCodes);
function validateStringValue(name, str) {
if (str === null)
return;
if (typeof str === 'object') {
if ('remove' in str && str.remove === true)
return;
// Required by entity/edit.js validation:
// values can be passed as objects to allow for flags (ex: 'remove=true')
if ('value' in str && str.value != null)
str = str.value;
// title is the API key for sitelinks
else if ('title' in str && str.title != null)
str = str.title;
}
if (!(isNonEmptyString(str))) {
throw newError(`invalid ${name}`, { str });
}
}
export function validateEntityId(entityId) {
if (!isEntityId(entityId)) {
throw newError('invalid entity id', { entityId });
}
}
export function validatePropertyId(propertyId) {
if (!isNonEmptyString(propertyId)) {
throw newError('missing property id', { propertyId });
}
if (!isPropertyId(propertyId)) {
throw newError('invalid property id', { propertyId });
}
}
export function validateLanguage(language) {
if (!(isNonEmptyString(language) && setHas(wikimediaLanguageCodesSet, language))) {
throw newError('invalid language', { language });
}
}
export const validateLabelOrDescription = validateStringValue;
export function validateAliases(value, options = {}) {
const { allowEmptyArray = false } = options;
value = forceArray(value);
if (!allowEmptyArray && value.length === 0)
throw newError('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 function validateSnakValue(property, datatype, value) {
if (hasSpecialSnaktype(value))
return;
if (value == null) {
throw newError('missing snak value', { property, value });
}
if (typeof value === 'object' && 'value' in value) {
value = value.value;
}
const builderDatatype = normalizeDatatype(datatype);
// eslint-disable-next-line import-x/namespace
if (datatypeTests[builderDatatype] == null) {
const context = { property, value, datatype, builderDatatype };
const featureRequestMessage = inviteToOpenAFeatureRequest({
title: `add support for ${datatype} datatype`,
context,
});
throw newError(`unsupported datatype: ${datatype}\n${featureRequestMessage}`, context);
}
// eslint-disable-next-line import-x/namespace
if (!datatypeTests[builderDatatype](value)) {
throw newError(`invalid ${builderDatatype} value`, { property, value });
}
}
export function validateSite(site) {
if (!(isNonEmptyString(site) && siteRegex.test(site))) {
throw newError('invalid site', { site });
}
}
export const validateSiteTitle = validateStringValue.bind(null, 'title');
export function validateBadges(badges) {
if (!isArray(badges)) {
throw newError('invalid badges', { badges });
}
for (const badge of badges) {
if (!isItemId(badge)) {
throw newError('invalid badge', { invalidBadge: badge, badges });
}
}
}
export function validateGuid(guid) {
if (!isNonEmptyString(guid)) {
throw newError('missing guid', { guid });
}
if (!isGuid(guid)) {
throw newError('invalid guid', { guid });
}
}
export function validateHash(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 newError('invalid hash', { hash });
}
}
export function validateRank(rank) {
if (!arrayIncludes(ranks, rank)) {
throw newError('invalid rank', { rank });
}
}
//# sourceMappingURL=validate.js.map