@zengenti/contensis-react-base 3.0.0-beta.76 → 3.0.0-beta.79

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.
@@ -1,4 +1,6 @@
1
- import { Op, Query } from 'contensis-core-api';
1
+ import { c as cachedSearch, h as history, d as deliveryApi, p as pickProject, r as rootSaga } from './App-af0670fa.js';
2
+ export { A as ReactApp } from './App-af0670fa.js';
3
+ import { Query as Query$1 } from 'contensis-delivery-api';
2
4
  import React from 'react';
3
5
  import { Provider } from 'react-redux';
4
6
  import { d as defaultExpressions, c as contentTypeIdExpression, f as filterExpressions, t as termExpressions, o as orderByExpression, a as customWhereExpressions } from './sagas-1f2b2aa0.js';
@@ -8,9 +10,8 @@ import 'deepmerge';
8
10
  import 'query-string';
9
11
  import 'immer';
10
12
  import 'deep-equal';
11
- import { s as setCachingHeaders } from './VersionInfo-f5403b09.js';
12
- import { c as cachedSearch, h as history, d as deliveryApi, p as pickProject, r as rootSaga } from './App-af0670fa.js';
13
- export { A as ReactApp } from './App-af0670fa.js';
13
+ import { Op, Query } from 'contensis-core-api';
14
+ import { s as setCachingHeaders } from './setCachingHeaders-d49060e1.js';
14
15
  import 'isomorphic-fetch';
15
16
  import express from 'express';
16
17
  import httpProxy from 'http-proxy';
@@ -31,11 +32,10 @@ import { CookiesProvider } from 'react-cookie';
31
32
  import { c as createStore, s as setVersionStatus, a as setVersion } from './version-c7268214.js';
32
33
  import { s as setCurrentProject } from './actions-fcfc8704.js';
33
34
  import { s as selectSurrogateKeys, a as selectRouteEntry, b as selectCurrentProject, g as getImmutableOrJS } from './selectors-337be432.js';
34
- import 'loglevel';
35
+ import 'history';
35
36
  import '@redux-saga/core/effects';
36
- import 'contensis-delivery-api';
37
+ import 'loglevel';
37
38
  import './version-6dd7b2cd.js';
38
- import 'history';
39
39
  import './login-ca2dc2f7.js';
40
40
  import './reducers-8e5d6232.js';
41
41
  import './ToJs-affd73f1.js';
@@ -48,254 +48,43 @@ import 'redux-thunk';
48
48
  import 'redux-saga';
49
49
  import 'redux-injectors';
50
50
 
51
- var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
52
-
53
51
  /**
54
- * Make a LinkDepth api at the uri specified in middlewareConfig.
55
- * The api supports a GET request and specified filters are supplied as query-string parameters.
56
- * The response should be a normal Delivery API response.
57
- * @param app Express app instance
58
- * @param middlewareConfig Middleware configuration that represents the content types we want to search within, any filters that are required and any linkFields we wish to search within to derive a set of search results from the entries that contain the linkFields. Each key inside of linkFields represents another "linkDepth" of entries and we can specify all the same contentTypeId, filters, and linkFields of their own. There is no currently no limit on how deep these linkFields can go
59
- * @returns Returns nothing if uri, contentTypeId or linkFields is not set in middlewareConfig
52
+ * Util class holds our search results helper boilerplate methods
60
53
  */
61
- const makeLinkDepthApi = (app, middlewareConfig) => {
62
- const {
63
- uri,
64
- contentTypeId,
65
- linkFields
66
- } = middlewareConfig;
67
- if (!contentTypeId || !linkFields || !uri) return;
68
- app.get(uri, makeLinkDepthMiddleware(middlewareConfig));
69
- };
70
- /** Create a content type hierarchy from supplied config and produces
71
- * a RequestHandler function to serve our Express middleware */
72
-
73
-
74
- const makeLinkDepthMiddleware = ({
75
- contentTypeId,
76
- filters,
77
- sharedFilters,
78
- linkFields
79
- }) => {
80
- try {
81
- // Recursive function to flatten and index a provided nested config
82
- const returnFieldIdKeys = (obj, level = 1) => {
83
- var _Object$entries$map;
84
-
85
- if (!obj) return {};
86
- const mappedConfig = Object.entries(obj).map(([k, v]) => ({
87
- contentTypeIds: Array.isArray(v.contentTypeId) ? v.contentTypeId : [v.contentTypeId || k],
88
- fieldId: k,
89
- filters: v.filters,
90
- sharedFilters: v.sharedFilters
91
- }));
92
- const inner = (_Object$entries$map = Object.entries(obj).map(([k, v]) => returnFieldIdKeys(v.linkFields, level + 1))) === null || _Object$entries$map === void 0 ? void 0 : _Object$entries$map[0];
93
- return {
94
- [level]: mappedConfig,
95
- ...inner
96
- };
97
- };
98
-
99
- const others = returnFieldIdKeys(linkFields); // Level 0 is read from the top-level of config
100
-
101
- const contentTypeHierarchy = {
102
- 0: [{
103
- contentTypeIds: Array.isArray(contentTypeId) ? contentTypeId : [contentTypeId],
104
- filters,
105
- sharedFilters
106
- }],
107
- ...others
108
- }; // The runtime express request handler
109
-
110
- const linkDepthMiddleware = async (req, res) => {
111
- try {
112
- // Short cache duration copied from canterbury project
113
- setCachingHeaders(res, {
114
- cacheControl: 'private',
115
- surrogateControl: '10'
116
- }); // Run our queries and provide a final result
117
- // our params are sourced from the query-string
118
-
119
- const result = await searchEventsTopDown(contentTypeHierarchy, req.query); // const result = await searchLinkDepthEntries(
120
- // contentTypeHierarchy,
121
- // req.query
122
- // );
54
+ class Util {
55
+ static GetIds(entries, fieldId) {
56
+ if (fieldId) {
57
+ return entries === null || entries === void 0 ? void 0 : entries.map(e => {
58
+ var _e$fieldId, _e$fieldId2, _e$fieldId2$sys;
123
59
 
124
- res.json(result);
125
- } catch (error) {
126
- // This is a runtime error encountered when processing a given request
127
- console.error(error);
128
- res.statusCode = 500;
129
- res.json(error);
130
- }
131
- };
60
+ return Array.isArray(e === null || e === void 0 ? void 0 : e[fieldId]) ? e === null || e === void 0 ? void 0 : (_e$fieldId = e[fieldId]) === null || _e$fieldId === void 0 ? void 0 : _e$fieldId.map(f => {
61
+ var _f$sys;
132
62
 
133
- return linkDepthMiddleware;
134
- } catch (error) {
135
- // This will be an error building the middleware
136
- // we can only serve what the error was as the request handler instead
137
- console.error(error);
63
+ return f === null || f === void 0 ? void 0 : (_f$sys = f.sys) === null || _f$sys === void 0 ? void 0 : _f$sys.id;
64
+ }) : (e === null || e === void 0 ? void 0 : (_e$fieldId2 = e[fieldId]) === null || _e$fieldId2 === void 0 ? void 0 : (_e$fieldId2$sys = _e$fieldId2.sys) === null || _e$fieldId2$sys === void 0 ? void 0 : _e$fieldId2$sys.id) || '';
65
+ }).flat();
66
+ }
138
67
 
139
- const errorMiddleware = async (req, res) => {
140
- res.statusCode = 500;
141
- res.json(JSON.stringify(error));
142
- };
68
+ return entries === null || entries === void 0 ? void 0 : entries.map(e => {
69
+ var _e$sys;
143
70
 
144
- return errorMiddleware;
71
+ return (e === null || e === void 0 ? void 0 : (_e$sys = e.sys) === null || _e$sys === void 0 ? void 0 : _e$sys.id) || '';
72
+ });
145
73
  }
146
- };
147
-
148
- const getVarsFromConfig = (config, params) => {
149
- // Build variables from query config to use in our Delivery API Query
150
- const contentTypeIds = config.map(c => c.contentTypeIds).flat(); // Filters are the filters we are looking to include with the Query at this level
151
-
152
- let filters = {}; // Shared filters are filters that share the same querystring key and are valid in multiple levels
153
-
154
- let sharedFilters = {};
155
- config.forEach(c => {
156
- filters = { ...filters,
157
- ...c.filters
158
- };
159
- sharedFilters = { ...sharedFilters,
160
- ...c.sharedFilters
161
- };
162
- }); // FieldIds are the field name(s) in the parent/current entry that the
163
- // entries are linked to, used to surface the next level based on id
164
- // retrieved at the previous level
165
-
166
- const fieldIds = config.map(c => c.fieldId).flat();
167
- const queryFilters = makeFilterExpressions(filters, params);
168
- const sharedQueryFilters = makeFilterExpressions(sharedFilters, params);
169
- return {
170
- contentTypeIds,
171
- fieldIds,
172
- filters,
173
- queryFilters,
174
- sharedFilters,
175
- sharedQueryFilters
176
- };
177
- };
178
-
179
- const makeDerivedIdsFilterExpression = (level, resultsAtLevel, ownIds = false, useFieldIds = false) => {
180
- const previouslyDerivedIdsFilter = [];
181
- const [prevFieldId, entries] = resultsAtLevel[level];
182
- const prevKey = prevFieldId;
183
- const prevResultIds = Util.GetIds(entries, useFieldIds ? prevFieldId : undefined);
184
- if (prevKey && (prevResultIds === null || prevResultIds === void 0 ? void 0 : prevResultIds.length) > 0) previouslyDerivedIdsFilter.push({
185
- key: ownIds ? 'sys.id' : `${prevFieldId}.sys.id`,
186
- values: prevResultIds,
187
- fieldOperator: 'in'
188
- });else previouslyDerivedIdsFilter.push({
189
- key: 'dud',
190
- values: ['1'],
191
- fieldOperator: 'in'
192
- });
193
- return previouslyDerivedIdsFilter;
194
- };
195
-
196
- const searchEventsTopDown = async (contentTypeHierarchy, params) => {
197
- // Determine linkDepth for the final query by how many levels are in
198
- // the contentTypeHierarchy object
199
- const linkDepth = Object.keys(contentTypeHierarchy).length - 1 || 0; // Pre-size our results array to the size of our hierarchy
200
-
201
- const resultsAtLevel = Object.values(contentTypeHierarchy).map((v, i, a) => {
202
- const fieldId = i === 0 ? a[i + 1][0] : v[0];
203
- return [fieldId.fieldId, []];
204
- }); // [fieldId, results][]
205
-
206
- for (const [level, levelConfig] of Object.entries(contentTypeHierarchy)) {
207
- // LinkDepth level / current index
208
- const currentLevel = Number(level); // Build variables from query config to use in our Delivery API Query
209
74
 
210
- const {
211
- contentTypeIds,
212
- fieldIds,
213
- queryFilters,
214
- sharedQueryFilters
215
- } = getVarsFromConfig(levelConfig, params); // We won't have fetched any derived results to
216
- // include as a field filter with the very first query
217
-
218
- let previouslyDerivedIdsFilter = [];
75
+ static GetItems(result) {
76
+ return this.GetResults(result) ? result.items : [];
77
+ }
219
78
 
220
- if (currentLevel !== 0) {
221
- previouslyDerivedIdsFilter = makeDerivedIdsFilterExpression(currentLevel - 1, resultsAtLevel, true, true);
79
+ static GetResults(result) {
80
+ if (result !== null && result !== void 0 && result.items) {
81
+ return result;
82
+ } else {
83
+ return null;
222
84
  }
85
+ }
223
86
 
224
- const query = searchQuery({
225
- contentTypeIds,
226
- filters: queryFilters,
227
- idFilters: previouslyDerivedIdsFilter,
228
- sharedFilters: sharedQueryFilters,
229
- versionStatus: params.versionStatus || 'published'
230
- }); // These are all sub-queries, we only want ids returned in these to include
231
- // them to filter by in our next level(s) queries, along with any other filters
232
- // configured and found at this level
233
-
234
- query.fields = currentLevel === 0 ? [] : ['sys.id']; // Scalability limitation for today
235
-
236
- query.pageSize = 2000;
237
- const levelQueryResult = await cachedSearch.searchUsingPost(query, 0);
238
- resultsAtLevel[currentLevel][1] = Util.GetItems(levelQueryResult);
239
- } // Build and run our final query containing all results
240
-
241
-
242
- const {
243
- contentTypeIds,
244
- queryFilters,
245
- sharedQueryFilters
246
- } = getVarsFromConfig(Object.values(contentTypeHierarchy)[0], params);
247
- const previouslyDerivedIdsFilter = makeDerivedIdsFilterExpression(1, resultsAtLevel);
248
- const query = finalQuery({
249
- contentTypeIds,
250
- filters: queryFilters,
251
- idFilters: previouslyDerivedIdsFilter,
252
- sharedFilters: sharedQueryFilters,
253
- versionStatus: params.versionStatus || 'published'
254
- }, Object.entries(contentTypeHierarchy).filter(([k]) => k !== '0').map(([level, levelConfig]) => {
255
- // LinkDepth level / current index
256
- const currentLevel = Number(level); // Build variables from query config to use in our Delivery API Query
257
-
258
- const {
259
- contentTypeIds,
260
- queryFilters,
261
- sharedQueryFilters
262
- } = getVarsFromConfig(levelConfig, params);
263
- const previousIdsFilter = makeDerivedIdsFilterExpression(currentLevel, resultsAtLevel, true);
264
- return {
265
- contentTypeIds,
266
- filters: queryFilters,
267
- idFilters: previousIdsFilter,
268
- sharedFilters: sharedQueryFilters,
269
- versionStatus: params.versionStatus || 'published'
270
- };
271
- })); // This is the final query to be run and response returned to the caller
272
- // Only this bit cares about linkDepth, fields and pagination parameters
273
-
274
- query.fields = JSON.parse(params.fields || '[]');
275
- query.pageSize = params.pageSize;
276
- query.pageIndex = params.pageIndex;
277
- query.orderBy = params.orderBy; // console.log(JSON.stringify(query.toJSON()));
278
-
279
- const finalQueryResult = await cachedSearch.searchUsingPost(query, linkDepth);
280
- const entriesWithResolvedParents = await resolveParentEntries(contentTypeIds, Array.from(new Set(resultsAtLevel[1][1].map(e => e.sys.contentTypeId || ''))), resultsAtLevel[0][0], Util.GetItems(finalQueryResult), params);
281
- return { ...finalQueryResult,
282
- items: entriesWithResolvedParents
283
- };
284
- };
285
-
286
- const resolveParentEntries = async (parentContentTypeIds, replaceContentTypeIds, parentFieldId, results, params) => {
287
- // Build variables from query config to use in our Delivery API Query
288
- const previousIdsFilter = makeDerivedIdsFilterExpression(0, [[parentFieldId, results]]);
289
- const query = searchQuery({
290
- contentTypeIds: parentContentTypeIds,
291
- idFilters: previousIdsFilter
292
- });
293
- query.fields = JSON.parse(params.fields || '[]');
294
- console.log(JSON.stringify(query.toJSON()));
295
- const parentResults = await cachedSearch.search(query, 0);
296
- return mergeResults(results, Util.GetItems(parentResults), replaceContentTypeIds, parentFieldId);
297
- };
298
-
87
+ }
299
88
  const mergeResults = (results, parentResults, replaceContentTypeIds, linkFieldId) => results.map(r => {
300
89
  if (replaceContentTypeIds.some(c => c === r.sys.contentTypeId)) {
301
90
  const resolvedParent = parentResults === null || parentResults === void 0 ? void 0 : parentResults.find(e => {
@@ -319,30 +108,32 @@ const mergeResults = (results, parentResults, replaceContentTypeIds, linkFieldId
319
108
  return r;
320
109
  }).filter(r => r);
321
110
 
322
- const finalQuery = ({
111
+ /* eslint-disable no-console */
112
+
113
+ /**
114
+ * Builds our complete Delivery API Query object from a set of provided arguments
115
+ * @param queryParams
116
+ * @returns Delivery API Query
117
+ */
118
+ const searchQuery = ({
323
119
  assetTypes,
324
120
  contentTypeIds,
121
+ customWhere,
325
122
  fields,
326
123
  filters,
327
- idFilters,
328
- sharedFilters,
124
+ idFilters = [],
125
+ sharedFilters = [],
329
126
  pageSize,
330
- pageIndex,
127
+ pageIndex = 0,
331
128
  orderBy,
332
129
  searchTerm,
333
130
  versionStatus = 'published',
334
131
  webpageTemplates,
335
132
  weightedSearchFields
336
- }, children) => {
337
- const expressions$1 = [...defaultExpressions(versionStatus), Op.or(Op.and(...contentTypeIdExpression(contentTypeIds, webpageTemplates, assetTypes), ...filterExpressions(filters), Op.or(...filterExpressions(sharedFilters) // Op.and(
338
- // ...sharedFilters.map(sf =>
339
- // Op.not(exp.fieldExpression(sf.key, true, 'exists')[0])
340
- // ),
341
- // ...exp.filterExpressions(idFilters)
342
- // )
343
- )), ...children.map(child => Op.and(...contentTypeIdExpression(child.contentTypeIds, child.webpageTemplates, child.assetTypes), ...filterExpressions(child.sharedFilters), ...filterExpressions(child.idFilters)))), ...termExpressions(searchTerm, weightedSearchFields)];
133
+ }) => {
134
+ const expressions$1 = [...defaultExpressions(versionStatus), ...contentTypeIdExpression(contentTypeIds, webpageTemplates, assetTypes), ...customWhereExpressions(customWhere), ...filterExpressions(filters), ...filterExpressions(idFilters), ...((sharedFilters === null || sharedFilters === void 0 ? void 0 : sharedFilters.length) > 0 ? [Op.or(...filterExpressions(sharedFilters, true))] : []), ...termExpressions(searchTerm || '', weightedSearchFields || [])];
344
135
  const query = new Query(...expressions$1);
345
- query.orderBy = orderByExpression(orderBy);
136
+ query.orderBy = orderByExpression(orderBy || []);
346
137
 
347
138
  if (fields && fields.length > 0) {
348
139
  query.fields = fields;
@@ -354,38 +145,12 @@ const finalQuery = ({
354
145
  query.pageSize = pageSize;
355
146
  return query;
356
147
  };
357
- /**
358
- * Create a filter expression from a provided filters configuration object
359
- * and populate them based on the presence of that key in params, filter
360
- * out any filter keys that do not have a value set in params
361
- * @param f filters configuration from any level
362
- * @param params request.query object from Express middleware
363
- * @returns FilterExpression[] we can use to use with searchQuery function
364
- */
365
-
366
-
367
- const makeFilterExpressions = (f, params) => Object.entries(f).map(([paramKey, filterConfig]) => {
368
- var _params$paramKey;
369
-
370
- const filterValues = (_params$paramKey = params[paramKey]) === null || _params$paramKey === void 0 ? void 0 : _params$paramKey.split(',');
371
- return typeof filterValues !== 'undefined' ? {
372
- key: typeof filterConfig === 'object' ? filterConfig.fieldId : filterConfig,
373
- values: filterValues,
374
- fieldOperator: typeof filterConfig === 'object' ? filterConfig.fieldOperator : 'equalTo',
375
- logicOperator: typeof filterConfig === 'object' ? filterConfig.logicOperator : 'or'
376
- } : null;
377
- }).filter(o => o);
378
- /**
379
- * Builds our complete Delivery API Query object from a set of provided arguments
380
- * @param queryParams
381
- * @returns Delivery API Query
382
- */
383
-
384
-
385
- const searchQuery = ({
148
+ const appendSearchQueryFilters = (query, idFilters) => {
149
+ query.where.addRange(filterExpressions(idFilters));
150
+ };
151
+ const finalQuery = ({
386
152
  assetTypes,
387
153
  contentTypeIds,
388
- customWhere,
389
154
  fields,
390
155
  filters,
391
156
  idFilters,
@@ -397,10 +162,16 @@ const searchQuery = ({
397
162
  versionStatus = 'published',
398
163
  webpageTemplates,
399
164
  weightedSearchFields
400
- }) => {
401
- const expressions$1 = [...defaultExpressions(versionStatus), ...contentTypeIdExpression(contentTypeIds, webpageTemplates, assetTypes), ...customWhereExpressions(customWhere), ...filterExpressions(filters), ...filterExpressions(idFilters), ...((sharedFilters === null || sharedFilters === void 0 ? void 0 : sharedFilters.length) > 0 ? [Op.or(...filterExpressions(sharedFilters, true))] : []), ...termExpressions(searchTerm, weightedSearchFields)];
165
+ }, children) => {
166
+ const expressions$1 = [...defaultExpressions(versionStatus), Op.or(Op.and(...contentTypeIdExpression(contentTypeIds, webpageTemplates, assetTypes), ...filterExpressions(filters), ...filterExpressions(idFilters || []), ...(sharedFilters !== null && sharedFilters !== void 0 && sharedFilters.length ? [Op.or(...filterExpressions(sharedFilters || []) // Op.and(
167
+ // ...sharedFilters.map(sf =>
168
+ // Op.not(exp.fieldExpression(sf.key, true, 'exists')[0])
169
+ // ),
170
+ // ...exp.filterExpressions(idFilters)
171
+ // )
172
+ )] : [])), ...children.map(child => Op.and(...contentTypeIdExpression(child.contentTypeIds, child.webpageTemplates, child.assetTypes), ...filterExpressions(child.sharedFilters || []), ...filterExpressions(child.idFilters || [])))), ...termExpressions(searchTerm || '', weightedSearchFields || [])];
402
173
  const query = new Query(...expressions$1);
403
- query.orderBy = orderByExpression(orderBy);
174
+ query.orderBy = orderByExpression(orderBy || []);
404
175
 
405
176
  if (fields && fields.length > 0) {
406
177
  query.fields = fields;
@@ -408,50 +179,489 @@ const searchQuery = ({
408
179
  // (query as any).includeDeleted = true;
409
180
 
410
181
 
411
- query.pageIndex = pageIndex;
182
+ query.pageIndex = pageIndex || 0;
412
183
  query.pageSize = pageSize;
413
184
  return query;
414
185
  };
415
186
  /**
416
- * Util class holds our search results helper boilerplate methods
187
+ * Create a filter expression from a provided filters configuration object
188
+ * and populate them based on the presence of that key in params, filter
189
+ * out any filter keys that do not have a value set in params
190
+ * @param f filters configuration from any level
191
+ * @param params request.query object from Express middleware
192
+ * @returns FilterExpression[] we can use to use with searchQuery function
417
193
  */
418
194
 
195
+ const makeFilterExpressions = (f, params) => {
196
+ const expressions = [];
419
197
 
420
- class Util {
421
- static GetIds(entries, fieldId) {
422
- if (fieldId) {
423
- return entries.map(e => {
424
- var _e$fieldId, _e$fieldId2, _e$fieldId2$sys;
198
+ for (const [paramKey, filterConfig] of Object.entries(f)) {
199
+ var _params$paramKey;
425
200
 
426
- return Array.isArray(e === null || e === void 0 ? void 0 : e[fieldId]) ? e === null || e === void 0 ? void 0 : (_e$fieldId = e[fieldId]) === null || _e$fieldId === void 0 ? void 0 : _e$fieldId.map(f => {
427
- var _f$sys;
201
+ const filterValues = (_params$paramKey = params[paramKey]) === null || _params$paramKey === void 0 ? void 0 : _params$paramKey.split(',');
202
+ if (typeof filterValues !== 'undefined') expressions.push({
203
+ key: typeof filterConfig === 'object' ? filterConfig.fieldId : filterConfig,
204
+ values: filterValues,
205
+ fieldOperator: typeof filterConfig === 'object' && filterConfig.fieldOperator ? filterConfig.fieldOperator : 'equalTo',
206
+ logicOperator: typeof filterConfig === 'object' && filterConfig.logicOperator ? filterConfig.logicOperator : 'or'
207
+ });
208
+ }
428
209
 
429
- return f === null || f === void 0 ? void 0 : (_f$sys = f.sys) === null || _f$sys === void 0 ? void 0 : _f$sys.id;
430
- }) : (e === null || e === void 0 ? void 0 : (_e$fieldId2 = e[fieldId]) === null || _e$fieldId2 === void 0 ? void 0 : (_e$fieldId2$sys = _e$fieldId2.sys) === null || _e$fieldId2$sys === void 0 ? void 0 : _e$fieldId2$sys.id) || '';
431
- }).flat();
432
- }
210
+ return expressions;
211
+ };
212
+ const makeDerivedIdsFilterExpression = (prevFieldId, entries, ownIds = false, alwaysApplyFilter = false) => {
213
+ const previouslyDerivedIdsFilter = [];
214
+ const prevResultIds = Util.GetIds(entries);
215
+ if (prevFieldId && (prevResultIds === null || prevResultIds === void 0 ? void 0 : prevResultIds.length) > 0) previouslyDerivedIdsFilter.push({
216
+ key: ownIds ? 'sys.id' : `${prevFieldId}.sys.id`,
217
+ values: prevResultIds,
218
+ fieldOperator: 'in',
219
+ logicOperator: 'or'
220
+ });else if (alwaysApplyFilter) previouslyDerivedIdsFilter.push({
221
+ key: 'intended-dud',
222
+ values: ['1'],
223
+ fieldOperator: 'in',
224
+ logicOperator: 'or'
225
+ });
226
+ return previouslyDerivedIdsFilter;
227
+ };
228
+ const resolveParentEntries = async (parentContentTypeIds, replaceContentTypeIds, parentFieldId, results, params, debug) => {
229
+ // Build variables from query config to use in our Delivery API Query
230
+ const previousIdsFilter = makeDerivedIdsFilterExpression(parentFieldId, results);
231
+ const query = searchQuery({
232
+ contentTypeIds: parentContentTypeIds,
233
+ idFilters: previousIdsFilter
234
+ });
235
+ query.fields = params.fields ? [...JSON.parse(params.fields), parentFieldId] : [];
236
+ if (debug) console.log(`\nResolve parent entries query: \n${JSON.stringify(query.toJSON()).substring(0, 1000)}`);
237
+ const parentResults = await cachedSearch.searchUsingPost(query, Number(params.linkDepth || 0), params.projectId);
238
+ return mergeResults(results, Util.GetItems(parentResults), replaceContentTypeIds, parentFieldId);
239
+ };
433
240
 
434
- return entries.map(e => {
435
- var _e$sys;
241
+ /* eslint-disable no-console */
436
242
 
437
- return (e === null || e === void 0 ? void 0 : (_e$sys = e.sys) === null || _e$sys === void 0 ? void 0 : _e$sys.id) || '';
243
+ class QueryLevelResults {
244
+ constructor({
245
+ level: _level,
246
+ contentTypeIds,
247
+ linkFields,
248
+ filters,
249
+ sharedFilters,
250
+ returnEntries,
251
+ resolveFirstParent,
252
+ params: _params = {},
253
+ parent: _parent,
254
+ debug = false
255
+ }) {
256
+ this.level = void 0;
257
+ this.contentTypeIds = void 0;
258
+ this.linkFieldIds = void 0;
259
+ this.linkFields = void 0;
260
+ this.filters = void 0;
261
+ this.sharedFilters = void 0;
262
+ this.returnEntries = void 0;
263
+ this.resolveFirstParent = void 0;
264
+ this.validatedLinks = [];
265
+ this.parent = void 0;
266
+ this.children = [];
267
+ this.runFirstQuery = void 0;
268
+ this.runFinalQuery = void 0;
269
+ this.params = {};
270
+ this.debug = void 0;
271
+ this.firstQuery = new Query$1();
272
+ this.firstResults = {};
273
+ this.finalQuery = new Query$1();
274
+ this.finalResults = {};
275
+
276
+ this.AddChild = ({
277
+ child
278
+ }) => {
279
+ this.children.push(child);
280
+ };
281
+
282
+ this.RunFirstQuery = async () => {
283
+ const {
284
+ firstQuery: query,
285
+ params,
286
+ parent,
287
+ runFirstQuery
288
+ } = this;
289
+
290
+ if (parent !== null && parent !== void 0 && parent.validatedLinks.length) {
291
+ // add any idFilters derived from parent query results
292
+ appendSearchQueryFilters(query, makeFilterExpressions(Object.fromEntries(parent.validatedLinks.map(vl => [vl.linkFieldId, {
293
+ fieldId: `sys.id`
294
+ }])), Object.fromEntries(parent.validatedLinks.map(vl => [vl.linkFieldId, vl.entryIds.join(',') || `no ids from parent ${parent.level}`]))));
295
+ }
296
+
297
+ if (runFirstQuery) {
298
+ if (this.debug) console.log(`\nLevel ${this.level} - First query: \n${JSON.stringify(query.toJSON()).substring(0, 1000)}`);
299
+ this.firstResults = await cachedSearch.searchUsingPost(query, 0, params.projectId); // mapResultsToValidatedLinks
300
+
301
+ for (const linkFieldId of this.linkFieldIds) {
302
+ this.validatedLinks.push({
303
+ contentTypeId: this.linkFields[linkFieldId].contentTypeId || '',
304
+ linkFieldId,
305
+ entryIds: Util.GetIds(this.firstResults.items, linkFieldId)
306
+ });
307
+ }
308
+ }
309
+ };
310
+
311
+ this.RunFinalQuery = async () => {
312
+ const {
313
+ level,
314
+ children,
315
+ finalQuery: query,
316
+ params,
317
+ runFinalQuery
318
+ } = this;
319
+
320
+ if (!children.some(c => c.returnEntries)) {
321
+ const firstChild = children === null || children === void 0 ? void 0 : children[0]; // add any idFilters derived from child query results
322
+
323
+ if (firstChild) appendSearchQueryFilters(query, makeFilterExpressions(Object.fromEntries(firstChild.validatedLinks.map(vl => [vl.linkFieldId, {
324
+ fieldId: `${vl.linkFieldId}.sys.id`
325
+ }])), Object.fromEntries(firstChild.validatedLinks.map(vl => [vl.linkFieldId, vl.entryIds.join(',') || `no ids from child ${firstChild.level}`]))));
326
+ }
327
+
328
+ if (level === 0 && this.returnEntries) {
329
+ // This is the final query to be run and response returned to the caller
330
+ // Only this bit cares about linkDepth, fields and pagination parameters
331
+ query.fields = JSON.parse(params.fields || '[]');
332
+ query.pageSize = params.pageSize;
333
+ query.pageIndex = params.pageIndex; // query.orderBy = params.orderBy;
334
+ }
335
+
336
+ if (runFinalQuery) {
337
+ if (this.debug) console.log(`\nLevel ${this.level} - Final query: \n${JSON.stringify(query.toJSON()).substring(0, 1000)}`);
338
+ this.finalResults = await cachedSearch.searchUsingPost(query, Number(params.linkDepth) || 0, params.projectId);
339
+ if (this.parent) this.parent.runFinalQuery = true; // mapResultsToValidatedLinks
340
+
341
+ for (const linkFieldId of ((_this$parent = this.parent) === null || _this$parent === void 0 ? void 0 : _this$parent.linkFieldIds) || []) {
342
+ var _this$parent, _this$parent2;
343
+
344
+ this.validatedLinks.push({
345
+ contentTypeId: ((_this$parent2 = this.parent) === null || _this$parent2 === void 0 ? void 0 : _this$parent2.linkFields[linkFieldId].contentTypeId) || '',
346
+ linkFieldId,
347
+ entryIds: Util.GetIds(this.finalResults.items)
348
+ });
349
+ }
350
+ }
351
+ };
352
+
353
+ this.GetResultsEntries = () => {
354
+ var _finalResults$items;
355
+
356
+ const {
357
+ finalResults,
358
+ firstResults
359
+ } = this;
360
+ return finalResults !== null && finalResults !== void 0 && (_finalResults$items = finalResults.items) !== null && _finalResults$items !== void 0 && _finalResults$items.length ? finalResults.items : firstResults.items;
361
+ };
362
+
363
+ this.GetResults = () => {
364
+ const {
365
+ finalResults,
366
+ firstResults
367
+ } = this;
368
+ return typeof (finalResults === null || finalResults === void 0 ? void 0 : finalResults.totalCount) !== 'undefined' ? finalResults : firstResults;
369
+ };
370
+
371
+ this.level = _level;
372
+ this.contentTypeIds = contentTypeIds;
373
+ this.linkFields = linkFields;
374
+ this.linkFieldIds = Object.keys(linkFields).map(fId => fId);
375
+ this.filters = filters;
376
+ this.sharedFilters = sharedFilters;
377
+ this.returnEntries = typeof returnEntries === 'undefined' ? _level === 0 : returnEntries;
378
+ this.resolveFirstParent = resolveFirstParent || false;
379
+ this.params = _params;
380
+ this.parent = _parent;
381
+ this.debug = debug;
382
+ this.runFirstQuery = Object.keys(_params).some(p => Object.keys(filters).includes(p) || Object.keys(sharedFilters).includes(p));
383
+ this.runFinalQuery = Object.keys(_params).some(p => Object.keys(filters).includes(p) || Object.keys(sharedFilters).includes(p));
384
+ this.firstQuery = searchQuery({
385
+ contentTypeIds,
386
+ filters: makeFilterExpressions(filters, _params),
387
+ sharedFilters: makeFilterExpressions(sharedFilters, _params),
388
+ // idFilters: parent?.validatedLinks
389
+ // ? makeFilterExpressions(parent.validatedLinks, params)
390
+ // : [], // these dont exist yet
391
+ fields: ['sys.id', ...this.linkFieldIds],
392
+ pageSize: 2000,
393
+ searchTerm: _params.term,
394
+ versionStatus: _params.versionStatus
395
+ });
396
+ this.finalQuery = searchQuery({
397
+ contentTypeIds,
398
+ filters: makeFilterExpressions(filters, _params),
399
+ sharedFilters: makeFilterExpressions(sharedFilters, _params),
400
+ fields: JSON.parse(_params.fields || '[]'),
401
+ pageIndex: _level === 0 ? Number(_params.pageIndex) : 0,
402
+ pageSize: _level === 0 ? Number(_params.pageSize) : 2000,
403
+ searchTerm: _params.term,
404
+ versionStatus: _params.versionStatus
438
405
  });
439
406
  }
440
407
 
441
- static GetItems(result) {
442
- return this.GetResults(result) ? result.items : [];
443
- }
408
+ }
444
409
 
445
- static GetResults(result) {
446
- if (result !== null && result !== void 0 && result.items) {
447
- return result;
448
- } else {
449
- return null;
450
- }
410
+ /* eslint-disable no-console */
411
+
412
+ class LinkDepthSearchService {
413
+ constructor({
414
+ contentTypeId: _contentTypeId = '',
415
+ filters: _filters = {},
416
+ sharedFilters: _sharedFilters = {},
417
+ linkFields: _linkFields = {},
418
+ params: _params,
419
+ debug = false
420
+ }) {
421
+ this.contentTypeIds = void 0;
422
+ this.filters = void 0;
423
+ this.sharedFilters = void 0;
424
+ this.linkFields = void 0;
425
+ this.params = void 0;
426
+ this.debug = void 0;
427
+ this.queryLevels = void 0;
428
+
429
+ this.DoSearch = async () => {
430
+ // Run queries "top-down" through each level of `linkField`
431
+ for (const queryLevel of this.queryLevels) {
432
+ await queryLevel.RunFirstQuery();
433
+ } // Run queries "bottom-up" through each level of `linkField`
434
+
435
+
436
+ for (const queryLevel of [...this.queryLevels].reverse()) {
437
+ await queryLevel.RunFinalQuery();
438
+ } // Run a final query that will aggregate the results from all levels
439
+ // adding all levels to the query that have `returnEntries` set true
440
+
441
+
442
+ return await this.RunFinalQueries();
443
+ };
444
+
445
+ this.RunFinalQueries = async () => {
446
+ const finalQueryLevels = this.queryLevels.filter(ql => ql.level > 0 && ql.returnEntries || ql.level === 0 && ql.returnEntries !== false); // Decide if we need a further final query if any child level(s) have had `returnEntries` set to true
447
+
448
+ if (finalQueryLevels.length > 1 || finalQueryLevels.length === 1 && finalQueryLevels[0].level !== 0) {
449
+ var _params$orderBy;
450
+
451
+ // Build final query
452
+ const {
453
+ contentTypeIds,
454
+ filters,
455
+ sharedFilters,
456
+ params
457
+ } = this;
458
+ const derivedIds = finalQueryLevels[0].children.filter(ql => !ql.returnEntries).map(ql => ql.validatedLinks).flat() || [];
459
+ const derivedIdFilters = derivedIds.map(vl => makeFilterExpressions({
460
+ [vl.linkFieldId]: {
461
+ fieldId: `${vl.linkFieldId}.sys.id`
462
+ }
463
+ }, {
464
+ [vl.linkFieldId]: vl.entryIds.join(',') || 'no results for filter'
465
+ })).flat() || []; // This is the final query to be run and response returned to the caller
466
+ // Only this bit cares about linkDepth, fields and pagination parameters
467
+
468
+ const query = finalQuery({
469
+ contentTypeIds,
470
+ filters: makeFilterExpressions(filters, params),
471
+ sharedFilters: makeFilterExpressions(sharedFilters, params),
472
+ idFilters: derivedIdFilters,
473
+ fields: params.fields ? [...JSON.parse(params.fields), ...finalQueryLevels.map(l => {
474
+ var _l$parent;
475
+
476
+ return ((_l$parent = l.parent) === null || _l$parent === void 0 ? void 0 : _l$parent.linkFieldIds) || [];
477
+ }).flat()] : [],
478
+ orderBy: (_params$orderBy = params.orderBy) === null || _params$orderBy === void 0 ? void 0 : _params$orderBy.split(','),
479
+ pageIndex: Number(params.pageIndex) || 0,
480
+ pageSize: typeof Number(params.pageSize) === 'number' ? Number(params.pageSize) : 25,
481
+ searchTerm: params.term,
482
+ versionStatus: params.versionStatus
483
+ }, (finalQueryLevels === null || finalQueryLevels === void 0 ? void 0 : finalQueryLevels[0].children.filter(ql => ql.returnEntries).map(ql => {
484
+ var _ql$parent, _ql$parent2;
485
+
486
+ const entriesAtLevel = ql.GetResultsEntries() || ((_ql$parent = ql.parent) === null || _ql$parent === void 0 ? void 0 : _ql$parent.GetResultsEntries());
487
+ const previousIdsFilter = ql.returnEntries || !!ql.children.some(qc => qc.returnEntries) ? (_ql$parent2 = ql.parent) === null || _ql$parent2 === void 0 ? void 0 : _ql$parent2.linkFieldIds.map(fieldId => makeDerivedIdsFilterExpression(fieldId, entriesAtLevel, true, ql.runFinalQuery)).flat() : [];
488
+ return {
489
+ contentTypeIds: ql.contentTypeIds,
490
+ filters: makeFilterExpressions(ql.filters, params),
491
+ sharedFilters: makeFilterExpressions(ql.sharedFilters, params),
492
+ idFilters: previousIdsFilter
493
+ };
494
+ })) || []);
495
+ if (this.debug) console.log(`\nFinal query: ${derivedIds.reduce((accumulator, object) => accumulator + object.entryIds.length, 0)} derived ids \n${JSON.stringify(query.toJSON()).substring(0, 1000)}`);
496
+ const finalQueryResult = await cachedSearch.searchUsingPost(query, Number(params.linkDepth) || 0, params.projectId); // Resolve any parent entries
497
+
498
+ const resolveParentLevels = finalQueryLevels.filter(ql => ql.resolveFirstParent);
499
+ let entries = finalQueryResult.items;
500
+
501
+ for (const resolveParents of resolveParentLevels) {
502
+ var _resolveParents$paren, _resolveParents$paren2;
503
+
504
+ entries = await resolveParentEntries(((_resolveParents$paren = resolveParents.parent) === null || _resolveParents$paren === void 0 ? void 0 : _resolveParents$paren.contentTypeIds) || [], resolveParents.contentTypeIds, ((_resolveParents$paren2 = resolveParents.parent) === null || _resolveParents$paren2 === void 0 ? void 0 : _resolveParents$paren2.linkFieldIds[0]) || 'unknown', finalQueryResult.items, // or entries?
505
+ this.params, this.debug);
506
+ }
507
+
508
+ return { ...finalQueryResult,
509
+ items: entries
510
+ };
511
+ } else {
512
+ var _this$queryLevels$fin;
513
+
514
+ if (this.debug) console.log(`\nNo further queries required\n`);
515
+ return (_this$queryLevels$fin = this.queryLevels.find(ql => ql.level === 0)) === null || _this$queryLevels$fin === void 0 ? void 0 : _this$queryLevels$fin.GetResults();
516
+ }
517
+ };
518
+
519
+ this.InitQueryLevels = () => {
520
+ const createChildQueryLevels = (linkFields, parentQueryLevel, level = 1) => {
521
+ return Object.entries(linkFields).map(([, {
522
+ contentTypeId = '',
523
+ filters = {},
524
+ linkFields = {},
525
+ resolveFirstParent,
526
+ returnEntries,
527
+ sharedFilters = {}
528
+ }]) => {
529
+ const thisLevel = new QueryLevelResults({
530
+ level,
531
+ contentTypeIds: Array.isArray(contentTypeId) ? contentTypeId : [contentTypeId],
532
+ filters: Object.fromEntries(Object.entries(filters).map(([fKey, fVal]) => [fKey, typeof fVal === 'string' ? {
533
+ fieldId: fVal
534
+ } : fVal])),
535
+ sharedFilters: Object.fromEntries(Object.entries(sharedFilters).map(([fKey, fVal]) => [fKey, typeof fVal === 'string' ? {
536
+ fieldId: fVal
537
+ } : fVal])),
538
+ linkFields,
539
+ parent: parentQueryLevel,
540
+ params,
541
+ resolveFirstParent,
542
+ returnEntries,
543
+ debug: this.debug
544
+ });
545
+ parentQueryLevel.AddChild({
546
+ child: thisLevel
547
+ });
548
+ return [thisLevel, ...createChildQueryLevels(linkFields, thisLevel, level + 1)];
549
+ }).flat();
550
+ };
551
+
552
+ const {
553
+ contentTypeIds,
554
+ filters,
555
+ sharedFilters,
556
+ linkFields,
557
+ params
558
+ } = this;
559
+ const firstLevel = new QueryLevelResults({
560
+ level: 0,
561
+ contentTypeIds,
562
+ filters: Object.fromEntries(Object.entries(filters).map(([fKey, fVal]) => [fKey, typeof fVal === 'string' ? {
563
+ fieldId: fVal
564
+ } : fVal])),
565
+ sharedFilters: Object.fromEntries(Object.entries(sharedFilters).map(([fKey, fVal]) => [fKey, typeof fVal === 'string' ? {
566
+ fieldId: fVal
567
+ } : fVal])),
568
+ linkFields,
569
+ params,
570
+ debug: this.debug
571
+ });
572
+ const queryLevels = [firstLevel, ...createChildQueryLevels(linkFields, firstLevel)]; // return queryLevels;
573
+ // If we are only returning entries from level 0
574
+ // we can skip running the first query and finalQuery will suffice
575
+
576
+ if (queryLevels.find(ql => ql.returnEntries && ql.level !== 0)) return queryLevels;else return queryLevels.map(ql => {
577
+ ql.runFirstQuery = false; // ql.runFinalQuery = false;
578
+
579
+ return ql;
580
+ });
581
+ };
582
+
583
+ this.contentTypeIds = Array.isArray(_contentTypeId) ? _contentTypeId : [_contentTypeId];
584
+ this.filters = _filters;
585
+ this.sharedFilters = _sharedFilters;
586
+ this.linkFields = _linkFields;
587
+ this.params = _params;
588
+ this.debug = debug;
589
+ this.queryLevels = this.InitQueryLevels();
451
590
  }
452
591
 
453
592
  }
454
593
 
594
+ /**
595
+ * Make a LinkDepth api at the uri specified in middlewareConfig.
596
+ * The api supports a GET request and specified filters are supplied as query-string parameters.
597
+ * The response should be a normal Delivery API response.
598
+ * @param app Express app instance
599
+ * @param middlewareConfig Middleware configuration that represents the content types we want to search within, any filters that are required and any linkFields we wish to search within to derive a set of search results from the entries that contain the linkFields. Each key inside of linkFields represents another "linkDepth" of entries and we can specify all the same contentTypeId, filters, and linkFields of their own. There is no currently no limit on how deep these linkFields can go
600
+ * @returns Returns nothing if uri, contentTypeId or linkFields is not set in middlewareConfig
601
+ */
602
+ const makeLinkDepthApi = (app, middlewareConfig) => {
603
+ const {
604
+ uri,
605
+ contentTypeId,
606
+ linkFields
607
+ } = middlewareConfig;
608
+ if (!contentTypeId || !linkFields || !uri) return;
609
+ app.get(uri, makeLinkDepthMiddleware(middlewareConfig));
610
+ };
611
+ /** Create a content type hierarchy from supplied config and produces
612
+ * a RequestHandler function to serve our Express middleware */
613
+
614
+
615
+ const makeLinkDepthMiddleware = ({
616
+ contentTypeId,
617
+ filters = {},
618
+ sharedFilters = {},
619
+ linkFields,
620
+ debug
621
+ }) => {
622
+ try {
623
+ // The runtime express request handler
624
+ const linkDepthMiddleware = async (req, res) => {
625
+ try {
626
+ // Short cache duration copied from canterbury project
627
+ setCachingHeaders(res, {
628
+ cacheControl: 'private',
629
+ surrogateControl: '10'
630
+ }); // Gather all params from the request, we will use them at the right query levels later
631
+
632
+ const params = Object.fromEntries([...Object.entries(req.params), ...Object.entries(req.query)].map(([k, v]) => [k, v === null || v === void 0 ? void 0 : v.toString()]));
633
+ const result = await new LinkDepthSearchService({
634
+ contentTypeId,
635
+ linkFields,
636
+ filters,
637
+ sharedFilters,
638
+ params,
639
+ debug
640
+ }).DoSearch();
641
+ res.json(result);
642
+ } catch (error) {
643
+ // This is a runtime error encountered when processing a given request
644
+ console.error(error);
645
+ res.statusCode = 500;
646
+ res.json(error);
647
+ }
648
+ };
649
+
650
+ return linkDepthMiddleware;
651
+ } catch (error) {
652
+ // This will be an error building the middleware
653
+ // we can only serve what the error was as the request handler instead
654
+ console.error(error);
655
+
656
+ const errorMiddleware = async (req, res) => {
657
+ res.statusCode = 500;
658
+ res.json(JSON.stringify(error));
659
+ };
660
+
661
+ return errorMiddleware;
662
+ }
663
+ };
664
+
455
665
  const servers$1 = SERVERS;
456
666
  /* global SERVERS */
457
667
 
@@ -624,6 +834,8 @@ const staticAssets = (app, {
624
834
  }));
625
835
  };
626
836
 
837
+ var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
838
+
627
839
  /**
628
840
  * Removes all key-value entries from the list cache.
629
841
  *
@@ -2792,9 +3004,9 @@ var getNative$1 = _getNative,
2792
3004
  root$2 = _root;
2793
3005
 
2794
3006
  /* Built-in method references that are verified to be native. */
2795
- var Set$2 = getNative$1(root$2, 'Set');
3007
+ var Set$1 = getNative$1(root$2, 'Set');
2796
3008
 
2797
- var _Set = Set$2;
3009
+ var _Set = Set$1;
2798
3010
 
2799
3011
  var getNative = _getNative,
2800
3012
  root$1 = _root;
@@ -2807,7 +3019,7 @@ var _WeakMap = WeakMap$1;
2807
3019
  var DataView = _DataView,
2808
3020
  Map = _Map,
2809
3021
  Promise$1 = _Promise,
2810
- Set$1 = _Set,
3022
+ Set = _Set,
2811
3023
  WeakMap = _WeakMap,
2812
3024
  baseGetTag = _baseGetTag,
2813
3025
  toSource = _toSource;
@@ -2825,7 +3037,7 @@ var dataViewTag$2 = '[object DataView]';
2825
3037
  var dataViewCtorString = toSource(DataView),
2826
3038
  mapCtorString = toSource(Map),
2827
3039
  promiseCtorString = toSource(Promise$1),
2828
- setCtorString = toSource(Set$1),
3040
+ setCtorString = toSource(Set),
2829
3041
  weakMapCtorString = toSource(WeakMap);
2830
3042
 
2831
3043
  /**
@@ -2841,7 +3053,7 @@ var getTag$3 = baseGetTag;
2841
3053
  if ((DataView && getTag$3(new DataView(new ArrayBuffer(1))) != dataViewTag$2) ||
2842
3054
  (Map && getTag$3(new Map) != mapTag$3) ||
2843
3055
  (Promise$1 && getTag$3(Promise$1.resolve()) != promiseTag) ||
2844
- (Set$1 && getTag$3(new Set$1) != setTag$3) ||
3056
+ (Set && getTag$3(new Set) != setTag$3) ||
2845
3057
  (WeakMap && getTag$3(new WeakMap) != weakMapTag$1)) {
2846
3058
  getTag$3 = function(value) {
2847
3059
  var result = baseGetTag(value),