From dd92d083172c704340792eb3e9d17ce59982ed29 Mon Sep 17 00:00:00 2001 From: BigBlueHat Date: Mon, 16 Mar 2026 13:48:36 -0400 Subject: [PATCH] Add very basic Playground to harden contexts. The playground is build with `petite-vue` with the parser bundled via `esbuild index.ts --format=esm --bundle --outfile=docs/bundle.js` The `docs/` folder is intended to be hosted via GitHub Pages. --- docs/app.js | 53 ++ docs/bundle.js | 1806 +++++++++++++++++++++++++++++++++++++++++++++++ docs/index.html | 46 ++ docs/out.js | 127 ++++ 4 files changed, 2032 insertions(+) create mode 100644 docs/app.js create mode 100644 docs/bundle.js create mode 100644 docs/index.html create mode 100644 docs/out.js diff --git a/docs/app.js b/docs/app.js new file mode 100644 index 0000000..3911837 --- /dev/null +++ b/docs/app.js @@ -0,0 +1,53 @@ +import {createApp} from 'https://unpkg.com/petite-vue?module'; +import {ContextParser} from './bundle.js'; + +createApp({ + // data + contextString: JSON.stringify([ + { + "@vocab": "http://vocab.org/", + "npmd": "https://linkedsoftwaredependencies.org/bundles/npm/", + "p": { "@id": "pred1", "@language": "nl" } + } + ], null, 2), + hardenedContext: "", + filename: "", + parseError: "", + + async updateHardenedContext() { + const parser = new ContextParser(); + const {contextRaw} = await parser.parse(JSON.parse(this.contextString)); + this.hardenedContext = JSON.stringify(contextRaw, null, 2); + }, + + // methods + async pickFile() { + const [fileHandle] = await window.showOpenFilePicker(); + this.filename = fileHandle.name; + const file = await fileHandle.getFile(); + const text = await file.text(); + try { + this.contextString = text; + this.setHardenedContext(JSON.parse(text)); + this.parseError = ""; + } catch(error) { + // TODO: error on selected files should be reported somewhere else + // ...and be blocking... + this.parseError = error.message; + console.error(error); + }; + }, + getContext($event) { + try { + this.setHardenedContext(JSON.parse($event.target.value)); + this.parseError = ""; + } catch(error) { + this.parseError = error.message; + console.error(error); + } + }, + setHardenedContext(context) { + console.log('Setting hardened context', context); + this.hardenedContext = JSON.stringify(context, null, 2); + } +}).mount(); \ No newline at end of file diff --git a/docs/bundle.js b/docs/bundle.js new file mode 100644 index 0000000..5aaf378 --- /dev/null +++ b/docs/bundle.js @@ -0,0 +1,1806 @@ +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); + +// node_modules/relative-to-absolute-iri/lib/Resolve.js +var require_Resolve = __commonJS({ + "node_modules/relative-to-absolute-iri/lib/Resolve.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.removeDotSegmentsOfPath = exports.removeDotSegments = exports.resolve = void 0; + function resolve4(relativeIRI, baseIRI) { + baseIRI = baseIRI || ""; + const baseFragmentPos = baseIRI.indexOf("#"); + if (baseFragmentPos > 0) { + baseIRI = baseIRI.substr(0, baseFragmentPos); + } + if (!relativeIRI.length) { + if (baseIRI.indexOf(":") < 0) { + throw new Error(`Found invalid baseIRI '${baseIRI}' for value '${relativeIRI}'`); + } + return baseIRI; + } + if (relativeIRI.startsWith("?")) { + const baseQueryPos = baseIRI.indexOf("?"); + if (baseQueryPos > 0) { + baseIRI = baseIRI.substr(0, baseQueryPos); + } + return baseIRI + relativeIRI; + } + if (relativeIRI.startsWith("#")) { + return baseIRI + relativeIRI; + } + if (!baseIRI.length) { + const relativeColonPos = relativeIRI.indexOf(":"); + if (relativeColonPos < 0) { + throw new Error(`Found invalid relative IRI '${relativeIRI}' for a missing baseIRI`); + } + return removeDotSegmentsOfPath(relativeIRI, relativeColonPos); + } + const valueColonPos = relativeIRI.indexOf(":"); + if (valueColonPos >= 0) { + return removeDotSegmentsOfPath(relativeIRI, valueColonPos); + } + const baseColonPos = baseIRI.indexOf(":"); + if (baseColonPos < 0) { + throw new Error(`Found invalid baseIRI '${baseIRI}' for value '${relativeIRI}'`); + } + const baseIRIScheme = baseIRI.substr(0, baseColonPos + 1); + if (relativeIRI.indexOf("//") === 0) { + return baseIRIScheme + removeDotSegmentsOfPath(relativeIRI, valueColonPos); + } + let baseSlashAfterColonPos; + if (baseIRI.indexOf("//", baseColonPos) === baseColonPos + 1) { + baseSlashAfterColonPos = baseIRI.indexOf("/", baseColonPos + 3); + if (baseSlashAfterColonPos < 0) { + if (baseIRI.length > baseColonPos + 3) { + return baseIRI + "/" + removeDotSegmentsOfPath(relativeIRI, valueColonPos); + } else { + return baseIRIScheme + removeDotSegmentsOfPath(relativeIRI, valueColonPos); + } + } + } else { + baseSlashAfterColonPos = baseIRI.indexOf("/", baseColonPos + 1); + if (baseSlashAfterColonPos < 0) { + return baseIRIScheme + removeDotSegmentsOfPath(relativeIRI, valueColonPos); + } + } + if (relativeIRI.indexOf("/") === 0) { + return baseIRI.substr(0, baseSlashAfterColonPos) + removeDotSegments(relativeIRI); + } + let baseIRIPath = baseIRI.substr(baseSlashAfterColonPos); + const baseIRILastSlashPos = baseIRIPath.lastIndexOf("/"); + if (baseIRILastSlashPos >= 0 && baseIRILastSlashPos < baseIRIPath.length - 1) { + baseIRIPath = baseIRIPath.substr(0, baseIRILastSlashPos + 1); + if (relativeIRI[0] === "." && relativeIRI[1] !== "." && relativeIRI[1] !== "/" && relativeIRI[2]) { + relativeIRI = relativeIRI.substr(1); + } + } + relativeIRI = baseIRIPath + relativeIRI; + relativeIRI = removeDotSegments(relativeIRI); + return baseIRI.substr(0, baseSlashAfterColonPos) + relativeIRI; + } + exports.resolve = resolve4; + function removeDotSegments(path) { + const segmentBuffers = []; + let i = 0; + while (i < path.length) { + switch (path[i]) { + case "/": + if (path[i + 1] === ".") { + if (path[i + 2] === ".") { + if (!isCharacterAllowedAfterRelativePathSegment(path[i + 3])) { + segmentBuffers.push([]); + i++; + break; + } + segmentBuffers.pop(); + if (!path[i + 3]) { + segmentBuffers.push([]); + } + i += 3; + } else { + if (!isCharacterAllowedAfterRelativePathSegment(path[i + 2])) { + segmentBuffers.push([]); + i++; + break; + } + if (!path[i + 2]) { + segmentBuffers.push([]); + } + i += 2; + } + } else { + segmentBuffers.push([]); + i++; + } + break; + case "#": + case "?": + if (!segmentBuffers.length) { + segmentBuffers.push([]); + } + segmentBuffers[segmentBuffers.length - 1].push(path.substr(i)); + i = path.length; + break; + default: + if (!segmentBuffers.length) { + segmentBuffers.push([]); + } + segmentBuffers[segmentBuffers.length - 1].push(path[i]); + i++; + break; + } + } + return "/" + segmentBuffers.map((buffer) => buffer.join("")).join("/"); + } + exports.removeDotSegments = removeDotSegments; + function removeDotSegmentsOfPath(iri, colonPosition) { + let searchOffset = colonPosition + 1; + if (colonPosition >= 0) { + if (iri[colonPosition + 1] === "/" && iri[colonPosition + 2] === "/") { + searchOffset = colonPosition + 3; + } + } else { + if (iri[0] === "/" && iri[1] === "/") { + searchOffset = 2; + } + } + const pathSeparator = iri.indexOf("/", searchOffset); + if (pathSeparator < 0) { + return iri; + } + const base = iri.substr(0, pathSeparator); + const path = iri.substr(pathSeparator); + return base + removeDotSegments(path); + } + exports.removeDotSegmentsOfPath = removeDotSegmentsOfPath; + function isCharacterAllowedAfterRelativePathSegment(character) { + return !character || character === "#" || character === "?" || character === "/"; + } + } +}); + +// node_modules/relative-to-absolute-iri/index.js +var require_relative_to_absolute_iri = __commonJS({ + "node_modules/relative-to-absolute-iri/index.js"(exports) { + "use strict"; + var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) { + if (k2 === void 0) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { + return m[k]; + } }); + }) : (function(o, m, k, k2) { + if (k2 === void 0) k2 = k; + o[k2] = m[k]; + })); + var __exportStar = exports && exports.__exportStar || function(m, exports2) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports2, p)) __createBinding(exports2, m, p); + }; + Object.defineProperty(exports, "__esModule", { value: true }); + __exportStar(require_Resolve(), exports); + } +}); + +// node_modules/http-link-header/lib/link.js +var require_link = __commonJS({ + "node_modules/http-link-header/lib/link.js"(exports, module) { + "use strict"; + var COMPATIBLE_ENCODING_PATTERN = /^utf-?8|ascii|utf-?16-?le|ucs-?2|base-?64|latin-?1$/i; + var WS_TRIM_PATTERN = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; + var WS_CHAR_PATTERN = /\s|\uFEFF|\xA0/; + var WS_FOLD_PATTERN = /\r?\n[\x20\x09]+/g; + var DELIMITER_PATTERN = /[;,"]/; + var WS_DELIMITER_PATTERN = /[;,"]|\s/; + var TOKEN_PATTERN = /^[!#$%&'*+\-\.^_`|~\da-zA-Z]+$/; + var STATE = { + IDLE: 1 << 0, + URI: 1 << 1, + ATTR: 1 << 2 + }; + function trim(value) { + return value.replace(WS_TRIM_PATTERN, ""); + } + function hasWhitespace(value) { + return WS_CHAR_PATTERN.test(value); + } + function skipWhitespace(value, offset) { + while (hasWhitespace(value[offset])) { + offset++; + } + return offset; + } + function needsQuotes(value) { + return WS_DELIMITER_PATTERN.test(value) || !TOKEN_PATTERN.test(value); + } + function shallowCompareObjects(object1, object2) { + return Object.keys(object1).length === Object.keys(object2).length && Object.keys(object1).every( + (key) => key in object2 && object1[key] === object2[key] + ); + } + var Link = class _Link { + /** + * Link + * @constructor + * @param {String} [value] + * @returns {Link} + */ + constructor(value) { + this.refs = []; + if (value) { + this.parse(value); + } + } + /** + * Get refs with given relation type + * @param {String} value + * @returns {Array} + */ + rel(value) { + var links = []; + var type = value.toLowerCase(); + for (var i = 0; i < this.refs.length; i++) { + if (this.refs[i].rel.toLowerCase() === type) { + links.push(this.refs[i]); + } + } + return links; + } + /** + * Get refs where given attribute has a given value + * @param {String} attr + * @param {String} value + * @returns {Array} + */ + get(attr, value) { + attr = attr.toLowerCase(); + var links = []; + for (var i = 0; i < this.refs.length; i++) { + if (this.refs[i][attr] === value) { + links.push(this.refs[i]); + } + } + return links; + } + /** Sets a reference. */ + set(link) { + this.refs.push(link); + return this; + } + /** + * Sets a reference if a reference with similar properties isn’t already set. + */ + setUnique(link) { + if (!this.refs.some((ref) => shallowCompareObjects(ref, link))) { + this.refs.push(link); + } + return this; + } + has(attr, value) { + attr = attr.toLowerCase(); + for (var i = 0; i < this.refs.length; i++) { + if (this.refs[i][attr] === value) { + return true; + } + } + return false; + } + parse(value, offset) { + offset = offset || 0; + value = offset ? value.slice(offset) : value; + value = trim(value).replace(WS_FOLD_PATTERN, ""); + var state = STATE.IDLE; + var length = value.length; + var offset = 0; + var ref = null; + while (offset < length) { + if (state === STATE.IDLE) { + if (hasWhitespace(value[offset])) { + offset++; + continue; + } else if (value[offset] === "<") { + if (ref != null) { + ref.rel != null ? this.refs.push(..._Link.expandRelations(ref)) : this.refs.push(ref); + } + var end = value.indexOf(">", offset); + if (end === -1) throw new Error("Expected end of URI delimiter at offset " + offset); + ref = { uri: value.slice(offset + 1, end) }; + offset = end; + state = STATE.URI; + } else { + throw new Error('Unexpected character "' + value[offset] + '" at offset ' + offset); + } + offset++; + } else if (state === STATE.URI) { + if (hasWhitespace(value[offset])) { + offset++; + continue; + } else if (value[offset] === ";") { + state = STATE.ATTR; + offset++; + } else if (value[offset] === ",") { + state = STATE.IDLE; + offset++; + } else { + throw new Error('Unexpected character "' + value[offset] + '" at offset ' + offset); + } + } else if (state === STATE.ATTR) { + if (value[offset] === ";" || hasWhitespace(value[offset])) { + offset++; + continue; + } + var end = value.indexOf("=", offset); + if (end === -1) throw new Error("Expected attribute delimiter at offset " + offset); + var attr = trim(value.slice(offset, end)).toLowerCase(); + var attrValue = ""; + offset = end + 1; + offset = skipWhitespace(value, offset); + if (value[offset] === '"') { + offset++; + while (offset < length) { + if (value[offset] === '"') { + offset++; + break; + } + if (value[offset] === "\\") { + offset++; + } + attrValue += value[offset]; + offset++; + } + } else { + var end = offset + 1; + while (!DELIMITER_PATTERN.test(value[end]) && end < length) { + end++; + } + attrValue = value.slice(offset, end); + offset = end; + } + if (ref[attr] && _Link.isSingleOccurenceAttr(attr)) { + } else if (attr[attr.length - 1] === "*") { + ref[attr] = _Link.parseExtendedValue(attrValue); + } else { + attrValue = attr === "type" ? attrValue.toLowerCase() : attrValue; + if (ref[attr] != null) { + if (Array.isArray(ref[attr])) { + ref[attr].push(attrValue); + } else { + ref[attr] = [ref[attr], attrValue]; + } + } else { + ref[attr] = attrValue; + } + } + switch (value[offset]) { + case ",": + state = STATE.IDLE; + break; + case ";": + state = STATE.ATTR; + break; + } + offset++; + } else { + throw new Error('Unknown parser state "' + state + '"'); + } + } + if (ref != null) { + ref.rel != null ? this.refs.push(..._Link.expandRelations(ref)) : this.refs.push(ref); + } + ref = null; + return this; + } + toString() { + var refs = []; + var link = ""; + var ref = null; + for (var i = 0; i < this.refs.length; i++) { + ref = this.refs[i]; + link = Object.keys(this.refs[i]).reduce(function(link2, attr) { + if (attr === "uri") return link2; + return link2 + "; " + _Link.formatAttribute(attr, ref[attr]); + }, "<" + ref.uri + ">"); + refs.push(link); + } + return refs.join(", "); + } + }; + Link.isCompatibleEncoding = function(value) { + return COMPATIBLE_ENCODING_PATTERN.test(value); + }; + Link.parse = function(value, offset) { + return new Link().parse(value, offset); + }; + Link.isSingleOccurenceAttr = function(attr) { + return attr === "rel" || attr === "type" || attr === "media" || attr === "title" || attr === "title*"; + }; + Link.isTokenAttr = function(attr) { + return attr === "rel" || attr === "type" || attr === "anchor"; + }; + Link.escapeQuotes = function(value) { + return value.replace(/"/g, '\\"'); + }; + Link.expandRelations = function(ref) { + var rels = ref.rel.split(" "); + return rels.map(function(rel) { + var value = Object.assign({}, ref); + value.rel = rel; + return value; + }); + }; + Link.parseExtendedValue = function(value) { + var parts = /([^']+)?(?:'([^']*)')?(.+)/.exec(value); + return { + language: parts[2].toLowerCase(), + encoding: Link.isCompatibleEncoding(parts[1]) ? null : parts[1].toLowerCase(), + value: Link.isCompatibleEncoding(parts[1]) ? decodeURIComponent(parts[3]) : parts[3] + }; + }; + Link.formatExtendedAttribute = function(attr, data) { + var encoding = (data.encoding || "utf-8").toUpperCase(); + var language = data.language || "en"; + var encodedValue = ""; + if (Buffer.isBuffer(data.value) && Link.isCompatibleEncoding(encoding)) { + encodedValue = data.value.toString(encoding); + } else if (Buffer.isBuffer(data.value)) { + encodedValue = data.value.toString("hex").replace(/[0-9a-f]{2}/gi, "%$1"); + } else { + encodedValue = encodeURIComponent(data.value); + } + return attr + "=" + encoding + "'" + language + "'" + encodedValue; + }; + Link.formatAttribute = function(attr, value) { + if (Array.isArray(value)) { + return value.map((item) => { + return Link.formatAttribute(attr, item); + }).join("; "); + } + if (attr[attr.length - 1] === "*" || typeof value !== "string") { + return Link.formatExtendedAttribute(attr, value); + } + if (Link.isTokenAttr(attr)) { + value = needsQuotes(value) ? '"' + Link.escapeQuotes(value) + '"' : Link.escapeQuotes(value); + } else if (needsQuotes(value)) { + value = encodeURIComponent(value); + value = value.replace(/%20/g, " ").replace(/%2C/g, ",").replace(/%3B/g, ";"); + value = '"' + value + '"'; + } + return attr + "=" + value; + }; + module.exports = Link; + } +}); + +// lib/ContextParser.ts +var import_relative_to_absolute_iri3 = __toESM(require_relative_to_absolute_iri()); + +// lib/ErrorCoded.ts +var ErrorCoded = class extends Error { + /* istanbul ignore next */ + constructor(message, code) { + super(message); + this.code = code; + } +}; +var ERROR_CODES = /* @__PURE__ */ ((ERROR_CODES2) => { + ERROR_CODES2["COLLIDING_KEYWORDS"] = "colliding keywords"; + ERROR_CODES2["CONFLICTING_INDEXES"] = "conflicting indexes"; + ERROR_CODES2["CYCLIC_IRI_MAPPING"] = "cyclic IRI mapping"; + ERROR_CODES2["INVALID_ID_VALUE"] = "invalid @id value"; + ERROR_CODES2["INVALID_INDEX_VALUE"] = "invalid @index value"; + ERROR_CODES2["INVALID_NEST_VALUE"] = "invalid @nest value"; + ERROR_CODES2["INVALID_PREFIX_VALUE"] = "invalid @prefix value"; + ERROR_CODES2["INVALID_PROPAGATE_VALUE"] = "invalid @propagate value"; + ERROR_CODES2["INVALID_REVERSE_VALUE"] = "invalid @reverse value"; + ERROR_CODES2["INVALID_IMPORT_VALUE"] = "invalid @import value"; + ERROR_CODES2["INVALID_VERSION_VALUE"] = "invalid @version value"; + ERROR_CODES2["INVALID_BASE_IRI"] = "invalid base IRI"; + ERROR_CODES2["INVALID_CONTAINER_MAPPING"] = "invalid container mapping"; + ERROR_CODES2["INVALID_CONTEXT_ENTRY"] = "invalid context entry"; + ERROR_CODES2["INVALID_CONTEXT_NULLIFICATION"] = "invalid context nullification"; + ERROR_CODES2["INVALID_DEFAULT_LANGUAGE"] = "invalid default language"; + ERROR_CODES2["INVALID_INCLUDED_VALUE"] = "invalid @included value"; + ERROR_CODES2["INVALID_IRI_MAPPING"] = "invalid IRI mapping"; + ERROR_CODES2["INVALID_JSON_LITERAL"] = "invalid JSON literal"; + ERROR_CODES2["INVALID_KEYWORD_ALIAS"] = "invalid keyword alias"; + ERROR_CODES2["INVALID_LANGUAGE_MAP_VALUE"] = "invalid language map value"; + ERROR_CODES2["INVALID_LANGUAGE_MAPPING"] = "invalid language mapping"; + ERROR_CODES2["INVALID_LANGUAGE_TAGGED_STRING"] = "invalid language-tagged string"; + ERROR_CODES2["INVALID_LANGUAGE_TAGGED_VALUE"] = "invalid language-tagged value"; + ERROR_CODES2["INVALID_LOCAL_CONTEXT"] = "invalid local context"; + ERROR_CODES2["INVALID_REMOTE_CONTEXT"] = "invalid remote context"; + ERROR_CODES2["INVALID_REVERSE_PROPERTY"] = "invalid reverse property"; + ERROR_CODES2["INVALID_REVERSE_PROPERTY_MAP"] = "invalid reverse property map"; + ERROR_CODES2["INVALID_REVERSE_PROPERTY_VALUE"] = "invalid reverse property value"; + ERROR_CODES2["INVALID_SCOPED_CONTEXT"] = "invalid scoped context"; + ERROR_CODES2["INVALID_SCRIPT_ELEMENT"] = "invalid script element"; + ERROR_CODES2["INVALID_SET_OR_LIST_OBJECT"] = "invalid set or list object"; + ERROR_CODES2["INVALID_TERM_DEFINITION"] = "invalid term definition"; + ERROR_CODES2["INVALID_TYPE_MAPPING"] = "invalid type mapping"; + ERROR_CODES2["INVALID_TYPE_VALUE"] = "invalid type value"; + ERROR_CODES2["INVALID_TYPED_VALUE"] = "invalid typed value"; + ERROR_CODES2["INVALID_VALUE_OBJECT"] = "invalid value object"; + ERROR_CODES2["INVALID_VALUE_OBJECT_VALUE"] = "invalid value object value"; + ERROR_CODES2["INVALID_VOCAB_MAPPING"] = "invalid vocab mapping"; + ERROR_CODES2["IRI_CONFUSED_WITH_PREFIX"] = "IRI confused with prefix"; + ERROR_CODES2["KEYWORD_REDEFINITION"] = "keyword redefinition"; + ERROR_CODES2["LOADING_DOCUMENT_FAILED"] = "loading document failed"; + ERROR_CODES2["LOADING_REMOTE_CONTEXT_FAILED"] = "loading remote context failed"; + ERROR_CODES2["MULTIPLE_CONTEXT_LINK_HEADERS"] = "multiple context link headers"; + ERROR_CODES2["PROCESSING_MODE_CONFLICT"] = "processing mode conflict"; + ERROR_CODES2["PROTECTED_TERM_REDEFINITION"] = "protected term redefinition"; + ERROR_CODES2["CONTEXT_OVERFLOW"] = "context overflow"; + ERROR_CODES2["INVALID_BASE_DIRECTION"] = "invalid base direction"; + ERROR_CODES2["RECURSIVE_CONTEXT_INCLUSION"] = "recursive context inclusion"; + ERROR_CODES2["INVALID_STREAMING_KEY_ORDER"] = "invalid streaming key order"; + ERROR_CODES2["INVALID_EMBEDDED_NODE"] = "invalid embedded node"; + ERROR_CODES2["INVALID_ANNOTATION"] = "invalid annotation"; + return ERROR_CODES2; +})(ERROR_CODES || {}); + +// lib/FetchDocumentLoader.ts +var import_http_link_header = __toESM(require_link()); +var import_relative_to_absolute_iri = __toESM(require_relative_to_absolute_iri()); +var FetchDocumentLoader = class { + constructor(fetcher) { + this.fetcher = fetcher; + } + async load(url) { + const response = await (this.fetcher || fetch)(url, { headers: new Headers({ accept: "application/ld+json" }) }); + if (response.ok && response.headers) { + let mediaType = response.headers.get("Content-Type"); + if (mediaType) { + const colonPos = mediaType.indexOf(";"); + if (colonPos > 0) { + mediaType = mediaType.substr(0, colonPos); + } + } + if (mediaType === "application/ld+json") { + return await response.json(); + } else { + if (response.headers.has("Link")) { + let alternateUrl; + response.headers.forEach((value, key) => { + if (key === "link") { + const linkHeader = (0, import_http_link_header.parse)(value); + for (const link of linkHeader.get("type", "application/ld+json")) { + if (link.rel === "alternate") { + if (alternateUrl) { + throw new Error("Multiple JSON-LD alternate links were found on " + url); + } + alternateUrl = (0, import_relative_to_absolute_iri.resolve)(link.uri, url); + } + } + } + }); + if (alternateUrl) { + return this.load(alternateUrl); + } + } + throw new ErrorCoded( + `Unsupported JSON-LD media type ${mediaType}`, + "loading document failed" /* LOADING_DOCUMENT_FAILED */ + ); + } + } else { + throw new Error(response.statusText || `Status code: ${response.status}`); + } + } +}; + +// lib/JsonLdContextNormalized.ts +var import_relative_to_absolute_iri2 = __toESM(require_relative_to_absolute_iri()); + +// lib/Util.ts +var Util = class _Util { + static { + // Regex for valid IRIs + this.IRI_REGEX = /^([A-Za-z][A-Za-z0-9+-.]*|_):[^ "<>{}|\\\[\]`#]*(#[^#]*)?$/; + } + static { + // Weaker regex for valid IRIs, this includes relative IRIs + this.IRI_REGEX_WEAK = /(?::[^:])|\//; + } + static { + // Regex for keyword form + this.KEYWORD_REGEX = /^@[a-z]+$/i; + } + static { + // Regex to see if an IRI ends with a gen-delim character (see RFC 3986) + this.ENDS_WITH_GEN_DELIM = /[:/?#\[\]@]$/; + } + static { + // Regex for language tags + this.REGEX_LANGUAGE_TAG = /^[a-zA-Z]+(-[a-zA-Z0-9]+)*$/; + } + static { + // Regex for base directions + this.REGEX_DIRECTION_TAG = /^(ltr)|(rtl)$/; + } + static { + // All known valid JSON-LD keywords + // @see https://www.w3.org/TR/json-ld11/#keywords + this.VALID_KEYWORDS = { + "@annotation": true, + // https://json-ld.github.io/json-ld-star/ + "@base": true, + "@container": true, + "@context": true, + "@direction": true, + "@graph": true, + "@id": true, + "@import": true, + "@included": true, + "@index": true, + "@json": true, + "@language": true, + "@list": true, + "@nest": true, + "@none": true, + "@prefix": true, + "@propagate": true, + "@protected": true, + "@reverse": true, + "@set": true, + "@type": true, + "@value": true, + "@version": true, + "@vocab": true + }; + } + static { + // Keys in the contexts that will not be expanded based on the base IRI + this.EXPAND_KEYS_BLACKLIST = [ + "@base", + "@vocab", + "@language", + "@version", + "@direction" + ]; + } + static { + // Keys in the contexts that may not be aliased from + this.ALIAS_DOMAIN_BLACKLIST = [ + "@container", + "@graph", + "@id", + "@index", + "@list", + "@nest", + "@none", + "@prefix", + "@reverse", + "@set", + "@type", + "@value", + "@version" + ]; + } + static { + // Keys in the contexts that may not be aliased to + this.ALIAS_RANGE_BLACKLIST = [ + "@context", + "@preserve" + ]; + } + static { + // All valid @container values + this.CONTAINERS = [ + "@list", + "@set", + "@index", + "@language", + "@graph", + "@id", + "@type" + ]; + } + static { + // All valid @container values under processing mode 1.0 + this.CONTAINERS_1_0 = [ + "@list", + "@set", + "@index" + ]; + } + /** + * Check if the given term is a valid compact IRI. + * Otherwise, it may be an IRI. + * @param {string} term A term. + * @return {boolean} If it is a compact IRI. + */ + static isCompactIri(term) { + return term.indexOf(":") > 0 && !(term && term[0] === "#"); + } + /** + * Get the prefix from the given term. + * @see https://json-ld.org/spec/latest/json-ld/#compact-iris + * @param {string} term A term that is an URL or a prefixed URL. + * @param {IJsonLdContextNormalizedRaw} context A context. + * @return {string} The prefix or null. + */ + static getPrefix(term, context) { + if (term && term[0] === "#") { + return null; + } + const separatorPos = term.indexOf(":"); + if (separatorPos >= 0) { + if (term.length > separatorPos + 1 && term.charAt(separatorPos + 1) === "/" && term.charAt(separatorPos + 2) === "/") { + return null; + } + const prefix = term.substr(0, separatorPos); + if (prefix === "_") { + return null; + } + if (context[prefix]) { + return prefix; + } + } + return null; + } + /** + * From a given context entry value, get the string value, or the @id field. + * @param contextValue A value for a term in a context. + * @return {string} The id value, or null. + */ + static getContextValueId(contextValue) { + if (contextValue === null || typeof contextValue === "string") { + return contextValue; + } + const id = contextValue["@id"]; + return id ? id : null; + } + /** + * Check if the given simple term definition (string-based value of a context term) + * should be considered a prefix. + * @param value A simple term definition value. + * @param options Options that define the way how expansion must be done. + */ + static isSimpleTermDefinitionPrefix(value, options) { + return !_Util.isPotentialKeyword(value) && (options.allowPrefixNonGenDelims || typeof value === "string" && (value[0] === "_" || _Util.isPrefixIriEndingWithGenDelim(value))); + } + /** + * Check if the given keyword is of the keyword format "@"1*ALPHA. + * @param {string} keyword A potential keyword. + * @return {boolean} If the given keyword is of the keyword format. + */ + static isPotentialKeyword(keyword) { + return typeof keyword === "string" && _Util.KEYWORD_REGEX.test(keyword); + } + /** + * Check if the given prefix ends with a gen-delim character. + * @param {string} prefixIri A prefix IRI. + * @return {boolean} If the given prefix IRI is valid. + */ + static isPrefixIriEndingWithGenDelim(prefixIri) { + return _Util.ENDS_WITH_GEN_DELIM.test(prefixIri); + } + /** + * Check if the given context value can be a prefix value. + * @param value A context value. + * @return {boolean} If it can be a prefix value. + */ + static isPrefixValue(value) { + return value && (typeof value === "string" || value && typeof value === "object"); + } + /** + * Check if the given IRI is valid. + * @param {string} iri A potential IRI. + * @return {boolean} If the given IRI is valid. + */ + static isValidIri(iri) { + return Boolean(iri && _Util.IRI_REGEX.test(iri)); + } + /** + * Check if the given IRI is valid, this includes the possibility of being a relative IRI. + * @param {string} iri A potential IRI. + * @return {boolean} If the given IRI is valid. + */ + static isValidIriWeak(iri) { + return !!iri && iri[0] !== ":" && _Util.IRI_REGEX_WEAK.test(iri); + } + /** + * Check if the given keyword is a defined according to the JSON-LD specification. + * @param {string} keyword A potential keyword. + * @return {boolean} If the given keyword is valid. + */ + static isValidKeyword(keyword) { + return _Util.VALID_KEYWORDS[keyword]; + } + /** + * Check if the given term is protected in the context. + * @param {IJsonLdContextNormalizedRaw} context A context. + * @param {string} key A context term. + * @return {boolean} If the given term has an @protected flag. + */ + static isTermProtected(context, key) { + const value = context[key]; + return !(typeof value === "string") && value && value["@protected"]; + } + /** + * Check if the given context has at least one protected term. + * @param context A context. + * @return If the context has a protected term. + */ + static hasProtectedTerms(context) { + for (const key of Object.keys(context)) { + if (_Util.isTermProtected(context, key)) { + return true; + } + } + return false; + } + /** + * Check if the given key is an internal reserved keyword. + * @param key A context key. + */ + static isReservedInternalKeyword(key) { + return key.startsWith("@__"); + } + /** + * Check if two objects are deepEqual to on another. + * @param object1 The first object to test. + * @param object2 The second object to test. + */ + static deepEqual(object1, object2) { + const objKeys1 = Object.keys(object1); + const objKeys2 = Object.keys(object2); + if (objKeys1.length !== objKeys2.length) return false; + return objKeys1.every((key) => { + const value1 = object1[key]; + const value2 = object2[key]; + return value1 === value2 || value1 !== null && value2 !== null && typeof value1 === "object" && typeof value2 === "object" && this.deepEqual(value1, value2); + }); + } +}; + +// lib/JsonLdContextNormalized.ts +var JsonLdContextNormalized = class { + constructor(contextRaw) { + this.contextRaw = contextRaw; + } + /** + * @return The raw inner context. + */ + getContextRaw() { + return this.contextRaw; + } + /** + * Expand the term or prefix of the given term if it has one, + * otherwise return the term as-is. + * + * This will try to expand the IRI as much as possible. + * + * Iff in vocab-mode, then other references to other terms in the context can be used, + * such as to `myTerm`: + * ``` + * { + * "myTerm": "http://example.org/myLongTerm" + * } + * ``` + * + * @param {string} term A term that is an URL or a prefixed URL. + * @param {boolean} expandVocab If the term is a predicate or type and should be expanded based on @vocab, + * otherwise it is considered a regular term that is expanded based on @base. + * @param {IExpandOptions} options Options that define the way how expansion must be done. + * @return {string} The expanded term, the term as-is, or null if it was explicitly disabled in the context. + * @throws If the term is aliased to an invalid value (not a string, IRI or keyword). + */ + expandTerm(term, expandVocab, options = defaultExpandOptions) { + const contextValue = this.contextRaw[term]; + if (contextValue === null || contextValue && contextValue["@id"] === null) { + return null; + } + let validIriMapping = true; + if (contextValue && expandVocab) { + const value = Util.getContextValueId(contextValue); + if (value && value !== term) { + if (typeof value !== "string" || !Util.isValidIri(value) && !Util.isValidKeyword(value)) { + if (!Util.isPotentialKeyword(value)) { + validIriMapping = false; + } + } else { + return value; + } + } + } + const prefix = Util.getPrefix(term, this.contextRaw); + const vocab = this.contextRaw["@vocab"]; + const vocabRelative = (!!vocab || vocab === "") && vocab.indexOf(":") < 0; + const base = this.contextRaw["@base"]; + const potentialKeyword = Util.isPotentialKeyword(term); + if (prefix) { + const contextPrefixValue = this.contextRaw[prefix]; + const value = Util.getContextValueId(contextPrefixValue); + if (value) { + if (typeof contextPrefixValue === "string" || !options.allowPrefixForcing) { + if (!Util.isSimpleTermDefinitionPrefix(value, options)) { + return term; + } + } else { + if (value[0] !== "_" && !potentialKeyword && !contextPrefixValue["@prefix"] && !(term in this.contextRaw)) { + return term; + } + } + return value + term.substr(prefix.length + 1); + } + } else if (expandVocab && (vocab || vocab === "" || options.allowVocabRelativeToBase && (base && vocabRelative)) && !potentialKeyword && !Util.isCompactIri(term)) { + if (vocabRelative) { + if (options.allowVocabRelativeToBase) { + return (vocab || base ? (0, import_relative_to_absolute_iri2.resolve)(vocab, base) : "") + term; + } else { + throw new ErrorCoded(`Relative vocab expansion for term '${term}' with vocab '${vocab}' is not allowed.`, "invalid vocab mapping" /* INVALID_VOCAB_MAPPING */); + } + } else { + return vocab + term; + } + } else if (!expandVocab && base && !potentialKeyword && !Util.isCompactIri(term)) { + return (0, import_relative_to_absolute_iri2.resolve)(term, base); + } + if (validIriMapping) { + return term; + } else { + throw new ErrorCoded(`Invalid IRI mapping found for context entry '${term}': '${JSON.stringify(contextValue)}'`, "invalid IRI mapping" /* INVALID_IRI_MAPPING */); + } + } + /** + * Compact the given term using @base, @vocab, an aliased term, or a prefixed term. + * + * This will try to compact the IRI as much as possible. + * + * @param {string} iri An IRI to compact. + * @param {boolean} vocab If the term is a predicate or type and should be compacted based on @vocab, + * otherwise it is considered a regular term that is compacted based on @base. + * @return {string} The compacted term or the IRI as-is. + */ + compactIri(iri, vocab) { + if (vocab && this.contextRaw["@vocab"] && iri.startsWith(this.contextRaw["@vocab"])) { + return iri.substr(this.contextRaw["@vocab"].length); + } + if (!vocab && this.contextRaw["@base"] && iri.startsWith(this.contextRaw["@base"])) { + return iri.substr(this.contextRaw["@base"].length); + } + const shortestPrefixing = { prefix: "", suffix: iri }; + for (const key in this.contextRaw) { + const value = this.contextRaw[key]; + if (value && !Util.isPotentialKeyword(key)) { + const contextIri = Util.getContextValueId(value); + if (iri.startsWith(contextIri)) { + const suffix = iri.substr(contextIri.length); + if (!suffix) { + if (vocab) { + return key; + } + } else if (suffix.length < shortestPrefixing.suffix.length) { + shortestPrefixing.prefix = key; + shortestPrefixing.suffix = suffix; + } + } + } + } + if (shortestPrefixing.prefix) { + return shortestPrefixing.prefix + ":" + shortestPrefixing.suffix; + } + return iri; + } +}; +var defaultExpandOptions = { + allowPrefixForcing: true, + allowPrefixNonGenDelims: false, + allowVocabRelativeToBase: true +}; + +// lib/ContextParser.ts +var ContextParser = class _ContextParser { + static { + this.DEFAULT_PROCESSING_MODE = 1.1; + } + constructor(options) { + options = options || {}; + this.documentLoader = options.documentLoader || new FetchDocumentLoader(); + this.documentCache = {}; + this.validateContext = !options.skipValidation; + this.expandContentTypeToBase = !!options.expandContentTypeToBase; + this.remoteContextsDepthLimit = options.remoteContextsDepthLimit || 32; + this.redirectSchemaOrgHttps = "redirectSchemaOrgHttps" in options ? !!options.redirectSchemaOrgHttps : true; + } + /** + * Validate the given @language value. + * An error will be thrown if it is invalid. + * @param value An @language value. + * @param {boolean} strictRange If the string value should be strictly checked against a regex. + * @param {string} errorCode The error code to emit on errors. + * @return {boolean} If validation passed. + * Can only be false if strictRange is false and the string value did not pass the regex. + */ + static validateLanguage(value, strictRange, errorCode) { + if (typeof value !== "string") { + throw new ErrorCoded(`The value of an '@language' must be a string, got '${JSON.stringify(value)}'`, errorCode); + } + if (!Util.REGEX_LANGUAGE_TAG.test(value)) { + if (strictRange) { + throw new ErrorCoded(`The value of an '@language' must be a valid language tag, got '${JSON.stringify(value)}'`, errorCode); + } else { + return false; + } + } + return true; + } + /** + * Validate the given @direction value. + * An error will be thrown if it is invalid. + * @param value An @direction value. + * @param {boolean} strictValues If the string value should be strictly checked against a regex. + * @return {boolean} If validation passed. + * Can only be false if strictRange is false and the string value did not pass the regex. + */ + static validateDirection(value, strictValues) { + if (typeof value !== "string") { + throw new ErrorCoded( + `The value of an '@direction' must be a string, got '${JSON.stringify(value)}'`, + "invalid base direction" /* INVALID_BASE_DIRECTION */ + ); + } + if (!Util.REGEX_DIRECTION_TAG.test(value)) { + if (strictValues) { + throw new ErrorCoded(`The value of an '@direction' must be 'ltr' or 'rtl', got '${JSON.stringify(value)}'`, "invalid base direction" /* INVALID_BASE_DIRECTION */); + } else { + return false; + } + } + return true; + } + /** + * Add an @id term for all @reverse terms. + * @param {IJsonLdContextNormalizedRaw} context A context. + * @return {IJsonLdContextNormalizedRaw} The mutated input context. + */ + idifyReverseTerms(context) { + for (const key of Object.keys(context)) { + let value = context[key]; + if (value && typeof value === "object") { + if (value["@reverse"] && !value["@id"]) { + if (typeof value["@reverse"] !== "string" || Util.isValidKeyword(value["@reverse"])) { + throw new ErrorCoded( + `Invalid @reverse value, must be absolute IRI or blank node: '${value["@reverse"]}'`, + "invalid IRI mapping" /* INVALID_IRI_MAPPING */ + ); + } + value = context[key] = { ...value, "@id": value["@reverse"] }; + value["@id"] = value["@reverse"]; + if (Util.isPotentialKeyword(value["@reverse"])) { + delete value["@reverse"]; + } else { + value["@reverse"] = true; + } + } + } + } + return context; + } + /** + * Expand all prefixed terms in the given context. + * @param {IJsonLdContextNormalizedRaw} context A context. + * @param {boolean} expandContentTypeToBase If @type inside the context may be expanded + * via @base if @vocab is set to null. + * @param {string[]} keys Optional set of keys from the context to expand. If left undefined, all + * keys in the context will be expanded. + */ + expandPrefixedTerms(context, expandContentTypeToBase, keys) { + const contextRaw = context.getContextRaw(); + for (const key of keys || Object.keys(contextRaw)) { + if (Util.EXPAND_KEYS_BLACKLIST.indexOf(key) < 0 && !Util.isReservedInternalKeyword(key)) { + const keyValue = contextRaw[key]; + if (Util.isPotentialKeyword(key) && Util.ALIAS_DOMAIN_BLACKLIST.indexOf(key) >= 0) { + if (key !== "@type" || typeof contextRaw[key] === "object" && !(contextRaw[key]["@protected"] || contextRaw[key]["@container"] === "@set")) { + throw new ErrorCoded(`Keywords can not be aliased to something else. +Tried mapping ${key} to ${JSON.stringify(keyValue)}`, "keyword redefinition" /* KEYWORD_REDEFINITION */); + } + } + if (Util.ALIAS_RANGE_BLACKLIST.indexOf(Util.getContextValueId(keyValue)) >= 0) { + throw new ErrorCoded(`Aliasing to certain keywords is not allowed. +Tried mapping ${key} to ${JSON.stringify(keyValue)}`, "invalid keyword alias" /* INVALID_KEYWORD_ALIAS */); + } + if (keyValue && Util.isPotentialKeyword(Util.getContextValueId(keyValue)) && keyValue["@prefix"] === true) { + throw new ErrorCoded( + `Tried to use keyword aliases as prefix: '${key}': '${JSON.stringify(keyValue)}'`, + "invalid term definition" /* INVALID_TERM_DEFINITION */ + ); + } + while (Util.isPrefixValue(contextRaw[key])) { + const value = contextRaw[key]; + let changed = false; + if (typeof value === "string") { + contextRaw[key] = context.expandTerm(value, true); + changed = changed || value !== contextRaw[key]; + } else { + const id = value["@id"]; + const type = value["@type"]; + const canAddIdEntry = !("@prefix" in value) || Util.isValidIri(key); + if ("@id" in value) { + if (id !== void 0 && id !== null && typeof id === "string") { + contextRaw[key] = { ...contextRaw[key], "@id": context.expandTerm(id, true) }; + changed = changed || id !== contextRaw[key]["@id"]; + } + } else if (!Util.isPotentialKeyword(key) && canAddIdEntry) { + const newId = context.expandTerm(key, true); + if (newId !== key) { + contextRaw[key] = { ...contextRaw[key], "@id": newId }; + changed = true; + } + } + if (type && typeof type === "string" && type !== "@vocab" && (!value["@container"] || !value["@container"]["@type"]) && canAddIdEntry) { + let expandedType = context.expandTerm(type, true); + if (expandContentTypeToBase && type === expandedType) { + expandedType = context.expandTerm(type, false); + } + if (expandedType !== type) { + changed = true; + contextRaw[key] = { ...contextRaw[key], "@type": expandedType }; + } + } + } + if (!changed) { + break; + } + } + } + } + } + /** + * Normalize the @language entries in the given context to lowercase. + * @param {IJsonLdContextNormalizedRaw} context A context. + * @param {IParseOptions} parseOptions The parsing options. + */ + normalize(context, { processingMode, normalizeLanguageTags }) { + if (normalizeLanguageTags || processingMode === 1) { + for (const key of Object.keys(context)) { + if (key === "@language" && typeof context[key] === "string") { + context[key] = context[key].toLowerCase(); + } else { + const value = context[key]; + if (value && typeof value === "object") { + if (typeof value["@language"] === "string") { + const lowercase = value["@language"].toLowerCase(); + if (lowercase !== value["@language"]) { + context[key] = { ...value, "@language": lowercase }; + } + } + } + } + } + } + } + /** + * Convert all @container strings and array values to hash-based values. + * @param {IJsonLdContextNormalizedRaw} context A context. + */ + containersToHash(context) { + for (const key of Object.keys(context)) { + const value = context[key]; + if (value && typeof value === "object") { + if (typeof value["@container"] === "string") { + context[key] = { ...value, "@container": { [value["@container"]]: true } }; + } else if (Array.isArray(value["@container"])) { + const newValue = {}; + for (const containerValue of value["@container"]) { + newValue[containerValue] = true; + } + context[key] = { ...value, "@container": newValue }; + } + } + } + } + /** + * Normalize and apply context-level @protected terms onto each term separately. + * @param {IJsonLdContextNormalizedRaw} context A context. + * @param {number} processingMode The processing mode. + */ + applyScopedProtected(context, { processingMode }, expandOptions) { + if (processingMode && processingMode >= 1.1) { + if (context["@protected"]) { + for (const key of Object.keys(context)) { + if (Util.isReservedInternalKeyword(key)) { + continue; + } + if (!Util.isPotentialKeyword(key) && !Util.isTermProtected(context, key)) { + const value = context[key]; + if (value && typeof value === "object") { + if (!("@protected" in context[key])) { + context[key] = { ...context[key], "@protected": true }; + } + } else { + context[key] = { + "@id": value, + "@protected": true + }; + if (Util.isSimpleTermDefinitionPrefix(value, expandOptions)) { + context[key] = { ...context[key], "@prefix": true }; + } + } + } + } + delete context["@protected"]; + } + } + } + /** + * Check if the given context inheritance does not contain any overrides of protected terms. + * @param {IJsonLdContextNormalizedRaw} contextBefore The context that may contain some protected terms. + * @param {IJsonLdContextNormalizedRaw} contextAfter A new context that is being applied on the first one. + * @param {IExpandOptions} expandOptions Options that are needed for any expansions during this validation. + * @param {string[]} keys Optional set of keys from the context to validate. If left undefined, all + * keys defined in contextAfter will be checked. + */ + validateKeywordRedefinitions(contextBefore, contextAfter, expandOptions, keys) { + for (const key of keys ?? Object.keys(contextAfter)) { + if (Util.isTermProtected(contextBefore, key)) { + if (typeof contextAfter[key] === "string") { + contextAfter[key] = { "@id": contextAfter[key], "@protected": true }; + } else { + contextAfter[key] = { ...contextAfter[key], "@protected": true }; + } + if (!Util.deepEqual(contextBefore[key], contextAfter[key])) { + throw new ErrorCoded( + `Attempted to override the protected keyword ${key} from ${JSON.stringify(Util.getContextValueId(contextBefore[key]))} to ${JSON.stringify(Util.getContextValueId(contextAfter[key]))}`, + "protected term redefinition" /* PROTECTED_TERM_REDEFINITION */ + ); + } + } + } + } + /** + * Validate the entries of the given context. + * @param {IJsonLdContextNormalizedRaw} context A context. + * @param {IParseOptions} options The parse options. + */ + validate(context, { processingMode }) { + for (const key of Object.keys(context)) { + if (Util.isReservedInternalKeyword(key)) { + continue; + } + if (key === "") { + throw new ErrorCoded( + `The empty term is not allowed, got: '${key}': '${JSON.stringify(context[key])}'`, + "invalid term definition" /* INVALID_TERM_DEFINITION */ + ); + } + const value = context[key]; + const valueType = typeof value; + if (Util.isPotentialKeyword(key)) { + switch (key.substr(1)) { + case "vocab": + if (value !== null && valueType !== "string") { + throw new ErrorCoded(`Found an invalid @vocab IRI: ${value}`, "invalid vocab mapping" /* INVALID_VOCAB_MAPPING */); + } + break; + case "base": + if (value !== null && valueType !== "string") { + throw new ErrorCoded(`Found an invalid @base IRI: ${context[key]}`, "invalid base IRI" /* INVALID_BASE_IRI */); + } + break; + case "language": + if (value !== null) { + _ContextParser.validateLanguage(value, true, "invalid default language" /* INVALID_DEFAULT_LANGUAGE */); + } + break; + case "version": + if (value !== null && valueType !== "number") { + throw new ErrorCoded(`Found an invalid @version number: ${value}`, "invalid @version value" /* INVALID_VERSION_VALUE */); + } + break; + case "direction": + if (value !== null) { + _ContextParser.validateDirection(value, true); + } + break; + case "propagate": + if (processingMode === 1) { + throw new ErrorCoded(`Found an illegal @propagate keyword: ${value}`, "invalid context entry" /* INVALID_CONTEXT_ENTRY */); + } + if (value !== null && valueType !== "boolean") { + throw new ErrorCoded(`Found an invalid @propagate value: ${value}`, "invalid @propagate value" /* INVALID_PROPAGATE_VALUE */); + } + break; + } + if (Util.isValidKeyword(key) && Util.isValidKeyword(Util.getContextValueId(value))) { + throw new ErrorCoded( + `Illegal keyword alias in term value, found: '${key}': '${Util.getContextValueId(value)}'`, + "keyword redefinition" /* KEYWORD_REDEFINITION */ + ); + } + continue; + } + if (value !== null) { + switch (valueType) { + case "string": + if (Util.getPrefix(value, context) === key) { + throw new ErrorCoded(`Detected cyclical IRI mapping in context entry: '${key}': '${JSON.stringify(value)}'`, "cyclic IRI mapping" /* CYCLIC_IRI_MAPPING */); + } + if (Util.isValidIriWeak(key)) { + if (value === "@type") { + throw new ErrorCoded( + `IRIs can not be mapped to @type, found: '${key}': '${value}'`, + "invalid IRI mapping" /* INVALID_IRI_MAPPING */ + ); + } else if (Util.isValidIri(value) && value !== new JsonLdContextNormalized(context).expandTerm(key)) { + throw new ErrorCoded( + `IRIs can not be mapped to other IRIs, found: '${key}': '${value}'`, + "invalid IRI mapping" /* INVALID_IRI_MAPPING */ + ); + } + } + break; + case "object": + if (!Util.isCompactIri(key) && !("@id" in value) && (value["@type"] === "@id" ? !context["@base"] : !context["@vocab"])) { + throw new ErrorCoded( + `Missing @id in context entry: '${key}': '${JSON.stringify(value)}'`, + "invalid IRI mapping" /* INVALID_IRI_MAPPING */ + ); + } + for (const objectKey of Object.keys(value)) { + const objectValue = value[objectKey]; + if (!objectValue) { + continue; + } + switch (objectKey) { + case "@id": + if (Util.isValidKeyword(objectValue) && objectValue !== "@type" && objectValue !== "@id" && objectValue !== "@graph" && objectValue !== "@nest") { + throw new ErrorCoded( + `Illegal keyword alias in term value, found: '${key}': '${JSON.stringify(value)}'`, + "invalid IRI mapping" /* INVALID_IRI_MAPPING */ + ); + } + if (Util.isValidIriWeak(key)) { + if (objectValue === "@type") { + throw new ErrorCoded( + `IRIs can not be mapped to @type, found: '${key}': '${JSON.stringify(value)}'`, + "invalid IRI mapping" /* INVALID_IRI_MAPPING */ + ); + } else if (Util.isValidIri(objectValue) && objectValue !== new JsonLdContextNormalized(context).expandTerm(key)) { + throw new ErrorCoded( + `IRIs can not be mapped to other IRIs, found: '${key}': '${JSON.stringify(value)}'`, + "invalid IRI mapping" /* INVALID_IRI_MAPPING */ + ); + } + } + if (typeof objectValue !== "string") { + throw new ErrorCoded( + `Detected non-string @id in context entry: '${key}': '${JSON.stringify(value)}'`, + "invalid IRI mapping" /* INVALID_IRI_MAPPING */ + ); + } + if (Util.getPrefix(objectValue, context) === key) { + throw new ErrorCoded(`Detected cyclical IRI mapping in context entry: '${key}': '${JSON.stringify(value)}'`, "cyclic IRI mapping" /* CYCLIC_IRI_MAPPING */); + } + break; + case "@type": + if (value["@container"] === "@type" && objectValue !== "@id" && objectValue !== "@vocab") { + throw new ErrorCoded( + `@container: @type only allows @type: @id or @vocab, but got: '${key}': '${objectValue}'`, + "invalid type mapping" /* INVALID_TYPE_MAPPING */ + ); + } + if (typeof objectValue !== "string") { + throw new ErrorCoded( + `The value of an '@type' must be a string, got '${JSON.stringify(valueType)}'`, + "invalid type mapping" /* INVALID_TYPE_MAPPING */ + ); + } + if (objectValue !== "@id" && objectValue !== "@vocab" && (processingMode === 1 || objectValue !== "@json") && (processingMode === 1 || objectValue !== "@none") && (objectValue[0] === "_" || !Util.isValidIri(objectValue))) { + throw new ErrorCoded( + `A context @type must be an absolute IRI, found: '${key}': '${objectValue}'`, + "invalid type mapping" /* INVALID_TYPE_MAPPING */ + ); + } + break; + case "@reverse": + if (typeof objectValue === "string" && value["@id"] && value["@id"] !== objectValue) { + throw new ErrorCoded(`Found non-matching @id and @reverse term values in '${key}':'${objectValue}' and '${value["@id"]}'`, "invalid reverse property" /* INVALID_REVERSE_PROPERTY */); + } + if ("@nest" in value) { + throw new ErrorCoded( + `@nest is not allowed in the reverse property '${key}'`, + "invalid reverse property" /* INVALID_REVERSE_PROPERTY */ + ); + } + break; + case "@container": + if (processingMode === 1) { + if (Object.keys(objectValue).length > 1 || Util.CONTAINERS_1_0.indexOf(Object.keys(objectValue)[0]) < 0) { + throw new ErrorCoded(`Invalid term @container for '${key}' ('${Object.keys(objectValue)}') in 1.0, must be only one of ${Util.CONTAINERS_1_0.join(", ")}`, "invalid container mapping" /* INVALID_CONTAINER_MAPPING */); + } + } + for (const containerValue of Object.keys(objectValue)) { + if (containerValue === "@list" && value["@reverse"]) { + throw new ErrorCoded(`Term value can not be @container: @list and @reverse at the same time on '${key}'`, "invalid reverse property" /* INVALID_REVERSE_PROPERTY */); + } + if (Util.CONTAINERS.indexOf(containerValue) < 0) { + throw new ErrorCoded(`Invalid term @container for '${key}' ('${containerValue}'), must be one of ${Util.CONTAINERS.join(", ")}`, "invalid container mapping" /* INVALID_CONTAINER_MAPPING */); + } + } + break; + case "@language": + _ContextParser.validateLanguage(objectValue, true, "invalid language mapping" /* INVALID_LANGUAGE_MAPPING */); + break; + case "@direction": + _ContextParser.validateDirection(objectValue, true); + break; + case "@prefix": + if (objectValue !== null && typeof objectValue !== "boolean") { + throw new ErrorCoded( + `Found an invalid term @prefix boolean in: '${key}': '${JSON.stringify(value)}'`, + "invalid @prefix value" /* INVALID_PREFIX_VALUE */ + ); + } + if (!("@id" in value) && !Util.isValidIri(key)) { + throw new ErrorCoded( + `Invalid @prefix definition for '${key}' ('${JSON.stringify(value)}'`, + "invalid term definition" /* INVALID_TERM_DEFINITION */ + ); + } + break; + case "@index": + if (processingMode === 1 || !value["@container"] || !value["@container"]["@index"]) { + throw new ErrorCoded(`Attempt to add illegal key to value object: '${key}': '${JSON.stringify(value)}'`, "invalid term definition" /* INVALID_TERM_DEFINITION */); + } + break; + case "@nest": + if (Util.isPotentialKeyword(objectValue) && objectValue !== "@nest") { + throw new ErrorCoded( + `Found an invalid term @nest value in: '${key}': '${JSON.stringify(value)}'`, + "invalid @nest value" /* INVALID_NEST_VALUE */ + ); + } + } + } + break; + default: + throw new ErrorCoded( + `Found an invalid term value: '${key}': '${value}'`, + "invalid term definition" /* INVALID_TERM_DEFINITION */ + ); + } + } + } + } + /** + * Apply the @base context entry to the given context under certain circumstances. + * @param context A context. + * @param options Parsing options. + * @param inheritFromParent If the @base value from the parent context can be inherited. + * @return The given context. + */ + applyBaseEntry(context, options, inheritFromParent) { + if (typeof context === "string") { + return context; + } + if (inheritFromParent && !("@base" in context) && options.parentContext && typeof options.parentContext === "object" && "@base" in options.parentContext) { + context["@base"] = options.parentContext["@base"]; + if (options.parentContext["@__baseDocument"]) { + context["@__baseDocument"] = true; + } + } + if (options.baseIRI && !options.external) { + if (!("@base" in context)) { + context["@base"] = options.baseIRI; + context["@__baseDocument"] = true; + } else if (context["@base"] !== null && typeof context["@base"] === "string" && !Util.isValidIri(context["@base"])) { + context["@base"] = (0, import_relative_to_absolute_iri3.resolve)( + context["@base"], + options.parentContext && options.parentContext["@base"] || options.baseIRI + ); + } + } + return context; + } + /** + * Resolve relative context IRIs, or return full IRIs as-is. + * @param {string} contextIri A context IRI. + * @param {string} baseIRI A base IRI. + * @return {string} The normalized context IRI. + */ + normalizeContextIri(contextIri, baseIRI) { + if (!Util.isValidIri(contextIri)) { + try { + contextIri = (0, import_relative_to_absolute_iri3.resolve)(contextIri, baseIRI); + } catch { + throw new Error(`Invalid context IRI: ${contextIri}`); + } + } + if (this.redirectSchemaOrgHttps && contextIri.startsWith("http://schema.org")) { + contextIri = "https://schema.org/"; + } + return contextIri; + } + /** + * Parse scoped contexts in the given context. + * @param {IJsonLdContextNormalizedRaw} context A context. + * @param {IParseOptions} options Parsing options. + * @return {IJsonLdContextNormalizedRaw} The mutated input context. + * @param {string[]} keys Optional set of keys from the context to parseInnerContexts of. If left undefined, all + * keys in the context will be iterated over. + */ + async parseInnerContexts(context, options, keys) { + for (const key of keys ?? Object.keys(context)) { + const value = context[key]; + if (value && typeof value === "object") { + if ("@context" in value && value["@context"] !== null && !options.ignoreScopedContexts) { + if (this.validateContext) { + try { + const parentContext = { ...context, [key]: { ...context[key] } }; + delete parentContext[key]["@context"]; + await this.parse( + value["@context"], + { ...options, external: false, parentContext, ignoreProtection: true, ignoreRemoteScopedContexts: true, ignoreScopedContexts: true } + ); + } catch (e) { + throw new ErrorCoded(e.message, "invalid scoped context" /* INVALID_SCOPED_CONTEXT */); + } + } + context[key] = { ...value, "@context": (await this.parse( + value["@context"], + { ...options, external: false, minimalProcessing: true, ignoreRemoteScopedContexts: true, parentContext: context } + )).getContextRaw() }; + } + } + } + return context; + } + async parse(context, options = {}, internalOptions = {}) { + const { + baseIRI, + parentContext, + external, + processingMode = _ContextParser.DEFAULT_PROCESSING_MODE, + normalizeLanguageTags, + ignoreProtection, + minimalProcessing + } = options; + const remoteContexts = options.remoteContexts || {}; + if (Object.keys(remoteContexts).length >= this.remoteContextsDepthLimit) { + throw new ErrorCoded( + "Detected an overflow in remote context inclusions: " + Object.keys(remoteContexts), + "context overflow" /* CONTEXT_OVERFLOW */ + ); + } + if (context === null || context === void 0) { + if (!ignoreProtection && parentContext && Util.hasProtectedTerms(parentContext)) { + throw new ErrorCoded( + "Illegal context nullification when terms are protected", + "invalid context nullification" /* INVALID_CONTEXT_NULLIFICATION */ + ); + } + return new JsonLdContextNormalized(this.applyBaseEntry({}, options, false)); + } else if (typeof context === "string") { + const contextIri = this.normalizeContextIri(context, baseIRI); + const overriddenLoad = this.getOverriddenLoad(contextIri, options); + if (overriddenLoad) { + return new JsonLdContextNormalized(overriddenLoad); + } + const parsedStringContext = await this.parse( + await this.load(contextIri), + { + ...options, + baseIRI: contextIri, + external: true, + remoteContexts: { ...remoteContexts, [contextIri]: true } + } + ); + this.applyBaseEntry(parsedStringContext.getContextRaw(), options, true); + return parsedStringContext; + } else if (Array.isArray(context)) { + const contextIris = []; + const contexts = await Promise.all(context.map((subContext, i) => { + if (typeof subContext === "string") { + const contextIri = this.normalizeContextIri(subContext, baseIRI); + contextIris[i] = contextIri; + const overriddenLoad = this.getOverriddenLoad(contextIri, options); + if (overriddenLoad) { + return overriddenLoad; + } + return this.load(contextIri); + } else { + return subContext; + } + })); + if (minimalProcessing) { + return new JsonLdContextNormalized(contexts); + } + const reducedContexts = await contexts.reduce( + (accContextPromise, contextEntry, i) => accContextPromise.then((accContext) => this.parse( + contextEntry, + { + ...options, + baseIRI: contextIris[i] || options.baseIRI, + external: !!contextIris[i] || options.external, + parentContext: accContext.getContextRaw(), + remoteContexts: contextIris[i] ? { ...remoteContexts, [contextIris[i]]: true } : remoteContexts + }, + // @ts-expect-error: This third argument causes a type error because we have hidden it from consumers + { + skipValidation: i < contexts.length - 1 + } + )), + Promise.resolve(new JsonLdContextNormalized(parentContext || {})) + ); + this.applyBaseEntry(reducedContexts.getContextRaw(), options, true); + return reducedContexts; + } else if (typeof context === "object") { + if ("@context" in context) { + if (options?.disallowDirectlyNestedContext) { + throw new ErrorCoded(`Keywords can not be aliased to something else. +Tried mapping @context to ${JSON.stringify(context["@context"])}`, "keyword redefinition" /* KEYWORD_REDEFINITION */); + } + return await this.parse(context["@context"], options); + } + context = { ...context }; + if (external) { + delete context["@base"]; + } + this.applyBaseEntry(context, options, true); + this.containersToHash(context); + if (minimalProcessing) { + return new JsonLdContextNormalized(context); + } + let importContext = {}; + if ("@import" in context) { + if (processingMode >= 1.1) { + if (typeof context["@import"] !== "string") { + throw new ErrorCoded( + "An @import value must be a string, but got " + typeof context["@import"], + "invalid @import value" /* INVALID_IMPORT_VALUE */ + ); + } + importContext = await this.loadImportContext(this.normalizeContextIri(context["@import"], baseIRI)); + delete context["@import"]; + } else { + throw new ErrorCoded( + "Context importing is not supported in JSON-LD 1.0", + "invalid context entry" /* INVALID_CONTEXT_ENTRY */ + ); + } + } + this.applyScopedProtected(importContext, { processingMode }, defaultExpandOptions); + const newContext = Object.assign(importContext, context); + this.idifyReverseTerms(newContext); + this.normalize(newContext, { processingMode, normalizeLanguageTags }); + this.applyScopedProtected(newContext, { processingMode }, defaultExpandOptions); + const keys = Object.keys(newContext); + const overlappingKeys = []; + if (typeof parentContext === "object") { + for (const key in parentContext) { + if (key in newContext) { + overlappingKeys.push(key); + } else { + newContext[key] = parentContext[key]; + } + } + } + await this.parseInnerContexts(newContext, options, keys); + const newContextWrapped = new JsonLdContextNormalized(newContext); + if ((newContext && newContext["@version"] || _ContextParser.DEFAULT_PROCESSING_MODE) >= 1.1 && (context["@vocab"] && typeof context["@vocab"] === "string" || context["@vocab"] === "")) { + if (parentContext && "@vocab" in parentContext && context["@vocab"].indexOf(":") < 0) { + newContext["@vocab"] = parentContext["@vocab"] + context["@vocab"]; + } else if (Util.isCompactIri(context["@vocab"]) || context["@vocab"] in newContext) { + newContext["@vocab"] = newContextWrapped.expandTerm(context["@vocab"], true); + } + } + this.expandPrefixedTerms(newContextWrapped, this.expandContentTypeToBase, keys); + if (!ignoreProtection && parentContext && processingMode >= 1.1) { + this.validateKeywordRedefinitions(parentContext, newContext, defaultExpandOptions, overlappingKeys); + } + if (this.validateContext && !internalOptions.skipValidation) { + this.validate(newContext, { processingMode }); + } + return newContextWrapped; + } else { + throw new ErrorCoded( + `Tried parsing a context that is not a string, array or object, but got ${context}`, + "invalid local context" /* INVALID_LOCAL_CONTEXT */ + ); + } + } + /** + * Fetch the given URL as a raw JSON-LD context. + * @param url An URL. + * @return A promise resolving to a raw JSON-LD context. + */ + async load(url) { + const cached = this.documentCache[url]; + if (cached) { + return cached; + } + let document; + try { + document = await this.documentLoader.load(url); + } catch (e) { + throw new ErrorCoded( + `Failed to load remote context ${url}: ${e.message}`, + "loading remote context failed" /* LOADING_REMOTE_CONTEXT_FAILED */ + ); + } + if (!("@context" in document)) { + throw new ErrorCoded( + `Missing @context in remote context at ${url}`, + "invalid remote context" /* INVALID_REMOTE_CONTEXT */ + ); + } + return this.documentCache[url] = document["@context"]; + } + /** + * Override the given context that may be loaded. + * + * This will check whether or not the url is recursively being loaded. + * @param url An URL. + * @param options Parsing options. + * @return An overridden context, or null. + * Optionally an error can be thrown if a cyclic context is detected. + */ + getOverriddenLoad(url, options) { + if (url in (options.remoteContexts || {})) { + if (options.ignoreRemoteScopedContexts) { + return url; + } else { + throw new ErrorCoded( + "Detected a cyclic context inclusion of " + url, + "recursive context inclusion" /* RECURSIVE_CONTEXT_INCLUSION */ + ); + } + } + return null; + } + /** + * Load an @import'ed context. + * @param importContextIri The full URI of an @import value. + */ + async loadImportContext(importContextIri) { + let importContext = await this.load(importContextIri); + if (typeof importContext !== "object" || Array.isArray(importContext)) { + throw new ErrorCoded( + "An imported context must be a single object: " + importContextIri, + "invalid remote context" /* INVALID_REMOTE_CONTEXT */ + ); + } + if ("@import" in importContext) { + throw new ErrorCoded( + "An imported context can not import another context: " + importContextIri, + "invalid context entry" /* INVALID_CONTEXT_ENTRY */ + ); + } + importContext = { ...importContext }; + this.containersToHash(importContext); + return importContext; + } +}; +export { + ContextParser, + ERROR_CODES, + ErrorCoded, + FetchDocumentLoader, + JsonLdContextNormalized, + Util, + defaultExpandOptions +}; diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..d3e773b --- /dev/null +++ b/docs/index.html @@ -0,0 +1,46 @@ + + + JSON-LD Context Hardener + + + + + + + + + +
+
+
+
+
+ + +
+
+
+
+
+
+
+ + +
+
+
+
+
+ + \ No newline at end of file diff --git a/docs/out.js b/docs/out.js new file mode 100644 index 0000000..b82eb1c --- /dev/null +++ b/docs/out.js @@ -0,0 +1,127 @@ +/* + * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development"). + * This devtool is neither made for production nor for readable output files. + * It uses "eval()" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with "devtool: false". + * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ({ + +/***/ "./node_modules/http-link-header/lib/link.js": +/*!***************************************************!*\ + !*** ./node_modules/http-link-header/lib/link.js ***! + \***************************************************/ +/***/ ((module) => { + +eval("\n\nvar COMPATIBLE_ENCODING_PATTERN = /^utf-?8|ascii|utf-?16-?le|ucs-?2|base-?64|latin-?1$/i\nvar WS_TRIM_PATTERN = /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g\nvar WS_CHAR_PATTERN = /\\s|\\uFEFF|\\xA0/\nvar WS_FOLD_PATTERN = /\\r?\\n[\\x20\\x09]+/g\nvar DELIMITER_PATTERN = /[;,\"]/\nvar WS_DELIMITER_PATTERN = /[;,\"]|\\s/\n\n/**\n * Token character pattern\n * @type {RegExp}\n * @see https://tools.ietf.org/html/rfc7230#section-3.2.6\n */\nvar TOKEN_PATTERN = /^[!#$%&'*+\\-\\.^_`|~\\da-zA-Z]+$/\n\nvar STATE = {\n IDLE: 1 << 0,\n URI: 1 << 1,\n ATTR: 1 << 2,\n}\n\nfunction trim( value ) {\n return value.replace( WS_TRIM_PATTERN, '' )\n}\n\nfunction hasWhitespace( value ) {\n return WS_CHAR_PATTERN.test( value )\n}\n\nfunction skipWhitespace( value, offset ) {\n while( hasWhitespace( value[offset] ) ) {\n offset++\n }\n return offset\n}\n\nfunction needsQuotes( value ) {\n return WS_DELIMITER_PATTERN.test( value ) ||\n !TOKEN_PATTERN.test( value )\n}\n\n/**\n * Shallow compares two objects to check if their properties match.\n * @param {object} object1 First object to compare.\n * @param {object} object2 Second object to compare.\n * @returns {boolean} Do the objects have matching properties.\n */\nfunction shallowCompareObjects( object1, object2 ) {\n return (\n Object.keys( object1 ).length === Object.keys( object2 ).length &&\n Object.keys( object1 ).every(\n ( key ) => key in object2 && object1[ key ] === object2[ key ]\n )\n );\n}\n\nclass Link {\n\n /**\n * Link\n * @constructor\n * @param {String} [value]\n * @returns {Link}\n */\n constructor( value ) {\n\n /** @type {Array} URI references */\n this.refs = []\n\n if( value ) {\n this.parse( value )\n }\n\n }\n\n /**\n * Get refs with given relation type\n * @param {String} value\n * @returns {Array}\n */\n rel( value ) {\n\n var links = []\n var type = value.toLowerCase()\n\n for( var i = 0; i < this.refs.length; i++ ) {\n if( this.refs[ i ].rel.toLowerCase() === type ) {\n links.push( this.refs[ i ] )\n }\n }\n\n return links\n\n }\n\n /**\n * Get refs where given attribute has a given value\n * @param {String} attr\n * @param {String} value\n * @returns {Array}\n */\n get( attr, value ) {\n\n attr = attr.toLowerCase()\n\n var links = []\n\n for( var i = 0; i < this.refs.length; i++ ) {\n if( this.refs[ i ][ attr ] === value ) {\n links.push( this.refs[ i ] )\n }\n }\n\n return links\n\n }\n\n /** Sets a reference. */\n set( link ) {\n this.refs.push( link )\n return this\n }\n\n /**\n * Sets a reference if a reference with similar properties isn’t already set.\n */\n setUnique( link ) {\n\n if( !this.refs.some(( ref ) => shallowCompareObjects( ref, link )) ) {\n this.refs.push( link )\n }\n\n return this\n\n }\n\n has( attr, value ) {\n\n attr = attr.toLowerCase()\n\n for( var i = 0; i < this.refs.length; i++ ) {\n if( this.refs[ i ][ attr ] === value ) {\n return true\n }\n }\n\n return false\n\n }\n\n parse( value, offset ) {\n\n offset = offset || 0\n value = offset ? value.slice( offset ) : value\n\n // Trim & unfold folded lines\n value = trim( value ).replace( WS_FOLD_PATTERN, '' )\n\n var state = STATE.IDLE\n var length = value.length\n var offset = 0\n var ref = null\n\n while( offset < length ) {\n if( state === STATE.IDLE ) {\n if( hasWhitespace( value[offset] ) ) {\n offset++\n continue\n } else if( value[offset] === '<' ) {\n if( ref != null ) {\n ref.rel != null ?\n this.refs.push( ...Link.expandRelations( ref ) ) :\n this.refs.push( ref )\n }\n var end = value.indexOf( '>', offset )\n if( end === -1 ) throw new Error( 'Expected end of URI delimiter at offset ' + offset )\n ref = { uri: value.slice( offset + 1, end ) }\n // this.refs.push( ref )\n offset = end\n state = STATE.URI\n } else {\n throw new Error( 'Unexpected character \"' + value[offset] + '\" at offset ' + offset )\n }\n offset++\n } else if( state === STATE.URI ) {\n if( hasWhitespace( value[offset] ) ) {\n offset++\n continue\n } else if( value[offset] === ';' ) {\n state = STATE.ATTR\n offset++\n } else if( value[offset] === ',' ) {\n state = STATE.IDLE\n offset++\n } else {\n throw new Error( 'Unexpected character \"' + value[offset] + '\" at offset ' + offset )\n }\n } else if( state === STATE.ATTR ) {\n if( value[offset] ===';' || hasWhitespace( value[offset] ) ) {\n offset++\n continue\n }\n var end = value.indexOf( '=', offset )\n if( end === -1 ) throw new Error( 'Expected attribute delimiter at offset ' + offset )\n var attr = trim( value.slice( offset, end ) ).toLowerCase()\n var attrValue = ''\n offset = end + 1\n offset = skipWhitespace( value, offset )\n if( value[offset] === '\"' ) {\n offset++\n while( offset < length ) {\n if( value[offset] === '\"' ) {\n offset++; break\n }\n if( value[offset] === '\\\\' ) {\n offset++\n }\n attrValue += value[offset]\n offset++\n }\n } else {\n var end = offset + 1\n while( !DELIMITER_PATTERN.test( value[end] ) && end < length ) {\n end++\n }\n attrValue = value.slice( offset, end )\n offset = end\n }\n if( ref[ attr ] && Link.isSingleOccurenceAttr( attr ) ) {\n // Ignore multiples of attributes which may only appear once\n } else if( attr[ attr.length - 1 ] === '*' ) {\n ref[ attr ] = Link.parseExtendedValue( attrValue )\n } else {\n attrValue = attr === 'type' ?\n attrValue.toLowerCase() : attrValue\n if( ref[ attr ] != null ) {\n if( Array.isArray( ref[ attr ] ) ) {\n ref[ attr ].push( attrValue )\n } else {\n ref[ attr ] = [ ref[ attr ], attrValue ]\n }\n } else {\n ref[ attr ] = attrValue\n }\n }\n switch( value[offset] ) {\n case ',': state = STATE.IDLE; break\n case ';': state = STATE.ATTR; break\n }\n offset++\n } else {\n throw new Error( 'Unknown parser state \"' + state + '\"' )\n }\n }\n\n if( ref != null ) {\n ref.rel != null ?\n this.refs.push( ...Link.expandRelations( ref ) ) :\n this.refs.push( ref )\n }\n\n ref = null\n\n return this\n\n }\n\n toString() {\n\n var refs = []\n var link = ''\n var ref = null\n\n for( var i = 0; i < this.refs.length; i++ ) {\n ref = this.refs[i]\n link = Object.keys( this.refs[i] ).reduce( function( link, attr ) {\n if( attr === 'uri' ) return link\n return link + '; ' + Link.formatAttribute( attr, ref[ attr ] )\n }, '<' + ref.uri + '>' )\n refs.push( link )\n }\n\n return refs.join( ', ' )\n\n }\n\n}\n\n/**\n * Determines whether an encoding can be\n * natively handled with a `Buffer`\n * @param {String} value\n * @returns {Boolean}\n */\nLink.isCompatibleEncoding = function( value ) {\n return COMPATIBLE_ENCODING_PATTERN.test( value )\n}\n\nLink.parse = function( value, offset ) {\n return new Link().parse( value, offset )\n}\n\nLink.isSingleOccurenceAttr = function( attr ) {\n return attr === 'rel' || attr === 'type' || attr === 'media' ||\n attr === 'title' || attr === 'title*'\n}\n\nLink.isTokenAttr = function( attr ) {\n return attr === 'rel' || attr === 'type' || attr === 'anchor'\n}\n\nLink.escapeQuotes = function( value ) {\n return value.replace( /\"/g, '\\\\\"' )\n}\n\nLink.expandRelations = function( ref ) {\n var rels = ref.rel.split( ' ' )\n return rels.map( function( rel ) {\n var value = Object.assign( {}, ref )\n value.rel = rel\n return value\n })\n}\n\n/**\n * Parses an extended value and attempts to decode it\n * @internal\n * @param {String} value\n * @return {Object}\n */\nLink.parseExtendedValue = function( value ) {\n var parts = /([^']+)?(?:'([^']*)')?(.+)/.exec( value )\n return {\n language: parts[2].toLowerCase(),\n encoding: Link.isCompatibleEncoding( parts[1] ) ?\n null : parts[1].toLowerCase(),\n value: Link.isCompatibleEncoding( parts[1] ) ?\n decodeURIComponent( parts[3] ) : parts[3]\n }\n}\n\n/**\n * Format a given extended attribute and it's value\n * @param {String} attr\n * @param {Object} data\n * @return {String}\n */\nLink.formatExtendedAttribute = function( attr, data ) {\n\n var encoding = ( data.encoding || 'utf-8' ).toUpperCase()\n var language = data.language || 'en'\n\n var encodedValue = ''\n\n if( Buffer.isBuffer( data.value ) && Link.isCompatibleEncoding( encoding ) ) {\n encodedValue = data.value.toString( encoding )\n } else if( Buffer.isBuffer( data.value ) ) {\n encodedValue = data.value.toString( 'hex' )\n .replace( /[0-9a-f]{2}/gi, '%$1' )\n } else {\n encodedValue = encodeURIComponent( data.value )\n }\n\n return attr + '=' + encoding + '\\'' +\n language + '\\'' + encodedValue\n\n}\n\n/**\n * Format a given attribute and it's value\n * @param {String} attr\n * @param {String|Object} value\n * @return {String}\n */\nLink.formatAttribute = function( attr, value ) {\n\n if( Array.isArray( value ) ) {\n return value.map(( item ) => {\n return Link.formatAttribute( attr, item )\n }).join( '; ' )\n }\n\n if( attr[ attr.length - 1 ] === '*' || typeof value !== 'string' ) {\n return Link.formatExtendedAttribute( attr, value )\n }\n\n if( Link.isTokenAttr( attr ) ) {\n value = needsQuotes( value ) ?\n '\"' + Link.escapeQuotes( value ) + '\"' :\n Link.escapeQuotes( value )\n } else if( needsQuotes( value ) ) {\n value = encodeURIComponent( value )\n // We don't need to escape <,> <;> within quotes\n value = value\n .replace( /%20/g, ' ' )\n .replace( /%2C/g, ',' )\n .replace( /%3B/g, ';' )\n\n value = '\"' + value + '\"'\n }\n\n return attr + '=' + value\n\n}\n\nmodule.exports = Link\n\n\n//# sourceURL=webpack://jsonld-context-parser/./node_modules/http-link-header/lib/link.js?"); + +/***/ }), + +/***/ "./node_modules/relative-to-absolute-iri/index.js": +/*!********************************************************!*\ + !*** ./node_modules/relative-to-absolute-iri/index.js ***! + \********************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + +eval("\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n}));\nvar __exportStar = (this && this.__exportStar) || function(m, exports) {\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\n__exportStar(__webpack_require__(/*! ./lib/Resolve */ \"./node_modules/relative-to-absolute-iri/lib/Resolve.js\"), exports);\n//# sourceMappingURL=index.js.map\n\n//# sourceURL=webpack://jsonld-context-parser/./node_modules/relative-to-absolute-iri/index.js?"); + +/***/ }), + +/***/ "./node_modules/relative-to-absolute-iri/lib/Resolve.js": +/*!**************************************************************!*\ + !*** ./node_modules/relative-to-absolute-iri/lib/Resolve.js ***! + \**************************************************************/ +/***/ ((__unused_webpack_module, exports) => { + +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.removeDotSegmentsOfPath = exports.removeDotSegments = exports.resolve = void 0;\n/**\n * Convert the given relative IRI to an absolute IRI\n * by taking into account the given optional baseIRI.\n *\n * @param {string} relativeIRI The relative IRI to convert to an absolute IRI.\n * @param {string} baseIRI The optional base IRI.\n * @return {string} an absolute IRI.\n */\nfunction resolve(relativeIRI, baseIRI) {\n baseIRI = baseIRI || '';\n const baseFragmentPos = baseIRI.indexOf('#');\n // Ignore any fragments in the base IRI\n if (baseFragmentPos > 0) {\n baseIRI = baseIRI.substr(0, baseFragmentPos);\n }\n // Convert empty value directly to base IRI\n if (!relativeIRI.length) {\n // At this point, the baseIRI MUST be absolute, otherwise we error\n if (baseIRI.indexOf(':') < 0) {\n throw new Error(`Found invalid baseIRI '${baseIRI}' for value '${relativeIRI}'`);\n }\n return baseIRI;\n }\n // If the value starts with a query character, concat directly (but strip the existing query)\n if (relativeIRI.startsWith('?')) {\n const baseQueryPos = baseIRI.indexOf('?');\n if (baseQueryPos > 0) {\n baseIRI = baseIRI.substr(0, baseQueryPos);\n }\n return baseIRI + relativeIRI;\n }\n // If the value starts with a fragment character, concat directly\n if (relativeIRI.startsWith('#')) {\n return baseIRI + relativeIRI;\n }\n // Ignore baseIRI if it is empty\n if (!baseIRI.length) {\n const relativeColonPos = relativeIRI.indexOf(':');\n if (relativeColonPos < 0) {\n throw new Error(`Found invalid relative IRI '${relativeIRI}' for a missing baseIRI`);\n }\n return removeDotSegmentsOfPath(relativeIRI, relativeColonPos);\n }\n // Ignore baseIRI if the value is absolute\n const valueColonPos = relativeIRI.indexOf(':');\n if (valueColonPos >= 0) {\n return removeDotSegmentsOfPath(relativeIRI, valueColonPos);\n }\n // At this point, the baseIRI MUST be absolute, otherwise we error\n const baseColonPos = baseIRI.indexOf(':');\n if (baseColonPos < 0) {\n throw new Error(`Found invalid baseIRI '${baseIRI}' for value '${relativeIRI}'`);\n }\n const baseIRIScheme = baseIRI.substr(0, baseColonPos + 1);\n // Inherit the baseIRI scheme if the value starts with '//'\n if (relativeIRI.indexOf('//') === 0) {\n return baseIRIScheme + removeDotSegmentsOfPath(relativeIRI, valueColonPos);\n }\n // Check cases where '://' occurs in the baseIRI, and where there is no '/' after a ':' anymore.\n let baseSlashAfterColonPos;\n if (baseIRI.indexOf('//', baseColonPos) === baseColonPos + 1) {\n // If there is no additional '/' after the '//'.\n baseSlashAfterColonPos = baseIRI.indexOf('/', baseColonPos + 3);\n if (baseSlashAfterColonPos < 0) {\n // If something other than a '/' follows the '://', append the value after a '/',\n // otherwise, prefix the value with only the baseIRI scheme.\n if (baseIRI.length > baseColonPos + 3) {\n return baseIRI + '/' + removeDotSegmentsOfPath(relativeIRI, valueColonPos);\n }\n else {\n return baseIRIScheme + removeDotSegmentsOfPath(relativeIRI, valueColonPos);\n }\n }\n }\n else {\n // If there is not even a single '/' after the ':'\n baseSlashAfterColonPos = baseIRI.indexOf('/', baseColonPos + 1);\n if (baseSlashAfterColonPos < 0) {\n // If we don't have a '/' after the ':',\n // prefix the value with only the baseIRI scheme.\n return baseIRIScheme + removeDotSegmentsOfPath(relativeIRI, valueColonPos);\n }\n }\n // If the value starts with a '/', then prefix it with everything before the first effective slash of the base IRI.\n if (relativeIRI.indexOf('/') === 0) {\n return baseIRI.substr(0, baseSlashAfterColonPos) + removeDotSegments(relativeIRI);\n }\n let baseIRIPath = baseIRI.substr(baseSlashAfterColonPos);\n const baseIRILastSlashPos = baseIRIPath.lastIndexOf('/');\n // Ignore everything after the last '/' in the baseIRI path\n if (baseIRILastSlashPos >= 0 && baseIRILastSlashPos < baseIRIPath.length - 1) {\n baseIRIPath = baseIRIPath.substr(0, baseIRILastSlashPos + 1);\n // Also remove the first character of the relative path if it starts with '.' (and not '..' or './')\n // This change is only allowed if there is something else following the path\n if (relativeIRI[0] === '.' && relativeIRI[1] !== '.' && relativeIRI[1] !== '/' && relativeIRI[2]) {\n relativeIRI = relativeIRI.substr(1);\n }\n }\n // Prefix the value with the baseIRI path where\n relativeIRI = baseIRIPath + relativeIRI;\n // Remove dot segment from the IRI\n relativeIRI = removeDotSegments(relativeIRI);\n // Prefix our transformed value with the part of the baseIRI until the first '/' after the first ':'.\n return baseIRI.substr(0, baseSlashAfterColonPos) + relativeIRI;\n}\nexports.resolve = resolve;\n/**\n * Remove dot segments from the given path,\n * as described in https://www.ietf.org/rfc/rfc3986.txt (page 32).\n * @param {string} path An IRI path.\n * @return {string} A path, will always start with a '/'.\n */\nfunction removeDotSegments(path) {\n // Prepare a buffer with segments between each '/.\n // Each segment represents an array of characters.\n const segmentBuffers = [];\n let i = 0;\n while (i < path.length) {\n // Remove '/.' or '/..'\n switch (path[i]) {\n case '/':\n if (path[i + 1] === '.') {\n if (path[i + 2] === '.') {\n // Start a new segment if we find an invalid character after the '.'\n if (!isCharacterAllowedAfterRelativePathSegment(path[i + 3])) {\n segmentBuffers.push([]);\n i++;\n break;\n }\n // Go to parent directory,\n // so we remove a parent segment\n segmentBuffers.pop();\n // Ensure that we end with a slash if there is a trailing '/..'\n if (!path[i + 3]) {\n segmentBuffers.push([]);\n }\n i += 3;\n }\n else {\n // Start a new segment if we find an invalid character after the '.'\n if (!isCharacterAllowedAfterRelativePathSegment(path[i + 2])) {\n segmentBuffers.push([]);\n i++;\n break;\n }\n // Ensure that we end with a slash if there is a trailing '/.'\n if (!path[i + 2]) {\n segmentBuffers.push([]);\n }\n // Go to the current directory,\n // so we do nothing\n i += 2;\n }\n }\n else {\n // Start a new segment\n segmentBuffers.push([]);\n i++;\n }\n break;\n case '#':\n case '?':\n // Query and fragment string should be appended unchanged\n if (!segmentBuffers.length) {\n segmentBuffers.push([]);\n }\n segmentBuffers[segmentBuffers.length - 1].push(path.substr(i));\n // Break the while loop\n i = path.length;\n break;\n default:\n // Not a special character, just append it to our buffer\n if (!segmentBuffers.length) {\n segmentBuffers.push([]);\n }\n segmentBuffers[segmentBuffers.length - 1].push(path[i]);\n i++;\n break;\n }\n }\n return '/' + segmentBuffers.map((buffer) => buffer.join('')).join('/');\n}\nexports.removeDotSegments = removeDotSegments;\n/**\n * Removes dot segments of the given IRI.\n * @param {string} iri An IRI (or part of IRI).\n * @param {number} colonPosition The position of the first ':' in the IRI.\n * @return {string} The IRI where dot segments were removed.\n */\nfunction removeDotSegmentsOfPath(iri, colonPosition) {\n // Determine where we should start looking for the first '/' that indicates the start of the path\n let searchOffset = colonPosition + 1;\n if (colonPosition >= 0) {\n if (iri[colonPosition + 1] === '/' && iri[colonPosition + 2] === '/') {\n searchOffset = colonPosition + 3;\n }\n }\n else {\n if (iri[0] === '/' && iri[1] === '/') {\n searchOffset = 2;\n }\n }\n // Determine the path\n const pathSeparator = iri.indexOf('/', searchOffset);\n if (pathSeparator < 0) {\n return iri;\n }\n const base = iri.substr(0, pathSeparator);\n const path = iri.substr(pathSeparator);\n // Remove dot segments from the path\n return base + removeDotSegments(path);\n}\nexports.removeDotSegmentsOfPath = removeDotSegmentsOfPath;\nfunction isCharacterAllowedAfterRelativePathSegment(character) {\n return !character || character === '#' || character === '?' || character === '/';\n}\n//# sourceMappingURL=Resolve.js.map\n\n//# sourceURL=webpack://jsonld-context-parser/./node_modules/relative-to-absolute-iri/lib/Resolve.js?"); + +/***/ }), + +/***/ "./lib/ContextParser.ts": +/*!******************************!*\ + !*** ./lib/ContextParser.ts ***! + \******************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.ContextParser = void 0;\nconst relative_to_absolute_iri_1 = __webpack_require__(/*! relative-to-absolute-iri */ \"./node_modules/relative-to-absolute-iri/index.js\");\nconst ErrorCoded_1 = __webpack_require__(/*! ./ErrorCoded */ \"./lib/ErrorCoded.ts\");\nconst FetchDocumentLoader_1 = __webpack_require__(/*! ./FetchDocumentLoader */ \"./lib/FetchDocumentLoader.ts\");\nconst JsonLdContextNormalized_1 = __webpack_require__(/*! ./JsonLdContextNormalized */ \"./lib/JsonLdContextNormalized.ts\");\nconst Util_1 = __webpack_require__(/*! ./Util */ \"./lib/Util.ts\");\n/**\n * Parses JSON-LD contexts.\n */\nclass ContextParser {\n constructor(options) {\n options = options || {};\n this.documentLoader = options.documentLoader || new FetchDocumentLoader_1.FetchDocumentLoader();\n this.documentCache = {};\n this.validateContext = !options.skipValidation;\n this.expandContentTypeToBase = !!options.expandContentTypeToBase;\n this.remoteContextsDepthLimit = options.remoteContextsDepthLimit || 32;\n this.redirectSchemaOrgHttps = 'redirectSchemaOrgHttps' in options ? !!options.redirectSchemaOrgHttps : true;\n }\n /**\n * Validate the given @language value.\n * An error will be thrown if it is invalid.\n * @param value An @language value.\n * @param {boolean} strictRange If the string value should be strictly checked against a regex.\n * @param {string} errorCode The error code to emit on errors.\n * @return {boolean} If validation passed.\n * Can only be false if strictRange is false and the string value did not pass the regex.\n */\n static validateLanguage(value, strictRange, errorCode) {\n if (typeof value !== 'string') {\n throw new ErrorCoded_1.ErrorCoded(`The value of an '@language' must be a string, got '${JSON.stringify(value)}'`, errorCode);\n }\n if (!Util_1.Util.REGEX_LANGUAGE_TAG.test(value)) {\n if (strictRange) {\n throw new ErrorCoded_1.ErrorCoded(`The value of an '@language' must be a valid language tag, got '${JSON.stringify(value)}'`, errorCode);\n }\n else {\n return false;\n }\n }\n return true;\n }\n /**\n * Validate the given @direction value.\n * An error will be thrown if it is invalid.\n * @param value An @direction value.\n * @param {boolean} strictValues If the string value should be strictly checked against a regex.\n * @return {boolean} If validation passed.\n * Can only be false if strictRange is false and the string value did not pass the regex.\n */\n static validateDirection(value, strictValues) {\n if (typeof value !== 'string') {\n throw new ErrorCoded_1.ErrorCoded(`The value of an '@direction' must be a string, got '${JSON.stringify(value)}'`, ErrorCoded_1.ERROR_CODES.INVALID_BASE_DIRECTION);\n }\n if (!Util_1.Util.REGEX_DIRECTION_TAG.test(value)) {\n if (strictValues) {\n throw new ErrorCoded_1.ErrorCoded(`The value of an '@direction' must be 'ltr' or 'rtl', got '${JSON.stringify(value)}'`, ErrorCoded_1.ERROR_CODES.INVALID_BASE_DIRECTION);\n }\n else {\n return false;\n }\n }\n return true;\n }\n /**\n * Add an @id term for all @reverse terms.\n * @param {IJsonLdContextNormalizedRaw} context A context.\n * @return {IJsonLdContextNormalizedRaw} The mutated input context.\n */\n idifyReverseTerms(context) {\n for (const key of Object.keys(context)) {\n let value = context[key];\n if (value && typeof value === 'object') {\n if (value['@reverse'] && !value['@id']) {\n if (typeof value['@reverse'] !== 'string' || Util_1.Util.isValidKeyword(value['@reverse'])) {\n throw new ErrorCoded_1.ErrorCoded(`Invalid @reverse value, must be absolute IRI or blank node: '${value['@reverse']}'`, ErrorCoded_1.ERROR_CODES.INVALID_IRI_MAPPING);\n }\n value = context[key] = Object.assign(Object.assign({}, value), { '@id': value['@reverse'] });\n value['@id'] = value['@reverse'];\n if (Util_1.Util.isPotentialKeyword(value['@reverse'])) {\n delete value['@reverse'];\n }\n else {\n value['@reverse'] = true;\n }\n }\n }\n }\n return context;\n }\n /**\n * Expand all prefixed terms in the given context.\n * @param {IJsonLdContextNormalizedRaw} context A context.\n * @param {boolean} expandContentTypeToBase If @type inside the context may be expanded\n * via @base if @vocab is set to null.\n * @param {string[]} keys Optional set of keys from the context to expand. If left undefined, all\n * keys in the context will be expanded.\n */\n expandPrefixedTerms(context, expandContentTypeToBase, keys) {\n const contextRaw = context.getContextRaw();\n for (const key of (keys || Object.keys(contextRaw))) {\n // Only expand allowed keys\n if (Util_1.Util.EXPAND_KEYS_BLACKLIST.indexOf(key) < 0 && !Util_1.Util.isReservedInternalKeyword(key)) {\n // Error if we try to alias a keyword to something else.\n const keyValue = contextRaw[key];\n if (Util_1.Util.isPotentialKeyword(key) && Util_1.Util.ALIAS_DOMAIN_BLACKLIST.indexOf(key) >= 0) {\n if (key !== '@type' || typeof contextRaw[key] === 'object'\n && !(contextRaw[key]['@protected'] || contextRaw[key]['@container'] === '@set')) {\n throw new ErrorCoded_1.ErrorCoded(`Keywords can not be aliased to something else.\nTried mapping ${key} to ${JSON.stringify(keyValue)}`, ErrorCoded_1.ERROR_CODES.KEYWORD_REDEFINITION);\n }\n }\n // Error if we try to alias to an illegal keyword\n if (Util_1.Util.ALIAS_RANGE_BLACKLIST.indexOf(Util_1.Util.getContextValueId(keyValue)) >= 0) {\n throw new ErrorCoded_1.ErrorCoded(`Aliasing to certain keywords is not allowed.\nTried mapping ${key} to ${JSON.stringify(keyValue)}`, ErrorCoded_1.ERROR_CODES.INVALID_KEYWORD_ALIAS);\n }\n // Error if this term was marked as prefix as well\n if (keyValue && Util_1.Util.isPotentialKeyword(Util_1.Util.getContextValueId(keyValue))\n && keyValue['@prefix'] === true) {\n throw new ErrorCoded_1.ErrorCoded(`Tried to use keyword aliases as prefix: '${key}': '${JSON.stringify(keyValue)}'`, ErrorCoded_1.ERROR_CODES.INVALID_TERM_DEFINITION);\n }\n // Loop because prefixes might be nested\n while (Util_1.Util.isPrefixValue(contextRaw[key])) {\n const value = contextRaw[key];\n let changed = false;\n if (typeof value === 'string') {\n contextRaw[key] = context.expandTerm(value, true);\n changed = changed || value !== contextRaw[key];\n }\n else {\n const id = value['@id'];\n const type = value['@type'];\n // If @id is missing, don't allow @id to be added if @prefix: true and key not being a valid IRI.\n const canAddIdEntry = !('@prefix' in value) || Util_1.Util.isValidIri(key);\n if ('@id' in value) {\n // Use @id value for expansion\n if (id !== undefined && id !== null && typeof id === 'string') {\n contextRaw[key] = Object.assign(Object.assign({}, contextRaw[key]), { '@id': context.expandTerm(id, true) });\n changed = changed || id !== contextRaw[key]['@id'];\n }\n }\n else if (!Util_1.Util.isPotentialKeyword(key) && canAddIdEntry) {\n // Add an explicit @id value based on the expanded key value\n const newId = context.expandTerm(key, true);\n if (newId !== key) {\n // Don't set @id if expansion failed\n contextRaw[key] = Object.assign(Object.assign({}, contextRaw[key]), { '@id': newId });\n changed = true;\n }\n }\n if (type && typeof type === 'string' && type !== '@vocab'\n && (!value['@container'] || !value['@container']['@type'])\n && canAddIdEntry) {\n // First check @vocab, then fallback to @base\n let expandedType = context.expandTerm(type, true);\n if (expandContentTypeToBase && type === expandedType) {\n expandedType = context.expandTerm(type, false);\n }\n if (expandedType !== type) {\n changed = true;\n contextRaw[key] = Object.assign(Object.assign({}, contextRaw[key]), { '@type': expandedType });\n }\n }\n }\n if (!changed) {\n break;\n }\n }\n }\n }\n }\n /**\n * Normalize the @language entries in the given context to lowercase.\n * @param {IJsonLdContextNormalizedRaw} context A context.\n * @param {IParseOptions} parseOptions The parsing options.\n */\n normalize(context, { processingMode, normalizeLanguageTags }) {\n // Lowercase language keys in 1.0\n if (normalizeLanguageTags || processingMode === 1.0) {\n for (const key of Object.keys(context)) {\n if (key === '@language' && typeof context[key] === 'string') {\n context[key] = context[key].toLowerCase();\n }\n else {\n const value = context[key];\n if (value && typeof value === 'object') {\n if (typeof value['@language'] === 'string') {\n const lowercase = value['@language'].toLowerCase();\n if (lowercase !== value['@language']) {\n context[key] = Object.assign(Object.assign({}, value), { '@language': lowercase });\n }\n }\n }\n }\n }\n }\n }\n /**\n * Convert all @container strings and array values to hash-based values.\n * @param {IJsonLdContextNormalizedRaw} context A context.\n */\n containersToHash(context) {\n for (const key of Object.keys(context)) {\n const value = context[key];\n if (value && typeof value === 'object') {\n if (typeof value['@container'] === 'string') {\n context[key] = Object.assign(Object.assign({}, value), { '@container': { [value['@container']]: true } });\n }\n else if (Array.isArray(value['@container'])) {\n const newValue = {};\n for (const containerValue of value['@container']) {\n newValue[containerValue] = true;\n }\n context[key] = Object.assign(Object.assign({}, value), { '@container': newValue });\n }\n }\n }\n }\n /**\n * Normalize and apply context-level @protected terms onto each term separately.\n * @param {IJsonLdContextNormalizedRaw} context A context.\n * @param {number} processingMode The processing mode.\n */\n applyScopedProtected(context, { processingMode }, expandOptions) {\n if (processingMode && processingMode >= 1.1) {\n if (context['@protected']) {\n for (const key of Object.keys(context)) {\n if (Util_1.Util.isReservedInternalKeyword(key)) {\n continue;\n }\n if (!Util_1.Util.isPotentialKeyword(key) && !Util_1.Util.isTermProtected(context, key)) {\n const value = context[key];\n if (value && typeof value === 'object') {\n if (!('@protected' in context[key])) {\n // Mark terms with object values as protected if they don't have an @protected: false annotation\n context[key] = Object.assign(Object.assign({}, context[key]), { '@protected': true });\n }\n }\n else {\n // Convert string-based term values to object-based values with @protected: true\n context[key] = {\n '@id': value,\n '@protected': true,\n };\n if (Util_1.Util.isSimpleTermDefinitionPrefix(value, expandOptions)) {\n context[key] = Object.assign(Object.assign({}, context[key]), { '@prefix': true });\n }\n }\n }\n }\n delete context['@protected'];\n }\n }\n }\n /**\n * Check if the given context inheritance does not contain any overrides of protected terms.\n * @param {IJsonLdContextNormalizedRaw} contextBefore The context that may contain some protected terms.\n * @param {IJsonLdContextNormalizedRaw} contextAfter A new context that is being applied on the first one.\n * @param {IExpandOptions} expandOptions Options that are needed for any expansions during this validation.\n * @param {string[]} keys Optional set of keys from the context to validate. If left undefined, all\n * keys defined in contextAfter will be checked.\n */\n validateKeywordRedefinitions(contextBefore, contextAfter, expandOptions, keys) {\n for (const key of (keys !== null && keys !== void 0 ? keys : Object.keys(contextAfter))) {\n if (Util_1.Util.isTermProtected(contextBefore, key)) {\n // The entry in the context before will always be in object-mode\n // If the new entry is in string-mode, convert it to object-mode\n // before checking if it is identical.\n if (typeof contextAfter[key] === 'string') {\n contextAfter[key] = { '@id': contextAfter[key], '@protected': true };\n }\n else {\n // We modify this deliberately,\n // as we need it for the value comparison (they must be identical modulo '@protected')),\n // and for the fact that this new value will override the first one.\n contextAfter[key] = Object.assign(Object.assign({}, contextAfter[key]), { '@protected': true });\n }\n // Error if they are not identical\n if (!Util_1.Util.deepEqual(contextBefore[key], contextAfter[key])) {\n throw new ErrorCoded_1.ErrorCoded(`Attempted to override the protected keyword ${key} from ${JSON.stringify(Util_1.Util.getContextValueId(contextBefore[key]))} to ${JSON.stringify(Util_1.Util.getContextValueId(contextAfter[key]))}`, ErrorCoded_1.ERROR_CODES.PROTECTED_TERM_REDEFINITION);\n }\n }\n }\n }\n /**\n * Validate the entries of the given context.\n * @param {IJsonLdContextNormalizedRaw} context A context.\n * @param {IParseOptions} options The parse options.\n */\n validate(context, { processingMode }) {\n for (const key of Object.keys(context)) {\n // Ignore reserved internal keywords.\n if (Util_1.Util.isReservedInternalKeyword(key)) {\n continue;\n }\n // Do not allow empty term\n if (key === '') {\n throw new ErrorCoded_1.ErrorCoded(`The empty term is not allowed, got: '${key}': '${JSON.stringify(context[key])}'`, ErrorCoded_1.ERROR_CODES.INVALID_TERM_DEFINITION);\n }\n const value = context[key];\n const valueType = typeof value;\n // First check if the key is a keyword\n if (Util_1.Util.isPotentialKeyword(key)) {\n switch (key.substr(1)) {\n case 'vocab':\n if (value !== null && valueType !== 'string') {\n throw new ErrorCoded_1.ErrorCoded(`Found an invalid @vocab IRI: ${value}`, ErrorCoded_1.ERROR_CODES.INVALID_VOCAB_MAPPING);\n }\n break;\n case 'base':\n if (value !== null && valueType !== 'string') {\n throw new ErrorCoded_1.ErrorCoded(`Found an invalid @base IRI: ${context[key]}`, ErrorCoded_1.ERROR_CODES.INVALID_BASE_IRI);\n }\n break;\n case 'language':\n if (value !== null) {\n ContextParser.validateLanguage(value, true, ErrorCoded_1.ERROR_CODES.INVALID_DEFAULT_LANGUAGE);\n }\n break;\n case 'version':\n if (value !== null && valueType !== 'number') {\n throw new ErrorCoded_1.ErrorCoded(`Found an invalid @version number: ${value}`, ErrorCoded_1.ERROR_CODES.INVALID_VERSION_VALUE);\n }\n break;\n case 'direction':\n if (value !== null) {\n ContextParser.validateDirection(value, true);\n }\n break;\n case 'propagate':\n if (processingMode === 1.0) {\n throw new ErrorCoded_1.ErrorCoded(`Found an illegal @propagate keyword: ${value}`, ErrorCoded_1.ERROR_CODES.INVALID_CONTEXT_ENTRY);\n }\n if (value !== null && valueType !== 'boolean') {\n throw new ErrorCoded_1.ErrorCoded(`Found an invalid @propagate value: ${value}`, ErrorCoded_1.ERROR_CODES.INVALID_PROPAGATE_VALUE);\n }\n break;\n }\n // Don't allow keywords to be overridden\n if (Util_1.Util.isValidKeyword(key) && Util_1.Util.isValidKeyword(Util_1.Util.getContextValueId(value))) {\n throw new ErrorCoded_1.ErrorCoded(`Illegal keyword alias in term value, found: '${key}': '${Util_1.Util\n .getContextValueId(value)}'`, ErrorCoded_1.ERROR_CODES.KEYWORD_REDEFINITION);\n }\n continue;\n }\n // Otherwise, consider the key a term\n if (value !== null) {\n switch (valueType) {\n case 'string':\n if (Util_1.Util.getPrefix(value, context) === key) {\n throw new ErrorCoded_1.ErrorCoded(`Detected cyclical IRI mapping in context entry: '${key}': '${JSON\n .stringify(value)}'`, ErrorCoded_1.ERROR_CODES.CYCLIC_IRI_MAPPING);\n }\n if (Util_1.Util.isValidIriWeak(key)) {\n if (value === '@type') {\n throw new ErrorCoded_1.ErrorCoded(`IRIs can not be mapped to @type, found: '${key}': '${value}'`, ErrorCoded_1.ERROR_CODES.INVALID_IRI_MAPPING);\n }\n else if (Util_1.Util.isValidIri(value) && value !== new JsonLdContextNormalized_1.JsonLdContextNormalized(context).expandTerm(key)) {\n throw new ErrorCoded_1.ErrorCoded(`IRIs can not be mapped to other IRIs, found: '${key}': '${value}'`, ErrorCoded_1.ERROR_CODES.INVALID_IRI_MAPPING);\n }\n }\n break;\n case 'object':\n if (!Util_1.Util.isCompactIri(key) && !('@id' in value)\n && (value['@type'] === '@id' ? !context['@base'] : !context['@vocab'])) {\n throw new ErrorCoded_1.ErrorCoded(`Missing @id in context entry: '${key}': '${JSON.stringify(value)}'`, ErrorCoded_1.ERROR_CODES.INVALID_IRI_MAPPING);\n }\n for (const objectKey of Object.keys(value)) {\n const objectValue = value[objectKey];\n if (!objectValue) {\n continue;\n }\n switch (objectKey) {\n case '@id':\n if (Util_1.Util.isValidKeyword(objectValue)\n && objectValue !== '@type' && objectValue !== '@id' && objectValue !== '@graph' && objectValue !== '@nest') {\n throw new ErrorCoded_1.ErrorCoded(`Illegal keyword alias in term value, found: '${key}': '${JSON.stringify(value)}'`, ErrorCoded_1.ERROR_CODES.INVALID_IRI_MAPPING);\n }\n if (Util_1.Util.isValidIriWeak(key)) {\n if (objectValue === '@type') {\n throw new ErrorCoded_1.ErrorCoded(`IRIs can not be mapped to @type, found: '${key}': '${JSON.stringify(value)}'`, ErrorCoded_1.ERROR_CODES.INVALID_IRI_MAPPING);\n }\n else if (Util_1.Util.isValidIri(objectValue)\n && objectValue !== new JsonLdContextNormalized_1.JsonLdContextNormalized(context).expandTerm(key)) {\n throw new ErrorCoded_1.ErrorCoded(`IRIs can not be mapped to other IRIs, found: '${key}': '${JSON.stringify(value)}'`, ErrorCoded_1.ERROR_CODES.INVALID_IRI_MAPPING);\n }\n }\n if (typeof objectValue !== 'string') {\n throw new ErrorCoded_1.ErrorCoded(`Detected non-string @id in context entry: '${key}': '${JSON.stringify(value)}'`, ErrorCoded_1.ERROR_CODES.INVALID_IRI_MAPPING);\n }\n if (Util_1.Util.getPrefix(objectValue, context) === key) {\n throw new ErrorCoded_1.ErrorCoded(`Detected cyclical IRI mapping in context entry: '${key}': '${JSON\n .stringify(value)}'`, ErrorCoded_1.ERROR_CODES.CYCLIC_IRI_MAPPING);\n }\n break;\n case '@type':\n if (value['@container'] === '@type' && objectValue !== '@id' && objectValue !== '@vocab') {\n throw new ErrorCoded_1.ErrorCoded(`@container: @type only allows @type: @id or @vocab, but got: '${key}': '${objectValue}'`, ErrorCoded_1.ERROR_CODES.INVALID_TYPE_MAPPING);\n }\n if (typeof objectValue !== 'string') {\n throw new ErrorCoded_1.ErrorCoded(`The value of an '@type' must be a string, got '${JSON.stringify(valueType)}'`, ErrorCoded_1.ERROR_CODES.INVALID_TYPE_MAPPING);\n }\n if (objectValue !== '@id' && objectValue !== '@vocab'\n && (processingMode === 1.0 || objectValue !== '@json')\n && (processingMode === 1.0 || objectValue !== '@none')\n && (objectValue[0] === '_' || !Util_1.Util.isValidIri(objectValue))) {\n throw new ErrorCoded_1.ErrorCoded(`A context @type must be an absolute IRI, found: '${key}': '${objectValue}'`, ErrorCoded_1.ERROR_CODES.INVALID_TYPE_MAPPING);\n }\n break;\n case '@reverse':\n if (typeof objectValue === 'string' && value['@id'] && value['@id'] !== objectValue) {\n throw new ErrorCoded_1.ErrorCoded(`Found non-matching @id and @reverse term values in '${key}':\\\n'${objectValue}' and '${value['@id']}'`, ErrorCoded_1.ERROR_CODES.INVALID_REVERSE_PROPERTY);\n }\n if ('@nest' in value) {\n throw new ErrorCoded_1.ErrorCoded(`@nest is not allowed in the reverse property '${key}'`, ErrorCoded_1.ERROR_CODES.INVALID_REVERSE_PROPERTY);\n }\n break;\n case '@container':\n if (processingMode === 1.0) {\n if (Object.keys(objectValue).length > 1\n || Util_1.Util.CONTAINERS_1_0.indexOf(Object.keys(objectValue)[0]) < 0) {\n throw new ErrorCoded_1.ErrorCoded(`Invalid term @container for '${key}' ('${Object.keys(objectValue)}') in 1.0, \\\nmust be only one of ${Util_1.Util.CONTAINERS_1_0.join(', ')}`, ErrorCoded_1.ERROR_CODES.INVALID_CONTAINER_MAPPING);\n }\n }\n for (const containerValue of Object.keys(objectValue)) {\n if (containerValue === '@list' && value['@reverse']) {\n throw new ErrorCoded_1.ErrorCoded(`Term value can not be @container: @list and @reverse at the same time on '${key}'`, ErrorCoded_1.ERROR_CODES.INVALID_REVERSE_PROPERTY);\n }\n if (Util_1.Util.CONTAINERS.indexOf(containerValue) < 0) {\n throw new ErrorCoded_1.ErrorCoded(`Invalid term @container for '${key}' ('${containerValue}'), \\\nmust be one of ${Util_1.Util.CONTAINERS.join(', ')}`, ErrorCoded_1.ERROR_CODES.INVALID_CONTAINER_MAPPING);\n }\n }\n break;\n case '@language':\n ContextParser.validateLanguage(objectValue, true, ErrorCoded_1.ERROR_CODES.INVALID_LANGUAGE_MAPPING);\n break;\n case '@direction':\n ContextParser.validateDirection(objectValue, true);\n break;\n case '@prefix':\n if (objectValue !== null && typeof objectValue !== 'boolean') {\n throw new ErrorCoded_1.ErrorCoded(`Found an invalid term @prefix boolean in: '${key}': '${JSON.stringify(value)}'`, ErrorCoded_1.ERROR_CODES.INVALID_PREFIX_VALUE);\n }\n if (!('@id' in value) && !Util_1.Util.isValidIri(key)) {\n throw new ErrorCoded_1.ErrorCoded(`Invalid @prefix definition for '${key}' ('${JSON.stringify(value)}'`, ErrorCoded_1.ERROR_CODES.INVALID_TERM_DEFINITION);\n }\n break;\n case '@index':\n if (processingMode === 1.0 || !value['@container'] || !value['@container']['@index']) {\n throw new ErrorCoded_1.ErrorCoded(`Attempt to add illegal key to value object: '${key}': '${JSON.stringify(value)}'`, ErrorCoded_1.ERROR_CODES.INVALID_TERM_DEFINITION);\n }\n break;\n case '@nest':\n if (Util_1.Util.isPotentialKeyword(objectValue) && objectValue !== '@nest') {\n throw new ErrorCoded_1.ErrorCoded(`Found an invalid term @nest value in: '${key}': '${JSON.stringify(value)}'`, ErrorCoded_1.ERROR_CODES.INVALID_NEST_VALUE);\n }\n }\n }\n break;\n default:\n throw new ErrorCoded_1.ErrorCoded(`Found an invalid term value: '${key}': '${value}'`, ErrorCoded_1.ERROR_CODES.INVALID_TERM_DEFINITION);\n }\n }\n }\n }\n /**\n * Apply the @base context entry to the given context under certain circumstances.\n * @param context A context.\n * @param options Parsing options.\n * @param inheritFromParent If the @base value from the parent context can be inherited.\n * @return The given context.\n */\n applyBaseEntry(context, options, inheritFromParent) {\n // In some special cases, this can be a string, so ignore those.\n if (typeof context === 'string') {\n return context;\n }\n // Give priority to @base in the parent context\n if (inheritFromParent && !('@base' in context) && options.parentContext\n && typeof options.parentContext === 'object' && '@base' in options.parentContext) {\n context['@base'] = options.parentContext['@base'];\n if (options.parentContext['@__baseDocument']) {\n context['@__baseDocument'] = true;\n }\n }\n // Override the base IRI if provided.\n if (options.baseIRI && !options.external) {\n if (!('@base' in context)) {\n // The context base is the document base\n context['@base'] = options.baseIRI;\n context['@__baseDocument'] = true;\n }\n else if (context['@base'] !== null && typeof context['@base'] === 'string'\n && !Util_1.Util.isValidIri(context['@base'])) {\n // The context base is relative to the document base\n context['@base'] = (0, relative_to_absolute_iri_1.resolve)(context['@base'], options.parentContext && options.parentContext['@base'] || options.baseIRI);\n }\n }\n return context;\n }\n /**\n * Resolve relative context IRIs, or return full IRIs as-is.\n * @param {string} contextIri A context IRI.\n * @param {string} baseIRI A base IRI.\n * @return {string} The normalized context IRI.\n */\n normalizeContextIri(contextIri, baseIRI) {\n if (!Util_1.Util.isValidIri(contextIri)) {\n try {\n contextIri = (0, relative_to_absolute_iri_1.resolve)(contextIri, baseIRI);\n }\n catch (_a) {\n throw new Error(`Invalid context IRI: ${contextIri}`);\n }\n }\n // TODO: Temporary workaround for fixing schema.org CORS issues (https://github.com/schemaorg/schemaorg/issues/2578#issuecomment-652324465)\n if (this.redirectSchemaOrgHttps && contextIri.startsWith('http://schema.org')) {\n contextIri = 'https://schema.org/';\n }\n return contextIri;\n }\n /**\n * Parse scoped contexts in the given context.\n * @param {IJsonLdContextNormalizedRaw} context A context.\n * @param {IParseOptions} options Parsing options.\n * @return {IJsonLdContextNormalizedRaw} The mutated input context.\n * @param {string[]} keys Optional set of keys from the context to parseInnerContexts of. If left undefined, all\n * keys in the context will be iterated over.\n */\n async parseInnerContexts(context, options, keys) {\n for (const key of (keys !== null && keys !== void 0 ? keys : Object.keys(context))) {\n const value = context[key];\n if (value && typeof value === 'object') {\n if ('@context' in value && value['@context'] !== null && !options.ignoreScopedContexts) {\n // Simulate a processing based on the parent context to check if there are any (potential errors).\n // Honestly, I find it a bit weird to do this here, as the context may be unused,\n // and the final effective context may differ based on any other embedded/scoped contexts.\n // But hey, it's part of the spec, so we have no choice...\n // https://w3c.github.io/json-ld-api/#h-note-10\n if (this.validateContext) {\n try {\n const parentContext = Object.assign(Object.assign({}, context), { [key]: Object.assign({}, context[key]) });\n delete parentContext[key]['@context'];\n await this.parse(value['@context'], Object.assign(Object.assign({}, options), { external: false, parentContext, ignoreProtection: true, ignoreRemoteScopedContexts: true, ignoreScopedContexts: true }));\n }\n catch (e) {\n throw new ErrorCoded_1.ErrorCoded(e.message, ErrorCoded_1.ERROR_CODES.INVALID_SCOPED_CONTEXT);\n }\n }\n context[key] = Object.assign(Object.assign({}, value), { '@context': (await this.parse(value['@context'], Object.assign(Object.assign({}, options), { external: false, minimalProcessing: true, ignoreRemoteScopedContexts: true, parentContext: context })))\n .getContextRaw() });\n }\n }\n }\n return context;\n }\n async parse(context, options = {}, \n // These options are only for internal use on recursive calls and should not be used by\n // libraries consuming this function\n internalOptions = {}) {\n const { baseIRI, parentContext, external, processingMode = ContextParser.DEFAULT_PROCESSING_MODE, normalizeLanguageTags, ignoreProtection, minimalProcessing, } = options;\n const remoteContexts = options.remoteContexts || {};\n // Avoid remote context overflows\n if (Object.keys(remoteContexts).length >= this.remoteContextsDepthLimit) {\n throw new ErrorCoded_1.ErrorCoded('Detected an overflow in remote context inclusions: ' + Object.keys(remoteContexts), ErrorCoded_1.ERROR_CODES.CONTEXT_OVERFLOW);\n }\n if (context === null || context === undefined) {\n // Don't allow context nullification and there are protected terms\n if (!ignoreProtection && parentContext && Util_1.Util.hasProtectedTerms(parentContext)) {\n throw new ErrorCoded_1.ErrorCoded('Illegal context nullification when terms are protected', ErrorCoded_1.ERROR_CODES.INVALID_CONTEXT_NULLIFICATION);\n }\n // Context that are explicitly set to null are empty.\n return new JsonLdContextNormalized_1.JsonLdContextNormalized(this.applyBaseEntry({}, options, false));\n }\n else if (typeof context === 'string') {\n const contextIri = this.normalizeContextIri(context, baseIRI);\n const overriddenLoad = this.getOverriddenLoad(contextIri, options);\n if (overriddenLoad) {\n return new JsonLdContextNormalized_1.JsonLdContextNormalized(overriddenLoad);\n }\n const parsedStringContext = await this.parse(await this.load(contextIri), Object.assign(Object.assign({}, options), { baseIRI: contextIri, external: true, remoteContexts: Object.assign(Object.assign({}, remoteContexts), { [contextIri]: true }) }));\n this.applyBaseEntry(parsedStringContext.getContextRaw(), options, true);\n return parsedStringContext;\n }\n else if (Array.isArray(context)) {\n // As a performance consideration, first load all external contexts in parallel.\n const contextIris = [];\n const contexts = await Promise.all(context.map((subContext, i) => {\n if (typeof subContext === 'string') {\n const contextIri = this.normalizeContextIri(subContext, baseIRI);\n contextIris[i] = contextIri;\n const overriddenLoad = this.getOverriddenLoad(contextIri, options);\n if (overriddenLoad) {\n return overriddenLoad;\n }\n return this.load(contextIri);\n }\n else {\n return subContext;\n }\n }));\n // Don't apply inheritance logic on minimal processing\n if (minimalProcessing) {\n return new JsonLdContextNormalized_1.JsonLdContextNormalized(contexts);\n }\n const reducedContexts = await contexts.reduce((accContextPromise, contextEntry, i) => accContextPromise\n .then((accContext) => this.parse(contextEntry, Object.assign(Object.assign({}, options), { baseIRI: contextIris[i] || options.baseIRI, external: !!contextIris[i] || options.external, parentContext: accContext.getContextRaw(), remoteContexts: contextIris[i] ? Object.assign(Object.assign({}, remoteContexts), { [contextIris[i]]: true }) : remoteContexts }), \n // @ts-expect-error: This third argument causes a type error because we have hidden it from consumers\n {\n skipValidation: i < contexts.length - 1,\n })), Promise.resolve(new JsonLdContextNormalized_1.JsonLdContextNormalized(parentContext || {})));\n // Override the base IRI if provided.\n this.applyBaseEntry(reducedContexts.getContextRaw(), options, true);\n return reducedContexts;\n }\n else if (typeof context === 'object') {\n if ('@context' in context) {\n if (options === null || options === void 0 ? void 0 : options.disallowDirectlyNestedContext) {\n throw new ErrorCoded_1.ErrorCoded(`Keywords can not be aliased to something else.\nTried mapping @context to ${JSON.stringify(context['@context'])}`, ErrorCoded_1.ERROR_CODES.KEYWORD_REDEFINITION);\n }\n return await this.parse(context['@context'], options);\n }\n // Make a deep clone of the given context, to avoid modifying it.\n context = Object.assign({}, context);\n // According to the JSON-LD spec, @base must be ignored from external contexts.\n if (external) {\n delete context['@base'];\n }\n // Override the base IRI if provided.\n this.applyBaseEntry(context, options, true);\n // Hashify container entries\n // Do this before protected term validation as that influences term format\n this.containersToHash(context);\n // Don't perform any other modifications if only minimal processing is needed.\n if (minimalProcessing) {\n return new JsonLdContextNormalized_1.JsonLdContextNormalized(context);\n }\n // In JSON-LD 1.1, load @import'ed context prior to processing.\n let importContext = {};\n if ('@import' in context) {\n if (processingMode >= 1.1) {\n // Only accept string values\n if (typeof context['@import'] !== 'string') {\n throw new ErrorCoded_1.ErrorCoded('An @import value must be a string, but got ' + typeof context['@import'], ErrorCoded_1.ERROR_CODES.INVALID_IMPORT_VALUE);\n }\n // Load context\n importContext = await this.loadImportContext(this.normalizeContextIri(context['@import'], baseIRI));\n delete context['@import'];\n }\n else {\n throw new ErrorCoded_1.ErrorCoded('Context importing is not supported in JSON-LD 1.0', ErrorCoded_1.ERROR_CODES.INVALID_CONTEXT_ENTRY);\n }\n }\n this.applyScopedProtected(importContext, { processingMode }, JsonLdContextNormalized_1.defaultExpandOptions);\n const newContext = Object.assign(importContext, context);\n // Handle terms (before protection checks)\n this.idifyReverseTerms(newContext);\n this.normalize(newContext, { processingMode, normalizeLanguageTags });\n this.applyScopedProtected(newContext, { processingMode }, JsonLdContextNormalized_1.defaultExpandOptions);\n const keys = Object.keys(newContext);\n const overlappingKeys = [];\n if (typeof parentContext === 'object') {\n // Merge different parts of the final context in order\n for (const key in parentContext) {\n if (key in newContext) {\n overlappingKeys.push(key);\n }\n else {\n newContext[key] = parentContext[key];\n }\n }\n }\n // Parse inner contexts with minimal processing\n await this.parseInnerContexts(newContext, options, keys);\n const newContextWrapped = new JsonLdContextNormalized_1.JsonLdContextNormalized(newContext);\n // In JSON-LD 1.1, @vocab can be relative to @vocab in the parent context, or a compact IRI.\n if ((newContext && newContext['@version'] || ContextParser.DEFAULT_PROCESSING_MODE) >= 1.1\n && ((context['@vocab'] && typeof context['@vocab'] === 'string') || context['@vocab'] === '')) {\n if (parentContext && '@vocab' in parentContext && context['@vocab'].indexOf(':') < 0) {\n newContext['@vocab'] = parentContext['@vocab'] + context['@vocab'];\n }\n else if (Util_1.Util.isCompactIri(context['@vocab']) || context['@vocab'] in newContext) {\n // @vocab is a compact IRI or refers exactly to a prefix\n newContext['@vocab'] = newContextWrapped.expandTerm(context['@vocab'], true);\n }\n }\n this.expandPrefixedTerms(newContextWrapped, this.expandContentTypeToBase, keys);\n // In JSON-LD 1.1, check if we are not redefining any protected keywords\n if (!ignoreProtection && parentContext && processingMode >= 1.1) {\n this.validateKeywordRedefinitions(parentContext, newContext, JsonLdContextNormalized_1.defaultExpandOptions, overlappingKeys);\n }\n if (this.validateContext && !internalOptions.skipValidation) {\n this.validate(newContext, { processingMode });\n }\n return newContextWrapped;\n }\n else {\n throw new ErrorCoded_1.ErrorCoded(`Tried parsing a context that is not a string, array or object, but got ${context}`, ErrorCoded_1.ERROR_CODES.INVALID_LOCAL_CONTEXT);\n }\n }\n /**\n * Fetch the given URL as a raw JSON-LD context.\n * @param url An URL.\n * @return A promise resolving to a raw JSON-LD context.\n */\n async load(url) {\n // First try to retrieve the context from cache\n const cached = this.documentCache[url];\n if (cached) {\n return cached;\n }\n // If not in cache, load it\n let document;\n try {\n document = await this.documentLoader.load(url);\n }\n catch (e) {\n throw new ErrorCoded_1.ErrorCoded(`Failed to load remote context ${url}: ${e.message}`, ErrorCoded_1.ERROR_CODES.LOADING_REMOTE_CONTEXT_FAILED);\n }\n // Validate the context\n if (!('@context' in document)) {\n throw new ErrorCoded_1.ErrorCoded(`Missing @context in remote context at ${url}`, ErrorCoded_1.ERROR_CODES.INVALID_REMOTE_CONTEXT);\n }\n return this.documentCache[url] = document['@context'];\n }\n /**\n * Override the given context that may be loaded.\n *\n * This will check whether or not the url is recursively being loaded.\n * @param url An URL.\n * @param options Parsing options.\n * @return An overridden context, or null.\n * Optionally an error can be thrown if a cyclic context is detected.\n */\n getOverriddenLoad(url, options) {\n if (url in (options.remoteContexts || {})) {\n if (options.ignoreRemoteScopedContexts) {\n return url;\n }\n else {\n throw new ErrorCoded_1.ErrorCoded('Detected a cyclic context inclusion of ' + url, ErrorCoded_1.ERROR_CODES.RECURSIVE_CONTEXT_INCLUSION);\n }\n }\n return null;\n }\n /**\n * Load an @import'ed context.\n * @param importContextIri The full URI of an @import value.\n */\n async loadImportContext(importContextIri) {\n // Load the context - and do a deep clone since we are about to mutate it\n let importContext = await this.load(importContextIri);\n // Require the context to be a non-array object\n if (typeof importContext !== 'object' || Array.isArray(importContext)) {\n throw new ErrorCoded_1.ErrorCoded('An imported context must be a single object: ' + importContextIri, ErrorCoded_1.ERROR_CODES.INVALID_REMOTE_CONTEXT);\n }\n // Error if the context contains another @import\n if ('@import' in importContext) {\n throw new ErrorCoded_1.ErrorCoded('An imported context can not import another context: ' + importContextIri, ErrorCoded_1.ERROR_CODES.INVALID_CONTEXT_ENTRY);\n }\n importContext = Object.assign({}, importContext);\n // Containers have to be converted into hash values the same way as for the importing context\n // Otherwise context validation will fail for container values\n this.containersToHash(importContext);\n return importContext;\n }\n}\nContextParser.DEFAULT_PROCESSING_MODE = 1.1;\nexports.ContextParser = ContextParser;\n\n\n//# sourceURL=webpack://jsonld-context-parser/./lib/ContextParser.ts?"); + +/***/ }), + +/***/ "./lib/ErrorCoded.ts": +/*!***************************!*\ + !*** ./lib/ErrorCoded.ts ***! + \***************************/ +/***/ ((__unused_webpack_module, exports) => { + +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.ERROR_CODES = exports.ErrorCoded = void 0;\n/**\n * An error that has a certain error code.\n *\n * The error code can be any string.\n * All standardized error codes are listed in {@link ERROR_CODES}.\n */\nclass ErrorCoded extends Error {\n /* istanbul ignore next */\n constructor(message, code) {\n super(message);\n this.code = code;\n }\n}\nexports.ErrorCoded = ErrorCoded;\n/**\n * All standardized JSON-LD error codes.\n * @see https://w3c.github.io/json-ld-api/#dom-jsonlderrorcode\n */\n// tslint:disable:object-literal-sort-keys\nvar ERROR_CODES;\n(function (ERROR_CODES) {\n ERROR_CODES[\"COLLIDING_KEYWORDS\"] = \"colliding keywords\";\n ERROR_CODES[\"CONFLICTING_INDEXES\"] = \"conflicting indexes\";\n ERROR_CODES[\"CYCLIC_IRI_MAPPING\"] = \"cyclic IRI mapping\";\n ERROR_CODES[\"INVALID_ID_VALUE\"] = \"invalid @id value\";\n ERROR_CODES[\"INVALID_INDEX_VALUE\"] = \"invalid @index value\";\n ERROR_CODES[\"INVALID_NEST_VALUE\"] = \"invalid @nest value\";\n ERROR_CODES[\"INVALID_PREFIX_VALUE\"] = \"invalid @prefix value\";\n ERROR_CODES[\"INVALID_PROPAGATE_VALUE\"] = \"invalid @propagate value\";\n ERROR_CODES[\"INVALID_REVERSE_VALUE\"] = \"invalid @reverse value\";\n ERROR_CODES[\"INVALID_IMPORT_VALUE\"] = \"invalid @import value\";\n ERROR_CODES[\"INVALID_VERSION_VALUE\"] = \"invalid @version value\";\n ERROR_CODES[\"INVALID_BASE_IRI\"] = \"invalid base IRI\";\n ERROR_CODES[\"INVALID_CONTAINER_MAPPING\"] = \"invalid container mapping\";\n ERROR_CODES[\"INVALID_CONTEXT_ENTRY\"] = \"invalid context entry\";\n ERROR_CODES[\"INVALID_CONTEXT_NULLIFICATION\"] = \"invalid context nullification\";\n ERROR_CODES[\"INVALID_DEFAULT_LANGUAGE\"] = \"invalid default language\";\n ERROR_CODES[\"INVALID_INCLUDED_VALUE\"] = \"invalid @included value\";\n ERROR_CODES[\"INVALID_IRI_MAPPING\"] = \"invalid IRI mapping\";\n ERROR_CODES[\"INVALID_JSON_LITERAL\"] = \"invalid JSON literal\";\n ERROR_CODES[\"INVALID_KEYWORD_ALIAS\"] = \"invalid keyword alias\";\n ERROR_CODES[\"INVALID_LANGUAGE_MAP_VALUE\"] = \"invalid language map value\";\n ERROR_CODES[\"INVALID_LANGUAGE_MAPPING\"] = \"invalid language mapping\";\n ERROR_CODES[\"INVALID_LANGUAGE_TAGGED_STRING\"] = \"invalid language-tagged string\";\n ERROR_CODES[\"INVALID_LANGUAGE_TAGGED_VALUE\"] = \"invalid language-tagged value\";\n ERROR_CODES[\"INVALID_LOCAL_CONTEXT\"] = \"invalid local context\";\n ERROR_CODES[\"INVALID_REMOTE_CONTEXT\"] = \"invalid remote context\";\n ERROR_CODES[\"INVALID_REVERSE_PROPERTY\"] = \"invalid reverse property\";\n ERROR_CODES[\"INVALID_REVERSE_PROPERTY_MAP\"] = \"invalid reverse property map\";\n ERROR_CODES[\"INVALID_REVERSE_PROPERTY_VALUE\"] = \"invalid reverse property value\";\n ERROR_CODES[\"INVALID_SCOPED_CONTEXT\"] = \"invalid scoped context\";\n ERROR_CODES[\"INVALID_SCRIPT_ELEMENT\"] = \"invalid script element\";\n ERROR_CODES[\"INVALID_SET_OR_LIST_OBJECT\"] = \"invalid set or list object\";\n ERROR_CODES[\"INVALID_TERM_DEFINITION\"] = \"invalid term definition\";\n ERROR_CODES[\"INVALID_TYPE_MAPPING\"] = \"invalid type mapping\";\n ERROR_CODES[\"INVALID_TYPE_VALUE\"] = \"invalid type value\";\n ERROR_CODES[\"INVALID_TYPED_VALUE\"] = \"invalid typed value\";\n ERROR_CODES[\"INVALID_VALUE_OBJECT\"] = \"invalid value object\";\n ERROR_CODES[\"INVALID_VALUE_OBJECT_VALUE\"] = \"invalid value object value\";\n ERROR_CODES[\"INVALID_VOCAB_MAPPING\"] = \"invalid vocab mapping\";\n ERROR_CODES[\"IRI_CONFUSED_WITH_PREFIX\"] = \"IRI confused with prefix\";\n ERROR_CODES[\"KEYWORD_REDEFINITION\"] = \"keyword redefinition\";\n ERROR_CODES[\"LOADING_DOCUMENT_FAILED\"] = \"loading document failed\";\n ERROR_CODES[\"LOADING_REMOTE_CONTEXT_FAILED\"] = \"loading remote context failed\";\n ERROR_CODES[\"MULTIPLE_CONTEXT_LINK_HEADERS\"] = \"multiple context link headers\";\n ERROR_CODES[\"PROCESSING_MODE_CONFLICT\"] = \"processing mode conflict\";\n ERROR_CODES[\"PROTECTED_TERM_REDEFINITION\"] = \"protected term redefinition\";\n ERROR_CODES[\"CONTEXT_OVERFLOW\"] = \"context overflow\";\n ERROR_CODES[\"INVALID_BASE_DIRECTION\"] = \"invalid base direction\";\n ERROR_CODES[\"RECURSIVE_CONTEXT_INCLUSION\"] = \"recursive context inclusion\";\n ERROR_CODES[\"INVALID_STREAMING_KEY_ORDER\"] = \"invalid streaming key order\";\n /**\n * JSON-LD-star\n */\n ERROR_CODES[\"INVALID_EMBEDDED_NODE\"] = \"invalid embedded node\";\n ERROR_CODES[\"INVALID_ANNOTATION\"] = \"invalid annotation\";\n})(ERROR_CODES = exports.ERROR_CODES || (exports.ERROR_CODES = {}));\n\n\n//# sourceURL=webpack://jsonld-context-parser/./lib/ErrorCoded.ts?"); + +/***/ }), + +/***/ "./lib/FetchDocumentLoader.ts": +/*!************************************!*\ + !*** ./lib/FetchDocumentLoader.ts ***! + \************************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.FetchDocumentLoader = void 0;\nconst ErrorCoded_1 = __webpack_require__(/*! ./ErrorCoded */ \"./lib/ErrorCoded.ts\");\nconst http_link_header_1 = __webpack_require__(/*! http-link-header */ \"./node_modules/http-link-header/lib/link.js\");\nconst relative_to_absolute_iri_1 = __webpack_require__(/*! relative-to-absolute-iri */ \"./node_modules/relative-to-absolute-iri/index.js\");\n/**\n * Loads documents via the fetch API.\n */\nclass FetchDocumentLoader {\n constructor(fetcher) {\n this.fetcher = fetcher;\n }\n async load(url) {\n const response = await (this.fetcher || fetch)(url, { headers: new Headers({ accept: 'application/ld+json' }) });\n if (response.ok && response.headers) {\n let mediaType = response.headers.get('Content-Type');\n if (mediaType) {\n const colonPos = mediaType.indexOf(';');\n if (colonPos > 0) {\n mediaType = mediaType.substr(0, colonPos);\n }\n }\n if (mediaType === 'application/ld+json') {\n // Return JSON-LD if proper content type was returned\n return (await response.json());\n }\n else {\n // Check for alternate link for a non-JSON-LD response\n if (response.headers.has('Link')) {\n let alternateUrl;\n response.headers.forEach((value, key) => {\n if (key === 'link') {\n const linkHeader = (0, http_link_header_1.parse)(value);\n for (const link of linkHeader.get('type', 'application/ld+json')) {\n if (link.rel === 'alternate') {\n if (alternateUrl) {\n throw new Error('Multiple JSON-LD alternate links were found on ' + url);\n }\n alternateUrl = (0, relative_to_absolute_iri_1.resolve)(link.uri, url);\n }\n }\n }\n });\n if (alternateUrl) {\n return this.load(alternateUrl);\n }\n }\n throw new ErrorCoded_1.ErrorCoded(`Unsupported JSON-LD media type ${mediaType}`, ErrorCoded_1.ERROR_CODES.LOADING_DOCUMENT_FAILED);\n }\n }\n else {\n throw new Error(response.statusText || `Status code: ${response.status}`);\n }\n }\n}\nexports.FetchDocumentLoader = FetchDocumentLoader;\n\n\n//# sourceURL=webpack://jsonld-context-parser/./lib/FetchDocumentLoader.ts?"); + +/***/ }), + +/***/ "./lib/JsonLdContextNormalized.ts": +/*!****************************************!*\ + !*** ./lib/JsonLdContextNormalized.ts ***! + \****************************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.defaultExpandOptions = exports.JsonLdContextNormalized = void 0;\nconst relative_to_absolute_iri_1 = __webpack_require__(/*! relative-to-absolute-iri */ \"./node_modules/relative-to-absolute-iri/index.js\");\nconst ErrorCoded_1 = __webpack_require__(/*! ./ErrorCoded */ \"./lib/ErrorCoded.ts\");\nconst Util_1 = __webpack_require__(/*! ./Util */ \"./lib/Util.ts\");\n/**\n * A class exposing operations over a normalized JSON-LD context.\n */\nclass JsonLdContextNormalized {\n constructor(contextRaw) {\n this.contextRaw = contextRaw;\n }\n /**\n * @return The raw inner context.\n */\n getContextRaw() {\n return this.contextRaw;\n }\n /**\n * Expand the term or prefix of the given term if it has one,\n * otherwise return the term as-is.\n *\n * This will try to expand the IRI as much as possible.\n *\n * Iff in vocab-mode, then other references to other terms in the context can be used,\n * such as to `myTerm`:\n * ```\n * {\n * \"myTerm\": \"http://example.org/myLongTerm\"\n * }\n * ```\n *\n * @param {string} term A term that is an URL or a prefixed URL.\n * @param {boolean} expandVocab If the term is a predicate or type and should be expanded based on @vocab,\n * otherwise it is considered a regular term that is expanded based on @base.\n * @param {IExpandOptions} options Options that define the way how expansion must be done.\n * @return {string} The expanded term, the term as-is, or null if it was explicitly disabled in the context.\n * @throws If the term is aliased to an invalid value (not a string, IRI or keyword).\n */\n expandTerm(term, expandVocab, options = exports.defaultExpandOptions) {\n const contextValue = this.contextRaw[term];\n // Immediately return if the term was disabled in the context\n if (contextValue === null || (contextValue && contextValue['@id'] === null)) {\n return null;\n }\n // Check the @id\n let validIriMapping = true;\n if (contextValue && expandVocab) {\n const value = Util_1.Util.getContextValueId(contextValue);\n if (value && value !== term) {\n if (typeof value !== 'string' || (!Util_1.Util.isValidIri(value) && !Util_1.Util.isValidKeyword(value))) {\n // Don't mark this mapping as invalid if we have an unknown keyword, but of the correct form.\n if (!Util_1.Util.isPotentialKeyword(value)) {\n validIriMapping = false;\n }\n }\n else {\n return value;\n }\n }\n }\n // Check if the term is prefixed\n const prefix = Util_1.Util.getPrefix(term, this.contextRaw);\n const vocab = this.contextRaw['@vocab'];\n const vocabRelative = (!!vocab || vocab === '') && vocab.indexOf(':') < 0;\n const base = this.contextRaw['@base'];\n const potentialKeyword = Util_1.Util.isPotentialKeyword(term);\n if (prefix) {\n const contextPrefixValue = this.contextRaw[prefix];\n const value = Util_1.Util.getContextValueId(contextPrefixValue);\n if (value) {\n if (typeof contextPrefixValue === 'string' || !options.allowPrefixForcing) {\n // If we have a simple term definition,\n // check the last character of the prefix to determine whether or not it is a prefix.\n // Validate that prefix ends with gen-delim character, unless @prefix is true\n if (!Util_1.Util.isSimpleTermDefinitionPrefix(value, options)) {\n // Treat the term as an absolute IRI\n return term;\n }\n }\n else {\n // If we have an expanded term definition, default to @prefix: false\n if (value[0] !== '_' && !potentialKeyword && !contextPrefixValue['@prefix'] && !(term in this.contextRaw)) {\n // Treat the term as an absolute IRI\n return term;\n }\n }\n return value + term.substr(prefix.length + 1);\n }\n }\n else if (expandVocab && ((vocab || vocab === '') || (options.allowVocabRelativeToBase && (base && vocabRelative)))\n && !potentialKeyword && !Util_1.Util.isCompactIri(term)) {\n if (vocabRelative) {\n if (options.allowVocabRelativeToBase) {\n return ((vocab || base) ? (0, relative_to_absolute_iri_1.resolve)(vocab, base) : '') + term;\n }\n else {\n throw new ErrorCoded_1.ErrorCoded(`Relative vocab expansion for term '${term}' with vocab '${vocab}' is not allowed.`, ErrorCoded_1.ERROR_CODES.INVALID_VOCAB_MAPPING);\n }\n }\n else {\n return vocab + term;\n }\n }\n else if (!expandVocab && base && !potentialKeyword && !Util_1.Util.isCompactIri(term)) {\n return (0, relative_to_absolute_iri_1.resolve)(term, base);\n }\n // Return the term as-is, unless we discovered an invalid IRI mapping for this term in the context earlier.\n if (validIriMapping) {\n return term;\n }\n else {\n throw new ErrorCoded_1.ErrorCoded(`Invalid IRI mapping found for context entry '${term}': '${JSON.stringify(contextValue)}'`, ErrorCoded_1.ERROR_CODES.INVALID_IRI_MAPPING);\n }\n }\n /**\n * Compact the given term using @base, @vocab, an aliased term, or a prefixed term.\n *\n * This will try to compact the IRI as much as possible.\n *\n * @param {string} iri An IRI to compact.\n * @param {boolean} vocab If the term is a predicate or type and should be compacted based on @vocab,\n * otherwise it is considered a regular term that is compacted based on @base.\n * @return {string} The compacted term or the IRI as-is.\n */\n compactIri(iri, vocab) {\n // Try @vocab compacting\n if (vocab && this.contextRaw['@vocab'] && iri.startsWith(this.contextRaw['@vocab'])) {\n return iri.substr(this.contextRaw['@vocab'].length);\n }\n // Try @base compacting\n if (!vocab && this.contextRaw['@base'] && iri.startsWith(this.contextRaw['@base'])) {\n return iri.substr(this.contextRaw['@base'].length);\n }\n // Loop over all terms in the context\n // This will try to prefix as short as possible.\n // Once a fully compacted alias is found, return immediately, as we can not go any shorter.\n const shortestPrefixing = { prefix: '', suffix: iri };\n for (const key in this.contextRaw) {\n const value = this.contextRaw[key];\n if (value && !Util_1.Util.isPotentialKeyword(key)) {\n const contextIri = Util_1.Util.getContextValueId(value);\n if (iri.startsWith(contextIri)) {\n const suffix = iri.substr(contextIri.length);\n if (!suffix) {\n if (vocab) {\n // Immediately return on compacted alias\n return key;\n }\n }\n else if (suffix.length < shortestPrefixing.suffix.length) {\n // Overwrite the shortest prefix\n shortestPrefixing.prefix = key;\n shortestPrefixing.suffix = suffix;\n }\n }\n }\n }\n // Return the shortest prefix\n if (shortestPrefixing.prefix) {\n return shortestPrefixing.prefix + ':' + shortestPrefixing.suffix;\n }\n return iri;\n }\n}\nexports.JsonLdContextNormalized = JsonLdContextNormalized;\nexports.defaultExpandOptions = {\n allowPrefixForcing: true,\n allowPrefixNonGenDelims: false,\n allowVocabRelativeToBase: true,\n};\n\n\n//# sourceURL=webpack://jsonld-context-parser/./lib/JsonLdContextNormalized.ts?"); + +/***/ }), + +/***/ "./lib/Util.ts": +/*!*********************!*\ + !*** ./lib/Util.ts ***! + \*********************/ +/***/ ((__unused_webpack_module, exports) => { + +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.Util = void 0;\nclass Util {\n /**\n * Check if the given term is a valid compact IRI.\n * Otherwise, it may be an IRI.\n * @param {string} term A term.\n * @return {boolean} If it is a compact IRI.\n */\n static isCompactIri(term) {\n return term.indexOf(':') > 0 && !(term && term[0] === '#');\n }\n /**\n * Get the prefix from the given term.\n * @see https://json-ld.org/spec/latest/json-ld/#compact-iris\n * @param {string} term A term that is an URL or a prefixed URL.\n * @param {IJsonLdContextNormalizedRaw} context A context.\n * @return {string} The prefix or null.\n */\n static getPrefix(term, context) {\n // Do not consider relative IRIs starting with a hash as compact IRIs\n if (term && term[0] === '#') {\n return null;\n }\n const separatorPos = term.indexOf(':');\n if (separatorPos >= 0) {\n // Suffix can not begin with two slashes\n if (term.length > separatorPos + 1\n && term.charAt(separatorPos + 1) === '/'\n && term.charAt(separatorPos + 2) === '/') {\n return null;\n }\n const prefix = term.substr(0, separatorPos);\n // Prefix can not be an underscore (this is a blank node)\n if (prefix === '_') {\n return null;\n }\n // Prefix must match a term in the active context\n if (context[prefix]) {\n return prefix;\n }\n }\n return null;\n }\n /**\n * From a given context entry value, get the string value, or the @id field.\n * @param contextValue A value for a term in a context.\n * @return {string} The id value, or null.\n */\n static getContextValueId(contextValue) {\n if (contextValue === null || typeof contextValue === 'string') {\n return contextValue;\n }\n const id = contextValue['@id'];\n return id ? id : null;\n }\n /**\n * Check if the given simple term definition (string-based value of a context term)\n * should be considered a prefix.\n * @param value A simple term definition value.\n * @param options Options that define the way how expansion must be done.\n */\n static isSimpleTermDefinitionPrefix(value, options) {\n return !Util.isPotentialKeyword(value)\n && (options.allowPrefixNonGenDelims || (typeof value === 'string' && (value[0] === '_' || Util.isPrefixIriEndingWithGenDelim(value))));\n }\n /**\n * Check if the given keyword is of the keyword format \"@\"1*ALPHA.\n * @param {string} keyword A potential keyword.\n * @return {boolean} If the given keyword is of the keyword format.\n */\n static isPotentialKeyword(keyword) {\n return typeof keyword === 'string' && Util.KEYWORD_REGEX.test(keyword);\n }\n /**\n * Check if the given prefix ends with a gen-delim character.\n * @param {string} prefixIri A prefix IRI.\n * @return {boolean} If the given prefix IRI is valid.\n */\n static isPrefixIriEndingWithGenDelim(prefixIri) {\n return Util.ENDS_WITH_GEN_DELIM.test(prefixIri);\n }\n /**\n * Check if the given context value can be a prefix value.\n * @param value A context value.\n * @return {boolean} If it can be a prefix value.\n */\n static isPrefixValue(value) {\n return value && (typeof value === 'string' || (value && typeof value === 'object'));\n }\n /**\n * Check if the given IRI is valid.\n * @param {string} iri A potential IRI.\n * @return {boolean} If the given IRI is valid.\n */\n static isValidIri(iri) {\n return Boolean(iri && Util.IRI_REGEX.test(iri));\n }\n /**\n * Check if the given IRI is valid, this includes the possibility of being a relative IRI.\n * @param {string} iri A potential IRI.\n * @return {boolean} If the given IRI is valid.\n */\n static isValidIriWeak(iri) {\n return !!iri && iri[0] !== ':' && Util.IRI_REGEX_WEAK.test(iri);\n }\n /**\n * Check if the given keyword is a defined according to the JSON-LD specification.\n * @param {string} keyword A potential keyword.\n * @return {boolean} If the given keyword is valid.\n */\n static isValidKeyword(keyword) {\n return Util.VALID_KEYWORDS[keyword];\n }\n /**\n * Check if the given term is protected in the context.\n * @param {IJsonLdContextNormalizedRaw} context A context.\n * @param {string} key A context term.\n * @return {boolean} If the given term has an @protected flag.\n */\n static isTermProtected(context, key) {\n const value = context[key];\n return !(typeof value === 'string') && value && value['@protected'];\n }\n /**\n * Check if the given context has at least one protected term.\n * @param context A context.\n * @return If the context has a protected term.\n */\n static hasProtectedTerms(context) {\n for (const key of Object.keys(context)) {\n if (Util.isTermProtected(context, key)) {\n return true;\n }\n }\n return false;\n }\n /**\n * Check if the given key is an internal reserved keyword.\n * @param key A context key.\n */\n static isReservedInternalKeyword(key) {\n return key.startsWith('@__');\n }\n /**\n * Check if two objects are deepEqual to on another.\n * @param object1 The first object to test.\n * @param object2 The second object to test.\n */\n static deepEqual(object1, object2) {\n const objKeys1 = Object.keys(object1);\n const objKeys2 = Object.keys(object2);\n if (objKeys1.length !== objKeys2.length)\n return false;\n return objKeys1.every((key) => {\n const value1 = object1[key];\n const value2 = object2[key];\n return (value1 === value2) || (value1 !== null &&\n value2 !== null &&\n typeof value1 === \"object\" &&\n typeof value2 === \"object\" &&\n this.deepEqual(value1, value2));\n });\n }\n ;\n}\n// Regex for valid IRIs\nUtil.IRI_REGEX = /^([A-Za-z][A-Za-z0-9+-.]*|_):[^ \"<>{}|\\\\\\[\\]`#]*(#[^#]*)?$/;\n// Weaker regex for valid IRIs, this includes relative IRIs\nUtil.IRI_REGEX_WEAK = /(?::[^:])|\\//;\n// Regex for keyword form\nUtil.KEYWORD_REGEX = /^@[a-z]+$/i;\n// Regex to see if an IRI ends with a gen-delim character (see RFC 3986)\nUtil.ENDS_WITH_GEN_DELIM = /[:/?#\\[\\]@]$/;\n// Regex for language tags\nUtil.REGEX_LANGUAGE_TAG = /^[a-zA-Z]+(-[a-zA-Z0-9]+)*$/;\n// Regex for base directions\nUtil.REGEX_DIRECTION_TAG = /^(ltr)|(rtl)$/;\n// All known valid JSON-LD keywords\n// @see https://www.w3.org/TR/json-ld11/#keywords\nUtil.VALID_KEYWORDS = {\n '@annotation': true,\n '@base': true,\n '@container': true,\n '@context': true,\n '@direction': true,\n '@graph': true,\n '@id': true,\n '@import': true,\n '@included': true,\n '@index': true,\n '@json': true,\n '@language': true,\n '@list': true,\n '@nest': true,\n '@none': true,\n '@prefix': true,\n '@propagate': true,\n '@protected': true,\n '@reverse': true,\n '@set': true,\n '@type': true,\n '@value': true,\n '@version': true,\n '@vocab': true,\n};\n// Keys in the contexts that will not be expanded based on the base IRI\nUtil.EXPAND_KEYS_BLACKLIST = [\n '@base',\n '@vocab',\n '@language',\n '@version',\n '@direction',\n];\n// Keys in the contexts that may not be aliased from\nUtil.ALIAS_DOMAIN_BLACKLIST = [\n '@container',\n '@graph',\n '@id',\n '@index',\n '@list',\n '@nest',\n '@none',\n '@prefix',\n '@reverse',\n '@set',\n '@type',\n '@value',\n '@version',\n];\n// Keys in the contexts that may not be aliased to\nUtil.ALIAS_RANGE_BLACKLIST = [\n '@context',\n '@preserve',\n];\n// All valid @container values\nUtil.CONTAINERS = [\n '@list',\n '@set',\n '@index',\n '@language',\n '@graph',\n '@id',\n '@type',\n];\n// All valid @container values under processing mode 1.0\nUtil.CONTAINERS_1_0 = [\n '@list',\n '@set',\n '@index',\n];\nexports.Util = Util;\n\n\n//# sourceURL=webpack://jsonld-context-parser/./lib/Util.ts?"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = __webpack_require__("./lib/ContextParser.ts"); +/******/ +/******/ })() +; \ No newline at end of file