@cavuno/board 3.2.0 → 4.1.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/CHANGELOG.md +433 -0
- package/README.md +6 -2
- package/dist/{_spec-nkWAraS0.d.mts → _spec-BZDv2dc5.d.mts} +100 -68
- package/dist/{_spec-nkWAraS0.d.ts → _spec-BZDv2dc5.d.ts} +100 -68
- package/dist/bin.mjs +7 -2
- package/dist/{blog-iV9XEIGf.d.ts → blog-BHx6iH3Z.d.ts} +1 -1
- package/dist/{blog-DGBHmExV.d.mts → blog-DyDvyQrI.d.mts} +1 -1
- package/dist/{board-JhdUWIoq.d.ts → board-BF3Qao6J.d.mts} +7 -6
- package/dist/{board-BJbXd_9_.d.mts → board-BTEZ0uiI.d.ts} +7 -6
- package/dist/breadcrumbs-SGaWth6C.d.ts +372 -0
- package/dist/breadcrumbs-icxRVydh.d.mts +372 -0
- package/dist/chunk-BGKNXG4H.mjs +146 -0
- package/dist/{chunk-NXY3OWGF.mjs → chunk-T2KC6XGV.mjs} +1 -1
- package/dist/{chunk-STE77MAT.mjs → chunk-YEAQ3JEI.mjs} +143 -134
- package/dist/doctor.js +1 -1
- package/dist/doctor.mjs +1 -1
- package/dist/filters.d.mts +25 -20
- package/dist/filters.d.ts +25 -20
- package/dist/filters.js +3 -692
- package/dist/filters.mjs +3 -29
- package/dist/format.d.mts +57 -231
- package/dist/format.d.ts +57 -231
- package/dist/format.js +327 -968
- package/dist/format.mjs +207 -264
- package/dist/go.js +11 -1
- package/dist/go.mjs +1 -1
- package/dist/index.d.mts +67 -76
- package/dist/index.d.ts +67 -76
- package/dist/index.js +45 -36
- package/dist/index.mjs +45 -36
- package/dist/{jobs-BiEvL9d7.d.ts → jobs-BX6d_sdd.d.mts} +4 -4
- package/dist/{jobs-lVvKCBCU.d.mts → jobs-BbLJfz1z.d.ts} +4 -4
- package/dist/paths.d.mts +89 -1
- package/dist/paths.d.ts +89 -1
- package/dist/paths.js +62 -14
- package/dist/paths.mjs +11 -3
- package/dist/route-contract.js +23 -13
- package/dist/route-contract.mjs +2 -2
- package/dist/{search-CCyFWPi3.d.mts → search-7B-mVRNA.d.ts} +14 -3
- package/dist/{search-CyRvVMUp.d.ts → search-OKrdAHv8.d.mts} +14 -3
- package/dist/seo.d.mts +30 -29
- package/dist/seo.d.ts +30 -29
- package/dist/seo.js +197 -718
- package/dist/seo.mjs +26 -24
- package/dist/server.d.mts +5 -5
- package/dist/server.d.ts +5 -5
- package/dist/sitemap.d.mts +5 -5
- package/dist/sitemap.d.ts +5 -5
- package/dist/sitemap.js +25 -14
- package/dist/sitemap.mjs +3 -2
- package/dist/skills.js +1 -1
- package/dist/skills.mjs +1 -1
- package/dist/suggest.d.mts +2 -2
- package/dist/suggest.d.ts +2 -2
- package/dist/suggest.js +17 -3
- package/dist/suggest.mjs +17 -3
- package/dist/well-known.js +23 -13
- package/dist/well-known.mjs +2 -2
- package/package.json +2 -4
- package/skills/cavuno-board-api-client/SKILL.md +42 -0
- package/skills/cavuno-board-applications/SKILL.md +4 -1
- package/skills/cavuno-board-filters/SKILL.md +11 -12
- package/skills/cavuno-board-format/SKILL.md +68 -56
- package/skills/cavuno-board-i18n/SKILL.md +102 -21
- package/skills/cavuno-board-search-suggestions/SKILL.md +8 -3
- package/skills/cavuno-board-seo/BLOG.md +4 -1
- package/skills/cavuno-board-seo/JOB_AND_BREADCRUMBS.md +5 -2
- package/skills/cavuno-board-seo/LISTING.md +35 -12
- package/skills/cavuno-board-seo/SALARY.md +83 -18
- package/skills/cavuno-board-seo/SKILL.md +3 -2
- package/skills/manifest.json +3 -3
- package/dist/breadcrumbs-1hMjcsqA.d.mts +0 -171
- package/dist/breadcrumbs-DexU07TT.d.ts +0 -171
- package/dist/chunk-IJCJ26SQ.mjs +0 -596
- package/dist/chunk-L7ZOYWHW.mjs +0 -98
- package/dist/chunk-LUGJWOT7.mjs +0 -96
- package/dist/ui-copy-CCkz6CVF.d.mts +0 -230
- package/dist/ui-copy-CCkz6CVF.d.ts +0 -230
package/dist/format.mjs
CHANGED
|
@@ -1,67 +1,77 @@
|
|
|
1
|
-
import {
|
|
2
|
-
fieldLabel
|
|
3
|
-
} from "./chunk-LUGJWOT7.mjs";
|
|
4
1
|
import {
|
|
5
2
|
buildJobBreadcrumbs,
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
formatSalaryStat,
|
|
4
|
+
formatSalaryStatRange,
|
|
5
|
+
normalizeLocale,
|
|
8
6
|
normalizeWebsiteUrl
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import
|
|
11
|
-
PUBLIC_LABEL_GROUPS,
|
|
12
|
-
getSalaryLexicon,
|
|
13
|
-
uiCopy
|
|
14
|
-
} from "./chunk-IJCJ26SQ.mjs";
|
|
7
|
+
} from "./chunk-YEAQ3JEI.mjs";
|
|
8
|
+
import "./chunk-BGKNXG4H.mjs";
|
|
15
9
|
|
|
16
10
|
// src/format/dates.ts
|
|
17
|
-
var
|
|
11
|
+
var rtfShortCache = /* @__PURE__ */ new Map();
|
|
12
|
+
var rtfNowCache = /* @__PURE__ */ new Map();
|
|
18
13
|
var dtfCache = /* @__PURE__ */ new Map();
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
let rtf =
|
|
14
|
+
var monthYearCache = /* @__PURE__ */ new Map();
|
|
15
|
+
function getShortRelativeTimeFormat(language) {
|
|
16
|
+
let rtf = rtfShortCache.get(language);
|
|
22
17
|
if (!rtf) {
|
|
23
|
-
rtf = new Intl.RelativeTimeFormat(
|
|
18
|
+
rtf = new Intl.RelativeTimeFormat(language, {
|
|
24
19
|
numeric: "always",
|
|
25
|
-
style: "
|
|
20
|
+
style: "short"
|
|
21
|
+
});
|
|
22
|
+
rtfShortCache.set(language, rtf);
|
|
23
|
+
}
|
|
24
|
+
return rtf;
|
|
25
|
+
}
|
|
26
|
+
function getNowRelativeTimeFormat(language) {
|
|
27
|
+
let rtf = rtfNowCache.get(language);
|
|
28
|
+
if (!rtf) {
|
|
29
|
+
rtf = new Intl.RelativeTimeFormat(language, {
|
|
30
|
+
numeric: "auto",
|
|
31
|
+
style: "short"
|
|
26
32
|
});
|
|
27
|
-
|
|
33
|
+
rtfNowCache.set(language, rtf);
|
|
28
34
|
}
|
|
29
35
|
return rtf;
|
|
30
36
|
}
|
|
31
37
|
function getDateTimeFormat(language) {
|
|
32
|
-
|
|
33
|
-
let dtf = dtfCache.get(key);
|
|
38
|
+
let dtf = dtfCache.get(language);
|
|
34
39
|
if (!dtf) {
|
|
35
|
-
dtf = new Intl.DateTimeFormat(
|
|
40
|
+
dtf = new Intl.DateTimeFormat(language, {
|
|
36
41
|
dateStyle: "medium",
|
|
37
42
|
timeZone: "UTC"
|
|
38
43
|
});
|
|
39
|
-
dtfCache.set(
|
|
44
|
+
dtfCache.set(language, dtf);
|
|
40
45
|
}
|
|
41
46
|
return dtf;
|
|
42
47
|
}
|
|
43
|
-
function
|
|
48
|
+
function getMonthYearFormat(language) {
|
|
49
|
+
let dtf = monthYearCache.get(language);
|
|
50
|
+
if (!dtf) {
|
|
51
|
+
dtf = new Intl.DateTimeFormat(language, {
|
|
52
|
+
month: "short",
|
|
53
|
+
year: "numeric",
|
|
54
|
+
timeZone: "UTC"
|
|
55
|
+
});
|
|
56
|
+
monthYearCache.set(language, dtf);
|
|
57
|
+
}
|
|
58
|
+
return dtf;
|
|
59
|
+
}
|
|
60
|
+
function formatShort(value, unit, language) {
|
|
44
61
|
try {
|
|
45
|
-
return
|
|
62
|
+
return getShortRelativeTimeFormat(language).format(value, unit);
|
|
46
63
|
} catch {
|
|
47
|
-
|
|
48
|
-
year: "y",
|
|
49
|
-
month: "mo",
|
|
50
|
-
week: "w",
|
|
51
|
-
day: "d",
|
|
52
|
-
hour: "h",
|
|
53
|
-
minute: "m",
|
|
54
|
-
second: "s"
|
|
55
|
-
};
|
|
56
|
-
return `${Math.abs(value)}${shortMap[unit] ?? unit}`;
|
|
64
|
+
return null;
|
|
57
65
|
}
|
|
58
66
|
}
|
|
59
67
|
function formatDate(locale, value) {
|
|
60
68
|
if (!value) return null;
|
|
61
69
|
const parsed = new Date(value);
|
|
62
70
|
if (Number.isNaN(parsed.getTime())) return null;
|
|
71
|
+
const normalized = normalizeLocale(locale);
|
|
72
|
+
if (!normalized) return null;
|
|
63
73
|
try {
|
|
64
|
-
return getDateTimeFormat(
|
|
74
|
+
return getDateTimeFormat(normalized).format(parsed);
|
|
65
75
|
} catch {
|
|
66
76
|
return parsed.toISOString().split("T")[0];
|
|
67
77
|
}
|
|
@@ -70,6 +80,8 @@ function formatPublishedRelativeDate(locale, value, referenceNowMs = Date.now())
|
|
|
70
80
|
if (!value) return null;
|
|
71
81
|
const parsed = new Date(value);
|
|
72
82
|
if (Number.isNaN(parsed.getTime())) return null;
|
|
83
|
+
const normalized = normalizeLocale(locale);
|
|
84
|
+
if (!normalized) return null;
|
|
73
85
|
const diff = referenceNowMs - parsed.getTime();
|
|
74
86
|
const absDiff = Math.abs(diff);
|
|
75
87
|
const minute = 60 * 1e3;
|
|
@@ -79,7 +91,11 @@ function formatPublishedRelativeDate(locale, value, referenceNowMs = Date.now())
|
|
|
79
91
|
const month = 30 * day;
|
|
80
92
|
const year = 365 * day;
|
|
81
93
|
if (absDiff < minute) {
|
|
82
|
-
|
|
94
|
+
try {
|
|
95
|
+
return getNowRelativeTimeFormat(normalized).format(0, "second");
|
|
96
|
+
} catch {
|
|
97
|
+
return formatShort(0, "second", normalized);
|
|
98
|
+
}
|
|
83
99
|
}
|
|
84
100
|
const units = [
|
|
85
101
|
{ unit: "year", ms: year },
|
|
@@ -93,249 +109,152 @@ function formatPublishedRelativeDate(locale, value, referenceNowMs = Date.now())
|
|
|
93
109
|
if (absDiff >= candidate.ms) {
|
|
94
110
|
const valueInUnit = Math.round(absDiff / candidate.ms);
|
|
95
111
|
const direction2 = diff >= 0 ? -valueInUnit : valueInUnit;
|
|
96
|
-
return
|
|
112
|
+
return formatShort(direction2, candidate.unit, normalized);
|
|
97
113
|
}
|
|
98
114
|
}
|
|
99
115
|
const seconds = Math.round(absDiff / 1e3);
|
|
100
116
|
const direction = diff >= 0 ? -seconds : seconds;
|
|
101
|
-
return
|
|
117
|
+
return formatShort(direction, "second", normalized);
|
|
102
118
|
}
|
|
103
119
|
function formatMonthYear(locale, dateStr) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
return job.remoteWorldwide ? "Remote (worldwide)" : "Remote";
|
|
117
|
-
}
|
|
118
|
-
if (!place) return fieldLabel(locale, job.remoteOption) ?? "";
|
|
119
|
-
return job.remoteOption === "hybrid" ? `${place} (hybrid)` : place;
|
|
120
|
-
}
|
|
121
|
-
function cardLocationLabel(locale, job) {
|
|
122
|
-
if (job.remoteOption === "remote") {
|
|
123
|
-
return job.remoteLocationLabel ? `Remote \xB7 ${job.remoteLocationLabel}` : "Remote";
|
|
120
|
+
if (!dateStr) return null;
|
|
121
|
+
const isDateOnly = /^\d{4}-\d{2}(-\d{2})?$/.test(dateStr);
|
|
122
|
+
const parsed = isDateOnly ? /* @__PURE__ */ new Date(
|
|
123
|
+
dateStr.length === 7 ? `${dateStr}-01T00:00:00.000Z` : `${dateStr}T00:00:00.000Z`
|
|
124
|
+
) : new Date(dateStr);
|
|
125
|
+
if (Number.isNaN(parsed.getTime())) return null;
|
|
126
|
+
const normalized = normalizeLocale(locale);
|
|
127
|
+
if (!normalized) return null;
|
|
128
|
+
try {
|
|
129
|
+
return getMonthYearFormat(normalized).format(parsed);
|
|
130
|
+
} catch {
|
|
131
|
+
return null;
|
|
124
132
|
}
|
|
125
|
-
return job.locationLabel ?? fieldLabel(locale, job.remoteOption) ?? "";
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// src/format/job-card.ts
|
|
129
|
-
function fullJobToCard(locale, job) {
|
|
130
|
-
return {
|
|
131
|
-
id: job.id,
|
|
132
|
-
object: "job_card",
|
|
133
|
-
slug: job.slug ?? "",
|
|
134
|
-
title: job.title,
|
|
135
|
-
publishedAt: job.publishedAt,
|
|
136
|
-
employmentType: job.employmentType,
|
|
137
|
-
remoteOption: job.remoteOption,
|
|
138
|
-
remoteLocationLabel: job.remoteWorldwide ? "Worldwide" : null,
|
|
139
|
-
salaryMin: job.salaryMin,
|
|
140
|
-
salaryMax: job.salaryMax,
|
|
141
|
-
salaryCurrency: job.salaryCurrency,
|
|
142
|
-
salaryTimeframe: job.salaryTimeframe,
|
|
143
|
-
isFeatured: job.isFeatured,
|
|
144
|
-
locationLabel: locationLabel(locale, job),
|
|
145
|
-
company: job.company?.slug ? {
|
|
146
|
-
slug: job.company.slug,
|
|
147
|
-
name: job.company.name ?? "",
|
|
148
|
-
logoUrl: job.company.logoUrl
|
|
149
|
-
} : null,
|
|
150
|
-
categories: job.categories,
|
|
151
|
-
skills: job.skills,
|
|
152
|
-
links: job.links
|
|
153
|
-
};
|
|
154
133
|
}
|
|
155
134
|
|
|
156
135
|
// src/format/salary-range.ts
|
|
157
|
-
var
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
NZD: "NZ$",
|
|
178
|
-
ZAR: "R ",
|
|
179
|
-
THB: "\u0E3F",
|
|
180
|
-
PHP: "\u20B1",
|
|
181
|
-
IDR: "Rp ",
|
|
182
|
-
MYR: "RM ",
|
|
183
|
-
VND: "\u20AB",
|
|
184
|
-
AED: "AED ",
|
|
185
|
-
SAR: "SAR ",
|
|
186
|
-
ILS: "\u20AA",
|
|
187
|
-
TRY: "\u20BA",
|
|
188
|
-
CZK: "K\u010D ",
|
|
189
|
-
HUF: "Ft ",
|
|
190
|
-
RON: "lei ",
|
|
191
|
-
BGN: "\u043B\u0432 ",
|
|
192
|
-
HRK: "kn ",
|
|
193
|
-
ISK: "kr ",
|
|
194
|
-
CLP: "CLP$",
|
|
195
|
-
COP: "COP$",
|
|
196
|
-
PEN: "S/",
|
|
197
|
-
ARS: "ARS$",
|
|
198
|
-
TWD: "NT$",
|
|
199
|
-
NGN: "\u20A6",
|
|
200
|
-
EGP: "E\xA3",
|
|
201
|
-
PKR: "\u20A8",
|
|
202
|
-
BDT: "\u09F3",
|
|
203
|
-
UAH: "\u20B4",
|
|
204
|
-
KZT: "\u20B8"
|
|
205
|
-
};
|
|
206
|
-
function getCurrencySymbol(currency) {
|
|
207
|
-
if (!currency) {
|
|
208
|
-
return "$";
|
|
209
|
-
}
|
|
210
|
-
const normalized = currency.trim().toUpperCase();
|
|
211
|
-
return CURRENCY_SYMBOLS[normalized] ?? `${normalized} `;
|
|
212
|
-
}
|
|
213
|
-
var compactFormatCache = /* @__PURE__ */ new Map();
|
|
214
|
-
function getCompactFormatter(language) {
|
|
215
|
-
const cached = compactFormatCache.get(language);
|
|
216
|
-
if (cached) return cached;
|
|
217
|
-
const formatter = new Intl.NumberFormat(language, {
|
|
218
|
-
notation: "compact",
|
|
219
|
-
compactDisplay: "short",
|
|
220
|
-
maximumFractionDigits: 1
|
|
221
|
-
});
|
|
222
|
-
compactFormatCache.set(language, formatter);
|
|
223
|
-
return formatter;
|
|
224
|
-
}
|
|
225
|
-
function formatCompactNumber(value, language) {
|
|
226
|
-
try {
|
|
227
|
-
return getCompactFormatter(language ?? "en").format(value);
|
|
228
|
-
} catch {
|
|
229
|
-
if (value >= 1e6) {
|
|
230
|
-
const millions = value / 1e6;
|
|
231
|
-
return millions % 1 === 0 ? `${millions}M` : `${millions.toFixed(1)}M`;
|
|
232
|
-
}
|
|
233
|
-
if (value >= 1e3) {
|
|
234
|
-
const thousands = value / 1e3;
|
|
235
|
-
return thousands % 1 === 0 ? `${thousands}k` : `${thousands.toFixed(1)}k`;
|
|
136
|
+
var currencyCache = /* @__PURE__ */ new Map();
|
|
137
|
+
function formatAmount(value, language, currencyCode, currencyDisplay = "symbol", notation = "compact") {
|
|
138
|
+
const cacheKey = `${language}:${currencyCode}:${currencyDisplay}:${notation}`;
|
|
139
|
+
let formatter = currencyCache.get(cacheKey);
|
|
140
|
+
if (formatter === void 0) {
|
|
141
|
+
try {
|
|
142
|
+
const options = {
|
|
143
|
+
style: "currency",
|
|
144
|
+
currency: currencyCode,
|
|
145
|
+
currencyDisplay,
|
|
146
|
+
notation
|
|
147
|
+
};
|
|
148
|
+
if (notation === "compact") {
|
|
149
|
+
options.compactDisplay = "short";
|
|
150
|
+
options.maximumFractionDigits = 1;
|
|
151
|
+
options.minimumFractionDigits = 0;
|
|
152
|
+
}
|
|
153
|
+
formatter = new Intl.NumberFormat(language, options);
|
|
154
|
+
} catch {
|
|
155
|
+
formatter = null;
|
|
236
156
|
}
|
|
237
|
-
|
|
157
|
+
currencyCache.set(cacheKey, formatter);
|
|
238
158
|
}
|
|
159
|
+
return formatter ? formatter.format(value) : null;
|
|
239
160
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
const cacheKey = `${language}:${currencyCode}`;
|
|
244
|
-
let formatter = compactCurrencyCache.get(cacheKey);
|
|
161
|
+
function formatRange(min, max, language, currencyCode, currencyDisplay = "symbol", notation = "compact") {
|
|
162
|
+
const cacheKey = `${language}:${currencyCode}:${currencyDisplay}:${notation}:range`;
|
|
163
|
+
let formatter = currencyCache.get(cacheKey);
|
|
245
164
|
if (formatter === void 0) {
|
|
246
165
|
try {
|
|
247
|
-
|
|
166
|
+
const options = {
|
|
248
167
|
style: "currency",
|
|
249
168
|
currency: currencyCode,
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
169
|
+
currencyDisplay,
|
|
170
|
+
notation
|
|
171
|
+
};
|
|
172
|
+
if (notation === "compact") {
|
|
173
|
+
options.compactDisplay = "short";
|
|
174
|
+
options.maximumFractionDigits = 1;
|
|
175
|
+
options.minimumFractionDigits = 0;
|
|
176
|
+
}
|
|
177
|
+
formatter = new Intl.NumberFormat(language, options);
|
|
254
178
|
} catch {
|
|
255
179
|
formatter = null;
|
|
256
180
|
}
|
|
257
|
-
|
|
181
|
+
currencyCache.set(cacheKey, formatter);
|
|
258
182
|
}
|
|
259
|
-
if (!formatter)
|
|
260
|
-
|
|
183
|
+
if (!formatter) return null;
|
|
184
|
+
return formatter.formatRange(min, max);
|
|
185
|
+
}
|
|
186
|
+
var SALARY_TIMEFRAMES = /* @__PURE__ */ new Set([
|
|
187
|
+
"per_year",
|
|
188
|
+
"per_month",
|
|
189
|
+
"per_week",
|
|
190
|
+
"per_day",
|
|
191
|
+
"per_hour"
|
|
192
|
+
]);
|
|
193
|
+
function notationForMagnitude(...values) {
|
|
194
|
+
let anyFinite = false;
|
|
195
|
+
for (const v of values) {
|
|
196
|
+
if (v == null || !Number.isFinite(v)) continue;
|
|
197
|
+
anyFinite = true;
|
|
198
|
+
if (Math.abs(v) >= 1e3) return "compact";
|
|
261
199
|
}
|
|
262
|
-
return
|
|
200
|
+
return anyFinite ? "standard" : "compact";
|
|
263
201
|
}
|
|
264
|
-
function
|
|
265
|
-
|
|
202
|
+
function formatSalaryRange(language, min, max, timeframe, currency = null, currencyDisplay = "symbol", notation) {
|
|
203
|
+
const minOk = min == null || Number.isFinite(min);
|
|
204
|
+
const maxOk = max == null || Number.isFinite(max);
|
|
205
|
+
if (!minOk || !maxOk) {
|
|
266
206
|
return null;
|
|
267
207
|
}
|
|
268
|
-
if (!timeframeLabel) {
|
|
269
|
-
return value;
|
|
270
|
-
}
|
|
271
|
-
return `${value} ${timeframeLabel}`;
|
|
272
|
-
}
|
|
273
|
-
function formatSalaryRange(language, min, max, timeframe, currency = null, timeframeOverrides) {
|
|
274
208
|
if (min == null && max == null) {
|
|
275
209
|
return null;
|
|
276
210
|
}
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
const
|
|
287
|
-
const enSourceWord = timeframe ? getSalaryLexicon("en").timeframe[timeframe] : void 0;
|
|
288
|
-
const lexiconTimeframe = timeframe ? lexicon.timeframe[timeframe] ?? null : null;
|
|
289
|
-
const timeframeLabel = rawOverride && rawOverride !== enSourceWord ? rawOverride : lexiconTimeframe;
|
|
290
|
-
const formatAmount = locale === "en" ? (value) => `${getCurrencySymbol(currency)}${formatCompactNumber(value, locale)}` : (value) => formatCompactCurrency(value, locale, currency);
|
|
211
|
+
const currencyCode = currency?.trim().toUpperCase() || null;
|
|
212
|
+
if (!currencyCode) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
const locale = normalizeLocale(language);
|
|
216
|
+
if (!locale) {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
const resolvedNotation = notation ?? notationForMagnitude(min, max);
|
|
220
|
+
const timeframeLabel = typeof timeframe === "string" && SALARY_TIMEFRAMES.has(timeframe) ? timeframe : null;
|
|
291
221
|
if (min != null && max != null) {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
222
|
+
const low = min <= max ? min : max;
|
|
223
|
+
const high = min <= max ? max : min;
|
|
224
|
+
const text2 = low === high ? formatAmount(
|
|
225
|
+
low,
|
|
226
|
+
locale,
|
|
227
|
+
currencyCode,
|
|
228
|
+
currencyDisplay,
|
|
229
|
+
resolvedNotation
|
|
230
|
+
) : formatRange(
|
|
231
|
+
low,
|
|
232
|
+
high,
|
|
233
|
+
locale,
|
|
234
|
+
currencyCode,
|
|
235
|
+
currencyDisplay,
|
|
236
|
+
resolvedNotation
|
|
295
237
|
);
|
|
238
|
+
return text2 ? { text: text2, timeframe: timeframeLabel, bound: "range" } : null;
|
|
296
239
|
}
|
|
297
240
|
if (min != null) {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
241
|
+
const text2 = formatAmount(
|
|
242
|
+
min,
|
|
243
|
+
locale,
|
|
244
|
+
currencyCode,
|
|
245
|
+
currencyDisplay,
|
|
246
|
+
resolvedNotation
|
|
301
247
|
);
|
|
248
|
+
return text2 ? { text: text2, timeframe: timeframeLabel, bound: "from" } : null;
|
|
302
249
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
250
|
+
const text = formatAmount(
|
|
251
|
+
max,
|
|
252
|
+
locale,
|
|
253
|
+
currencyCode,
|
|
254
|
+
currencyDisplay,
|
|
255
|
+
resolvedNotation
|
|
306
256
|
);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// src/format/company-intro.ts
|
|
310
|
-
var NAMED_ENTITIES = {
|
|
311
|
-
amp: "&",
|
|
312
|
-
lt: "<",
|
|
313
|
-
gt: ">",
|
|
314
|
-
quot: '"',
|
|
315
|
-
apos: "'",
|
|
316
|
-
nbsp: " "
|
|
317
|
-
};
|
|
318
|
-
function decodeEntities(input) {
|
|
319
|
-
return input.replace(/&(#\d+|#x[0-9a-f]+|[a-z]+);/gi, (match, body) => {
|
|
320
|
-
const token = String(body);
|
|
321
|
-
if (token[0] === "#") {
|
|
322
|
-
const code = token[1] === "x" || token[1] === "X" ? parseInt(token.slice(2), 16) : parseInt(token.slice(1), 10);
|
|
323
|
-
if (!Number.isInteger(code) || code < 0 || code > 1114111) return match;
|
|
324
|
-
return String.fromCodePoint(code);
|
|
325
|
-
}
|
|
326
|
-
return NAMED_ENTITIES[token.toLowerCase()] ?? match;
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
function companyIntro(summary, description) {
|
|
330
|
-
const trimmedSummary = summary?.trim();
|
|
331
|
-
if (trimmedSummary) return trimmedSummary;
|
|
332
|
-
if (!description) return null;
|
|
333
|
-
const text = decodeEntities(
|
|
334
|
-
description.replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<br\s*\/?>/gi, " ").replace(/<\/(p|div|li|h[1-6])>/gi, " ").replace(/<[^>]*>/g, "")
|
|
335
|
-
).replace(/\s+/g, " ").trim();
|
|
336
|
-
if (!text) return null;
|
|
337
|
-
const [first] = text.split(/(?<=[.!?])\s+/);
|
|
338
|
-
return first ?? text;
|
|
257
|
+
return text ? { text, timeframe: timeframeLabel, bound: "upTo" } : null;
|
|
339
258
|
}
|
|
340
259
|
|
|
341
260
|
// src/format/countries.ts
|
|
@@ -605,8 +524,14 @@ function collator(language) {
|
|
|
605
524
|
}
|
|
606
525
|
}
|
|
607
526
|
function countryOptions(language) {
|
|
608
|
-
const
|
|
609
|
-
|
|
527
|
+
const locale = normalizeLocale(language);
|
|
528
|
+
if (!locale) {
|
|
529
|
+
return COUNTRY_CODES.map((code) => ({ code, name: code })).sort(
|
|
530
|
+
(a, b) => a.code < b.code ? -1 : a.code > b.code ? 1 : 0
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
const names = regionNames(locale);
|
|
534
|
+
const compare = collator(locale).compare;
|
|
610
535
|
return COUNTRY_CODES.map((code) => ({
|
|
611
536
|
code,
|
|
612
537
|
name: names?.of(code) ?? code
|
|
@@ -614,24 +539,27 @@ function countryOptions(language) {
|
|
|
614
539
|
}
|
|
615
540
|
|
|
616
541
|
// src/format/custom-fields.ts
|
|
542
|
+
function resolveMultiSelectLabels(def, raw) {
|
|
543
|
+
if (!Array.isArray(raw) || raw.length === 0) return null;
|
|
544
|
+
const labels = raw.map((key) => def.options?.find((o) => o.key === key)?.label).filter((label) => Boolean(label));
|
|
545
|
+
return labels.length > 0 ? labels : null;
|
|
546
|
+
}
|
|
617
547
|
function renderTextValue(def, raw) {
|
|
618
548
|
switch (def.type) {
|
|
619
549
|
case "number":
|
|
620
|
-
return
|
|
550
|
+
return null;
|
|
551
|
+
case "multi_select":
|
|
552
|
+
return null;
|
|
621
553
|
case "single_select": {
|
|
622
554
|
if (typeof raw !== "string") return null;
|
|
623
555
|
return def.options?.find((o) => o.key === raw)?.label ?? null;
|
|
624
556
|
}
|
|
625
|
-
case "multi_select": {
|
|
626
|
-
if (!Array.isArray(raw) || raw.length === 0) return null;
|
|
627
|
-
const labels = raw.map((key) => def.options?.find((o) => o.key === key)?.label).filter((label) => Boolean(label));
|
|
628
|
-
return labels.length > 0 ? labels.join(", ") : null;
|
|
629
|
-
}
|
|
630
557
|
default:
|
|
631
558
|
return typeof raw === "string" && raw.trim() !== "" ? raw : null;
|
|
632
559
|
}
|
|
633
560
|
}
|
|
634
|
-
function resolveCustomFieldDisplay(definitions, values) {
|
|
561
|
+
function resolveCustomFieldDisplay(language, definitions, values) {
|
|
562
|
+
void language;
|
|
635
563
|
const entries = [];
|
|
636
564
|
for (const def of definitions ?? []) {
|
|
637
565
|
const raw = values?.[def.key];
|
|
@@ -646,6 +574,29 @@ function resolveCustomFieldDisplay(definitions, values) {
|
|
|
646
574
|
}
|
|
647
575
|
continue;
|
|
648
576
|
}
|
|
577
|
+
if (def.type === "number") {
|
|
578
|
+
if (typeof raw === "number" && Number.isFinite(raw)) {
|
|
579
|
+
entries.push({
|
|
580
|
+
key: def.key,
|
|
581
|
+
label: def.label,
|
|
582
|
+
kind: "number",
|
|
583
|
+
value: raw
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
588
|
+
if (def.type === "multi_select") {
|
|
589
|
+
const labels = resolveMultiSelectLabels(def, raw);
|
|
590
|
+
if (labels) {
|
|
591
|
+
entries.push({
|
|
592
|
+
key: def.key,
|
|
593
|
+
label: def.label,
|
|
594
|
+
kind: "multi_select",
|
|
595
|
+
values: labels
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
continue;
|
|
599
|
+
}
|
|
649
600
|
const value = renderTextValue(def, raw);
|
|
650
601
|
if (value !== null) {
|
|
651
602
|
entries.push({ key: def.key, label: def.label, kind: "text", value });
|
|
@@ -655,22 +606,14 @@ function resolveCustomFieldDisplay(definitions, values) {
|
|
|
655
606
|
}
|
|
656
607
|
export {
|
|
657
608
|
COUNTRY_CODES,
|
|
658
|
-
PUBLIC_LABEL_GROUPS,
|
|
659
609
|
buildJobBreadcrumbs,
|
|
660
|
-
cardLocationLabel,
|
|
661
|
-
companyIntro,
|
|
662
610
|
countryOptions,
|
|
663
|
-
fieldLabel,
|
|
664
611
|
formatDate,
|
|
665
612
|
formatMonthYear,
|
|
666
613
|
formatPublishedRelativeDate,
|
|
667
614
|
formatSalaryRange,
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
fullJobToCard,
|
|
671
|
-
getSalaryLexicon,
|
|
672
|
-
locationLabel,
|
|
615
|
+
formatSalaryStat,
|
|
616
|
+
formatSalaryStatRange,
|
|
673
617
|
normalizeWebsiteUrl,
|
|
674
|
-
resolveCustomFieldDisplay
|
|
675
|
-
uiCopy
|
|
618
|
+
resolveCustomFieldDisplay
|
|
676
619
|
};
|
package/dist/go.js
CHANGED
|
@@ -27,8 +27,18 @@ __export(go_exports, {
|
|
|
27
27
|
module.exports = __toCommonJS(go_exports);
|
|
28
28
|
|
|
29
29
|
// src/paths/index.ts
|
|
30
|
+
function encodePathSegment(segment) {
|
|
31
|
+
try {
|
|
32
|
+
return encodeURIComponent(decodeURIComponent(segment)).replace(
|
|
33
|
+
/%3A/gi,
|
|
34
|
+
":"
|
|
35
|
+
);
|
|
36
|
+
} catch {
|
|
37
|
+
return encodeURIComponent(segment).replace(/%3A/gi, ":");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
30
40
|
function jobDetailPath(companySlug, jobSlug) {
|
|
31
|
-
return `/companies/${companySlug}/jobs/${jobSlug}`;
|
|
41
|
+
return `/companies/${encodePathSegment(companySlug)}/jobs/${encodePathSegment(jobSlug)}`;
|
|
32
42
|
}
|
|
33
43
|
var BOARD_PATHS = {
|
|
34
44
|
home: "/",
|