// 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 } from "@rdfjs/types"; import type { Url, UrlString, Thing, ThingPersisted } from "../interfaces"; import type { XmlSchemaTypeIri, Time } from "../datatypes"; import { normalizeLocale, xmlSchemaTypes, deserializeBoolean, deserializeDatetime, deserializeDecimal, deserializeInteger, internal_isValidUrl, deserializeDate, deserializeTime, } from "../datatypes"; import { internal_throwIfNotThing } from "./thing.internal"; import { isThing, ValidPropertyUrlExpectedError, ValidValueUrlExpectedError, asIri, } from "./thing"; import { internal_toIriString } from "../interfaces.internal"; import { freeze } from "../rdf.internal"; /** * Create a new Thing with all values removed for the given Property. * * The original `thing` is not modified; this function returns a cloned Thing with updated values. * * @param thing [[Thing]] to remove values from. * @param property Property for which to remove all values from the Thing. * @returns A new Thing equal to the input Thing with all values removed for the given Property. */ export function removeAll( thing: T, property: Url | UrlString, ): T; export function removeAll(thing: Thing, property: Url | UrlString): Thing { internal_throwIfNotThing(thing); if (!internal_isValidUrl(property)) { throw new ValidPropertyUrlExpectedError(property); } const predicateIri = internal_toIriString(property); const newPredicates = { ...thing.predicates }; delete newPredicates[predicateIri]; return freeze({ ...thing, predicates: freeze(newPredicates), }); } /** * Create a new Thing with the given URL removed for the given Property. * * The original `thing` is not modified; this function returns a cloned Thing with updated values. * * @param thing Thing to remove a URL value from. * @param property Property for which to remove the given URL value. * @param value URL to remove from `thing` for the given `Property`. * @returns A new Thing equal to the input Thing with the given value removed for the given Property. */ export const removeUrl: RemoveOfType = ( thing, property, value, ) => { internal_throwIfNotThing(thing); if (!internal_isValidUrl(property)) { throw new ValidPropertyUrlExpectedError(property); } const predicateIri = internal_toIriString(property); if (!isThing(value) && !internal_isValidUrl(value)) { throw new ValidValueUrlExpectedError(value); } const iriToRemove = isThing(value) ? asIri(value) : internal_toIriString(value); const updatedNamedNodes = freeze( thing.predicates[predicateIri]?.namedNodes?.filter( (namedNode) => namedNode.toLowerCase() !== iriToRemove.toLowerCase(), ) ?? [], ); const updatedPredicate = freeze({ ...thing.predicates[predicateIri], namedNodes: updatedNamedNodes, }); const updatedPredicates = freeze({ ...thing.predicates, [predicateIri]: updatedPredicate, }); return freeze({ ...thing, predicates: updatedPredicates, }); }; /** @hidden Alias of [[removeUrl]] for those who prefer IRI terminology. */ export const removeIri = removeUrl; /** * Create a new Thing with the given boolean removed for the given Property. * * The original `thing` is not modified; this function returns a cloned Thing with updated values. * * @param thing Thing to remove a boolean value from. * @param property Property for which to remove the given boolean value. * @param value Boolean to remove from `thing` for the given `property`. * @returns A new Thing equal to the input Thing with the given value removed for the given Property. */ export const removeBoolean: RemoveOfType = ( thing, property, value, ) => { internal_throwIfNotThing(thing); return removeLiteralMatching( thing, property, xmlSchemaTypes.boolean, (foundBoolean) => deserializeBoolean(foundBoolean) === value, ); }; /** * Create a new Thing with the given datetime removed for the given Property. * * The original `thing` is not modified; this function returns a cloned Thing with updated values. * * @param thing Thing to remove a datetime value from. * @param property Property for which to remove the given datetime value. * @param value Datetime to remove from `thing` for the given `property`. * @returns A new Thing equal to the input Thing with the given value removed for the given Property. */ export const removeDatetime: RemoveOfType = (thing, property, value) => { internal_throwIfNotThing(thing); return removeLiteralMatching( thing, property, xmlSchemaTypes.dateTime, (foundDatetime) => deserializeDatetime(foundDatetime)?.getTime() === value.getTime(), ); }; /** * Create a new Thing with the given date removed for the given Property. * * The original `thing` is not modified; this function returns a cloned Thing with updated values. * * @param thing Thing to remove a date value from. * @param property Property for which to remove the given date value. * @param value Date to remove from `thing` for the given `property`. * @returns A new Thing equal to the input Thing with the given value removed for the given Property. * @since 1.10.0 */ export const removeDate: RemoveOfType = (thing, property, value) => { internal_throwIfNotThing(thing); return removeLiteralMatching( thing, property, xmlSchemaTypes.date, function (foundDate) { const deserializedDate = deserializeDate(foundDate); if (deserializedDate) { return ( deserializedDate.getFullYear() === value.getFullYear() && deserializedDate.getMonth() === value.getMonth() && deserializedDate.getUTCDate() === value.getUTCDate() ); } return false; }, ); }; /** * Create a new Thing with the given datetime removed for the given Property. * * The original `thing` is not modified; this function returns a cloned Thing with updated values. * * @param thing Thing to remove a datetime value from. * @param property Property for which to remove the given datetime value. * @param value Time to remove from `thing` for the given `property`. * @returns A new Thing equal to the input Thing with the given value removed for the given Property. * @since 1.10.0 */ export const removeTime: RemoveOfType