@fluid-topics/ft-wc-utils 1.1.112 → 1.1.114

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.
@@ -0,0 +1,39 @@
1
+ import { FtSearchRequest, FtSearchSortCriterion } from "@fluid-topics/public-api";
2
+ export interface EnrichedFtSearchRequest extends FtSearchRequest {
3
+ otherQueryParams?: Record<string, string>;
4
+ }
5
+ /** @deprecated replace with SearchPlaceConverter.serialize */
6
+ export declare function serializeRequest(baseUrl: string, request: EnrichedFtSearchRequest): string;
7
+ export declare enum SearchPlaceQueryParams {
8
+ LOCALE = "content-lang",
9
+ QUERY = "query",
10
+ SCOPE = "scope",
11
+ FILTERS = "filters",
12
+ VIRTUAL_FIELD = "virtual-field",
13
+ PERIOD = "period",
14
+ VALUE_FILTERS = "value-filters",
15
+ DATE_FILTERS = "date-filters",
16
+ RANGE_FILTERS = "range-filters",
17
+ SORT = "sort"
18
+ }
19
+ export declare function isSearchPlaceQueryParams(param: string): param is SearchPlaceQueryParams;
20
+ export declare class SearchPlaceConverter {
21
+ private readonly baseUrl;
22
+ private readonly predefinedSorts;
23
+ private readonly scopeMapping;
24
+ constructor(baseUrl: string, predefinedSorts: Record<string, Array<FtSearchSortCriterion>>);
25
+ serialize(request: EnrichedFtSearchRequest, searchPage?: string): string;
26
+ toURLSearchParams(request: EnrichedFtSearchRequest): URLSearchParams;
27
+ parse(url: string): EnrichedFtSearchRequest;
28
+ fromURLSearchParams(params: URLSearchParams): EnrichedFtSearchRequest;
29
+ private parseCompatFilters;
30
+ private splitUnknownFilter;
31
+ private parseValueFilters;
32
+ private parseDateFilters;
33
+ private parseRangeFilters;
34
+ private readonly filtersEscapeMapping;
35
+ private escapeFilters;
36
+ private superEscapeFilters;
37
+ private unescapeFilterValue;
38
+ private parseLegacyPeriodFilter;
39
+ }
@@ -0,0 +1,234 @@
1
+ import { FtDateFilterType, isFtDateFilterType, isFtVirtualField } from "@fluid-topics/public-api";
2
+ function quote(value) {
3
+ return `"${value}"`;
4
+ }
5
+ function unquote(value) {
6
+ if (value.startsWith("\"") && value.endsWith("\"")) {
7
+ return value.replace(/(^"+)|("+$)/g, "");
8
+ }
9
+ return value;
10
+ }
11
+ /** @deprecated replace with SearchPlaceConverter.serialize */
12
+ export function serializeRequest(baseUrl, request) {
13
+ return new SearchPlaceConverter(baseUrl, {}).serialize(request);
14
+ }
15
+ export var SearchPlaceQueryParams;
16
+ (function (SearchPlaceQueryParams) {
17
+ SearchPlaceQueryParams["LOCALE"] = "content-lang";
18
+ SearchPlaceQueryParams["QUERY"] = "query";
19
+ SearchPlaceQueryParams["SCOPE"] = "scope";
20
+ SearchPlaceQueryParams["FILTERS"] = "filters";
21
+ SearchPlaceQueryParams["VIRTUAL_FIELD"] = "virtual-field";
22
+ SearchPlaceQueryParams["PERIOD"] = "period";
23
+ SearchPlaceQueryParams["VALUE_FILTERS"] = "value-filters";
24
+ SearchPlaceQueryParams["DATE_FILTERS"] = "date-filters";
25
+ SearchPlaceQueryParams["RANGE_FILTERS"] = "range-filters";
26
+ SearchPlaceQueryParams["SORT"] = "sort";
27
+ })(SearchPlaceQueryParams || (SearchPlaceQueryParams = {}));
28
+ const SearchPlaceQueryParamsValues = new Set(Object.values(SearchPlaceQueryParams));
29
+ export function isSearchPlaceQueryParams(param) {
30
+ return SearchPlaceQueryParamsValues.has(param);
31
+ }
32
+ export class SearchPlaceConverter {
33
+ constructor(baseUrl, predefinedSorts) {
34
+ this.baseUrl = baseUrl;
35
+ this.predefinedSorts = predefinedSorts;
36
+ this.scopeMapping = {
37
+ "documents": "DOCUMENTS",
38
+ "topics": "ALL_TOPICS",
39
+ };
40
+ this.filtersEscapeMapping = [
41
+ ["*", "\\*", "[ft-escaped-star-character]"],
42
+ ["~", "\\\\~", "[ft-escaped-tilde-character]"],
43
+ ["_", "\\\\\\\\_", "[ft-escaped-underscore-character]"],
44
+ ];
45
+ }
46
+ serialize(request, searchPage = `/search`) {
47
+ const queryParams = this.toURLSearchParams(request).toString();
48
+ return new URL(`${this.baseUrl.replace(/\/+$/, "")}${searchPage}?${queryParams}`).href;
49
+ }
50
+ toURLSearchParams(request) {
51
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
52
+ const params = new URLSearchParams({
53
+ [SearchPlaceQueryParams.LOCALE]: (_a = request.contentLocale) !== null && _a !== void 0 ? _a : "all",
54
+ });
55
+ if (((_b = request.query) === null || _b === void 0 ? void 0 : _b.length) > 0) {
56
+ params.append(SearchPlaceQueryParams.QUERY, request.query);
57
+ }
58
+ if (request.scope && request.scope !== "DEFAULT") {
59
+ params.append(SearchPlaceQueryParams.SCOPE, request.scope.toLowerCase());
60
+ }
61
+ if (request.virtualField && request.virtualField !== "EVERYWHERE") {
62
+ params.append(SearchPlaceQueryParams.VIRTUAL_FIELD, request.virtualField.toLowerCase());
63
+ }
64
+ if (((_c = request.sort) === null || _c === void 0 ? void 0 : _c.length) > 0 && request.sort[0].key === "ft:lastEdition") {
65
+ params.append(SearchPlaceQueryParams.SORT, "last_update");
66
+ }
67
+ const valueFilters = (_e = (_d = request.metadataFilters) === null || _d === void 0 ? void 0 : _d.filter(f => f.valueFilter)) !== null && _e !== void 0 ? _e : [];
68
+ if (valueFilters.length > 0) {
69
+ const serializedValues = valueFilters.map(f => {
70
+ var _a, _b;
71
+ const values = ((_b = (_a = f.valueFilter) === null || _a === void 0 ? void 0 : _a.values) !== null && _b !== void 0 ? _b : [])
72
+ .map(value => this.escapeFilters(value))
73
+ .map(value => encodeURIComponent(quote(value)))
74
+ .join("_");
75
+ return `${f.key}~${values}`;
76
+ }).join("*");
77
+ params.append(SearchPlaceQueryParams.VALUE_FILTERS, serializedValues);
78
+ }
79
+ const dateFilters = (_g = (_f = request.metadataFilters) === null || _f === void 0 ? void 0 : _f.filter(f => f.dateFilter)) !== null && _g !== void 0 ? _g : [];
80
+ if (dateFilters.length > 0) {
81
+ const serializedDates = dateFilters.map(f => { var _a; return `${f.key}~${(_a = f.dateFilter) === null || _a === void 0 ? void 0 : _a.type.toLowerCase()}`; })
82
+ .join("*");
83
+ params.append(SearchPlaceQueryParams.DATE_FILTERS, serializedDates);
84
+ }
85
+ const rangeFilters = (_j = (_h = request.metadataFilters) === null || _h === void 0 ? void 0 : _h.filter(f => f.rangeFilter)) !== null && _j !== void 0 ? _j : [];
86
+ if (rangeFilters.length > 0) {
87
+ const serializedRanges = rangeFilters.map(f => { var _a, _b; return `${f.key}~${(_a = f.rangeFilter) === null || _a === void 0 ? void 0 : _a.from}_${(_b = f.rangeFilter) === null || _b === void 0 ? void 0 : _b.to}`; })
88
+ .join("*");
89
+ params.append(SearchPlaceQueryParams.RANGE_FILTERS, serializedRanges);
90
+ }
91
+ const otherQueryParams = (_k = request.otherQueryParams) !== null && _k !== void 0 ? _k : {};
92
+ for (let key in otherQueryParams) {
93
+ params.append(key, otherQueryParams[key]);
94
+ }
95
+ return params;
96
+ }
97
+ parse(url) {
98
+ var _a;
99
+ const urlSplit = url.split("?");
100
+ const fromParams = this.fromURLSearchParams(new URLSearchParams(urlSplit.slice(1).join("?")));
101
+ const maybeScopeFromPath = urlSplit[0].split("/search/")[1];
102
+ return maybeScopeFromPath == null ? fromParams : { ...fromParams, scope: (_a = this.scopeMapping[maybeScopeFromPath]) !== null && _a !== void 0 ? _a : fromParams.scope };
103
+ }
104
+ fromURLSearchParams(params) {
105
+ var _a, _b, _c, _d, _e, _f, _g, _h;
106
+ const virtualField = ((_a = params.get(SearchPlaceQueryParams.VIRTUAL_FIELD)) !== null && _a !== void 0 ? _a : "EVERYWHERE").toUpperCase();
107
+ const sortType = ((_b = params.get(SearchPlaceQueryParams.SORT)) !== null && _b !== void 0 ? _b : "DEFAULT").toUpperCase();
108
+ const scope = (_c = params.get(SearchPlaceQueryParams.SCOPE)) !== null && _c !== void 0 ? _c : "default";
109
+ const otherQueryParams = {};
110
+ for (let key of params.keys()) {
111
+ if (!isSearchPlaceQueryParams(key)) {
112
+ otherQueryParams[key] = params.get(key);
113
+ }
114
+ }
115
+ return {
116
+ contentLocale: params.get(SearchPlaceQueryParams.LOCALE) === "all" ? undefined : ((_d = params.get(SearchPlaceQueryParams.LOCALE)) !== null && _d !== void 0 ? _d : undefined),
117
+ query: decodeURIComponent((_e = params.get(SearchPlaceQueryParams.QUERY)) !== null && _e !== void 0 ? _e : ""),
118
+ scope: (_f = this.scopeMapping[scope]) !== null && _f !== void 0 ? _f : "DEFAULT",
119
+ virtualField: isFtVirtualField(virtualField) ? virtualField : "EVERYWHERE",
120
+ sort: (_h = (_g = this.predefinedSorts[sortType]) !== null && _g !== void 0 ? _g : this.predefinedSorts["DEFAULT"]) !== null && _h !== void 0 ? _h : [],
121
+ metadataFilters: this.parseCompatFilters(params),
122
+ facets: [],
123
+ paging: { page: 1, perPage: 20 },
124
+ otherQueryParams,
125
+ };
126
+ }
127
+ parseCompatFilters(params) {
128
+ var _a, _b, _c, _d, _e, _f;
129
+ let legacyFilters = [];
130
+ if (params.has(SearchPlaceQueryParams.FILTERS)) {
131
+ legacyFilters = this.parseValueFilters((_a = params.get(SearchPlaceQueryParams.FILTERS)) !== null && _a !== void 0 ? _a : "");
132
+ }
133
+ if ((_b = params.has(SearchPlaceQueryParams.PERIOD)) !== null && _b !== void 0 ? _b : "") {
134
+ legacyFilters = [
135
+ ...legacyFilters,
136
+ ...this.parseLegacyPeriodFilter(((_c = params.get(SearchPlaceQueryParams.PERIOD)) !== null && _c !== void 0 ? _c : "").toUpperCase())
137
+ ];
138
+ }
139
+ return [
140
+ ...legacyFilters,
141
+ ...this.parseValueFilters((_d = params.get(SearchPlaceQueryParams.VALUE_FILTERS)) !== null && _d !== void 0 ? _d : ""),
142
+ ...this.parseDateFilters((_e = params.get(SearchPlaceQueryParams.DATE_FILTERS)) !== null && _e !== void 0 ? _e : ""),
143
+ ...this.parseRangeFilters((_f = params.get(SearchPlaceQueryParams.RANGE_FILTERS)) !== null && _f !== void 0 ? _f : ""),
144
+ ];
145
+ }
146
+ splitUnknownFilter(s) {
147
+ return this.superEscapeFilters(decodeURIComponent(s))
148
+ .split("*")
149
+ .map(oneFilter => oneFilter.split("~"));
150
+ }
151
+ parseValueFilters(s) {
152
+ if (s.length === 0) {
153
+ return [];
154
+ }
155
+ return this.splitUnknownFilter(s)
156
+ .map(oneFilterSplit => ({
157
+ key: oneFilterSplit[0],
158
+ valueFilter: {
159
+ values: oneFilterSplit[1].split("_")
160
+ .map(unquote)
161
+ .map(value => this.unescapeFilterValue(value)),
162
+ negative: false
163
+ }
164
+ }));
165
+ }
166
+ parseDateFilters(s) {
167
+ if (s.length === 0) {
168
+ return [];
169
+ }
170
+ return this.splitUnknownFilter(s)
171
+ .map(oneFilterSplit => ({
172
+ key: oneFilterSplit[0],
173
+ dateFilter: {
174
+ type: FtDateFilterType[oneFilterSplit[1].toUpperCase()]
175
+ }
176
+ }));
177
+ }
178
+ parseRangeFilters(s) {
179
+ if (s.length === 0) {
180
+ return [];
181
+ }
182
+ return this.splitUnknownFilter(s)
183
+ .map(oneFilterSplit => ({
184
+ key: oneFilterSplit[0],
185
+ rangeFilter: {
186
+ from: oneFilterSplit[1].split("_")[0],
187
+ to: oneFilterSplit[1].split("_")[1]
188
+ }
189
+ }));
190
+ }
191
+ escapeFilters(s) {
192
+ for (let [c, escaped, superEscaped] of this.filtersEscapeMapping) {
193
+ s = s.replaceAll(c, escaped);
194
+ }
195
+ return s;
196
+ }
197
+ superEscapeFilters(s) {
198
+ for (let [c, escaped, superEscaped] of this.filtersEscapeMapping) {
199
+ s = s.replaceAll(escaped, superEscaped);
200
+ }
201
+ return s;
202
+ }
203
+ unescapeFilterValue(value) {
204
+ for (let [c, escaped, superEscaped] of this.filtersEscapeMapping) {
205
+ value = value.replace(superEscaped, c);
206
+ }
207
+ return value;
208
+ }
209
+ parseLegacyPeriodFilter(period) {
210
+ if (isFtDateFilterType(period)) {
211
+ return [
212
+ {
213
+ key: "ft:lastEdition",
214
+ dateFilter: {
215
+ type: FtDateFilterType[period]
216
+ }
217
+ }
218
+ ];
219
+ }
220
+ if (period.startsWith("CUSTOM_")) {
221
+ const [_, from, to] = period.split("_");
222
+ return [
223
+ {
224
+ key: "ft:lastEdition",
225
+ rangeFilter: {
226
+ from: from,
227
+ to: to
228
+ }
229
+ }
230
+ ];
231
+ }
232
+ return [];
233
+ }
234
+ }