@opengeospatial/jsonld-ui-utils 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -1,84 +1,84 @@
1
1
  import * as N3 from 'n3';
2
- import * as jsonldLib from 'jsonld';
3
2
  import { RdfXmlParser } from 'rdfxml-streaming-parser';
4
3
 
5
- const jsonFetch = async url => {
6
- const response = await fetch(url, {
7
- headers: {
8
- 'Accept': 'application/json'
9
- }
10
- });
11
- return await response.json();
4
+ const jsonFetch = async (url) => {
5
+ const response = await fetch(url, {
6
+ headers: { 'Accept': 'application/json' },
7
+ });
8
+ return await response.json();
12
9
  };
13
- const mergeContexts = definitions => {
14
- const mergePair = (a, b) => {
15
- if (!a || !Object.keys(a).length) {
16
- return b;
17
- }
18
- const result = {
19
- ...a
10
+ const mergeContexts = (definitions) => {
11
+ const mergePair = (a, b) => {
12
+ if (!a || !Object.keys(a).length) {
13
+ return b;
14
+ }
15
+ const result = { ...a };
16
+ for (const [k, v] of Object.entries(b)) {
17
+ result[k] = v;
18
+ }
19
+ return result;
20
20
  };
21
- for (const [k, v] of Object.entries(b)) {
22
- result[k] = v;
21
+ if (!definitions.length) {
22
+ return {};
23
23
  }
24
- return result;
25
- };
26
- if (!definitions.length) {
27
- return {};
28
- }
29
- if (definitions.length === 1) {
30
- return definitions[0];
31
- }
32
- let currentContext = definitions[0];
33
- for (let i = 1; i < definitions.length; i++) {
34
- currentContext = mergePair(currentContext, definitions[i]);
35
- }
36
- return currentContext;
24
+ if (definitions.length === 1) {
25
+ return definitions[0];
26
+ }
27
+ let currentContext = definitions[0];
28
+ for (let i = 1; i < definitions.length; i++) {
29
+ currentContext = mergePair(currentContext, definitions[i]);
30
+ }
31
+ return currentContext;
37
32
  };
38
33
  async function loadContext(context) {
39
- const loadedUrls = new Map();
40
- const walk = async (definition, refChain) => {
41
- for (const [key, value] of Object.entries(definition)) {
42
- if (key === '@context') {
43
- // @ts-ignore
44
- definition[key] = await load(value, refChain);
45
- } else if (typeof value === 'object' && value !== null) {
46
- await walk(value, refChain);
47
- }
48
- }
49
- };
50
- const load = async (context, refChain) => {
51
- if (context === null || typeof context === 'undefined') {
52
- return {};
34
+ const loadedUrls = new Map();
35
+ const walk = async (definition, refChain) => {
36
+ for (const [key, value] of Object.entries(definition)) {
37
+ if (key === '@context') {
38
+ // @ts-ignore
39
+ definition[key] = await load(value, refChain);
40
+ }
41
+ else if (typeof value === 'object' && value !== null) {
42
+ await walk(value, refChain);
43
+ }
44
+ }
45
+ };
46
+ const load = async (context, refChain) => {
47
+ if (context === null || typeof context === 'undefined') {
48
+ return {};
49
+ }
50
+ if (Array.isArray(context)) {
51
+ // fetch and merge
52
+ const contextEntries = await Promise.all(context.map(e => load(e, refChain)));
53
+ return mergeContexts(contextEntries);
54
+ }
55
+ else if (typeof context === 'object') {
56
+ await walk(context, refChain);
57
+ return context;
58
+ }
59
+ else {
60
+ if (refChain === null || refChain === void 0 ? void 0 : refChain.includes(context)) {
61
+ throw new Error('Circular dependencies found: ' + refChain.join(' -> ') + ' -> ' + context);
62
+ }
63
+ const newRefChain = Array.isArray(refChain) ? refChain === null || refChain === void 0 ? void 0 : refChain.slice() : [];
64
+ newRefChain.push(context);
65
+ let newContext;
66
+ if (!loadedUrls.has(context)) {
67
+ newContext = await jsonFetch(context);
68
+ loadedUrls.set(context, newContext);
69
+ }
70
+ else {
71
+ newContext = loadedUrls.get(context);
72
+ }
73
+ return load(newContext['@context'], newRefChain);
74
+ }
75
+ };
76
+ if (typeof context === 'object' && context !== null && '@context' in context) {
77
+ return load(context['@context']);
53
78
  }
54
- if (Array.isArray(context)) {
55
- // fetch and merge
56
- const contextEntries = await Promise.all(context.map(e => load(e, refChain)));
57
- return mergeContexts(contextEntries);
58
- } else if (typeof context === 'object') {
59
- await walk(context, refChain);
60
- return context;
61
- } else {
62
- if (refChain === null || refChain === void 0 ? void 0 : refChain.includes(context)) {
63
- throw new Error('Circular dependencies found: ' + refChain.join(' -> ') + ' -> ' + context);
64
- }
65
- const newRefChain = Array.isArray(refChain) ? refChain === null || refChain === void 0 ? void 0 : refChain.slice() : [];
66
- newRefChain.push(context);
67
- let newContext;
68
- if (!loadedUrls.has(context)) {
69
- newContext = await jsonFetch(context);
70
- loadedUrls.set(context, newContext);
71
- } else {
72
- newContext = loadedUrls.get(context);
73
- }
74
- return load(newContext['@context'], newRefChain);
79
+ else {
80
+ return load(context);
75
81
  }
76
- };
77
- if (typeof context === 'object' && context !== null && '@context' in context) {
78
- return load(context['@context']);
79
- } else {
80
- return load(context);
81
- }
82
82
  }
83
83
 
84
84
  var jsonld = /*#__PURE__*/Object.freeze({
@@ -86,410 +86,472 @@ var jsonld = /*#__PURE__*/Object.freeze({
86
86
  loadContext: loadContext
87
87
  });
88
88
 
89
- const ns = base => local => `${base}${local}`;
89
+ const ns = (base) => (local) => `${base}${local}`;
90
90
  const SKOS = ns('http://www.w3.org/2004/02/skos/core#');
91
91
  const RDFS = ns('http://www.w3.org/2000/01/rdf-schema#');
92
92
  const DCT = ns('http://purl.org/dc/terms/');
93
93
  const DC = ns('http://purl.org/dc/elements/1.1/');
94
94
  const SDO = ns('https://schema.org/');
95
95
  const FOAF = ns('http://xmlns.com/foaf/0.1/');
96
- const labelPredicates = [SKOS('prefLabel'), DCT('title'), DC('title'), SDO('name'), FOAF('name'), RDFS('label')];
97
- const descriptionPredicates = [SKOS('definition'), DCT('description'), DC('description'), RDFS('comment')];
96
+ const labelPredicates = [
97
+ SKOS('prefLabel'),
98
+ DCT('title'),
99
+ DC('title'),
100
+ SDO('name'),
101
+ FOAF('name'),
102
+ RDFS('label'),
103
+ ];
104
+ const descriptionPredicates = [
105
+ SKOS('definition'),
106
+ DCT('description'),
107
+ DC('description'),
108
+ RDFS('comment'),
109
+ ];
98
110
 
99
111
  const defaultFetchResourceOptions = {
100
- labelPredicates,
101
- descriptionPredicates
112
+ labelPredicates,
113
+ descriptionPredicates,
102
114
  };
103
115
  const fetchResourceCache = {};
104
- const N3_CONTENT_TYPES = new Set(['text/turtle', 'text/n3', 'application/n-triples', 'application/n-quads', 'application/trig', 'text/anot+turtle']);
105
- const ACCEPT_HEADER = ['text/turtle', 'application/n-triples', 'application/n-quads', 'application/trig', 'application/ld+json', 'application/rdf+xml'].join(', ');
106
- function findInStore(store, subjectUri, predicates) {
107
- var _a;
108
- const subj = N3.DataFactory.namedNode(subjectUri);
109
- for (const predUri of predicates) {
110
- const quads = store.getQuads(subj, N3.DataFactory.namedNode(predUri), null, null).filter(q => q.object.termType === 'Literal');
111
- if (!quads.length) continue;
112
- const en = quads.find(q => q.object.language === 'en');
113
- const noLang = quads.find(q => !q.object.language);
114
- return ((_a = en !== null && en !== void 0 ? en : noLang) !== null && _a !== void 0 ? _a : quads[0]).object.value;
115
- }
116
- return null;
116
+ const requestCache = {};
117
+ const N3_CONTENT_TYPES = new Set([
118
+ 'text/turtle',
119
+ 'text/n3',
120
+ 'application/n-triples',
121
+ 'application/n-quads',
122
+ 'application/trig',
123
+ 'text/anot+turtle',
124
+ ]);
125
+ const ACCEPT_HEADER = [
126
+ 'text/turtle',
127
+ 'application/n-triples',
128
+ 'application/n-quads',
129
+ 'application/trig',
130
+ 'application/ld+json',
131
+ 'application/rdf+xml',
132
+ ].join(', ');
133
+ function getUserLanguages() {
134
+ var _a;
135
+ if (typeof navigator !== 'undefined' && ((_a = navigator.languages) === null || _a === void 0 ? void 0 : _a.length)) {
136
+ return Array.from(navigator.languages);
137
+ }
138
+ try {
139
+ return [Intl.DateTimeFormat().resolvedOptions().locale];
140
+ }
141
+ catch (_b) {
142
+ return [];
143
+ }
144
+ }
145
+ function findInStore(store, subjectUri, predicates, userLangs = getUserLanguages()) {
146
+ const subj = N3.DataFactory.namedNode(subjectUri);
147
+ for (const predUri of predicates) {
148
+ const quads = store
149
+ .getQuads(subj, N3.DataFactory.namedNode(predUri), null, null)
150
+ .filter(q => q.object.termType === 'Literal');
151
+ if (!quads.length) {
152
+ continue;
153
+ }
154
+ for (const lang of userLangs) {
155
+ const base = lang.split('-')[0].toLowerCase();
156
+ const match = quads.find(q => {
157
+ var _a;
158
+ const qLang = (_a = q.object.language) === null || _a === void 0 ? void 0 : _a.toLowerCase();
159
+ return qLang === lang.toLowerCase() || (qLang === null || qLang === void 0 ? void 0 : qLang.split('-')[0]) === base;
160
+ });
161
+ if (match) {
162
+ return match.object.value;
163
+ }
164
+ }
165
+ const noLang = quads.find(q => !q.object.language);
166
+ if (noLang) {
167
+ return noLang.object.value;
168
+ }
169
+ const en = quads.find(q => { var _a; return ((_a = q.object.language) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'en'; });
170
+ return (en !== null && en !== void 0 ? en : quads[0]).object.value;
171
+ }
172
+ return null;
117
173
  }
118
174
  function parseTurtle(text, baseIRI, contentType) {
119
- const store = new N3.Store();
120
- const format = contentType === 'text/anot+turtle' ? 'text/turtle' : contentType;
121
- const parser = new N3.Parser({
122
- baseIRI,
123
- format
124
- });
125
- return new Promise((resolve, reject) => {
126
- parser.parse(text, (err, quad) => {
127
- if (err) return reject(err);
128
- if (quad) store.addQuad(quad);else resolve(store);
175
+ const store = new N3.Store();
176
+ const format = contentType === 'text/anot+turtle' ? 'text/turtle' : contentType;
177
+ const parser = new N3.Parser({ baseIRI, format });
178
+ return new Promise((resolve, reject) => {
179
+ parser.parse(text, (err, quad) => {
180
+ if (err) {
181
+ return reject(err);
182
+ }
183
+ if (quad) {
184
+ store.addQuad(quad);
185
+ }
186
+ else {
187
+ resolve(store);
188
+ }
189
+ });
129
190
  });
130
- });
131
191
  }
132
192
  async function parseJsonLd(text, baseIRI) {
133
- const doc = JSON.parse(text);
134
- const nquads = await jsonldLib.toRDF(doc, {
135
- format: 'application/n-quads',
136
- base: baseIRI
137
- });
138
- return parseTurtle(nquads, baseIRI, 'application/n-quads');
193
+ const jsonldMod = await import('jsonld');
194
+ if (!jsonldMod) {
195
+ throw new Error('jsonld peer dependency is not available');
196
+ }
197
+ const doc = JSON.parse(text);
198
+ const nquads = await jsonldMod.toRDF(doc, { format: 'application/n-quads', base: baseIRI });
199
+ return parseTurtle(nquads, baseIRI, 'application/n-quads');
139
200
  }
140
201
  async function parseRdfXml(text, baseIRI) {
141
- const store = new N3.Store();
142
- return new Promise((resolve, reject) => {
143
- const parser = new RdfXmlParser({
144
- baseIRI
202
+ const store = new N3.Store();
203
+ return new Promise((resolve, reject) => {
204
+ const parser = new RdfXmlParser({ baseIRI });
205
+ parser.on('data', (quad) => store.addQuad(quad));
206
+ parser.on('error', reject);
207
+ parser.on('end', () => resolve(store));
208
+ parser.write(text);
209
+ parser.end();
145
210
  });
146
- parser.on('data', quad => store.addQuad(quad));
147
- parser.on('error', reject);
148
- parser.on('end', () => resolve(store));
149
- parser.write(text);
150
- parser.end();
151
- });
152
211
  }
153
- const toArray = val => !val ? [] : Array.isArray(val) ? val : [val];
154
- const getSparqlQuery = uri => `DESCRIBE <${uri}>`;
155
- const tryFetchAndParse = async (fetchFn, uri, options) => {
156
- var _a;
157
- let response;
158
- try {
159
- response = await fetchFn();
160
- if (!response.ok) return null;
161
- } catch (_b) {
162
- return null;
163
- }
164
- const contentType = ((_a = response.headers.get('content-type')) === null || _a === void 0 ? void 0 : _a.split(';')[0].trim()) || 'text/turtle';
165
- const text = await response.text();
166
- let store;
167
- try {
168
- if (N3_CONTENT_TYPES.has(contentType)) {
169
- store = await parseTurtle(text, uri, contentType);
170
- } else if (contentType === 'application/ld+json') {
171
- store = await parseJsonLd(text, uri);
172
- } else if (contentType === 'application/rdf+xml') {
173
- store = await parseRdfXml(text, uri);
174
- } else {
175
- return null;
212
+ const toArray = (val) => !val ? [] : Array.isArray(val) ? val : [val];
213
+ const getSparqlQuery = (uri) => `DESCRIBE <${uri}>`;
214
+ const fetchAndParse = async (fetchFn, baseIRI) => {
215
+ var _a;
216
+ let response;
217
+ try {
218
+ response = await fetchFn();
219
+ if (!response.ok) {
220
+ return null;
221
+ }
222
+ }
223
+ catch (_b) {
224
+ return null;
225
+ }
226
+ const contentType = ((_a = response.headers.get('content-type')) === null || _a === void 0 ? void 0 : _a.split(';')[0].trim()) || 'text/turtle';
227
+ const text = await response.text();
228
+ try {
229
+ if (N3_CONTENT_TYPES.has(contentType)) {
230
+ return parseTurtle(text, baseIRI, contentType);
231
+ }
232
+ if (contentType === 'application/ld+json') {
233
+ return parseJsonLd(text, baseIRI);
234
+ }
235
+ if (contentType === 'application/rdf+xml') {
236
+ return parseRdfXml(text, baseIRI);
237
+ }
238
+ }
239
+ catch (_c) {
176
240
  }
177
- } catch (_c) {
178
241
  return null;
179
- }
180
- const label = findInStore(store, uri, options.labelPredicates);
181
- if (!label) return null;
182
- return {
183
- uri,
184
- label,
185
- description: findInStore(store, uri, options.descriptionPredicates)
186
- };
242
+ };
243
+ const fetchAndParseDocument = (docUrl, fetchFn) => {
244
+ if (!(docUrl in requestCache)) {
245
+ requestCache[docUrl] = fetchAndParse(fetchFn, docUrl);
246
+ }
247
+ return requestCache[docUrl];
248
+ };
249
+ const findResourceInStore = async (storePromise, uri, options) => {
250
+ const store = await storePromise;
251
+ if (!store) {
252
+ return null;
253
+ }
254
+ const label = findInStore(store, uri, options.labelPredicates);
255
+ if (!label) {
256
+ return null;
257
+ }
258
+ return { uri, label, description: findInStore(store, uri, options.descriptionPredicates) };
187
259
  };
188
260
  const actualFetchResource = async (uri, options) => {
189
- // 1. Direct
190
- let result = await tryFetchAndParse(() => fetch(uri, {
191
- headers: {
192
- 'Accept': ACCEPT_HEADER
261
+ const docUrl = uri.includes('#') ? uri.split('#')[0] : uri;
262
+ // 1. Direct (cached by document URL so hash siblings share one request)
263
+ let result = await findResourceInStore(fetchAndParseDocument(docUrl, () => fetch(docUrl, { headers: { 'Accept': ACCEPT_HEADER } })), uri, options);
264
+ // 2. Rainbow proxies (in order) — not supported for hash URIs
265
+ const isHashUri = uri.includes('#');
266
+ for (const instance of [...toArray(options.fallbackRainbowInstances), ...toArray(options.fallbackRainbowInstance)]) {
267
+ if (result || isHashUri) {
268
+ break;
269
+ }
270
+ const rainbowURL = new URL(instance);
271
+ rainbowURL.searchParams.set('uri', uri);
272
+ const rainbowUrlStr = rainbowURL.toString();
273
+ result = await findResourceInStore(fetchAndParseDocument(rainbowUrlStr, () => fetch(rainbowUrlStr, { headers: { 'Accept': ACCEPT_HEADER } })), uri, options);
193
274
  }
194
- }), uri, options);
195
- // 2. Rainbow proxies (in order)
196
- for (const instance of [...toArray(options.fallbackRainbowInstances), ...toArray(options.fallbackRainbowInstance)]) {
197
- if (result) break;
198
- const rainbowURL = new URL(instance);
199
- rainbowURL.searchParams.set('uri', uri);
200
- result = await tryFetchAndParse(() => fetch(rainbowURL.toString(), {
201
- headers: {
202
- 'Accept': ACCEPT_HEADER
203
- }
204
- }), uri, options);
205
- }
206
- // 3. SPARQL endpoints (in order)
207
- for (const endpoint of [...toArray(options.fallbackSparqlEndpoints), ...toArray(options.fallbackSparqlEndpoint)]) {
208
- if (result) break;
209
- const formBody = new URLSearchParams({
210
- query: getSparqlQuery(uri)
211
- });
212
- result = await tryFetchAndParse(() => fetch(endpoint, {
213
- method: 'POST',
214
- headers: {
215
- 'Content-Type': 'application/x-www-form-urlencoded',
216
- 'Accept': 'text/turtle, application/n-triples'
217
- },
218
- body: formBody.toString()
219
- }), uri, options);
220
- }
221
- if (!result) {
222
- throw new Error(`No label data found for <${uri}>`);
223
- }
224
- return result;
275
+ // 3. SPARQL endpoints (in order) — each DESCRIBE is unique per URI, no request cache
276
+ for (const endpoint of [...toArray(options.fallbackSparqlEndpoints), ...toArray(options.fallbackSparqlEndpoint)]) {
277
+ if (result) {
278
+ break;
279
+ }
280
+ const formBody = new URLSearchParams({ query: getSparqlQuery(uri) });
281
+ result = await findResourceInStore(fetchAndParse(() => fetch(endpoint, {
282
+ method: 'POST',
283
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'text/turtle, application/n-triples' },
284
+ body: formBody.toString(),
285
+ }), uri), uri, options);
286
+ }
287
+ if (!result) {
288
+ throw new Error(`No label data found for <${uri}>`);
289
+ }
290
+ return result;
225
291
  };
226
292
  async function fetchResource(uri, options = {}) {
227
- const mergedOptions = {
228
- ...defaultFetchResourceOptions,
229
- ...options
230
- };
231
- if (!(uri in fetchResourceCache)) {
232
- fetchResourceCache[uri] = actualFetchResource(uri, mergedOptions);
233
- }
234
- return fetchResourceCache[uri];
293
+ const mergedOptions = { ...defaultFetchResourceOptions, ...options };
294
+ if (!(uri in fetchResourceCache)) {
295
+ fetchResourceCache[uri] = actualFetchResource(uri, mergedOptions);
296
+ }
297
+ return fetchResourceCache[uri];
235
298
  }
236
299
  async function loadFeature(url) {
237
- const response = await fetch(url, {
238
- headers: {
239
- 'Accept': 'application/ld+json, application/json;q=0.9, */*;q=0.1'
300
+ const response = await fetch(url, {
301
+ headers: {
302
+ 'Accept': 'application/ld+json, application/json;q=0.9, */*;q=0.1',
303
+ },
304
+ });
305
+ if (!response.ok) {
306
+ throw new Error(`Could not load feature ${url}: ${response.status} - ${response.statusText}`);
240
307
  }
241
- });
242
- if (!response.ok) {
243
- throw new Error(`Could not load feature ${url}: ${response.status} - ${response.statusText}`);
244
- }
245
- const feature = await response.json();
246
- const context = await loadContext(feature);
247
- return {
248
- feature,
249
- context
250
- };
308
+ const feature = await response.json();
309
+ const context = await loadContext(feature);
310
+ return {
311
+ feature,
312
+ context,
313
+ };
251
314
  }
252
315
 
253
316
  var resource = /*#__PURE__*/Object.freeze({
254
317
  __proto__: null,
255
318
  defaultFetchResourceOptions: defaultFetchResourceOptions,
256
319
  fetchResource: fetchResource,
320
+ findInStore: findInStore,
257
321
  loadFeature: loadFeature
258
322
  });
259
323
 
260
324
  const defaultAugmentOptions = {
261
- replaceElements: true,
262
- ...defaultFetchResourceOptions
325
+ replaceElements: true,
326
+ ...defaultFetchResourceOptions,
263
327
  };
264
328
  function createPropertiesTable(feature, container, options = {
265
- propertiesField: 'properties'
329
+ propertiesField: 'properties',
266
330
  }) {
267
- const createLevel = (parent, value, addHeaders = false) => {
268
- if (Array.isArray(value)) {
269
- for (const entry of value) {
270
- const newElem = createLevel(parent, entry);
271
- newElem.classList.add('array-entry');
272
- }
273
- return parent;
274
- } else if (value === null || typeof value === 'undefined' || typeof value !== 'object') {
275
- const span = document.createElement('span');
276
- span.classList.add('literal-value');
277
- span.textContent = '' + value;
278
- parent.appendChild(span);
279
- return span;
280
- } else {
281
- const table = document.createElement('table');
282
- table.classList.add('object-table');
283
- if (addHeaders) {
284
- table.innerHTML = '<thead><tr><th>Property</th><th>Value</th></tr></thead>';
285
- }
286
- const tbody = document.createElement('tbody');
287
- Object.entries(value).forEach(([k, v]) => {
288
- const row = document.createElement('tr');
289
- const keyCell = document.createElement('td');
290
- keyCell.classList.add('object-property');
291
- keyCell.setAttribute('data-property', k);
292
- keyCell.textContent = k;
293
- row.appendChild(keyCell);
294
- const valueCell = document.createElement('td');
295
- valueCell.classList.add('object-value');
296
- createLevel(valueCell, v);
297
- row.appendChild(valueCell);
298
- tbody.appendChild(row);
299
- });
300
- table.appendChild(tbody);
301
- parent.appendChild(table);
302
- return table;
303
- }
304
- };
305
- if (options.propertiesField) {
306
- createLevel(container, feature[options.propertiesField], true);
307
- } else {
308
- createLevel(container, feature, true);
309
- }
310
- }
311
- async function augment(rootElem, context, options = {}) {
312
- const mergedOptions = {
313
- ...defaultAugmentOptions,
314
- ...options
315
- };
316
- const resolveTerm = (term, contextStack, useVocab = true, useBase = false) => {
317
- if (term.indexOf('://') !== -1) {
318
- return {
319
- '@id': term
320
- };
321
- }
322
- let closestVocab = null;
323
- let closestBase = null;
324
- for (let i = contextStack.length - 1; i >= 0; i--) {
325
- if (term in contextStack[i]) {
326
- let resolvedTerm = contextStack[i][term];
327
- let resolvedId;
328
- if (resolvedTerm === null || typeof resolvedTerm === 'undefined' || typeof resolvedTerm === 'boolean' || Array.isArray(resolvedTerm)) {
329
- continue;
331
+ const createLevel = (parent, value, addHeaders = false) => {
332
+ if (Array.isArray(value)) {
333
+ for (const entry of value) {
334
+ const newElem = createLevel(parent, entry);
335
+ newElem.classList.add('array-entry');
336
+ }
337
+ return parent;
330
338
  }
331
- if (typeof resolvedTerm === 'string') {
332
- if (resolvedTerm === '@type') {
333
- return {
334
- '@id': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'
335
- };
336
- }
337
- resolvedId = resolvedTerm;
338
- resolvedTerm = {
339
- '@id': resolvedTerm
340
- };
341
- } else if (typeof resolvedTerm === 'object' && '@id' in resolvedTerm && typeof resolvedTerm['@id'] === 'string') {
342
- resolvedId = resolvedTerm['@id'];
343
- } else {
344
- continue;
339
+ else if (value === null || typeof value === 'undefined' || typeof value !== 'object') {
340
+ const span = document.createElement('span');
341
+ span.classList.add('literal-value');
342
+ span.textContent = '' + value;
343
+ parent.appendChild(span);
344
+ return span;
345
345
  }
346
- const idx = resolvedId.indexOf(':');
347
- if (idx > -1) {
348
- const prefix = resolvedId.substring(0, idx);
349
- const localPart = resolvedId.substring(idx + 1);
350
- if (localPart.startsWith('//')) {
351
- // Full URI -> return
352
- return resolvedTerm;
353
- }
354
- const resolvedPrefix = resolveTerm(prefix, contextStack);
355
- if (resolvedPrefix !== null && '@id' in resolvedPrefix && typeof resolvedPrefix['@id'] === 'string') {
356
- // Prefix found and resolved
357
- resolvedTerm['@id'] = `${resolvedPrefix['@id']}${localPart}`;
358
- }
359
- return resolvedTerm;
346
+ else {
347
+ const table = document.createElement('table');
348
+ table.classList.add('object-table');
349
+ if (addHeaders) {
350
+ table.innerHTML = '<thead><tr><th>Property</th><th>Value</th></tr></thead>';
351
+ }
352
+ const tbody = document.createElement('tbody');
353
+ Object.entries(value).forEach(([k, v]) => {
354
+ const row = document.createElement('tr');
355
+ const keyCell = document.createElement('td');
356
+ keyCell.classList.add('object-property');
357
+ keyCell.setAttribute('data-property', k);
358
+ keyCell.textContent = k;
359
+ row.appendChild(keyCell);
360
+ const valueCell = document.createElement('td');
361
+ valueCell.classList.add('object-value');
362
+ createLevel(valueCell, v);
363
+ row.appendChild(valueCell);
364
+ tbody.appendChild(row);
365
+ });
366
+ table.appendChild(tbody);
367
+ parent.appendChild(table);
368
+ return table;
360
369
  }
361
- }
362
- if (closestVocab === null && contextStack[i]['@vocab']) {
363
- closestVocab = contextStack[i]['@vocab'];
364
- }
365
- if (closestBase === null && contextStack[i]['@base']) {
366
- closestBase = contextStack[i]['@base'];
367
- }
370
+ };
371
+ const wrapper = document.createElement('div');
372
+ wrapper.classList.add('object-properties');
373
+ container.appendChild(wrapper);
374
+ if (options.propertiesField) {
375
+ createLevel(wrapper, feature[options.propertiesField], true);
368
376
  }
369
- if (term.indexOf(':') === -1) {
370
- if (useVocab && closestVocab) {
371
- return {
372
- '@id': `${closestVocab}${term}`
373
- };
374
- }
375
- if (useBase && closestBase) {
376
- return {
377
- '@id': `${closestBase}${term}`
378
- };
379
- }
377
+ else {
378
+ createLevel(wrapper, feature, true);
380
379
  }
381
- return null;
382
- };
383
- const findPropertyChildren = elem => {
384
- const walker = document.createTreeWalker(elem, NodeFilter.SHOW_ELEMENT, {
385
- acceptNode(node) {
386
- const nodeElem = node;
387
- if (node !== elem && nodeElem.classList.contains('object-value')) {
388
- return NodeFilter.FILTER_REJECT;
389
- }
390
- if (nodeElem.classList.contains('object-property')) {
391
- return NodeFilter.FILTER_ACCEPT;
380
+ }
381
+ async function augment(rootElem, context, options = {}) {
382
+ const mergedOptions = { ...defaultAugmentOptions, ...options };
383
+ const resolveTerm = (term, contextStack, useVocab = true, useBase = false) => {
384
+ if (term.indexOf('://') !== -1) {
385
+ return { '@id': term };
392
386
  }
393
- return NodeFilter.FILTER_SKIP;
394
- }
395
- });
396
- const result = [];
397
- let cur;
398
- while (cur = walker.nextNode()) {
399
- result.push(cur);
400
- }
401
- return result;
402
- };
403
- const findLiteralChildren = elem => {
404
- const result = [];
405
- const walker = document.createTreeWalker(elem, NodeFilter.SHOW_ELEMENT, {
406
- acceptNode(node) {
407
- const nodeElem = node;
408
- if (nodeElem.classList.contains('object-property') || nodeElem.classList.contains('object-value')) {
409
- return NodeFilter.FILTER_REJECT;
387
+ let closestVocab = null;
388
+ let closestBase = null;
389
+ for (let i = contextStack.length - 1; i >= 0; i--) {
390
+ if (term in contextStack[i]) {
391
+ let resolvedTerm = contextStack[i][term];
392
+ let resolvedId;
393
+ if (resolvedTerm === null || typeof resolvedTerm === 'undefined' || typeof resolvedTerm === 'boolean'
394
+ || Array.isArray(resolvedTerm)) {
395
+ continue;
396
+ }
397
+ if (typeof resolvedTerm === 'string') {
398
+ if (resolvedTerm === '@type') {
399
+ return { '@id': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' };
400
+ }
401
+ resolvedId = resolvedTerm;
402
+ resolvedTerm = { '@id': resolvedTerm };
403
+ }
404
+ else if (typeof resolvedTerm === 'object' && '@id' in resolvedTerm && typeof resolvedTerm['@id'] === 'string') {
405
+ resolvedId = resolvedTerm['@id'];
406
+ }
407
+ else {
408
+ continue;
409
+ }
410
+ const idx = resolvedId.indexOf(':');
411
+ if (idx > -1) {
412
+ const prefix = resolvedId.substring(0, idx);
413
+ const localPart = resolvedId.substring(idx + 1);
414
+ if (localPart.startsWith('//')) {
415
+ // Full URI -> return
416
+ return resolvedTerm;
417
+ }
418
+ const resolvedPrefix = resolveTerm(prefix, contextStack);
419
+ if (resolvedPrefix !== null && '@id' in resolvedPrefix && typeof resolvedPrefix['@id'] === 'string') {
420
+ // Prefix found and resolved
421
+ resolvedTerm['@id'] = `${resolvedPrefix['@id']}${localPart}`;
422
+ }
423
+ return resolvedTerm;
424
+ }
425
+ }
426
+ if (closestVocab === null && contextStack[i]['@vocab']) {
427
+ closestVocab = contextStack[i]['@vocab'];
428
+ }
429
+ if (closestBase === null && contextStack[i]['@base']) {
430
+ closestBase = contextStack[i]['@base'];
431
+ }
410
432
  }
411
- if (nodeElem.classList.contains('literal-value')) {
412
- result.push(nodeElem);
413
- return NodeFilter.FILTER_REJECT;
433
+ if (term.indexOf(':') === -1) {
434
+ if (useVocab && closestVocab) {
435
+ return { '@id': `${closestVocab}${term}` };
436
+ }
437
+ if (useBase && closestBase) {
438
+ return { '@id': `${closestBase}${term}` };
439
+ }
414
440
  }
415
- return NodeFilter.FILTER_SKIP;
416
- }
417
- });
418
- while (walker.nextNode()) {}
419
- return result;
420
- };
421
- const updateElement = (elem, resourceUri, replaceElements = true) => {
422
- elem.setAttribute('data-uri', resourceUri);
423
- elem.classList.add('resource-loading');
424
- fetchResource(resourceUri, mergedOptions).then(resourceData => {
425
- let elemToUpdate = elem.querySelector('.resource-link') || elem;
426
- if (resourceData.label) {
427
- elem.setAttribute('data-label', resourceData.label);
428
- if (mergedOptions.replaceElements) {
429
- elemToUpdate.textContent = resourceData.label;
441
+ return null;
442
+ };
443
+ const findPropertyChildren = (elem) => {
444
+ const walker = document.createTreeWalker(elem, NodeFilter.SHOW_ELEMENT, {
445
+ acceptNode(node) {
446
+ const nodeElem = node;
447
+ if (node !== elem && nodeElem.classList.contains('object-value')) {
448
+ return NodeFilter.FILTER_REJECT;
449
+ }
450
+ if (nodeElem.classList.contains('object-property')) {
451
+ return NodeFilter.FILTER_ACCEPT;
452
+ }
453
+ return NodeFilter.FILTER_SKIP;
454
+ },
455
+ });
456
+ const result = [];
457
+ let cur;
458
+ while ((cur = walker.nextNode())) {
459
+ result.push(cur);
430
460
  }
431
- }
432
- if (resourceData.description) {
433
- elem.setAttribute('data-description', resourceData.description);
434
- if (mergedOptions.replaceElements) {
435
- elemToUpdate.title = resourceData.description;
461
+ return result;
462
+ };
463
+ const findLiteralChildren = (elem) => {
464
+ const result = [];
465
+ const walker = document.createTreeWalker(elem, NodeFilter.SHOW_ELEMENT, {
466
+ acceptNode(node) {
467
+ const nodeElem = node;
468
+ if (nodeElem.classList.contains('object-property') || nodeElem.classList.contains('object-value')) {
469
+ return NodeFilter.FILTER_REJECT;
470
+ }
471
+ if (nodeElem.classList.contains('literal-value')) {
472
+ result.push(nodeElem);
473
+ return NodeFilter.FILTER_REJECT;
474
+ }
475
+ return NodeFilter.FILTER_SKIP;
476
+ },
477
+ });
478
+ while (walker.nextNode()) {
436
479
  }
437
- }
438
- elem.classList.add('resource-resolved');
439
- }).catch(e => {
440
- console.error(`Error resolving URI ${resourceUri}: ${e}`, {
441
- cause: e
442
- });
443
- elem.classList.add('resource-error');
444
- }).finally(() => {
445
- elem.classList.remove('resource-loading');
446
- });
447
- if (replaceElements) {
448
- const link = document.createElement("a");
449
- link.href = resourceUri;
450
- link.target = '_blank';
451
- link.classList.add('resource-link');
452
- while (elem.firstChild) {
453
- link.appendChild(elem.firstChild);
454
- }
455
- elem.appendChild(link);
456
- }
457
- };
458
- const augmentInner = (elem, contextStack) => {
459
- var _a;
460
- const propElems = findPropertyChildren(elem);
461
- for (const propElem of propElems) {
462
- let propertyName = null;
463
- propertyName = propElem.getAttribute('data-property');
464
- if (!propertyName) {
465
- propertyName = propElem.textContent.trim();
466
- }
467
- const resolvedProperty = resolveTerm(propertyName, contextStack);
468
- let newContextStack = contextStack;
469
- const valueElem = (_a = propElem.parentElement) === null || _a === void 0 ? void 0 : _a.querySelector('.object-value');
470
- if (resolvedProperty && '@id' in resolvedProperty && typeof resolvedProperty['@id'] === 'string') {
471
- const propertyUri = resolvedProperty['@id'];
472
- updateElement(propElem, propertyUri, mergedOptions.replaceElements);
473
- if ('@context' in resolvedProperty) {
474
- newContextStack = [...contextStack, resolvedProperty['@context']];
480
+ return result;
481
+ };
482
+ const updateElement = (elem, resourceUri, replaceElements = true) => {
483
+ elem.setAttribute('data-uri', resourceUri);
484
+ elem.classList.add('resource-loading');
485
+ fetchResource(resourceUri, mergedOptions)
486
+ .then(resourceData => {
487
+ let elemToUpdate = elem.querySelector('.resource-link') || elem;
488
+ if (resourceData.label) {
489
+ elem.setAttribute('data-label', resourceData.label);
490
+ if (mergedOptions.replaceElements) {
491
+ elemToUpdate.textContent = resourceData.label;
492
+ }
493
+ }
494
+ if (resourceData.description) {
495
+ elem.setAttribute('data-description', resourceData.description);
496
+ if (mergedOptions.replaceElements) {
497
+ elemToUpdate.title = resourceData.description;
498
+ }
499
+ }
500
+ elem.classList.add('resource-resolved');
501
+ })
502
+ .catch(e => {
503
+ console.error(`Error resolving URI ${resourceUri}: ${e}`, { cause: e });
504
+ elem.classList.add('resource-error');
505
+ })
506
+ .finally(() => {
507
+ elem.classList.remove('resource-loading');
508
+ });
509
+ if (replaceElements) {
510
+ const link = document.createElement("a");
511
+ link.href = resourceUri;
512
+ link.target = '_blank';
513
+ link.classList.add('resource-link');
514
+ while (elem.firstChild) {
515
+ link.appendChild(elem.firstChild);
516
+ }
517
+ elem.appendChild(link);
475
518
  }
476
- if (resolvedProperty['@type'] === '@id' && valueElem) {
477
- const literalElems = findLiteralChildren(valueElem);
478
- literalElems.forEach(literalElem => {
479
- const resolvedLiteral = resolveTerm(literalElem.textContent.trim(), newContextStack, false, true);
480
- if (resolvedLiteral && '@id' in resolvedLiteral && typeof resolvedLiteral['@id'] === 'string') {
481
- const resourceUri = resolvedLiteral['@id'];
482
- updateElement(literalElem, resourceUri, mergedOptions.replaceElements);
519
+ };
520
+ const augmentInner = (elem, contextStack) => {
521
+ var _a;
522
+ const propElems = findPropertyChildren(elem);
523
+ for (const propElem of propElems) {
524
+ let propertyName = null;
525
+ propertyName = propElem.getAttribute('data-property');
526
+ if (!propertyName) {
527
+ propertyName = propElem.textContent.trim();
528
+ }
529
+ const resolvedProperty = resolveTerm(propertyName, contextStack);
530
+ let newContextStack = contextStack;
531
+ const valueElem = (_a = propElem.parentElement) === null || _a === void 0 ? void 0 : _a.querySelector('.object-value');
532
+ if (resolvedProperty && '@id' in resolvedProperty && typeof resolvedProperty['@id'] === 'string') {
533
+ const propertyUri = resolvedProperty['@id'];
534
+ updateElement(propElem, propertyUri, mergedOptions.replaceElements);
535
+ if ('@context' in resolvedProperty) {
536
+ newContextStack = [...contextStack, resolvedProperty['@context']];
537
+ }
538
+ if (resolvedProperty['@type'] === '@id' && valueElem) {
539
+ const literalElems = findLiteralChildren(valueElem);
540
+ literalElems.forEach(literalElem => {
541
+ const resolvedLiteral = resolveTerm(literalElem.textContent.trim(), newContextStack, false, true);
542
+ if (resolvedLiteral && '@id' in resolvedLiteral && typeof resolvedLiteral['@id'] === 'string') {
543
+ const resourceUri = resolvedLiteral['@id'];
544
+ updateElement(literalElem, resourceUri, mergedOptions.replaceElements);
545
+ }
546
+ });
547
+ }
548
+ }
549
+ if (valueElem) {
550
+ augmentInner(valueElem, newContextStack);
483
551
  }
484
- });
485
552
  }
486
- }
487
- if (valueElem) {
488
- augmentInner(valueElem, newContextStack);
489
- }
490
- }
491
- };
492
- augmentInner(rootElem, [context]);
553
+ };
554
+ augmentInner(rootElem, [context]);
493
555
  }
494
556
 
495
557
  var augment$1 = /*#__PURE__*/Object.freeze({
@@ -499,10 +561,10 @@ var augment$1 = /*#__PURE__*/Object.freeze({
499
561
  });
500
562
 
501
563
  var index = {
502
- ...resource,
503
- ...jsonld,
504
- ...augment$1
564
+ ...resource,
565
+ ...jsonld,
566
+ ...augment$1,
505
567
  };
506
568
 
507
- export { augment, createPropertiesTable, index as default, defaultFetchResourceOptions, fetchResource, loadContext, loadFeature };
569
+ export { augment, createPropertiesTable, index as default, defaultFetchResourceOptions, fetchResource, findInStore, loadContext, loadFeature };
508
570
  //# sourceMappingURL=index.esm.js.map