wikibase-edit
Version:
Edit Wikibase from NodeJS
85 lines (83 loc) • 3.37 kB
text/typescript
import { isEntityId, isItemId } from 'wikibase-sdk'
import { parseCalendar } from './claim/parse_calendar.js'
import { parseUnit } from './claim/quantity.js'
import { newError } from './error.js'
import { isNonEmptyString, isNumber, isStringNumber } from './utils.js'
export const string = isNonEmptyString
export const entity = isEntityId
// See https://www.mediawiki.org/wiki/Wikibase/DataModel#Dates_and_times
// The positive years will be signed later
export const time = time => {
time = time.value || time
let precision, calendar, calendarmodel
if (typeof time === 'object') {
const dateObject = time
;({ precision, calendar, calendarmodel, time } = time)
if (typeof precision === 'number' && (precision < 0 || precision > 14)) {
return false
}
if (precision > 11) throw newError('time precision not supported by the Wikibase API', dateObject)
calendarmodel = calendarmodel || calendar
if (calendarmodel && !parseCalendar(calendarmodel, time)) {
throw newError('invalid calendar', dateObject)
}
}
time = time.toString()
const sign = time[0] === '-' ? '-' : '+'
const year = time.replace(/^(-|\+)/, '').split('-')[0]
// Parsing as an ISO String should not throw an Invalid time value error
// Only trying to parse 5-digit years or below, as higher years
// will fail, even when valid Wikibase dates
// Excluding negative years as the format expected by Wikibase
// doesn't have the padding zeros expected by ISO
if (sign === '+' && year.length <= 5) {
try {
time = time.replace(/^\+/, '')
let isoTime = time
// ISO validation would fail if either date or month are 0
// Replace date or date and month digits with 01
// if precision is less than 11 or 10, respectively
if (precision != null) {
if (precision < 10) {
isoTime = isoTime.replace(/^(\d{4})-\d{1,2}-\d{1,2}/, '$1-01-01')
} else if (precision < 11) {
isoTime = isoTime.replace(/^(\d{4}-\d{1,2})-\d{1,2}/, '$1-01')
}
}
new Date(isoTime).toISOString()
} catch (err) {
if (err.name === 'RangeError') return false
else throw err
}
}
if (precision != null && precision > 11) {
return /^(-|\+)?\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2,3}Z$/.test(time)
} else if (time.match('T')) {
return /^(-|\+)?\d{4,16}-\d{2}-\d{2}T00:00:00(\.000)?Z$/.test(time)
} else {
return /^(-|\+)?\d{4,16}(-\d{2}){0,2}$/.test(time)
}
}
export const monolingualtext = value => {
value = value.value || value
const { text, language } = value
return isNonEmptyString(text) && isNonEmptyString(language)
}
// cf https://www.mediawiki.org/wiki/Wikibase/DataModel#Quantities
export const quantity = amount => {
amount = amount.value || amount
if (typeof amount === 'object') {
let unit
;({ unit, amount } = amount)
if (unit && !isItemId(parseUnit(unit)) && unit !== '1') return false
}
// Accepting both numbers or string numbers as the amount will be
// turned as a string lib/claim/builders.js signAmount function anyway
return isNumber(amount) || isStringNumber(amount)
}
export const globecoordinate = obj => {
obj = obj.value || obj
if (typeof obj !== 'object') return false
const { latitude, longitude, precision } = obj
return isNumber(latitude) && isNumber(longitude) && isNumber(precision)
}