UNPKG

wikibase-edit

Version:

Edit Wikibase from NodeJS

148 lines (136 loc) 5.51 kB
import { flatten } from 'lodash-es' import { newError } from '../error.js' import { isString, forceArray, isntEmpty, objectKeys } from '../utils.js' import { validateAliases, validateBadges, validateLabelOrDescription, validateLanguage, validatePropertyId, validateSite, validateSiteTitle } from '../validate.js' import { buildClaim } from './build_claim.js' import { reconcileClaimFactory } from './reconcile_claim.js' import type { Reconciliation } from './validate_reconciliation_object.js' import type { PropertiesDatatypes } from '../properties/fetch_properties_datatypes.js' import type { AbsoluteUrl } from '../types/common.js' import type { Claims, CustomSimplifiedClaim, PropertyId, SimplifiedClaim, SimplifiedPropertyClaims, SimplifiedSitelinks, SimplifiedTerm, Sitelink, SitelinkBadges, SitelinkTitle, Statements, Term, WikimediaLanguageCode } from 'wikibase-sdk' type CustomSimplifiedClaims = Record<PropertyId, SimplifiedPropertyClaims | SimplifiedClaim | CustomSimplifiedClaim[] | CustomSimplifiedClaim> function formatBadgesArray (badges: SitelinkBadges | string) { let badgeArray: SitelinkBadges if (isString(badges)) { badgeArray = badges.split('|') as SitelinkBadges } else { badgeArray = badges } validateBadges(badgeArray) return badgeArray } export function formatTermsObject (name: 'label' | 'description' | 'alias', values: Record<WikimediaLanguageCode, string | string[] | null>) { const obj = {} objectKeys(values).forEach(lang => { let value = values[lang] validateLanguage(lang) if (name === 'alias') { value = forceArray(value) validateAliases(value, { allowEmptyArray: true }) obj[lang] = value.map(alias => buildLanguageValue(alias, lang)) } else { if (value instanceof Array) { throw new Error(`invalid value: ${JSON.stringify(value)} (${typeof value})`) } validateLabelOrDescription(name, value) obj[lang] = buildLanguageValue(value, lang) } }) return obj } export function formatClaims (claims: CustomSimplifiedClaims, properties: PropertiesDatatypes, instance: AbsoluteUrl, reconciliation: Reconciliation, existingClaims: Claims | Statements) { if (!properties) throw newError('expected properties') return objectKeys(claims) .reduce(formatClaimFactory(claims, properties, instance, reconciliation, existingClaims), {}) } export function formatSitelinks (sitelinks: SimplifiedSitelinks) { const obj = {} objectKeys(sitelinks).forEach(site => { validateSite(site) const title = sitelinks[site] if (title === null) { // Passing an empty string removes the sitelink obj[site] = buildSiteTitle('', site) } else { validateSiteTitle(title) obj[site] = buildSiteTitle(title, site) } }) return obj } export const formatBadges = formatBadgesArray function formatClaimFactory (claims: CustomSimplifiedClaims, properties: PropertiesDatatypes, instance: AbsoluteUrl, reconciliation: Reconciliation, existingClaims: Claims | Statements) { return function formatClaim (obj, property) { if (!properties) throw newError('expected properties') if (!instance) throw newError('expected instance') validatePropertyId(property) const values = forceArray(claims[property]) obj[property] = obj[property] || [] obj[property] = values.map(value => buildClaim(property, properties, value, instance)) if (existingClaims?.[property] != null) { obj[property] = obj[property] .map(reconcileClaimFactory(reconciliation, existingClaims[property])) .filter(isntEmpty) obj[property] = flatten(obj[property]) validateReconciledClaims(obj[property]) } return obj } } interface EditedTerm { language: WikimediaLanguageCode value: string add?: boolean | string remove?: boolean } function buildLanguageValue (value: SimplifiedTerm | Term | null, language: WikimediaLanguageCode) { // Re-building an object to avoid passing any undesired key/value const valueObj: Partial<EditedTerm> = { language } if (isString(value)) { valueObj.value = value } else if (value === null) { valueObj.remove = true } else { valueObj.value = value.value if ('remove' in value && value.remove === true) valueObj.remove = true if ('add' in value && value.add != null) valueObj.add = '' } return valueObj as EditedTerm } interface EditedSitelink { // Not using Wikimedia Site type to accept non-Wikimedia sitelinks site: string title: SitelinkTitle badges: SitelinkBadges url?: AbsoluteUrl remove?: boolean } function buildSiteTitle (title: SitelinkTitle | Sitelink, site: string) { // Re-building an object to avoid passing any undesired key/value const valueObj: Partial<EditedSitelink> = { site } if (isString(title)) { valueObj.title = title } else { valueObj.title = title.title if (title.badges) { valueObj.badges = formatBadgesArray(title.badges) } if ('remove' in title && title.remove === true) valueObj.remove = true } return valueObj } function validateReconciledClaims (propertyClaims: SimplifiedClaim[] | CustomSimplifiedClaim[]) { const claimsByGuid = {} for (const claim of propertyClaims) { if (typeof claim === 'object' && 'id' in claim) { const { id } = claim if (id) { if (claimsByGuid[id] != null) { throw newError('can not match several times the same claim', { claim }) } else { claimsByGuid[id] = claim } } } } }