extract-ios-device-names.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /* eslint-env node */
  2. import {existsSync, unlinkSync} from 'node:fs';
  3. import fs from 'node:fs/promises';
  4. import path from 'node:path';
  5. // joining path of directory
  6. const tmpOutputPath = path.join(
  7. __dirname,
  8. '../static/app/constants/ios-device-list.tmp.tsx'
  9. );
  10. const outputPath = path.join(__dirname, '../static/app/constants/ios-device-list.tsx');
  11. const directoryPath = path.join(__dirname, '../node_modules/ios-device-list/');
  12. type Generation = string;
  13. type Identifier = string;
  14. type Mapping = Record<Identifier, Generation>;
  15. async function getDefinitionFiles(): Promise<string[]> {
  16. const files: string[] = [];
  17. const maybeJSONFiles = await fs.readdir(directoryPath);
  18. // listing all files using forEach
  19. for (const file of maybeJSONFiles) {
  20. if (!file.endsWith('.json') || file === 'package.json') {
  21. continue;
  22. }
  23. files.push(path.join(path.resolve(directoryPath), file));
  24. }
  25. return files;
  26. }
  27. async function collectDefinitions(files: string[]): Promise<Mapping> {
  28. const definitions: Mapping = {};
  29. const queue = [...files];
  30. while (queue.length > 0) {
  31. const file = queue.pop();
  32. if (!file) {
  33. throw new Error('Empty queue');
  34. }
  35. const contents = await fs.readFile(file, 'utf8');
  36. const content = JSON.parse(contents);
  37. if (typeof content?.[0]?.Identifier === 'undefined') {
  38. continue;
  39. }
  40. for (let i = 0; i < content.length; i++) {
  41. if (content[i].Identifier) {
  42. definitions[content[i].Identifier] = content[i].Generation;
  43. }
  44. }
  45. }
  46. return definitions;
  47. }
  48. const HEADER = `
  49. // THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
  50. // generated using scripts/extract-ios-device-names.ts as part of build step.
  51. // the purpose of the script is to extract only the iOS information that Sentry cares about
  52. // and discard the rest of the JSON so we do not end up bloating bundle size.
  53. `;
  54. // The formatting issues will be picked up by the CI and can quickly be fixed by
  55. // running `yarn fix` command that triggers the linter and formatter.
  56. const template = (contents: string) => {
  57. return `
  58. ${HEADER}
  59. const iOSDeviceMapping: Record<string, string> = ${contents}
  60. export {iOSDeviceMapping}
  61. `;
  62. };
  63. async function run() {
  64. const files = await getDefinitionFiles();
  65. const definitions = await collectDefinitions(files);
  66. const formatted = template(JSON.stringify(definitions, undefined, 2));
  67. // All exit code has to synchronous
  68. function cleanup() {
  69. if (existsSync(tmpOutputPath)) {
  70. unlinkSync(tmpOutputPath);
  71. }
  72. }
  73. process.once('exit', cleanup);
  74. process.once('SIGINT', () => {
  75. cleanup();
  76. process.exit(1);
  77. });
  78. // Write to tmp output path
  79. await fs.writeFile(tmpOutputPath, formatted);
  80. // Rename the file (atomic)
  81. await fs.rename(tmpOutputPath, outputPath);
  82. }
  83. run()
  84. // eslint-disable-next-line no-console
  85. .catch(error => console.error(`Failed to run extract-ios-device-names`, error));