test.mjs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /* eslint-disable no-console, prefer-arrow-callback */
  2. import path from 'node:path'
  3. import process from 'node:process'
  4. import fs from 'node:fs'
  5. import { fileURLToPath } from 'node:url'
  6. import glob from 'glob'
  7. import chalk from 'chalk'
  8. import { getLocales, getPaths, omit } from './helpers.mjs'
  9. const root = fileURLToPath(new URL('../../', import.meta.url))
  10. const leadingLocaleName = 'en_US'
  11. const mode = process.argv[2]
  12. const pluginLocaleDependencies = {
  13. core: ['provider-views', 'companion-client'],
  14. }
  15. function getAllFilesPerPlugin (pluginNames) {
  16. const filesPerPlugin = {}
  17. function getFiles (name) {
  18. return glob
  19. .sync(`${root}/packages/@uppy/${name}/lib/**/*.js`)
  20. .filter((filePath) => !filePath.includes('locale.js'))
  21. .map((filePath) => fs.readFileSync(filePath, 'utf-8'))
  22. }
  23. for (const name of pluginNames) {
  24. filesPerPlugin[name] = getFiles(name)
  25. if (name in pluginLocaleDependencies) {
  26. for (const subDeb of pluginLocaleDependencies[name]) {
  27. filesPerPlugin[name].push(...getFiles(subDeb))
  28. }
  29. }
  30. }
  31. return filesPerPlugin
  32. }
  33. async function unused (filesPerPlugin, data) {
  34. for (const [name, fileStrings] of Object.entries(filesPerPlugin)) {
  35. const fileString = fileStrings.join('\n')
  36. const localePath = path.join(
  37. root,
  38. 'packages',
  39. '@uppy',
  40. name,
  41. 'src',
  42. 'locale.js',
  43. )
  44. const locale = (await import(localePath)).default
  45. for (const key of Object.keys(locale.strings)) {
  46. const regPat = new RegExp(
  47. `(i18n|i18nArray)\\([^\\)]*['\`"]${key}['\`"]`,
  48. 'g',
  49. )
  50. if (!fileString.match(regPat)) {
  51. return Promise.reject(new Error(`Unused locale key "${key}" in @uppy/${name}`))
  52. }
  53. }
  54. }
  55. return data
  56. }
  57. function warnings ({ leadingLocale, followerLocales }) {
  58. const entries = Object.entries(followerLocales)
  59. const logs = []
  60. for (const [name, locale] of entries) {
  61. const missing = Object.keys(leadingLocale).filter((key) => !(key in locale))
  62. const excess = Object.keys(locale).filter((key) => !(key in leadingLocale))
  63. logs.push('\n')
  64. logs.push(`--> Keys from ${leadingLocaleName} missing in ${name}`)
  65. logs.push('\n')
  66. for (const key of missing) {
  67. let value = leadingLocale[key]
  68. if (typeof value === 'object') {
  69. // For values with plural forms, just take the first one right now
  70. value = value[Object.keys(value)[0]]
  71. }
  72. logs.push(
  73. [
  74. `${chalk.cyan(name)} locale has missing string: '${chalk.red(key)}'`,
  75. `that is present in ${chalk.cyan(leadingLocaleName)}`,
  76. `with value: ${chalk.yellow(value)}`,
  77. ].join(' '),
  78. )
  79. }
  80. logs.push('\n')
  81. logs.push(`--> Keys from ${name} missing in ${leadingLocaleName}`)
  82. logs.push('\n')
  83. for (const key of excess) {
  84. logs.push(
  85. [
  86. `${chalk.cyan(name)} locale has excess string:`,
  87. `'${chalk.yellow(key)}' that is not present`,
  88. `in ${chalk.cyan(leadingLocaleName)}.`,
  89. ].join(' '),
  90. )
  91. }
  92. }
  93. console.log(logs.join('\n'))
  94. }
  95. function test () {
  96. switch (mode) {
  97. case 'unused':
  98. return getPaths(`${root}/packages/@uppy/**/src/locale.js`)
  99. .then((paths) => unused(getAllFilesPerPlugin(paths.map((filePath) => path.basename(path.join(filePath, '..', '..'))))))
  100. case 'warnings':
  101. return getLocales(`${root}/packages/@uppy/locales/src/*.js`)
  102. .then((locales) => warnings({
  103. leadingLocale: locales[leadingLocaleName],
  104. followerLocales: omit(locales, leadingLocaleName),
  105. }))
  106. default:
  107. return Promise.reject(new Error(`Invalid mode "${mode}"`))
  108. }
  109. }
  110. await test()
  111. console.log('\n')
  112. console.log('No blocking issues found')