index.mjs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /* eslint-disable no-console, prefer-arrow-callback */
  2. import path from 'node:path'
  3. import fs from 'node:fs'
  4. import { open, readFile, writeFile } from 'node:fs/promises'
  5. import { fileURLToPath } from 'node:url'
  6. import dedent from 'dedent'
  7. import { remark } from 'remark'
  8. import { headingRange } from 'mdast-util-heading-range'
  9. import remarkFrontmatter from 'remark-frontmatter'
  10. import remarkConfig from '../remark-lint-uppy/index.js'
  11. import { getLocales, sortObjectAlphabetically } from './helpers.mjs'
  12. const { settings: remarkSettings } = remarkConfig
  13. const root = fileURLToPath(new URL('../../', import.meta.url))
  14. const localesPath = path.join(root, 'packages', '@uppy', 'locales')
  15. const templatePath = path.join(localesPath, 'template.js')
  16. const englishLocalePath = path.join(localesPath, 'src', 'en_US.js')
  17. async function getLocalesAndCombinedLocale () {
  18. const locales = await getLocales(`${root}/packages/@uppy/**/src/locale.js`)
  19. const combinedLocale = {}
  20. for (const [pluginName, locale] of Object.entries(locales)) {
  21. for (const [key, value] of Object.entries(locale.strings)) {
  22. if (key in combinedLocale && value !== combinedLocale[key]) {
  23. throw new Error(`'${key}' from ${pluginName} already exists in locale pack.`)
  24. }
  25. combinedLocale[key] = value
  26. }
  27. }
  28. return [locales, sortObjectAlphabetically(combinedLocale)]
  29. }
  30. function generateTypes (pluginName, locale) {
  31. const allowedStringTypes = Object.keys(locale.strings)
  32. .map((key) => ` | '${key}'`)
  33. .join('\n')
  34. const pluginClassName = pluginName
  35. .split('-')
  36. .map((str) => str.replace(/^\w/, (c) => c.toUpperCase()))
  37. .join('')
  38. const localePath = path.join(
  39. root,
  40. 'packages',
  41. '@uppy',
  42. pluginName,
  43. 'types',
  44. 'generatedLocale.d.ts',
  45. )
  46. const localeTypes = dedent`
  47. /* eslint-disable */
  48. import type { Locale } from '@uppy/core'
  49. type ${pluginClassName}Locale = Locale<
  50. ${allowedStringTypes}
  51. >
  52. export default ${pluginClassName}Locale
  53. `
  54. return writeFile(localePath, localeTypes)
  55. }
  56. async function generateLocaleDocs (pluginName) {
  57. const fileName = `${pluginName}.md`
  58. const docPath = path.join(root, 'website', 'src', 'docs', fileName)
  59. const localePath = path.join(root, 'packages', '@uppy', pluginName, 'src', 'locale.js')
  60. const rangeOptions = { test: 'locale: {}', ignoreFinalDefinitions: true }
  61. let docFile
  62. try {
  63. docFile = await open(docPath, 'r+')
  64. } catch (err) {
  65. console.error(
  66. `⚠️ Could not find markdown documentation file for "${pluginName}". Make sure the plugin name matches the markdown file name.`,
  67. )
  68. throw err
  69. }
  70. const file = await remark()
  71. .data('settings', remarkSettings)
  72. .use(remarkFrontmatter)
  73. .use(() => (tree) => {
  74. // Replace all nodes after the locale heading until the next heading (or eof)
  75. headingRange(tree, rangeOptions, (start, _, end) => [
  76. start,
  77. {
  78. type: 'code',
  79. lang: 'js',
  80. meta: null,
  81. value: fs.readFileSync(localePath, 'utf-8').trimEnd(),
  82. },
  83. end,
  84. ])
  85. })
  86. .process(await docFile.readFile())
  87. const { bytesWritten } = await docFile.write(String(file), 0, 'utf-8')
  88. await docFile.truncate(bytesWritten)
  89. await docFile.close()
  90. }
  91. const [[locales, combinedLocale], fileString] = await Promise.all([
  92. getLocalesAndCombinedLocale(),
  93. readFile(templatePath, 'utf-8'),
  94. ])
  95. const formattedLocale = JSON.stringify(combinedLocale, null, ' ')
  96. await Promise.all([
  97. // Populate template
  98. writeFile(englishLocalePath, fileString.replace('en_US.strings = {}', `en_US.strings = ${formattedLocale}`))
  99. .then(() => console.log(`✅ Generated '${englishLocalePath}'`)),
  100. // Create locale files
  101. ...Object.entries(locales).flatMap(([pluginName, locale]) => [
  102. generateLocaleDocs(pluginName)
  103. .then(() => console.log(`✅ Generated locale docs for ${pluginName}`)),
  104. generateTypes(pluginName, locale)
  105. .then(() => console.log(`✅ Generated types for ${pluginName}`)),
  106. ]),
  107. ])