// Copyright Inrupt Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the // Software, and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // import type { Literal, NamedNode, Quad_Object } from "@rdfjs/types"; import type { UrlString, Url, Thing, IriString } from "../interfaces"; import { internal_throwIfNotThing } from "./thing.internal"; import type { XmlSchemaTypeIri, Time } from "../datatypes"; import { serializeBoolean, serializeDatetime, serializeDate, serializeDecimal, serializeInteger, normalizeLocale, xmlSchemaTypes, internal_isValidUrl, isNamedNode, serializeTime, } from "../datatypes"; import { asIri, isThing, isThingLocal, ValidPropertyUrlExpectedError, ValidValueUrlExpectedError, } from "./thing"; import { internal_toIriString } from "../interfaces.internal"; import { freeze, getBlankNodeId } from "../rdf.internal"; /** * Create a new Thing with a URL added for a Property. * * This preserves existing values for the given Property. To replace them, see [[setUrl]]. * * The original `thing` is not modified; this function returns a cloned Thing with updated values. * * @param thing Thing to add a URL value to. * @param property Property for which to add the given URL value. * @param url URL to add to `thing` for the given `property`. * @returns A new Thing equal to the input Thing with the given value added for the given Property. */ export const addUrl: AddOfType = ( thing, property, url, ) => { internal_throwIfNotThing(thing); if (!internal_isValidUrl(property)) { throw new ValidPropertyUrlExpectedError(property); } if (!isThing(url) && !internal_isValidUrl(url)) { throw new ValidValueUrlExpectedError(url); } const predicateIri = internal_toIriString(property); const existingPredicate = thing.predicates[predicateIri] ?? {}; const existingNamedNodes = existingPredicate.namedNodes ?? []; let iriToAdd: IriString; if (isNamedNode(url)) { iriToAdd = url.value; } else if (typeof url === "string") { iriToAdd = url; } else if (isThingLocal(url)) { iriToAdd = url.url; } else { iriToAdd = asIri(url); } const updatedNamedNodes = freeze( existingNamedNodes.concat(internal_toIriString(iriToAdd)), ); const updatedPredicate = freeze({ ...existingPredicate, namedNodes: updatedNamedNodes, }); const updatedPredicates = freeze({ ...thing.predicates, [predicateIri]: updatedPredicate, }); const updatedThing = freeze({ ...thing, predicates: updatedPredicates, }); return updatedThing; }; /** @hidden Alias for [[addUrl]] for those who prefer IRI terminology. */ export const addIri = addUrl; /** * Create a new Thing with a boolean added for a Property. * * This preserves existing values for the given Property. To replace them, see [[setBoolean]]. * * The original `thing` is not modified; this function returns a cloned Thing with updated values. * * @param thing Thing to add a boolean value to. * @param property Property for which to add the given boolean value. * @param value Boolean to add to `thing` for the given `property`. * @returns A new Thing equal to the input Thing with the given value added for the given Property. */ export const addBoolean: AddOfType = (thing, property, value) => { internal_throwIfNotThing(thing); return addLiteralOfType( thing, property, serializeBoolean(value), xmlSchemaTypes.boolean, ); }; /** * Create a new Thing with a datetime added for a Property. * * This preserves existing values for the given Property. To replace them, see [[setDatetime]]. * * The original `thing` is not modified; this function returns a cloned Thing with updated values. * * @param thing Thing to add a datetime value to. * @param property Property for which to add the given datetime value. * @param value Datetime to add to `thing` for the given `property`. * @returns A new Thing equal to the input Thing with the given value added for the given Property. */ export const addDatetime: AddOfType = (thing, property, value) => { internal_throwIfNotThing(thing); return addLiteralOfType( thing, property, serializeDatetime(value), xmlSchemaTypes.dateTime, ); }; /** * Create a new Thing with a date added for a Property. * * This preserves existing values for the given Property. To replace them, see [[setDate]]. * * The original `thing` is not modified; this function returns a cloned Thing with updated values. * * @param thing Thing to add a date value to. * @param property Property for which to add the given date value. * @param value Date to add to `thing` for the given `property`. * @returns A new Thing equal to the input Thing with the given value added for the given Property. * @since 1.10.0 */ export const addDate: AddOfType = (thing, property, value) => { internal_throwIfNotThing(thing); return addLiteralOfType( thing, property, serializeDate(value), xmlSchemaTypes.date, ); }; /** * Create a new Thing with a time added for a Property. * * This preserves existing values for the given Property. To replace them, see [[setDatetime]]. * * The original `thing` is not modified; this function returns a cloned Thing with updated values. * * @param thing Thing to add a datetime value to. * @param property Property for which to add the given datetime value. * @param value time to add to `thing` for the given `property`. * @returns A new Thing equal to the input Thing with the given value added for the given Property. * @since 1.10.0 */ export const addTime: AddOfType