From ddfff51503a95d4d886d733b31395a9af82e0bc1 Mon Sep 17 00:00:00 2001 From: Alex Komz Date: Fri, 19 Jan 2024 20:50:20 +0300 Subject: [PATCH 1/4] fix(settings): replaces dynamic import with getting a ready static module loader --- src/settings/locales.ts | 147 +++++++++++++++++++++++++++++++++++++++ src/settings/settings.ts | 5 +- 2 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 src/settings/locales.ts diff --git a/src/settings/locales.ts b/src/settings/locales.ts new file mode 100644 index 0000000..6fc07c8 --- /dev/null +++ b/src/settings/locales.ts @@ -0,0 +1,147 @@ +type LocaleLoader = () => Promise; + +export const localeLoaders: Record = { + af: () => import('dayjs/locale/af.js'), + am: () => import('dayjs/locale/am.js'), + 'ar-dz': () => import('dayjs/locale/ar-dz.js'), + 'ar-iq': () => import('dayjs/locale/ar-iq.js'), + 'ar-kw': () => import('dayjs/locale/ar-kw.js'), + 'ar-ly': () => import('dayjs/locale/ar-ly.js'), + 'ar-ma': () => import('dayjs/locale/ar-ma.js'), + 'ar-sa': () => import('dayjs/locale/ar-sa.js'), + 'ar-tn': () => import('dayjs/locale/ar-tn.js'), + ar: () => import('dayjs/locale/ar.js'), + az: () => import('dayjs/locale/az.js'), + be: () => import('dayjs/locale/be.js'), + bg: () => import('dayjs/locale/bg.js'), + bi: () => import('dayjs/locale/bi.js'), + bm: () => import('dayjs/locale/bm.js'), + 'bn-bd': () => import('dayjs/locale/bn-bd.js'), + bn: () => import('dayjs/locale/bn.js'), + bo: () => import('dayjs/locale/bo.js'), + br: () => import('dayjs/locale/br.js'), + bs: () => import('dayjs/locale/bs.js'), + ca: () => import('dayjs/locale/ca.js'), + cs: () => import('dayjs/locale/cs.js'), + cv: () => import('dayjs/locale/cv.js'), + cy: () => import('dayjs/locale/cy.js'), + da: () => import('dayjs/locale/da.js'), + 'de-at': () => import('dayjs/locale/de-at.js'), + 'de-ch': () => import('dayjs/locale/de-ch.js'), + de: () => import('dayjs/locale/de.js'), + dv: () => import('dayjs/locale/dv.js'), + el: () => import('dayjs/locale/el.js'), + 'en-au': () => import('dayjs/locale/en-au.js'), + 'en-ca': () => import('dayjs/locale/en-ca.js'), + 'en-gb': () => import('dayjs/locale/en-gb.js'), + 'en-ie': () => import('dayjs/locale/en-ie.js'), + 'en-il': () => import('dayjs/locale/en-il.js'), + 'en-in': () => import('dayjs/locale/en-in.js'), + 'en-nz': () => import('dayjs/locale/en-nz.js'), + 'en-sg': () => import('dayjs/locale/en-sg.js'), + 'en-tt': () => import('dayjs/locale/en-tt.js'), + en: () => import('dayjs/locale/en.js'), + eo: () => import('dayjs/locale/eo.js'), + 'es-do': () => import('dayjs/locale/es-do.js'), + 'es-mx': () => import('dayjs/locale/es-mx.js'), + 'es-pr': () => import('dayjs/locale/es-pr.js'), + 'es-us': () => import('dayjs/locale/es-us.js'), + es: () => import('dayjs/locale/es.js'), + et: () => import('dayjs/locale/et.js'), + eu: () => import('dayjs/locale/eu.js'), + fa: () => import('dayjs/locale/fa.js'), + fi: () => import('dayjs/locale/fi.js'), + fo: () => import('dayjs/locale/fo.js'), + 'fr-ca': () => import('dayjs/locale/fr-ca.js'), + 'fr-ch': () => import('dayjs/locale/fr-ch.js'), + fr: () => import('dayjs/locale/fr.js'), + fy: () => import('dayjs/locale/fy.js'), + ga: () => import('dayjs/locale/ga.js'), + gd: () => import('dayjs/locale/gd.js'), + gl: () => import('dayjs/locale/gl.js'), + 'gom-latn': () => import('dayjs/locale/gom-latn.js'), + gu: () => import('dayjs/locale/gu.js'), + he: () => import('dayjs/locale/he.js'), + hi: () => import('dayjs/locale/hi.js'), + hr: () => import('dayjs/locale/hr.js'), + ht: () => import('dayjs/locale/ht.js'), + hu: () => import('dayjs/locale/hu.js'), + 'hy-am': () => import('dayjs/locale/hy-am.js'), + id: () => import('dayjs/locale/id.js'), + is: () => import('dayjs/locale/is.js'), + 'it-ch': () => import('dayjs/locale/it-ch.js'), + it: () => import('dayjs/locale/it.js'), + ja: () => import('dayjs/locale/ja.js'), + jv: () => import('dayjs/locale/jv.js'), + ka: () => import('dayjs/locale/ka.js'), + kk: () => import('dayjs/locale/kk.js'), + km: () => import('dayjs/locale/km.js'), + kn: () => import('dayjs/locale/kn.js'), + ko: () => import('dayjs/locale/ko.js'), + ku: () => import('dayjs/locale/ku.js'), + ky: () => import('dayjs/locale/ky.js'), + lb: () => import('dayjs/locale/lb.js'), + lo: () => import('dayjs/locale/lo.js'), + lt: () => import('dayjs/locale/lt.js'), + lv: () => import('dayjs/locale/lv.js'), + me: () => import('dayjs/locale/me.js'), + mi: () => import('dayjs/locale/mi.js'), + mk: () => import('dayjs/locale/mk.js'), + ml: () => import('dayjs/locale/ml.js'), + mn: () => import('dayjs/locale/mn.js'), + mr: () => import('dayjs/locale/mr.js'), + 'ms-my': () => import('dayjs/locale/ms-my.js'), + ms: () => import('dayjs/locale/ms.js'), + mt: () => import('dayjs/locale/mt.js'), + my: () => import('dayjs/locale/my.js'), + nb: () => import('dayjs/locale/nb.js'), + ne: () => import('dayjs/locale/ne.js'), + 'nl-be': () => import('dayjs/locale/nl-be.js'), + nl: () => import('dayjs/locale/nl.js'), + nn: () => import('dayjs/locale/nn.js'), + 'oc-lnc': () => import('dayjs/locale/oc-lnc.js'), + 'pa-in': () => import('dayjs/locale/pa-in.js'), + pl: () => import('dayjs/locale/pl.js'), + 'pt-br': () => import('dayjs/locale/pt-br.js'), + pt: () => import('dayjs/locale/pt.js'), + rn: () => import('dayjs/locale/rn.js'), + ro: () => import('dayjs/locale/ro.js'), + ru: () => import('dayjs/locale/ru.js'), + rw: () => import('dayjs/locale/rw.js'), + sd: () => import('dayjs/locale/sd.js'), + se: () => import('dayjs/locale/se.js'), + si: () => import('dayjs/locale/si.js'), + sk: () => import('dayjs/locale/sk.js'), + sl: () => import('dayjs/locale/sl.js'), + sq: () => import('dayjs/locale/sq.js'), + 'sr-cyrl': () => import('dayjs/locale/sr-cyrl.js'), + sr: () => import('dayjs/locale/sr.js'), + ss: () => import('dayjs/locale/ss.js'), + 'sv-fi': () => import('dayjs/locale/sv-fi.js'), + sv: () => import('dayjs/locale/sv.js'), + sw: () => import('dayjs/locale/sw.js'), + ta: () => import('dayjs/locale/ta.js'), + te: () => import('dayjs/locale/te.js'), + tet: () => import('dayjs/locale/tet.js'), + tg: () => import('dayjs/locale/tg.js'), + th: () => import('dayjs/locale/th.js'), + tk: () => import('dayjs/locale/tk.js'), + 'tl-ph': () => import('dayjs/locale/tl-ph.js'), + tlh: () => import('dayjs/locale/tlh.js'), + tr: () => import('dayjs/locale/tr.js'), + tzl: () => import('dayjs/locale/tzl.js'), + 'tzm-latn': () => import('dayjs/locale/tzm-latn.js'), + tzm: () => import('dayjs/locale/tzm.js'), + 'ug-cn': () => import('dayjs/locale/ug-cn.js'), + uk: () => import('dayjs/locale/uk.js'), + ur: () => import('dayjs/locale/ur.js'), + 'uz-latn': () => import('dayjs/locale/uz-latn.js'), + uz: () => import('dayjs/locale/uz.js'), + vi: () => import('dayjs/locale/vi.js'), + 'x-pseudo': () => import('dayjs/locale/x-pseudo.js'), + yo: () => import('dayjs/locale/yo.js'), + 'zh-cn': () => import('dayjs/locale/zh-cn.js'), + 'zh-hk': () => import('dayjs/locale/zh-hk.js'), + 'zh-tw': () => import('dayjs/locale/zh-tw.js'), + zh: () => import('dayjs/locale/zh.js'), +}; diff --git a/src/settings/settings.ts b/src/settings/settings.ts index d527b45..7e614c2 100644 --- a/src/settings/settings.ts +++ b/src/settings/settings.ts @@ -3,6 +3,7 @@ import cloneDeep from 'lodash/cloneDeep'; import dayjs from '../dayjs'; import {normalizeTimeZone} from '../timeZone'; +import {localeLoaders} from './locales'; import type {UpdateLocaleConfig} from './types'; class Settings { @@ -22,8 +23,8 @@ class Settings { if (!this.isLocaleLoaded(locale)) { try { const localeInLowerCase = locale.toLocaleLowerCase(); - // https://github.com/iamkun/dayjs/issues/792#issuecomment-639961997 - await import(`dayjs/locale/${localeInLowerCase}.js`); + const localeLoader = localeLoaders[localeInLowerCase]; + await localeLoader(); this.loadedLocales.add(localeInLowerCase); } catch (error) { throw new Error( From 55b3b997e393e166793fd2a5125236f450500df0 Mon Sep 17 00:00:00 2001 From: Alex Komz Date: Sat, 20 Jan 2024 15:18:27 +0300 Subject: [PATCH 2/4] feat(settings): adds a script to automatically update locales --- scripts/updateLocales.js | 70 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 scripts/updateLocales.js diff --git a/scripts/updateLocales.js b/scripts/updateLocales.js new file mode 100644 index 0000000..3ae31c4 --- /dev/null +++ b/scripts/updateLocales.js @@ -0,0 +1,70 @@ +/** + * Fetches and writes to the locale file from github dayjs + * node.js >= 20 lts + * @module Locale + * */ + +const fs = require('node:fs/promises'); + +const LOCALES_PATH = 'src/settings/locales.ts'; +const GITHUB_LOCALES_URL = 'https://github.com/iamkun/dayjs/tree/dev/src/locale'; + +const fetchLocalesList = async (githubUrl) => { + try { + const res = await fetch(githubUrl); + const json = await res.json(); + const {items} = json.payload.tree; + + return items.map((item) => item.name); + } catch (error) { + throw new Error( + `Something went wrong when trying to retrieve data from github dayjs, check if the URL is correct ${GITHUB_LOCALES_URL}`, + ); + } +}; + +const createLocaleFile = async (localesPath) => { + if (require('node:fs').existsSync(localesPath)) { + await fs.rm(localesPath); + } + + return await fs.open(localesPath, 'w'); +}; + +(async function () { + try { + const localesList = await fetchLocalesList(GITHUB_LOCALES_URL); + + console.log('Locales loaded successfully'); + + const localeFile = await createLocaleFile(LOCALES_PATH); + + console.log(`File "${LOCALES_PATH}" created successfully`); + + const localeLoaderType = + "type LocaleLoader = () => Promise;\n\n"; + + await localeFile.appendFile(localeLoaderType); + await localeFile.appendFile('export const localeLoaders: Record = '); + await localeFile.appendFile('{\n'); + + await Promise.allSettled( + localesList.map(async (locale) => { + if (locale === '' || locale === undefined || locale === null) return; + + const localeName = locale.substring(0, locale.lastIndexOf('.')); + const localeModulesObjectPart = ` "${localeName}": () => import('dayjs/locale/${locale}'),\n`; + + await localeFile.appendFile(localeModulesObjectPart); + + console.log(`Locale "${localeName}" written successfully`); + }), + ); + + await localeFile.appendFile('};\n'); + + console.log(`Object "localeLoaders" written in file "${LOCALES_PATH}" successfully`); + } catch (error) { + console.error(error); + } +})(); From 9001bf09965becc796ae9009cc0bd9169c28c8c9 Mon Sep 17 00:00:00 2001 From: Alex Komz Date: Tue, 23 Jan 2024 19:32:56 +0300 Subject: [PATCH 3/4] fix(scripts): optimizes the script by reducing the number of i/o operations to one --- scripts/updateLocales.js | 52 ++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/scripts/updateLocales.js b/scripts/updateLocales.js index 3ae31c4..a5c1610 100644 --- a/scripts/updateLocales.js +++ b/scripts/updateLocales.js @@ -23,7 +23,7 @@ const fetchLocalesList = async (githubUrl) => { } }; -const createLocaleFile = async (localesPath) => { +const createLocalesFile = async (localesPath) => { if (require('node:fs').existsSync(localesPath)) { await fs.rm(localesPath); } @@ -31,39 +31,45 @@ const createLocaleFile = async (localesPath) => { return await fs.open(localesPath, 'w'); }; -(async function () { - try { - const localesList = await fetchLocalesList(GITHUB_LOCALES_URL); +const buildLocalesContent = (localesList) => { + const isEmptyStr = (s) => !s.length || !s; + + const localeChunks = []; + + localeChunks.push("type LocaleLoader = () => Promise;\n"); + localeChunks.push('export const localeLoaders: Record = {'); + + localesList.forEach((locale) => { + if (isEmptyStr(locale)) return; - console.log('Locales loaded successfully'); + const name = locale.substring(0, locale.lastIndexOf('.')); + const localeName = name.includes('-') ? `'${name}'` : name; - const localeFile = await createLocaleFile(LOCALES_PATH); + localeChunks.push(` ${localeName}: () => import('dayjs/locale/${locale}'),`); + }); - console.log(`File "${LOCALES_PATH}" created successfully`); + localeChunks.push('};\n'); - const localeLoaderType = - "type LocaleLoader = () => Promise;\n\n"; + return localeChunks.join('\n'); +}; + +(async function () { + try { + const localesList = await fetchLocalesList(GITHUB_LOCALES_URL); - await localeFile.appendFile(localeLoaderType); - await localeFile.appendFile('export const localeLoaders: Record = '); - await localeFile.appendFile('{\n'); + console.info('Locales loaded successfully'); - await Promise.allSettled( - localesList.map(async (locale) => { - if (locale === '' || locale === undefined || locale === null) return; + const localeFile = await createLocalesFile(LOCALES_PATH); - const localeName = locale.substring(0, locale.lastIndexOf('.')); - const localeModulesObjectPart = ` "${localeName}": () => import('dayjs/locale/${locale}'),\n`; + console.info(`File "${LOCALES_PATH}" created successfully`); - await localeFile.appendFile(localeModulesObjectPart); + const localesContent = buildLocalesContent(localesList); - console.log(`Locale "${localeName}" written successfully`); - }), - ); + console.info(`File content built successfully`); - await localeFile.appendFile('};\n'); + await localeFile.appendFile(localesContent); - console.log(`Object "localeLoaders" written in file "${LOCALES_PATH}" successfully`); + console.info(`Object "localeLoaders" written in file "${LOCALES_PATH}" successfully`); } catch (error) { console.error(error); } From 2918e796ce4418dca0a796d156115a045558c575 Mon Sep 17 00:00:00 2001 From: Alex Komz Date: Thu, 25 Jan 2024 17:19:01 +0300 Subject: [PATCH 4/4] fix(scripts): uses the node_modules package as the source and adds the call to package.json --- package.json | 1 + scripts/updateLocales.js | 33 ++++++++++++++++----------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 08f1174..6d97460 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "test:watch": "jest --watchAll", "typecheck": "tsc --noEmit", "prepublishOnly": "npm run lint && npm run test && npm run build", + "updateLocales": "node scripts/updateLocales.js", "prepare": "husky install" }, "files": [ diff --git a/scripts/updateLocales.js b/scripts/updateLocales.js index a5c1610..6adbf44 100644 --- a/scripts/updateLocales.js +++ b/scripts/updateLocales.js @@ -4,31 +4,30 @@ * @module Locale * */ -const fs = require('node:fs/promises'); +const fs = require('node:fs'); +const fsPromises = require('node:fs/promises'); +const VALID_FILE_PATTERN = /^((?!index).)*.js$/; const LOCALES_PATH = 'src/settings/locales.ts'; -const GITHUB_LOCALES_URL = 'https://github.com/iamkun/dayjs/tree/dev/src/locale'; +const LOCALES_DIR_PATH = 'node_modules/dayjs/locale'; -const fetchLocalesList = async (githubUrl) => { - try { - const res = await fetch(githubUrl); - const json = await res.json(); - const {items} = json.payload.tree; - - return items.map((item) => item.name); - } catch (error) { - throw new Error( - `Something went wrong when trying to retrieve data from github dayjs, check if the URL is correct ${GITHUB_LOCALES_URL}`, - ); +const getLocalesList = async (localesDirPath) => { + if (fs.existsSync(localesDirPath)) { + const localesList = await fsPromises.readdir(localesDirPath); + return localesList.filter((locale) => VALID_FILE_PATTERN.test(locale)); } + + throw new Error( + 'The script was called before the dayjs library was installed, install it and try again', + ); }; const createLocalesFile = async (localesPath) => { - if (require('node:fs').existsSync(localesPath)) { - await fs.rm(localesPath); + if (fs.existsSync(localesPath)) { + await fsPromises.rm(localesPath); } - return await fs.open(localesPath, 'w'); + return await fsPromises.open(localesPath, 'w'); }; const buildLocalesContent = (localesList) => { @@ -55,7 +54,7 @@ const buildLocalesContent = (localesList) => { (async function () { try { - const localesList = await fetchLocalesList(GITHUB_LOCALES_URL); + const localesList = await getLocalesList(LOCALES_DIR_PATH); console.info('Locales loaded successfully');