|
|
|
@ -8,44 +8,64 @@ import {
|
|
|
|
putLatestEtag,
|
|
|
|
putLatestEtag,
|
|
|
|
} from './database';
|
|
|
|
} from './database';
|
|
|
|
import { toSupportedLocale, toSupportedLocaleOrCustom } from './locale';
|
|
|
|
import { toSupportedLocale, toSupportedLocaleOrCustom } from './locale';
|
|
|
|
import type { CustomEmojiData, LocaleOrCustom } from './types';
|
|
|
|
import type { CustomEmojiData } from './types';
|
|
|
|
import { emojiLogger } from './utils';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const log = emojiLogger('loader');
|
|
|
|
export async function importEmojiData(localeString: string, path?: string) {
|
|
|
|
|
|
|
|
|
|
|
|
export async function importEmojiData(localeString: string) {
|
|
|
|
|
|
|
|
const locale = toSupportedLocale(localeString);
|
|
|
|
const locale = toSupportedLocale(localeString);
|
|
|
|
const emojis = await fetchAndCheckEtag<CompactEmoji[]>(locale);
|
|
|
|
|
|
|
|
|
|
|
|
// Validate the provided path.
|
|
|
|
|
|
|
|
if (path && !/^[/a-z]*\/packs\/assets\/compact-\w+\.json$/.test(path)) {
|
|
|
|
|
|
|
|
throw new Error('Invalid path for emoji data');
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// Otherwise get the path if not provided.
|
|
|
|
|
|
|
|
path ??= await localeToPath(locale);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const emojis = await fetchAndCheckEtag<CompactEmoji[]>(locale, path);
|
|
|
|
if (!emojis) {
|
|
|
|
if (!emojis) {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const flattenedEmojis: FlatCompactEmoji[] = flattenEmojiData(emojis);
|
|
|
|
const flattenedEmojis: FlatCompactEmoji[] = flattenEmojiData(emojis);
|
|
|
|
log('loaded %d for %s locale', flattenedEmojis.length, locale);
|
|
|
|
|
|
|
|
await putEmojiData(flattenedEmojis, locale);
|
|
|
|
await putEmojiData(flattenedEmojis, locale);
|
|
|
|
|
|
|
|
return flattenedEmojis;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export async function importCustomEmojiData() {
|
|
|
|
export async function importCustomEmojiData() {
|
|
|
|
const emojis = await fetchAndCheckEtag<CustomEmojiData[]>('custom');
|
|
|
|
const emojis = await fetchAndCheckEtag<CustomEmojiData[]>(
|
|
|
|
|
|
|
|
'custom',
|
|
|
|
|
|
|
|
'/api/v1/custom_emojis',
|
|
|
|
|
|
|
|
);
|
|
|
|
if (!emojis) {
|
|
|
|
if (!emojis) {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
log('loaded %d custom emojis', emojis.length);
|
|
|
|
|
|
|
|
await putCustomEmojiData(emojis);
|
|
|
|
await putCustomEmojiData(emojis);
|
|
|
|
|
|
|
|
return emojis;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const modules = import.meta.glob<string>(
|
|
|
|
|
|
|
|
'../../../../../node_modules/emojibase-data/**/compact.json',
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
query: '?url',
|
|
|
|
|
|
|
|
import: 'default',
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function localeToPath(locale: Locale) {
|
|
|
|
|
|
|
|
const key = `../../../../../node_modules/emojibase-data/${locale}/compact.json`;
|
|
|
|
|
|
|
|
if (!modules[key] || typeof modules[key] !== 'function') {
|
|
|
|
|
|
|
|
throw new Error(`Unsupported locale: ${locale}`);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return modules[key]();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function fetchAndCheckEtag<ResultType extends object[]>(
|
|
|
|
export async function fetchAndCheckEtag<ResultType extends object[]>(
|
|
|
|
localeOrCustom: LocaleOrCustom,
|
|
|
|
localeString: string,
|
|
|
|
|
|
|
|
path: string,
|
|
|
|
): Promise<ResultType | null> {
|
|
|
|
): Promise<ResultType | null> {
|
|
|
|
const locale = toSupportedLocaleOrCustom(localeOrCustom);
|
|
|
|
const locale = toSupportedLocaleOrCustom(localeString);
|
|
|
|
|
|
|
|
|
|
|
|
// Use location.origin as this script may be loaded from a CDN domain.
|
|
|
|
// Use location.origin as this script may be loaded from a CDN domain.
|
|
|
|
const url = new URL(location.origin);
|
|
|
|
const url = new URL(path, location.origin);
|
|
|
|
if (locale === 'custom') {
|
|
|
|
|
|
|
|
url.pathname = '/api/v1/custom_emojis';
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
const modulePath = await localeToPath(locale);
|
|
|
|
|
|
|
|
url.pathname = modulePath;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const oldEtag = await loadLatestEtag(locale);
|
|
|
|
const oldEtag = await loadLatestEtag(locale);
|
|
|
|
const response = await fetch(url, {
|
|
|
|
const response = await fetch(url, {
|
|
|
|
@ -60,38 +80,20 @@ async function fetchAndCheckEtag<ResultType extends object[]>(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!response.ok) {
|
|
|
|
if (!response.ok) {
|
|
|
|
throw new Error(
|
|
|
|
throw new Error(
|
|
|
|
`Failed to fetch emoji data for ${localeOrCustom}: ${response.statusText}`,
|
|
|
|
`Failed to fetch emoji data for ${locale}: ${response.statusText}`,
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const data = (await response.json()) as ResultType;
|
|
|
|
const data = (await response.json()) as ResultType;
|
|
|
|
if (!Array.isArray(data)) {
|
|
|
|
if (!Array.isArray(data)) {
|
|
|
|
throw new Error(
|
|
|
|
throw new Error(`Unexpected data format for ${locale}: expected an array`);
|
|
|
|
`Unexpected data format for ${localeOrCustom}: expected an array`,
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Store the ETag for future requests
|
|
|
|
// Store the ETag for future requests
|
|
|
|
const etag = response.headers.get('ETag');
|
|
|
|
const etag = response.headers.get('ETag');
|
|
|
|
if (etag) {
|
|
|
|
if (etag) {
|
|
|
|
await putLatestEtag(etag, localeOrCustom);
|
|
|
|
await putLatestEtag(etag, localeString);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return data;
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const modules = import.meta.glob<string>(
|
|
|
|
|
|
|
|
'../../../../../node_modules/emojibase-data/**/compact.json',
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
query: '?url',
|
|
|
|
|
|
|
|
import: 'default',
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function localeToPath(locale: Locale) {
|
|
|
|
|
|
|
|
const key = `../../../../../node_modules/emojibase-data/${locale}/compact.json`;
|
|
|
|
|
|
|
|
if (!modules[key] || typeof modules[key] !== 'function') {
|
|
|
|
|
|
|
|
throw new Error(`Unsupported locale: ${locale}`);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return modules[key]();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|