@everipedia/iq-utils 1.0.1 → 2.0.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 +6 -0
- package/dist/index.d.mts +1002 -0
- package/dist/index.d.ts +1002 -0
- package/dist/index.js +650 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +600 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +51 -53
- package/build/main/data/constants.d.ts +0 -24
- package/build/main/data/constants.js +0 -28
- package/build/main/index.d.ts +0 -7
- package/build/main/index.js +0 -24
- package/build/main/lib/checkWikiValidity.d.ts +0 -67
- package/build/main/lib/checkWikiValidity.js +0 -209
- package/build/main/lib/helpers/wiki.helpers.d.ts +0 -32
- package/build/main/lib/helpers/wiki.helpers.js +0 -86
- package/build/main/lib/isDeepEqual.d.ts +0 -3
- package/build/main/lib/isDeepEqual.js +0 -53
- package/build/main/lib/wikiScore.d.ts +0 -2
- package/build/main/lib/wikiScore.js +0 -127
- package/build/main/schema/wiki.schema.d.ts +0 -798
- package/build/main/schema/wiki.schema.js +0 -289
- package/build/main/types/wiki.d.ts +0 -9
- package/build/main/types/wiki.js +0 -14
- package/build/main/types/wikiBuilder.d.ts +0 -11
- package/build/main/types/wikiBuilder.js +0 -3
- package/build/module/data/constants.d.ts +0 -24
- package/build/module/data/constants.js +0 -25
- package/build/module/index.d.ts +0 -7
- package/build/module/index.js +0 -8
- package/build/module/lib/checkWikiValidity.d.ts +0 -67
- package/build/module/lib/checkWikiValidity.js +0 -191
- package/build/module/lib/helpers/wiki.helpers.d.ts +0 -32
- package/build/module/lib/helpers/wiki.helpers.js +0 -75
- package/build/module/lib/isDeepEqual.d.ts +0 -3
- package/build/module/lib/isDeepEqual.js +0 -51
- package/build/module/lib/wikiScore.d.ts +0 -2
- package/build/module/lib/wikiScore.js +0 -121
- package/build/module/schema/wiki.schema.d.ts +0 -798
- package/build/module/schema/wiki.schema.js +0 -286
- package/build/module/types/wiki.d.ts +0 -9
- package/build/module/types/wiki.js +0 -11
- package/build/module/types/wikiBuilder.d.ts +0 -11
- package/build/module/types/wikiBuilder.js +0 -2
package/dist/index.js
ADDED
|
@@ -0,0 +1,650 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var zod = require('zod');
|
|
4
|
+
|
|
5
|
+
// src/data/constants.ts
|
|
6
|
+
var WIKI_SUMMARY_MAX_LENGTH = 255;
|
|
7
|
+
var WIKI_CONTENT_MIN_WORDS = 100;
|
|
8
|
+
var WIKI_TITLE_MAX_LENGTH = 60;
|
|
9
|
+
var MEDIA_UPLOAD_PENDING_SUFFIX = "default";
|
|
10
|
+
var MAX_MEDIA_COUNT = 25;
|
|
11
|
+
var IPFS_HASH_LENGTH = 46;
|
|
12
|
+
var EditorContentOverride = "%OVERRIDE@EDITOR@MARKDOWN%";
|
|
13
|
+
var CreateNewWikiSlug = "/*CREATE+NEW+WIKI*/";
|
|
14
|
+
var MIN_CONTENT_WORD_COUNT = 10;
|
|
15
|
+
var GOOD_CONTENT_WORD_COUNT = 500;
|
|
16
|
+
var IDEAL_CONTENT_WORD_COUNT = 1500;
|
|
17
|
+
var CONTENT_SCORE_WEIGHT = 0.8;
|
|
18
|
+
var INTERNAL_LINKS_SCORE_WEIGHT = 0.5;
|
|
19
|
+
var CITATIONS_SCORE_WEIGHT = 0.5;
|
|
20
|
+
var MEDIA_SCORE_WEIGHT = 0.3;
|
|
21
|
+
var TAGS_SCORE_WEIGHT = 0.3;
|
|
22
|
+
var SUMMARY_SCORE_WEIGHT = 0.5;
|
|
23
|
+
var SOCIAL_SCORE_WEIGHT = 0.5;
|
|
24
|
+
var IDEAL_INTERNAL_LINKS_COUNT = 10;
|
|
25
|
+
var IDEAL_CITATIONS_COUNT = 10;
|
|
26
|
+
var IDEAL_MEDIA_COUNT = 5;
|
|
27
|
+
var IDEAL_TAGS_COUNT = 3;
|
|
28
|
+
var IDEAL_SUMMARY_LENGTH = 100;
|
|
29
|
+
var IDEAL_SOCIAL_MEDIA_COUNT = 4;
|
|
30
|
+
var WHITELISTED_DOMAINS = [
|
|
31
|
+
"youtube.com/watch",
|
|
32
|
+
"youtu.be",
|
|
33
|
+
"vimeo.com",
|
|
34
|
+
"alpha.everipedia.org/wiki",
|
|
35
|
+
"beta.everipedia.org/wiki",
|
|
36
|
+
"iq.wiki/wiki",
|
|
37
|
+
"ipfs.everipedia.org/ipfs"
|
|
38
|
+
];
|
|
39
|
+
var WHITELISTED_LINK_NAMES = ["YOUTUBE@VID", "DUNE@EMBED"];
|
|
40
|
+
|
|
41
|
+
// src/lib/wiki-helpers.ts
|
|
42
|
+
var countWords = (text) => text.split(" ").filter((word) => word !== "").length;
|
|
43
|
+
var isValidUrl = (urlString) => {
|
|
44
|
+
try {
|
|
45
|
+
return Boolean(new URL(urlString));
|
|
46
|
+
} catch (_e) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var validateMediaContent = (media) => {
|
|
51
|
+
return media.every((item) => {
|
|
52
|
+
if (item.source === MediaSource.Enum.IPFS_IMG || item.source === MediaSource.Enum.IPFS_VID) {
|
|
53
|
+
return item.id.length === IPFS_HASH_LENGTH;
|
|
54
|
+
}
|
|
55
|
+
if (item.source === MediaSource.Enum.YOUTUBE) {
|
|
56
|
+
const youtubePattern = /^.*(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/|shorts\/|watch\?v=)([^#&?]*).*/;
|
|
57
|
+
return item.id === `https://www.youtube.com/watch?v=${item.name}` && youtubePattern.test(item.id);
|
|
58
|
+
}
|
|
59
|
+
if (item.source === MediaSource.Enum.VIMEO) {
|
|
60
|
+
return item.id === `https://vimeo.com/${item.name}`;
|
|
61
|
+
}
|
|
62
|
+
return item.type ? item.type in MediaType : true;
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
var validateMediaCount = (media) => {
|
|
66
|
+
const iconMediaCount = media.filter(
|
|
67
|
+
(item) => item.type === MediaType.Enum.ICON
|
|
68
|
+
).length;
|
|
69
|
+
return media.length <= MAX_MEDIA_COUNT && iconMediaCount <= 1;
|
|
70
|
+
};
|
|
71
|
+
var validateEventWiki = (wiki) => {
|
|
72
|
+
if (wiki.tags.some((tag) => tag.id === "Events")) {
|
|
73
|
+
const referencesData = wiki.metadata.find((meta) => meta.id === CommonMetaIds.Enum.references)?.value || "[]";
|
|
74
|
+
const references = JSON.parse(
|
|
75
|
+
referencesData
|
|
76
|
+
);
|
|
77
|
+
const hasEventLink = references.some(
|
|
78
|
+
(item) => item.description.toLowerCase() === "event link"
|
|
79
|
+
);
|
|
80
|
+
return hasEventLink && Array.isArray(wiki.events) && wiki.events.length > 0;
|
|
81
|
+
}
|
|
82
|
+
return true;
|
|
83
|
+
};
|
|
84
|
+
var areContentLinksVerified = (content) => {
|
|
85
|
+
const markdownLinks = content.match(/\[(.*?)\]\((.*?)\)/g);
|
|
86
|
+
return markdownLinks?.every((link) => {
|
|
87
|
+
const [, linkText, linkUrl] = RegExp(/\[(.*?)\]\((.*?)\)/).exec(link) || [];
|
|
88
|
+
if (linkText && linkUrl && WHITELISTED_LINK_NAMES.includes(linkText) && !isValidUrl(linkUrl)) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
if (linkUrl && !linkUrl.startsWith("#")) {
|
|
92
|
+
const validDomainPattern = new RegExp(
|
|
93
|
+
`^https?://(www\\.)?(${WHITELISTED_DOMAINS.join("|")})`
|
|
94
|
+
);
|
|
95
|
+
return validDomainPattern.test(linkUrl);
|
|
96
|
+
}
|
|
97
|
+
return true;
|
|
98
|
+
}) ?? true;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// src/schema/index.ts
|
|
102
|
+
var MediaType = zod.z.enum(["GALLERY", "ICON"]);
|
|
103
|
+
var MediaSource = zod.z.enum(["IPFS_IMG", "VIMEO", "YOUTUBE", "IPFS_VID"]);
|
|
104
|
+
var CommonMetaIds = zod.z.enum([
|
|
105
|
+
"references",
|
|
106
|
+
"website",
|
|
107
|
+
"contract_url",
|
|
108
|
+
"location",
|
|
109
|
+
"email_url",
|
|
110
|
+
"facebook_profile",
|
|
111
|
+
"instagram_profile",
|
|
112
|
+
"twitter_profile",
|
|
113
|
+
"linkedin_profile",
|
|
114
|
+
"youtube_profile",
|
|
115
|
+
"discord_profile",
|
|
116
|
+
"reddit_profile",
|
|
117
|
+
"telegram_profile",
|
|
118
|
+
"github_profile",
|
|
119
|
+
"coinmarketcap_url",
|
|
120
|
+
"coingecko_profile",
|
|
121
|
+
"opensea_profile",
|
|
122
|
+
"medium_profile",
|
|
123
|
+
"mirror_profile",
|
|
124
|
+
"tiktok_profile",
|
|
125
|
+
"etherscan_profile",
|
|
126
|
+
"arbiscan_profile",
|
|
127
|
+
"polygonscan_profile",
|
|
128
|
+
"bscscan_profile",
|
|
129
|
+
"optimistic_etherscan_profile",
|
|
130
|
+
"basescan_profile",
|
|
131
|
+
"ftmscan_profile",
|
|
132
|
+
"solscan_profile",
|
|
133
|
+
"avascan_profile",
|
|
134
|
+
"nearblocks_profile",
|
|
135
|
+
"troscan_profile",
|
|
136
|
+
"xrpscan_profile",
|
|
137
|
+
"kavascan_profile",
|
|
138
|
+
"tonscan_profile",
|
|
139
|
+
"celoscan_profile",
|
|
140
|
+
"cronoscan_profile",
|
|
141
|
+
"zkscan_profile",
|
|
142
|
+
"explorer_injective_profile",
|
|
143
|
+
"blastscan_profile"
|
|
144
|
+
]);
|
|
145
|
+
var EditSpecificMetaIds = zod.z.enum([
|
|
146
|
+
"previous_cid",
|
|
147
|
+
"commit-message",
|
|
148
|
+
"words-changed",
|
|
149
|
+
"percent-changed",
|
|
150
|
+
"blocks-changed",
|
|
151
|
+
"wiki-score"
|
|
152
|
+
]);
|
|
153
|
+
var ValidatorCodes = zod.z.enum([
|
|
154
|
+
"VALID_WIKI",
|
|
155
|
+
"ID_ERROR",
|
|
156
|
+
"LANGUAGE_ERROR",
|
|
157
|
+
"USER_ERROR",
|
|
158
|
+
"WORD_COUNT_ERROR",
|
|
159
|
+
"CATEGORY_ERROR",
|
|
160
|
+
"SUMMARY_ERROR",
|
|
161
|
+
"IMAGE_ERROR",
|
|
162
|
+
"TAG_ERROR",
|
|
163
|
+
"EXTERNAL_URL_ERROR",
|
|
164
|
+
"METADATA_ERROR",
|
|
165
|
+
"MEDIA_ERROR",
|
|
166
|
+
"GLOBAL_RATE_LIMIT",
|
|
167
|
+
"LINKED_WIKIS",
|
|
168
|
+
"EVENTS_ERROR"
|
|
169
|
+
]);
|
|
170
|
+
var LanguagesISO = zod.z.enum(["en", "es", "zh", "ko"]);
|
|
171
|
+
var LinkedWikiKey = zod.z.enum(["founders", "blockchains", "speakers"]);
|
|
172
|
+
var EventType = zod.z.enum(["CREATED", "DEFAULT", "MULTIDATE"]);
|
|
173
|
+
var Tag = zod.z.enum([
|
|
174
|
+
"Artists",
|
|
175
|
+
"AI",
|
|
176
|
+
"BinanceSmartChain",
|
|
177
|
+
"Blockchains",
|
|
178
|
+
"CEXes",
|
|
179
|
+
"Collections",
|
|
180
|
+
"Collectors",
|
|
181
|
+
"Conference",
|
|
182
|
+
"DEXes",
|
|
183
|
+
"Developers",
|
|
184
|
+
"Entertainment",
|
|
185
|
+
"Ethereum",
|
|
186
|
+
"Events",
|
|
187
|
+
"Forum",
|
|
188
|
+
"Founders",
|
|
189
|
+
"Festival",
|
|
190
|
+
"Games",
|
|
191
|
+
"Glossary",
|
|
192
|
+
"Hackathon",
|
|
193
|
+
"Marketplaces",
|
|
194
|
+
"Memecoins",
|
|
195
|
+
"Organizations",
|
|
196
|
+
"Online",
|
|
197
|
+
"PeopleInDeFi",
|
|
198
|
+
"Polkadot",
|
|
199
|
+
"Polygon",
|
|
200
|
+
"Protocols",
|
|
201
|
+
"Solana",
|
|
202
|
+
"Speakers",
|
|
203
|
+
"Stablecoins",
|
|
204
|
+
"Venture"
|
|
205
|
+
]);
|
|
206
|
+
var Category = zod.z.enum([
|
|
207
|
+
"nfts",
|
|
208
|
+
"defi",
|
|
209
|
+
"exchanges",
|
|
210
|
+
"cryptocurrencies",
|
|
211
|
+
"daos",
|
|
212
|
+
"people",
|
|
213
|
+
"dapps",
|
|
214
|
+
"organizations"
|
|
215
|
+
]);
|
|
216
|
+
var ProfileLinks = zod.z.object({
|
|
217
|
+
twitter: zod.z.string().nullable(),
|
|
218
|
+
website: zod.z.string().nullable(),
|
|
219
|
+
instagram: zod.z.string().nullable()
|
|
220
|
+
});
|
|
221
|
+
var ProfileData = zod.z.object({
|
|
222
|
+
id: zod.z.string().nullable(),
|
|
223
|
+
username: zod.z.string().nullable(),
|
|
224
|
+
bio: zod.z.string().nullable(),
|
|
225
|
+
links: zod.z.array(ProfileLinks).nullable(),
|
|
226
|
+
banner: zod.z.string().nullable(),
|
|
227
|
+
avatar: zod.z.string().nullable()
|
|
228
|
+
});
|
|
229
|
+
var Image = zod.z.object({
|
|
230
|
+
id: zod.z.string(),
|
|
231
|
+
type: zod.z.string()
|
|
232
|
+
});
|
|
233
|
+
var Media = zod.z.object({
|
|
234
|
+
id: zod.z.string(),
|
|
235
|
+
size: zod.z.string().nullish(),
|
|
236
|
+
name: zod.z.string().nullish(),
|
|
237
|
+
type: MediaType.nullish(),
|
|
238
|
+
caption: zod.z.string().nullish(),
|
|
239
|
+
thumbnail: zod.z.string().nullish(),
|
|
240
|
+
source: MediaSource
|
|
241
|
+
});
|
|
242
|
+
var MetaData = zod.z.object({
|
|
243
|
+
id: zod.z.union([CommonMetaIds, EditSpecificMetaIds]),
|
|
244
|
+
value: zod.z.any()
|
|
245
|
+
});
|
|
246
|
+
var BaseCategory = zod.z.object({
|
|
247
|
+
id: Category,
|
|
248
|
+
title: zod.z.string()
|
|
249
|
+
});
|
|
250
|
+
var BaseEvents = zod.z.object({
|
|
251
|
+
id: zod.z.string().optional().nullable(),
|
|
252
|
+
date: zod.z.string().nullable(),
|
|
253
|
+
title: zod.z.string().optional().nullable(),
|
|
254
|
+
type: EventType.nullable(),
|
|
255
|
+
description: zod.z.string().optional().nullable(),
|
|
256
|
+
link: zod.z.string().optional().nullable(),
|
|
257
|
+
multiDateStart: zod.z.string().optional().nullable(),
|
|
258
|
+
multiDateEnd: zod.z.string().optional().nullable(),
|
|
259
|
+
continent: zod.z.string().optional().nullable(),
|
|
260
|
+
country: zod.z.string().optional().nullable(),
|
|
261
|
+
action: zod.z.enum(["DELETE", "EDIT", "CREATE"]).optional().nullable()
|
|
262
|
+
});
|
|
263
|
+
var WikiReference = zod.z.object({
|
|
264
|
+
id: zod.z.string(),
|
|
265
|
+
title: zod.z.string()
|
|
266
|
+
});
|
|
267
|
+
var Wiki = zod.z.object({
|
|
268
|
+
id: zod.z.string(),
|
|
269
|
+
title: zod.z.string().min(1, "Add a Title at the top for this Wiki to continue").max(
|
|
270
|
+
WIKI_TITLE_MAX_LENGTH,
|
|
271
|
+
`Title should be less than ${WIKI_TITLE_MAX_LENGTH} characters`
|
|
272
|
+
),
|
|
273
|
+
ipfs: zod.z.string().optional(),
|
|
274
|
+
content: zod.z.string().min(1, "Add a Content section to continue").refine(
|
|
275
|
+
(content) => countWords(content) >= WIKI_CONTENT_MIN_WORDS,
|
|
276
|
+
`Add a minimum of ${WIKI_CONTENT_MIN_WORDS} words in the content section to continue`
|
|
277
|
+
).refine(
|
|
278
|
+
areContentLinksVerified,
|
|
279
|
+
"Please remove all external links from the content"
|
|
280
|
+
),
|
|
281
|
+
summary: zod.z.string().max(
|
|
282
|
+
WIKI_SUMMARY_MAX_LENGTH,
|
|
283
|
+
`Summary exceeds maximum limit of ${WIKI_SUMMARY_MAX_LENGTH}`
|
|
284
|
+
),
|
|
285
|
+
images: zod.z.array(Image).min(1, "Add a main image on the right column to continue"),
|
|
286
|
+
categories: zod.z.array(BaseCategory).min(1, "Add one category to continue"),
|
|
287
|
+
tags: zod.z.array(
|
|
288
|
+
zod.z.object({
|
|
289
|
+
id: zod.z.string()
|
|
290
|
+
})
|
|
291
|
+
).transform(
|
|
292
|
+
(tags) => tags.map((tag) => ({
|
|
293
|
+
id: Tag.parse(tag.id)
|
|
294
|
+
}))
|
|
295
|
+
).refine(
|
|
296
|
+
(tags) => {
|
|
297
|
+
const invalidTags = tags.filter(
|
|
298
|
+
(tag) => !Tag.safeParse(tag.id).success
|
|
299
|
+
);
|
|
300
|
+
if (invalidTags.length > 0) {
|
|
301
|
+
throw new Error(
|
|
302
|
+
`Invalid tag(s) found: ${invalidTags.map((tag) => tag.id).join(", ")}`
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
return true;
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
message: "Invalid tag(s) found"
|
|
309
|
+
}
|
|
310
|
+
),
|
|
311
|
+
media: zod.z.array(Media).max(MAX_MEDIA_COUNT).refine((media) => {
|
|
312
|
+
if (!media) return true;
|
|
313
|
+
return validateMediaContent(media) && validateMediaCount(media);
|
|
314
|
+
}, "Media is invalid").optional(),
|
|
315
|
+
metadata: zod.z.array(MetaData).refine((metadata) => {
|
|
316
|
+
const references = metadata.find(
|
|
317
|
+
(meta) => meta.id === CommonMetaIds.Enum.references
|
|
318
|
+
);
|
|
319
|
+
return !references?.value || references.value.length > 0;
|
|
320
|
+
}, "Please add at least one citation"),
|
|
321
|
+
events: zod.z.array(BaseEvents).optional().nullable(),
|
|
322
|
+
user: zod.z.object({
|
|
323
|
+
id: zod.z.string(),
|
|
324
|
+
profile: ProfileData.nullable()
|
|
325
|
+
}),
|
|
326
|
+
author: zod.z.object({
|
|
327
|
+
id: zod.z.string(),
|
|
328
|
+
profile: ProfileData.nullable()
|
|
329
|
+
}),
|
|
330
|
+
language: LanguagesISO.default(LanguagesISO.Enum.en),
|
|
331
|
+
version: zod.z.number().default(1),
|
|
332
|
+
hidden: zod.z.boolean().default(false),
|
|
333
|
+
promoted: zod.z.number().default(0),
|
|
334
|
+
views: zod.z.number().optional().default(0),
|
|
335
|
+
linkedWikis: zod.z.object({
|
|
336
|
+
[LinkedWikiKey.Enum.blockchains]: zod.z.array(zod.z.string()).optional().nullable(),
|
|
337
|
+
[LinkedWikiKey.Enum.founders]: zod.z.array(zod.z.string()).optional().nullable(),
|
|
338
|
+
[LinkedWikiKey.Enum.speakers]: zod.z.array(zod.z.string()).optional().nullable()
|
|
339
|
+
}).nullable().optional().default({}),
|
|
340
|
+
founderWikis: zod.z.array(WikiReference).optional().default([]),
|
|
341
|
+
blockchainWikis: zod.z.array(WikiReference).optional().default([])
|
|
342
|
+
}).refine(
|
|
343
|
+
(arg) => validateEventWiki(
|
|
344
|
+
arg
|
|
345
|
+
),
|
|
346
|
+
{
|
|
347
|
+
message: "Event wikis must have an event link citation and at least one event date",
|
|
348
|
+
path: ["events"]
|
|
349
|
+
}
|
|
350
|
+
);
|
|
351
|
+
var Reference = zod.z.object({
|
|
352
|
+
id: zod.z.string(),
|
|
353
|
+
description: zod.z.string(),
|
|
354
|
+
timestamp: zod.z.number(),
|
|
355
|
+
url: zod.z.string()
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// src/lib/wiki-score.ts
|
|
359
|
+
var contentQuality = (wordCount) => {
|
|
360
|
+
const scoreMin = 0;
|
|
361
|
+
const scoreMax = 1;
|
|
362
|
+
let score = 0;
|
|
363
|
+
if (wordCount < MIN_CONTENT_WORD_COUNT) {
|
|
364
|
+
return scoreMin;
|
|
365
|
+
}
|
|
366
|
+
if (wordCount >= MIN_CONTENT_WORD_COUNT && wordCount <= GOOD_CONTENT_WORD_COUNT) {
|
|
367
|
+
score = wordCount / GOOD_CONTENT_WORD_COUNT;
|
|
368
|
+
score *= 0.8;
|
|
369
|
+
}
|
|
370
|
+
if (wordCount > GOOD_CONTENT_WORD_COUNT && wordCount < IDEAL_CONTENT_WORD_COUNT) {
|
|
371
|
+
const baseScore = 0.8;
|
|
372
|
+
const wordCountAboveGood = wordCount - GOOD_CONTENT_WORD_COUNT;
|
|
373
|
+
const extraScoreFactor = wordCountAboveGood / (IDEAL_CONTENT_WORD_COUNT - GOOD_CONTENT_WORD_COUNT);
|
|
374
|
+
const extraScore = Math.sqrt(extraScoreFactor) * 0.2;
|
|
375
|
+
score = baseScore + extraScore;
|
|
376
|
+
}
|
|
377
|
+
if (wordCount >= IDEAL_CONTENT_WORD_COUNT) {
|
|
378
|
+
return scoreMax;
|
|
379
|
+
}
|
|
380
|
+
if (score < scoreMin) {
|
|
381
|
+
return scoreMin;
|
|
382
|
+
}
|
|
383
|
+
if (score > scoreMax) {
|
|
384
|
+
return scoreMax;
|
|
385
|
+
}
|
|
386
|
+
return score;
|
|
387
|
+
};
|
|
388
|
+
var countQuality = (idealCount, realCount) => {
|
|
389
|
+
const scoreMin = 0;
|
|
390
|
+
const scoreMax = 1;
|
|
391
|
+
const score = realCount / idealCount;
|
|
392
|
+
if (score < scoreMin) {
|
|
393
|
+
return scoreMin;
|
|
394
|
+
}
|
|
395
|
+
if (score > scoreMax) {
|
|
396
|
+
return scoreMax;
|
|
397
|
+
}
|
|
398
|
+
return score;
|
|
399
|
+
};
|
|
400
|
+
var getHostnameFromRegex = (url) => {
|
|
401
|
+
const matches = RegExp(/^https?:\/\/([^/?#]+)(?:[/?#]|$)/i).exec(url);
|
|
402
|
+
return matches?.[1];
|
|
403
|
+
};
|
|
404
|
+
var getWikiInternalLinks = (content) => {
|
|
405
|
+
const markdownLinkRegex = /\[(.*?)\]\((.*?)\)/g;
|
|
406
|
+
let internalLinksCount = 0;
|
|
407
|
+
let match = markdownLinkRegex.exec(content);
|
|
408
|
+
while (match !== null) {
|
|
409
|
+
const url = match[2];
|
|
410
|
+
if (url && !url.startsWith("#")) {
|
|
411
|
+
const hostname = getHostnameFromRegex(url);
|
|
412
|
+
if (hostname === "everipedia.org" || hostname === "iq.wiki" || hostname?.endsWith(".everipedia.org")) {
|
|
413
|
+
internalLinksCount++;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
match = markdownLinkRegex.exec(content);
|
|
417
|
+
}
|
|
418
|
+
return internalLinksCount;
|
|
419
|
+
};
|
|
420
|
+
var getWikiCitationLinks = (wiki) => {
|
|
421
|
+
const rawWikiReferences = wiki.metadata.find(
|
|
422
|
+
(m) => m.id === CommonMetaIds.Enum.references
|
|
423
|
+
)?.value;
|
|
424
|
+
if (rawWikiReferences === void 0 || rawWikiReferences?.trim().length === 0) {
|
|
425
|
+
return 0;
|
|
426
|
+
}
|
|
427
|
+
const wikiReferences = JSON.parse(rawWikiReferences);
|
|
428
|
+
return wikiReferences.length;
|
|
429
|
+
};
|
|
430
|
+
var getSocialsCount = (wiki) => {
|
|
431
|
+
let socialsCount = 0;
|
|
432
|
+
for (const meta of wiki.metadata) {
|
|
433
|
+
if (CommonMetaIds.options.includes(meta.id)) {
|
|
434
|
+
if (meta.value) {
|
|
435
|
+
socialsCount += 1;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
return socialsCount;
|
|
440
|
+
};
|
|
441
|
+
var calculateWikiScore = (wiki) => {
|
|
442
|
+
const wordCount = wiki.content.split(" ").length;
|
|
443
|
+
const internalLinksCount = getWikiInternalLinks(wiki.content);
|
|
444
|
+
const citationCount = getWikiCitationLinks(wiki);
|
|
445
|
+
const mediaCount = wiki.media?.length || 0;
|
|
446
|
+
const tagsCount = wiki.tags?.length || 0;
|
|
447
|
+
const summaryWordCount = wiki.summary?.length || 0;
|
|
448
|
+
const socialsCount = getSocialsCount(wiki);
|
|
449
|
+
const contentScore = contentQuality(wordCount);
|
|
450
|
+
const internalLinksScore = countQuality(
|
|
451
|
+
IDEAL_INTERNAL_LINKS_COUNT,
|
|
452
|
+
internalLinksCount
|
|
453
|
+
);
|
|
454
|
+
const citationScore = countQuality(IDEAL_CITATIONS_COUNT, citationCount);
|
|
455
|
+
const mediaScore = countQuality(IDEAL_MEDIA_COUNT, mediaCount);
|
|
456
|
+
const tagsScore = countQuality(IDEAL_TAGS_COUNT, tagsCount);
|
|
457
|
+
const summaryScore = countQuality(IDEAL_SUMMARY_LENGTH, summaryWordCount);
|
|
458
|
+
const socialsScore = countQuality(IDEAL_SOCIAL_MEDIA_COUNT, socialsCount);
|
|
459
|
+
const sumOfWeights = CONTENT_SCORE_WEIGHT + INTERNAL_LINKS_SCORE_WEIGHT + CITATIONS_SCORE_WEIGHT + MEDIA_SCORE_WEIGHT + TAGS_SCORE_WEIGHT + SUMMARY_SCORE_WEIGHT + SOCIAL_SCORE_WEIGHT;
|
|
460
|
+
const score = (contentScore * CONTENT_SCORE_WEIGHT + internalLinksScore * INTERNAL_LINKS_SCORE_WEIGHT + citationScore * CITATIONS_SCORE_WEIGHT + mediaScore * MEDIA_SCORE_WEIGHT + tagsScore * TAGS_SCORE_WEIGHT + summaryScore * SUMMARY_SCORE_WEIGHT + socialsScore * SOCIAL_SCORE_WEIGHT) / sumOfWeights;
|
|
461
|
+
const percentScore = Math.floor(score * 100);
|
|
462
|
+
return percentScore;
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
// src/lib/check-wiki-validity.ts
|
|
466
|
+
var countWords2 = (text) => text.split(" ").filter((word) => word !== "").length;
|
|
467
|
+
var isValidUrl2 = (urlString) => {
|
|
468
|
+
try {
|
|
469
|
+
return Boolean(new URL(urlString));
|
|
470
|
+
} catch (_e) {
|
|
471
|
+
return false;
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
var areContentLinksVerified2 = (content) => {
|
|
475
|
+
const markdownLinks = content.match(/\[(.*?)\]\((.*?)\)/g);
|
|
476
|
+
return markdownLinks?.every((link) => {
|
|
477
|
+
const [, linkText, linkUrl] = RegExp(/\[(.*?)\]\((.*?)\)/).exec(link) || [];
|
|
478
|
+
if (linkText && linkUrl && WHITELISTED_LINK_NAMES.includes(linkText) && !isValidUrl2(linkUrl)) {
|
|
479
|
+
return true;
|
|
480
|
+
}
|
|
481
|
+
if (linkUrl && !linkUrl.startsWith("#")) {
|
|
482
|
+
const validDomainPattern = new RegExp(
|
|
483
|
+
`^https?://(www\\.)?(${WHITELISTED_DOMAINS.join("|")})`
|
|
484
|
+
);
|
|
485
|
+
return validDomainPattern.test(linkUrl);
|
|
486
|
+
}
|
|
487
|
+
return true;
|
|
488
|
+
}) ?? true;
|
|
489
|
+
};
|
|
490
|
+
var isMediaValid = (wiki) => {
|
|
491
|
+
if (!wiki.media) return true;
|
|
492
|
+
const isMediaContentValid = wiki.media.every((media) => {
|
|
493
|
+
if (media.source === MediaSource.Enum.IPFS_IMG || media.source === MediaSource.Enum.IPFS_VID) {
|
|
494
|
+
return media.id.length === IPFS_HASH_LENGTH;
|
|
495
|
+
}
|
|
496
|
+
if (media.source === MediaSource.Enum.YOUTUBE) {
|
|
497
|
+
const youtubePattern = /^.*(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/|shorts\/|watch\?v=)([^#&?]*).*/;
|
|
498
|
+
return media.id === `https://www.youtube.com/watch?v=${media.name}` && youtubePattern.test(media.id);
|
|
499
|
+
}
|
|
500
|
+
if (media.source === MediaSource.Enum.VIMEO) {
|
|
501
|
+
return media.id === `https://vimeo.com/${media.name}`;
|
|
502
|
+
}
|
|
503
|
+
return media.type ? MediaType.options.includes(media.type) : true;
|
|
504
|
+
});
|
|
505
|
+
const iconMediaCount = wiki.media.filter(
|
|
506
|
+
(media) => media.type === MediaType.Enum.ICON
|
|
507
|
+
).length;
|
|
508
|
+
return wiki.media.length <= MAX_MEDIA_COUNT && isMediaContentValid && iconMediaCount <= 1;
|
|
509
|
+
};
|
|
510
|
+
var isAnyMediaUploading = (wiki) => wiki.media?.some((media) => media.id.endsWith(MEDIA_UPLOAD_PENDING_SUFFIX)) ?? false;
|
|
511
|
+
var isEventUrlMissing = (wiki) => {
|
|
512
|
+
if (wiki.tags.some((tag) => tag.id === "Events")) {
|
|
513
|
+
const referencesData = wiki.metadata.find((meta) => meta.id === CommonMetaIds.Enum.references)?.value || "[]";
|
|
514
|
+
const references = JSON.parse(referencesData);
|
|
515
|
+
return !references.some(
|
|
516
|
+
(item) => item.description.toLowerCase() === "event link"
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
return false;
|
|
520
|
+
};
|
|
521
|
+
var isEventDateMissing = (wiki) => wiki.tags.some((tag) => tag.id === "Events") && wiki.events?.length === 0;
|
|
522
|
+
var isSummaryTooLong = (wiki) => !!(wiki.summary && wiki.summary.length > WIKI_SUMMARY_MAX_LENGTH);
|
|
523
|
+
var hasNoCitations = (wiki) => {
|
|
524
|
+
const references = wiki.metadata.find(
|
|
525
|
+
(meta) => meta.id === CommonMetaIds.Enum.references
|
|
526
|
+
);
|
|
527
|
+
return !references?.value || references.value.length === 0;
|
|
528
|
+
};
|
|
529
|
+
var validateWiki = (wiki) => {
|
|
530
|
+
const wordCount = countWords2(wiki.content || "");
|
|
531
|
+
if (!wiki.title) {
|
|
532
|
+
return {
|
|
533
|
+
isValid: false,
|
|
534
|
+
error: "Add a Title at the top for this Wiki to continue"
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
if (wiki.title.length > WIKI_TITLE_MAX_LENGTH) {
|
|
538
|
+
return {
|
|
539
|
+
isValid: false,
|
|
540
|
+
error: `Title should be less than ${WIKI_TITLE_MAX_LENGTH} characters`
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
if (!wiki.content) {
|
|
544
|
+
return { isValid: false, error: "Add a Content section to continue" };
|
|
545
|
+
}
|
|
546
|
+
if (wordCount < WIKI_CONTENT_MIN_WORDS) {
|
|
547
|
+
return {
|
|
548
|
+
isValid: false,
|
|
549
|
+
error: `Add a minimum of ${WIKI_CONTENT_MIN_WORDS} words in the content section to continue. You have written ${wordCount}`
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
if (!areContentLinksVerified2(wiki.content)) {
|
|
553
|
+
return {
|
|
554
|
+
isValid: false,
|
|
555
|
+
error: "Please remove all external links from the content"
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
if (!wiki.images?.length) {
|
|
559
|
+
return {
|
|
560
|
+
isValid: false,
|
|
561
|
+
error: "Add a main image on the right column to continue"
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
if (wiki.categories.length === 0) {
|
|
565
|
+
return { isValid: false, error: "Add one category to continue" };
|
|
566
|
+
}
|
|
567
|
+
if (isSummaryTooLong(wiki)) {
|
|
568
|
+
return {
|
|
569
|
+
isValid: false,
|
|
570
|
+
error: `Summary exceeds maximum limit of ${WIKI_SUMMARY_MAX_LENGTH}`
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
if (isAnyMediaUploading(wiki)) {
|
|
574
|
+
return {
|
|
575
|
+
isValid: false,
|
|
576
|
+
error: "Some media are still uploading, please wait"
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
if (hasNoCitations(wiki)) {
|
|
580
|
+
return { isValid: false, error: "Please add at least one citation" };
|
|
581
|
+
}
|
|
582
|
+
if (isEventUrlMissing(wiki)) {
|
|
583
|
+
return {
|
|
584
|
+
isValid: false,
|
|
585
|
+
error: "Please cite the event official website with 'Event Link' description"
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
if (isEventDateMissing(wiki)) {
|
|
589
|
+
return {
|
|
590
|
+
isValid: false,
|
|
591
|
+
error: 'Please open the "Edit Wiki Details Modal" and enter a valid event date'
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
if (!isMediaValid(wiki)) {
|
|
595
|
+
return { isValid: false, error: "Media is invalid" };
|
|
596
|
+
}
|
|
597
|
+
return { isValid: true };
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
exports.BaseEvents = BaseEvents;
|
|
601
|
+
exports.CITATIONS_SCORE_WEIGHT = CITATIONS_SCORE_WEIGHT;
|
|
602
|
+
exports.CONTENT_SCORE_WEIGHT = CONTENT_SCORE_WEIGHT;
|
|
603
|
+
exports.Category = Category;
|
|
604
|
+
exports.CommonMetaIds = CommonMetaIds;
|
|
605
|
+
exports.CreateNewWikiSlug = CreateNewWikiSlug;
|
|
606
|
+
exports.EditSpecificMetaIds = EditSpecificMetaIds;
|
|
607
|
+
exports.EditorContentOverride = EditorContentOverride;
|
|
608
|
+
exports.GOOD_CONTENT_WORD_COUNT = GOOD_CONTENT_WORD_COUNT;
|
|
609
|
+
exports.IDEAL_CITATIONS_COUNT = IDEAL_CITATIONS_COUNT;
|
|
610
|
+
exports.IDEAL_CONTENT_WORD_COUNT = IDEAL_CONTENT_WORD_COUNT;
|
|
611
|
+
exports.IDEAL_INTERNAL_LINKS_COUNT = IDEAL_INTERNAL_LINKS_COUNT;
|
|
612
|
+
exports.IDEAL_MEDIA_COUNT = IDEAL_MEDIA_COUNT;
|
|
613
|
+
exports.IDEAL_SOCIAL_MEDIA_COUNT = IDEAL_SOCIAL_MEDIA_COUNT;
|
|
614
|
+
exports.IDEAL_SUMMARY_LENGTH = IDEAL_SUMMARY_LENGTH;
|
|
615
|
+
exports.IDEAL_TAGS_COUNT = IDEAL_TAGS_COUNT;
|
|
616
|
+
exports.INTERNAL_LINKS_SCORE_WEIGHT = INTERNAL_LINKS_SCORE_WEIGHT;
|
|
617
|
+
exports.IPFS_HASH_LENGTH = IPFS_HASH_LENGTH;
|
|
618
|
+
exports.Image = Image;
|
|
619
|
+
exports.MAX_MEDIA_COUNT = MAX_MEDIA_COUNT;
|
|
620
|
+
exports.MEDIA_SCORE_WEIGHT = MEDIA_SCORE_WEIGHT;
|
|
621
|
+
exports.MEDIA_UPLOAD_PENDING_SUFFIX = MEDIA_UPLOAD_PENDING_SUFFIX;
|
|
622
|
+
exports.MIN_CONTENT_WORD_COUNT = MIN_CONTENT_WORD_COUNT;
|
|
623
|
+
exports.Media = Media;
|
|
624
|
+
exports.MediaSource = MediaSource;
|
|
625
|
+
exports.MediaType = MediaType;
|
|
626
|
+
exports.Reference = Reference;
|
|
627
|
+
exports.SOCIAL_SCORE_WEIGHT = SOCIAL_SCORE_WEIGHT;
|
|
628
|
+
exports.SUMMARY_SCORE_WEIGHT = SUMMARY_SCORE_WEIGHT;
|
|
629
|
+
exports.TAGS_SCORE_WEIGHT = TAGS_SCORE_WEIGHT;
|
|
630
|
+
exports.Tag = Tag;
|
|
631
|
+
exports.ValidatorCodes = ValidatorCodes;
|
|
632
|
+
exports.WHITELISTED_DOMAINS = WHITELISTED_DOMAINS;
|
|
633
|
+
exports.WHITELISTED_LINK_NAMES = WHITELISTED_LINK_NAMES;
|
|
634
|
+
exports.WIKI_CONTENT_MIN_WORDS = WIKI_CONTENT_MIN_WORDS;
|
|
635
|
+
exports.WIKI_SUMMARY_MAX_LENGTH = WIKI_SUMMARY_MAX_LENGTH;
|
|
636
|
+
exports.WIKI_TITLE_MAX_LENGTH = WIKI_TITLE_MAX_LENGTH;
|
|
637
|
+
exports.Wiki = Wiki;
|
|
638
|
+
exports.areContentLinksVerified = areContentLinksVerified2;
|
|
639
|
+
exports.calculateWikiScore = calculateWikiScore;
|
|
640
|
+
exports.countWords = countWords2;
|
|
641
|
+
exports.hasNoCitations = hasNoCitations;
|
|
642
|
+
exports.isAnyMediaUploading = isAnyMediaUploading;
|
|
643
|
+
exports.isEventDateMissing = isEventDateMissing;
|
|
644
|
+
exports.isEventUrlMissing = isEventUrlMissing;
|
|
645
|
+
exports.isMediaValid = isMediaValid;
|
|
646
|
+
exports.isSummaryTooLong = isSummaryTooLong;
|
|
647
|
+
exports.isValidUrl = isValidUrl2;
|
|
648
|
+
exports.validateWiki = validateWiki;
|
|
649
|
+
//# sourceMappingURL=index.js.map
|
|
650
|
+
//# sourceMappingURL=index.js.map
|