jsonld
Version:
A JSON-LD Processor and API implementation in JavaScript.
179 lines (159 loc) • 872 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["jsonld"] = factory();
else
root["jsonld"] = factory();
})(window, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ({
/***/ "./lib/ContextResolver.js":
/*!********************************!*\
!*** ./lib/ContextResolver.js ***!
\********************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("/*\n * Copyright (c) 2019 Digital Bazaar, Inc. All rights reserved.\n */\n\n\n__webpack_require__(/*! core-js/modules/es.array.iterator.js */ \"./node_modules/core-js/modules/es.array.iterator.js\");\n__webpack_require__(/*! core-js/modules/es.json.stringify.js */ \"./node_modules/core-js/modules/es.json.stringify.js\");\n__webpack_require__(/*! core-js/modules/es.promise.js */ \"./node_modules/core-js/modules/es.promise.js\");\n__webpack_require__(/*! core-js/modules/web.dom-collections.iterator.js */ \"./node_modules/core-js/modules/web.dom-collections.iterator.js\");\nconst {\n isArray: _isArray,\n isObject: _isObject,\n isString: _isString\n} = __webpack_require__(/*! ./types */ \"./lib/types.js\");\nconst {\n asArray: _asArray\n} = __webpack_require__(/*! ./util */ \"./lib/util.js\");\nconst {\n prependBase\n} = __webpack_require__(/*! ./url */ \"./lib/url.js\");\nconst JsonLdError = __webpack_require__(/*! ./JsonLdError */ \"./lib/JsonLdError.js\");\nconst ResolvedContext = __webpack_require__(/*! ./ResolvedContext */ \"./lib/ResolvedContext.js\");\nconst MAX_CONTEXT_URLS = 10;\nmodule.exports = class ContextResolver {\n /**\n * Creates a ContextResolver.\n *\n * @param sharedCache a shared LRU cache with `get` and `set` APIs.\n */\n constructor({\n sharedCache\n }) {\n this.perOpCache = new Map();\n this.sharedCache = sharedCache;\n }\n async resolve({\n activeCtx,\n context,\n documentLoader,\n base,\n cycles = new Set()\n }) {\n // process `@context`\n if (context && _isObject(context) && context['@context']) {\n context = context['@context'];\n }\n\n // context is one or more contexts\n context = _asArray(context);\n\n // resolve each context in the array\n const allResolved = [];\n for (const ctx of context) {\n if (_isString(ctx)) {\n // see if `ctx` has been resolved before...\n let _resolved = this._get(ctx);\n if (!_resolved) {\n // not resolved yet, resolve\n _resolved = await this._resolveRemoteContext({\n activeCtx,\n url: ctx,\n documentLoader,\n base,\n cycles\n });\n }\n\n // add to output and continue\n if (_isArray(_resolved)) {\n allResolved.push(..._resolved);\n } else {\n allResolved.push(_resolved);\n }\n continue;\n }\n if (ctx === null) {\n // handle `null` context, nothing to cache\n allResolved.push(new ResolvedContext({\n document: null\n }));\n continue;\n }\n if (!_isObject(ctx)) {\n _throwInvalidLocalContext(context);\n }\n // context is an object, get/create `ResolvedContext` for it\n const key = JSON.stringify(ctx);\n let resolved = this._get(key);\n if (!resolved) {\n // create a new static `ResolvedContext` and cache it\n resolved = new ResolvedContext({\n document: ctx\n });\n this._cacheResolvedContext({\n key,\n resolved,\n tag: 'static'\n });\n }\n allResolved.push(resolved);\n }\n return allResolved;\n }\n _get(key) {\n // get key from per operation cache; no `tag` is used with this cache so\n // any retrieved context will always be the same during a single operation\n let resolved = this.perOpCache.get(key);\n if (!resolved) {\n // see if the shared cache has a `static` entry for this URL\n const tagMap = this.sharedCache.get(key);\n if (tagMap) {\n resolved = tagMap.get('static');\n if (resolved) {\n this.perOpCache.set(key, resolved);\n }\n }\n }\n return resolved;\n }\n _cacheResolvedContext({\n key,\n resolved,\n tag\n }) {\n this.perOpCache.set(key, resolved);\n if (tag !== undefined) {\n let tagMap = this.sharedCache.get(key);\n if (!tagMap) {\n tagMap = new Map();\n this.sharedCache.set(key, tagMap);\n }\n tagMap.set(tag, resolved);\n }\n return resolved;\n }\n async _resolveRemoteContext({\n activeCtx,\n url,\n documentLoader,\n base,\n cycles\n }) {\n // resolve relative URL and fetch context\n url = prependBase(base, url);\n const {\n context,\n remoteDoc\n } = await this._fetchContext({\n activeCtx,\n url,\n documentLoader,\n cycles\n });\n\n // update base according to remote document and resolve any relative URLs\n base = remoteDoc.documentUrl || url;\n _resolveContextUrls({\n context,\n base\n });\n\n // resolve, cache, and return context\n const resolved = await this.resolve({\n activeCtx,\n context,\n documentLoader,\n base,\n cycles\n });\n this._cacheResolvedContext({\n key: url,\n resolved,\n tag: remoteDoc.tag\n });\n return resolved;\n }\n async _fetchContext({\n activeCtx,\n url,\n documentLoader,\n cycles\n }) {\n // check for max context URLs fetched during a resolve operation\n if (cycles.size > MAX_CONTEXT_URLS) {\n throw new JsonLdError('Maximum number of @context URLs exceeded.', 'jsonld.ContextUrlError', {\n code: activeCtx.processingMode === 'json-ld-1.0' ? 'loading remote context failed' : 'context overflow',\n max: MAX_CONTEXT_URLS\n });\n }\n\n // check for context URL cycle\n // shortcut to avoid extra work that would eventually hit the max above\n if (cycles.has(url)) {\n throw new JsonLdError('Cyclical @context URLs detected.', 'jsonld.ContextUrlError', {\n code: activeCtx.processingMode === 'json-ld-1.0' ? 'recursive context inclusion' : 'context overflow',\n url\n });\n }\n\n // track cycles\n cycles.add(url);\n let context;\n let remoteDoc;\n try {\n remoteDoc = await documentLoader(url);\n context = remoteDoc.document || null;\n // parse string context as JSON\n if (_isString(context)) {\n context = JSON.parse(context);\n }\n } catch (e) {\n throw new JsonLdError('Dereferencing a URL did not result in a valid JSON-LD object. ' + 'Possible causes are an inaccessible URL perhaps due to ' + 'a same-origin policy (ensure the server uses CORS if you are ' + 'using client-side JavaScript), too many redirects, a ' + 'non-JSON response, or more than one HTTP Link Header was ' + 'provided for a remote context. ' + `URL: \"${url}\".`, 'jsonld.InvalidUrl', {\n code: 'loading remote context failed',\n url,\n cause: e\n });\n }\n\n // ensure ctx is an object\n if (!_isObject(context)) {\n throw new JsonLdError('Dereferencing a URL did not result in a JSON object. The ' + 'response was valid JSON, but it was not a JSON object. ' + `URL: \"${url}\".`, 'jsonld.InvalidUrl', {\n code: 'invalid remote context',\n url\n });\n }\n\n // use empty context if no @context key is present\n if (!('@context' in context)) {\n context = {\n '@context': {}\n };\n } else {\n context = {\n '@context': context['@context']\n };\n }\n\n // append @context URL to context if given\n if (remoteDoc.contextUrl) {\n if (!_isArray(context['@context'])) {\n context['@context'] = [context['@context']];\n }\n context['@context'].push(remoteDoc.contextUrl);\n }\n return {\n context,\n remoteDoc\n };\n }\n};\nfunction _throwInvalidLocalContext(ctx) {\n throw new JsonLdError('Invalid JSON-LD syntax; @context must be an object.', 'jsonld.SyntaxError', {\n code: 'invalid local context',\n context: ctx\n });\n}\n\n/**\n * Resolve all relative `@context` URLs in the given context by inline\n * replacing them with absolute URLs.\n *\n * @param context the context.\n * @param base the base IRI to use to resolve relative IRIs.\n */\nfunction _resolveContextUrls({\n context,\n base\n}) {\n if (!context) {\n return;\n }\n const ctx = context['@context'];\n if (_isString(ctx)) {\n context['@context'] = prependBase(base, ctx);\n return;\n }\n if (_isArray(ctx)) {\n for (let i = 0; i < ctx.length; ++i) {\n const element = ctx[i];\n if (_isString(element)) {\n ctx[i] = prependBase(base, element);\n continue;\n }\n if (_isObject(element)) {\n _resolveContextUrls({\n context: {\n '@context': element\n },\n base\n });\n }\n }\n return;\n }\n if (!_isObject(ctx)) {\n // no @context URLs can be found in non-object\n return;\n }\n\n // ctx is an object, resolve any context URLs in terms\n for (const term in ctx) {\n _resolveContextUrls({\n context: ctx[term],\n base\n });\n }\n}\n\n//# sourceURL=webpack://%5Bname%5D/./lib/ContextResolver.js?");
/***/ }),
/***/ "./lib/JsonLdError.js":
/*!****************************!*\
!*** ./lib/JsonLdError.js ***!
\****************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("/*\n * Copyright (c) 2017 Digital Bazaar, Inc. All rights reserved.\n */\n\n\nmodule.exports = class JsonLdError extends Error {\n /**\n * Creates a JSON-LD Error.\n *\n * @param msg the error message.\n * @param type the error type.\n * @param details the error details.\n */\n constructor(message = 'An unspecified JSON-LD error occurred.', name = 'jsonld.Error', details = {}) {\n super(message);\n this.name = name;\n this.message = message;\n this.details = details;\n }\n};\n\n//# sourceURL=webpack://%5Bname%5D/./lib/JsonLdError.js?");
/***/ }),
/***/ "./lib/JsonLdProcessor.js":
/*!********************************!*\
!*** ./lib/JsonLdProcessor.js ***!
\********************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("/*\n * Copyright (c) 2017 Digital Bazaar, Inc. All rights reserved.\n */\n\n\n__webpack_require__(/*! core-js/modules/es.promise.js */ \"./node_modules/core-js/modules/es.promise.js\");\nmodule.exports = jsonld => {\n class JsonLdProcessor {\n toString() {\n return '[object JsonLdProcessor]';\n }\n }\n Object.defineProperty(JsonLdProcessor, 'prototype', {\n writable: false,\n enumerable: false\n });\n Object.defineProperty(JsonLdProcessor.prototype, 'constructor', {\n writable: true,\n enumerable: false,\n configurable: true,\n value: JsonLdProcessor\n });\n\n // The Web IDL test harness will check the number of parameters defined in\n // the functions below. The number of parameters must exactly match the\n // required (non-optional) parameters of the JsonLdProcessor interface as\n // defined here:\n // https://www.w3.org/TR/json-ld-api/#the-jsonldprocessor-interface\n\n JsonLdProcessor.compact = function (input, ctx) {\n if (arguments.length < 2) {\n return Promise.reject(new TypeError('Could not compact, too few arguments.'));\n }\n return jsonld.compact(input, ctx);\n };\n JsonLdProcessor.expand = function (input) {\n if (arguments.length < 1) {\n return Promise.reject(new TypeError('Could not expand, too few arguments.'));\n }\n return jsonld.expand(input);\n };\n JsonLdProcessor.flatten = function (input) {\n if (arguments.length < 1) {\n return Promise.reject(new TypeError('Could not flatten, too few arguments.'));\n }\n return jsonld.flatten(input);\n };\n return JsonLdProcessor;\n};\n\n//# sourceURL=webpack://%5Bname%5D/./lib/JsonLdProcessor.js?");
/***/ }),
/***/ "./lib/NQuads.js":
/*!***********************!*\
!*** ./lib/NQuads.js ***!
\***********************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("/*\n * Copyright (c) 2017 Digital Bazaar, Inc. All rights reserved.\n */\n\n\n// TODO: move `NQuads` to its own package\nmodule.exports = __webpack_require__(/*! rdf-canonize */ \"./node_modules/rdf-canonize/index.js\").NQuads;\n\n//# sourceURL=webpack://%5Bname%5D/./lib/NQuads.js?");
/***/ }),
/***/ "./lib/RequestQueue.js":
/*!*****************************!*\
!*** ./lib/RequestQueue.js ***!
\*****************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("/*\n * Copyright (c) 2017-2019 Digital Bazaar, Inc. All rights reserved.\n */\n\n\n__webpack_require__(/*! core-js/modules/es.promise.js */ \"./node_modules/core-js/modules/es.promise.js\");\nmodule.exports = class RequestQueue {\n /**\n * Creates a simple queue for requesting documents.\n */\n constructor() {\n this._requests = {};\n }\n wrapLoader(loader) {\n const self = this;\n self._loader = loader;\n return function /* url */\n () {\n return self.add.apply(self, arguments);\n };\n }\n async add(url) {\n let promise = this._requests[url];\n if (promise) {\n // URL already queued, wait for it to load\n return Promise.resolve(promise);\n }\n\n // queue URL and load it\n promise = this._requests[url] = this._loader(url);\n try {\n return await promise;\n } finally {\n delete this._requests[url];\n }\n }\n};\n\n//# sourceURL=webpack://%5Bname%5D/./lib/RequestQueue.js?");
/***/ }),
/***/ "./lib/ResolvedContext.js":
/*!********************************!*\
!*** ./lib/ResolvedContext.js ***!
\********************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("/*\n * Copyright (c) 2019 Digital Bazaar, Inc. All rights reserved.\n */\n\n\nconst LRU = __webpack_require__(/*! lru-cache */ \"./node_modules/lru-cache/index.js\");\nconst MAX_ACTIVE_CONTEXTS = 10;\nmodule.exports = class ResolvedContext {\n /**\n * Creates a ResolvedContext.\n *\n * @param document the context document.\n */\n constructor({\n document\n }) {\n this.document = document;\n // TODO: enable customization of processed context cache\n // TODO: limit based on size of processed contexts vs. number of them\n this.cache = new LRU({\n max: MAX_ACTIVE_CONTEXTS\n });\n }\n getProcessed(activeCtx) {\n return this.cache.get(activeCtx);\n }\n setProcessed(activeCtx, processedCtx) {\n this.cache.set(activeCtx, processedCtx);\n }\n};\n\n//# sourceURL=webpack://%5Bname%5D/./lib/ResolvedContext.js?");
/***/ }),
/***/ "./lib/compact.js":
/*!************************!*\
!*** ./lib/compact.js ***!
\************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("/*\n * Copyright (c) 2017 Digital Bazaar, Inc. All rights reserved.\n */\n\n\n__webpack_require__(/*! core-js/modules/es.array.includes.js */ \"./node_modules/core-js/modules/es.array.includes.js\");\n__webpack_require__(/*! core-js/modules/es.array.iterator.js */ \"./node_modules/core-js/modules/es.array.iterator.js\");\n__webpack_require__(/*! core-js/modules/es.array.reverse.js */ \"./node_modules/core-js/modules/es.array.reverse.js\");\n__webpack_require__(/*! core-js/modules/es.array.sort.js */ \"./node_modules/core-js/modules/es.array.sort.js\");\n__webpack_require__(/*! core-js/modules/es.promise.js */ \"./node_modules/core-js/modules/es.promise.js\");\n__webpack_require__(/*! core-js/modules/es.regexp.exec.js */ \"./node_modules/core-js/modules/es.regexp.exec.js\");\n__webpack_require__(/*! core-js/modules/es.regexp.test.js */ \"./node_modules/core-js/modules/es.regexp.test.js\");\n__webpack_require__(/*! core-js/modules/es.string.includes.js */ \"./node_modules/core-js/modules/es.string.includes.js\");\n__webpack_require__(/*! core-js/modules/es.string.replace.js */ \"./node_modules/core-js/modules/es.string.replace.js\");\n__webpack_require__(/*! core-js/modules/es.string.starts-with.js */ \"./node_modules/core-js/modules/es.string.starts-with.js\");\n__webpack_require__(/*! core-js/modules/esnext.iterator.map.js */ \"./node_modules/core-js/modules/esnext.iterator.map.js\");\n__webpack_require__(/*! core-js/modules/web.dom-collections.iterator.js */ \"./node_modules/core-js/modules/web.dom-collections.iterator.js\");\nconst JsonLdError = __webpack_require__(/*! ./JsonLdError */ \"./lib/JsonLdError.js\");\nconst {\n isArray: _isArray,\n isObject: _isObject,\n isString: _isString,\n isUndefined: _isUndefined\n} = __webpack_require__(/*! ./types */ \"./lib/types.js\");\nconst {\n isList: _isList,\n isValue: _isValue,\n isGraph: _isGraph,\n isSimpleGraph: _isSimpleGraph,\n isSubjectReference: _isSubjectReference\n} = __webpack_require__(/*! ./graphTypes */ \"./lib/graphTypes.js\");\nconst {\n expandIri: _expandIri,\n getContextValue: _getContextValue,\n isKeyword: _isKeyword,\n process: _processContext,\n processingMode: _processingMode\n} = __webpack_require__(/*! ./context */ \"./lib/context.js\");\nconst {\n removeBase: _removeBase,\n prependBase: _prependBase\n} = __webpack_require__(/*! ./url */ \"./lib/url.js\");\nconst {\n REGEX_KEYWORD,\n addValue: _addValue,\n asArray: _asArray,\n compareShortestLeast: _compareShortestLeast\n} = __webpack_require__(/*! ./util */ \"./lib/util.js\");\nconst api = {};\nmodule.exports = api;\n\n/**\n * Recursively compacts an element using the given active context. All values\n * must be in expanded form before this method is called.\n *\n * @param activeCtx the active context to use.\n * @param activeProperty the compacted property associated with the element\n * to compact, null for none.\n * @param element the element to compact.\n * @param options the compaction options.\n *\n * @return a promise that resolves to the compacted value.\n */\napi.compact = async ({\n activeCtx,\n activeProperty: _activeProperty = null,\n element,\n options: _options = {}\n}) => {\n // recursively compact array\n if (_isArray(element)) {\n let rval = [];\n for (let i = 0; i < element.length; ++i) {\n const compacted = await api.compact({\n activeCtx,\n activeProperty: _activeProperty,\n element: element[i],\n options: _options\n });\n if (compacted === null) {\n // FIXME: need event?\n continue;\n }\n rval.push(compacted);\n }\n if (_options.compactArrays && rval.length === 1) {\n // use single element if no container is specified\n const container = _getContextValue(activeCtx, _activeProperty, '@container') || [];\n if (container.length === 0) {\n rval = rval[0];\n }\n }\n return rval;\n }\n\n // use any scoped context on activeProperty\n const ctx = _getContextValue(activeCtx, _activeProperty, '@context');\n if (!_isUndefined(ctx)) {\n activeCtx = await _processContext({\n activeCtx,\n localCtx: ctx,\n propagate: true,\n overrideProtected: true,\n options: _options\n });\n }\n\n // recursively compact object\n if (_isObject(element)) {\n if (_options.link && '@id' in element && _options.link.hasOwnProperty(element['@id'])) {\n // check for a linked element to reuse\n const linked = _options.link[element['@id']];\n for (let i = 0; i < linked.length; ++i) {\n if (linked[i].expanded === element) {\n return linked[i].compacted;\n }\n }\n }\n\n // do value compaction on @values and subject references\n if (_isValue(element) || _isSubjectReference(element)) {\n const _rval = api.compactValue({\n activeCtx,\n activeProperty: _activeProperty,\n value: element,\n options: _options\n });\n if (_options.link && _isSubjectReference(element)) {\n // store linked element\n if (!_options.link.hasOwnProperty(element['@id'])) {\n _options.link[element['@id']] = [];\n }\n _options.link[element['@id']].push({\n expanded: element,\n compacted: _rval\n });\n }\n return _rval;\n }\n\n // if expanded property is @list and we're contained within a list\n // container, recursively compact this item to an array\n if (_isList(element)) {\n const container = _getContextValue(activeCtx, _activeProperty, '@container') || [];\n if (container.includes('@list')) {\n return api.compact({\n activeCtx,\n activeProperty: _activeProperty,\n element: element['@list'],\n options: _options\n });\n }\n }\n\n // FIXME: avoid misuse of active property as an expanded property?\n const insideReverse = _activeProperty === '@reverse';\n const rval = {};\n\n // original context before applying property-scoped and local contexts\n const inputCtx = activeCtx;\n\n // revert to previous context, if there is one,\n // and element is not a value object or a node reference\n if (!_isValue(element) && !_isSubjectReference(element)) {\n activeCtx = activeCtx.revertToPreviousContext();\n }\n\n // apply property-scoped context after reverting term-scoped context\n const propertyScopedCtx = _getContextValue(inputCtx, _activeProperty, '@context');\n if (!_isUndefined(propertyScopedCtx)) {\n activeCtx = await _processContext({\n activeCtx,\n localCtx: propertyScopedCtx,\n propagate: true,\n overrideProtected: true,\n options: _options\n });\n }\n if (_options.link && '@id' in element) {\n // store linked element\n if (!_options.link.hasOwnProperty(element['@id'])) {\n _options.link[element['@id']] = [];\n }\n _options.link[element['@id']].push({\n expanded: element,\n compacted: rval\n });\n }\n\n // apply any context defined on an alias of @type\n // if key is @type and any compacted value is a term having a local\n // context, overlay that context\n let types = element['@type'] || [];\n if (types.length > 1) {\n types = Array.from(types).sort();\n }\n // find all type-scoped contexts based on current context, prior to\n // updating it\n const typeContext = activeCtx;\n for (const type of types) {\n const compactedType = api.compactIri({\n activeCtx: typeContext,\n iri: type,\n relativeTo: {\n vocab: true\n }\n });\n\n // Use any type-scoped context defined on this value\n const _ctx = _getContextValue(inputCtx, compactedType, '@context');\n if (!_isUndefined(_ctx)) {\n activeCtx = await _processContext({\n activeCtx,\n localCtx: _ctx,\n options: _options,\n propagate: false\n });\n }\n }\n\n // process element keys in order\n const keys = Object.keys(element).sort();\n for (const expandedProperty of keys) {\n const expandedValue = element[expandedProperty];\n\n // compact @id\n if (expandedProperty === '@id') {\n let compactedValue = _asArray(expandedValue).map(expandedIri => api.compactIri({\n activeCtx,\n iri: expandedIri,\n relativeTo: {\n vocab: false\n },\n base: _options.base\n }));\n if (compactedValue.length === 1) {\n compactedValue = compactedValue[0];\n }\n\n // use keyword alias and add value\n const alias = api.compactIri({\n activeCtx,\n iri: '@id',\n relativeTo: {\n vocab: true\n }\n });\n rval[alias] = compactedValue;\n continue;\n }\n\n // compact @type(s)\n if (expandedProperty === '@type') {\n // resolve type values against previous context\n let compactedValue = _asArray(expandedValue).map(expandedIri => api.compactIri({\n activeCtx: inputCtx,\n iri: expandedIri,\n relativeTo: {\n vocab: true\n }\n }));\n if (compactedValue.length === 1) {\n compactedValue = compactedValue[0];\n }\n\n // use keyword alias and add value\n const alias = api.compactIri({\n activeCtx,\n iri: '@type',\n relativeTo: {\n vocab: true\n }\n });\n const container = _getContextValue(activeCtx, alias, '@container') || [];\n\n // treat as array for @type if @container includes @set\n const typeAsSet = container.includes('@set') && _processingMode(activeCtx, 1.1);\n const isArray = typeAsSet || _isArray(compactedValue) && expandedValue.length === 0;\n _addValue(rval, alias, compactedValue, {\n propertyIsArray: isArray\n });\n continue;\n }\n\n // handle @reverse\n if (expandedProperty === '@reverse') {\n // recursively compact expanded value\n const compactedValue = await api.compact({\n activeCtx,\n activeProperty: '@reverse',\n element: expandedValue,\n options: _options\n });\n\n // handle double-reversed properties\n for (const compactedProperty in compactedValue) {\n if (activeCtx.mappings.has(compactedProperty) && activeCtx.mappings.get(compactedProperty).reverse) {\n const value = compactedValue[compactedProperty];\n const container = _getContextValue(activeCtx, compactedProperty, '@container') || [];\n const useArray = container.includes('@set') || !_options.compactArrays;\n _addValue(rval, compactedProperty, value, {\n propertyIsArray: useArray\n });\n delete compactedValue[compactedProperty];\n }\n }\n if (Object.keys(compactedValue).length > 0) {\n // use keyword alias and add value\n const alias = api.compactIri({\n activeCtx,\n iri: expandedProperty,\n relativeTo: {\n vocab: true\n }\n });\n _addValue(rval, alias, compactedValue);\n }\n continue;\n }\n if (expandedProperty === '@preserve') {\n // compact using activeProperty\n const compactedValue = await api.compact({\n activeCtx,\n activeProperty: _activeProperty,\n element: expandedValue,\n options: _options\n });\n if (!(_isArray(compactedValue) && compactedValue.length === 0)) {\n _addValue(rval, expandedProperty, compactedValue);\n }\n continue;\n }\n\n // handle @index property\n if (expandedProperty === '@index') {\n // drop @index if inside an @index container\n const container = _getContextValue(activeCtx, _activeProperty, '@container') || [];\n if (container.includes('@index')) {\n continue;\n }\n\n // use keyword alias and add value\n const alias = api.compactIri({\n activeCtx,\n iri: expandedProperty,\n relativeTo: {\n vocab: true\n }\n });\n _addValue(rval, alias, expandedValue);\n continue;\n }\n\n // skip array processing for keywords that aren't\n // @graph, @list, or @included\n if (expandedProperty !== '@graph' && expandedProperty !== '@list' && expandedProperty !== '@included' && _isKeyword(expandedProperty)) {\n // use keyword alias and add value as is\n const alias = api.compactIri({\n activeCtx,\n iri: expandedProperty,\n relativeTo: {\n vocab: true\n }\n });\n _addValue(rval, alias, expandedValue);\n continue;\n }\n\n // Note: expanded value must be an array due to expansion algorithm.\n if (!_isArray(expandedValue)) {\n throw new JsonLdError('JSON-LD expansion error; expanded value must be an array.', 'jsonld.SyntaxError');\n }\n\n // preserve empty arrays\n if (expandedValue.length === 0) {\n const itemActiveProperty = api.compactIri({\n activeCtx,\n iri: expandedProperty,\n value: expandedValue,\n relativeTo: {\n vocab: true\n },\n reverse: insideReverse\n });\n const nestProperty = activeCtx.mappings.has(itemActiveProperty) ? activeCtx.mappings.get(itemActiveProperty)['@nest'] : null;\n let nestResult = rval;\n if (nestProperty) {\n _checkNestProperty(activeCtx, nestProperty, _options);\n if (!_isObject(rval[nestProperty])) {\n rval[nestProperty] = {};\n }\n nestResult = rval[nestProperty];\n }\n _addValue(nestResult, itemActiveProperty, expandedValue, {\n propertyIsArray: true\n });\n }\n\n // recusively process array values\n for (const expandedItem of expandedValue) {\n // compact property and get container type\n const itemActiveProperty = api.compactIri({\n activeCtx,\n iri: expandedProperty,\n value: expandedItem,\n relativeTo: {\n vocab: true\n },\n reverse: insideReverse\n });\n\n // if itemActiveProperty is a @nest property, add values to nestResult,\n // otherwise rval\n const nestProperty = activeCtx.mappings.has(itemActiveProperty) ? activeCtx.mappings.get(itemActiveProperty)['@nest'] : null;\n let nestResult = rval;\n if (nestProperty) {\n _checkNestProperty(activeCtx, nestProperty, _options);\n if (!_isObject(rval[nestProperty])) {\n rval[nestProperty] = {};\n }\n nestResult = rval[nestProperty];\n }\n const container = _getContextValue(activeCtx, itemActiveProperty, '@container') || [];\n\n // get simple @graph or @list value if appropriate\n const isGraph = _isGraph(expandedItem);\n const isList = _isList(expandedItem);\n let inner;\n if (isList) {\n inner = expandedItem['@list'];\n } else if (isGraph) {\n inner = expandedItem['@graph'];\n }\n\n // recursively compact expanded item\n let compactedItem = await api.compact({\n activeCtx,\n activeProperty: itemActiveProperty,\n element: isList || isGraph ? inner : expandedItem,\n options: _options\n });\n\n // handle @list\n if (isList) {\n // ensure @list value is an array\n if (!_isArray(compactedItem)) {\n compactedItem = [compactedItem];\n }\n if (!container.includes('@list')) {\n // wrap using @list alias\n compactedItem = {\n [api.compactIri({\n activeCtx,\n iri: '@list',\n relativeTo: {\n vocab: true\n }\n })]: compactedItem\n };\n\n // include @index from expanded @list, if any\n if ('@index' in expandedItem) {\n compactedItem[api.compactIri({\n activeCtx,\n iri: '@index',\n relativeTo: {\n vocab: true\n }\n })] = expandedItem['@index'];\n }\n } else {\n _addValue(nestResult, itemActiveProperty, compactedItem, {\n valueIsArray: true,\n allowDuplicate: true\n });\n continue;\n }\n }\n\n // Graph object compaction cases\n if (isGraph) {\n if (container.includes('@graph') && (container.includes('@id') || container.includes('@index') && _isSimpleGraph(expandedItem))) {\n // get or create the map object\n let mapObject;\n if (nestResult.hasOwnProperty(itemActiveProperty)) {\n mapObject = nestResult[itemActiveProperty];\n } else {\n nestResult[itemActiveProperty] = mapObject = {};\n }\n\n // index on @id or @index or alias of @none\n const key = (container.includes('@id') ? expandedItem['@id'] : expandedItem['@index']) || api.compactIri({\n activeCtx,\n iri: '@none',\n relativeTo: {\n vocab: true\n }\n });\n // add compactedItem to map, using value of `@id` or a new blank\n // node identifier\n\n _addValue(mapObject, key, compactedItem, {\n propertyIsArray: !_options.compactArrays || container.includes('@set')\n });\n } else if (container.includes('@graph') && _isSimpleGraph(expandedItem)) {\n // container includes @graph but not @id or @index and value is a\n // simple graph object add compact value\n // if compactedItem contains multiple values, it is wrapped in\n // `@included`\n if (_isArray(compactedItem) && compactedItem.length > 1) {\n compactedItem = {\n '@included': compactedItem\n };\n }\n _addValue(nestResult, itemActiveProperty, compactedItem, {\n propertyIsArray: !_options.compactArrays || container.includes('@set')\n });\n } else {\n // wrap using @graph alias, remove array if only one item and\n // compactArrays not set\n if (_isArray(compactedItem) && compactedItem.length === 1 && _options.compactArrays) {\n compactedItem = compactedItem[0];\n }\n compactedItem = {\n [api.compactIri({\n activeCtx,\n iri: '@graph',\n relativeTo: {\n vocab: true\n }\n })]: compactedItem\n };\n\n // include @id from expanded graph, if any\n if ('@id' in expandedItem) {\n compactedItem[api.compactIri({\n activeCtx,\n iri: '@id',\n relativeTo: {\n vocab: true\n }\n })] = expandedItem['@id'];\n }\n\n // include @index from expanded graph, if any\n if ('@index' in expandedItem) {\n compactedItem[api.compactIri({\n activeCtx,\n iri: '@index',\n relativeTo: {\n vocab: true\n }\n })] = expandedItem['@index'];\n }\n _addValue(nestResult, itemActiveProperty, compactedItem, {\n propertyIsArray: !_options.compactArrays || container.includes('@set')\n });\n }\n } else if (container.includes('@language') || container.includes('@index') || container.includes('@id') || container.includes('@type')) {\n // handle language and index maps\n // get or create the map object\n let mapObject;\n if (nestResult.hasOwnProperty(itemActiveProperty)) {\n mapObject = nestResult[itemActiveProperty];\n } else {\n nestResult[itemActiveProperty] = mapObject = {};\n }\n let key;\n if (container.includes('@language')) {\n // if container is a language map, simplify compacted value to\n // a simple string\n if (_isValue(compactedItem)) {\n compactedItem = compactedItem['@value'];\n }\n key = expandedItem['@language'];\n } else if (container.includes('@index')) {\n const indexKey = _getContextValue(activeCtx, itemActiveProperty, '@index') || '@index';\n const containerKey = api.compactIri({\n activeCtx,\n iri: indexKey,\n relativeTo: {\n vocab: true\n }\n });\n if (indexKey === '@index') {\n key = expandedItem['@index'];\n delete compactedItem[containerKey];\n } else {\n let others;\n [key, ...others] = _asArray(compactedItem[indexKey] || []);\n if (!_isString(key)) {\n // Will use @none if it isn't a string.\n key = null;\n } else {\n switch (others.length) {\n case 0:\n delete compactedItem[indexKey];\n break;\n case 1:\n compactedItem[indexKey] = others[0];\n break;\n default:\n compactedItem[indexKey] = others;\n break;\n }\n }\n }\n } else if (container.includes('@id')) {\n const idKey = api.compactIri({\n activeCtx,\n iri: '@id',\n relativeTo: {\n vocab: true\n }\n });\n key = compactedItem[idKey];\n delete compactedItem[idKey];\n } else if (container.includes('@type')) {\n const typeKey = api.compactIri({\n activeCtx,\n iri: '@type',\n relativeTo: {\n vocab: true\n }\n });\n let _types;\n [key, ..._types] = _asArray(compactedItem[typeKey] || []);\n switch (_types.length) {\n case 0:\n delete compactedItem[typeKey];\n break;\n case 1:\n compactedItem[typeKey] = _types[0];\n break;\n default:\n compactedItem[typeKey] = _types;\n break;\n }\n\n // If compactedItem contains a single entry\n // whose key maps to @id, recompact without @type\n if (Object.keys(compactedItem).length === 1 && '@id' in expandedItem) {\n compactedItem = await api.compact({\n activeCtx,\n activeProperty: itemActiveProperty,\n element: {\n '@id': expandedItem['@id']\n },\n options: _options\n });\n }\n }\n\n // if compacting this value which has no key, index on @none\n if (!key) {\n key = api.compactIri({\n activeCtx,\n iri: '@none',\n relativeTo: {\n vocab: true\n }\n });\n }\n // add compact value to map object using key from expanded value\n // based on the container type\n _addValue(mapObject, key, compactedItem, {\n propertyIsArray: container.includes('@set')\n });\n } else {\n // use an array if: compactArrays flag is false,\n // @container is @set or @list , value is an empty\n // array, or key is @graph\n const isArray = !_options.compactArrays || container.includes('@set') || container.includes('@list') || _isArray(compactedItem) && compactedItem.length === 0 || expandedProperty === '@list' || expandedProperty === '@graph';\n\n // add compact value\n _addValue(nestResult, itemActiveProperty, compactedItem, {\n propertyIsArray: isArray\n });\n }\n }\n }\n return rval;\n }\n\n // only primitives remain which are already compact\n return element;\n};\n\n/**\n * Compacts an IRI or keyword into a term or prefix if it can be. If the\n * IRI has an associated value it may be passed.\n *\n * @param activeCtx the active context to use.\n * @param iri the IRI to compact.\n * @param value the value to check or null.\n * @param relativeTo options for how to compact IRIs:\n * vocab: true to split after @vocab, false not to.\n * @param reverse true if a reverse property is being compacted, false if not.\n * @param base the absolute URL to use for compacting document-relative IRIs.\n *\n * @return the compacted term, prefix, keyword alias, or the original IRI.\n */\napi.compactIri = ({\n activeCtx,\n iri,\n value: _value = null,\n relativeTo: _relativeTo = {\n vocab: false\n },\n reverse: _reverse = false,\n base: _base = null\n}) => {\n // can't compact null\n if (iri === null) {\n return iri;\n }\n\n // if context is from a property term scoped context composed with a\n // type-scoped context, then use the previous context instead\n if (activeCtx.isPropertyTermScoped && activeCtx.previousContext) {\n activeCtx = activeCtx.previousContext;\n }\n const inverseCtx = activeCtx.getInverse();\n\n // if term is a keyword, it may be compacted to a simple alias\n if (_isKeyword(iri) && iri in inverseCtx && '@none' in inverseCtx[iri] && '@type' in inverseCtx[iri]['@none'] && '@none' in inverseCtx[iri]['@none']['@type']) {\n return inverseCtx[iri]['@none']['@type']['@none'];\n }\n\n // use inverse context to pick a term if iri is relative to vocab\n if (_relativeTo.vocab && iri in inverseCtx) {\n const defaultLanguage = activeCtx['@language'] || '@none';\n\n // prefer @index if available in value\n const containers = [];\n if (_isObject(_value) && '@index' in _value && !('@graph' in _value)) {\n containers.push('@index', '@index@set');\n }\n\n // if value is a preserve object, use its value\n if (_isObject(_value) && '@preserve' in _value) {\n _value = _value['@preserve'][0];\n }\n\n // prefer most specific container including @graph, prefering @set\n // variations\n if (_isGraph(_value)) {\n // favor indexmap if the graph is indexed\n if ('@index' in _value) {\n containers.push('@graph@index', '@graph@index@set', '@index', '@index@set');\n }\n // favor idmap if the graph is has an @id\n if ('@id' in _value) {\n containers.push('@graph@id', '@graph@id@set');\n }\n containers.push('@graph', '@graph@set', '@set');\n // allow indexmap if the graph is not indexed\n if (!('@index' in _value)) {\n containers.push('@graph@index', '@graph@index@set', '@index', '@index@set');\n }\n // allow idmap if the graph does not have an @id\n if (!('@id' in _value)) {\n containers.push('@graph@id', '@graph@id@set');\n }\n } else if (_isObject(_value) && !_isValue(_value)) {\n containers.push('@id', '@id@set', '@type', '@set@type');\n }\n\n // defaults for term selection based on type/language\n let typeOrLanguage = '@language';\n let typeOrLanguageValue = '@null';\n if (_reverse) {\n typeOrLanguage = '@type';\n typeOrLanguageValue = '@reverse';\n containers.push('@set');\n } else if (_isList(_value)) {\n // choose the most specific term that works for all elements in @list\n // only select @list containers if @index is NOT in value\n if (!('@index' in _value)) {\n containers.push('@list');\n }\n const list = _value['@list'];\n if (list.length === 0) {\n // any empty list can be matched against any term that uses the\n // @list container regardless of @type or @language\n typeOrLanguage = '@any';\n typeOrLanguageValue = '@none';\n } else {\n let commonLanguage = list.length === 0 ? defaultLanguage : null;\n let commonType = null;\n for (let i = 0; i < list.length; ++i) {\n const item = list[i];\n let itemLanguage = '@none';\n let itemType = '@none';\n if (_isValue(item)) {\n if ('@direction' in item) {\n const lang = (item['@language'] || '').toLowerCase();\n const dir = item['@direction'];\n itemLanguage = `${lang}_${dir}`;\n } else if ('@language' in item) {\n itemLanguage = item['@language'].toLowerCase();\n } else if ('@type' in item) {\n itemType = item['@type'];\n } else {\n // plain literal\n itemLanguage = '@null';\n }\n } else {\n itemType = '@id';\n }\n if (commonLanguage === null) {\n commonLanguage = itemLanguage;\n } else if (itemLanguage !== commonLanguage && _isValue(item)) {\n commonLanguage = '@none';\n }\n if (commonType === null) {\n commonType = itemType;\n } else if (itemType !== commonType) {\n commonType = '@none';\n }\n // there are different languages and types in the list, so choose\n // the most generic term, no need to keep iterating the list\n if (commonLanguage === '@none' && commonType === '@none') {\n break;\n }\n }\n commonLanguage = commonLanguage || '@none';\n commonType = commonType || '@none';\n if (commonType !== '@none') {\n typeOrLanguage = '@type';\n typeOrLanguageValue = commonType;\n } else {\n typeOrLanguageValue = commonLanguage;\n }\n }\n } else {\n if (_isValue(_value)) {\n if ('@language' in _value && !('@index' in _value)) {\n containers.push('@language', '@language@set');\n typeOrLanguageValue = _value['@language'];\n const dir = _value['@direction'];\n if (dir) {\n typeOrLanguageValue = `${typeOrLanguageValue}_${dir}`;\n }\n } else if ('@direction' in _value && !('@index' in _value)) {\n typeOrLanguageValue = `_${_value['@direction']}`;\n } else if ('@type' in _value) {\n