extract-ios-device-names.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /* eslint-env node */
  2. import path from 'path';
  3. import fs from 'fs';
  4. import prettier from 'prettier';
  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. async function getDefinitionFiles(): Promise<string[]> {
  13. const files: string[] = [];
  14. const maybeJSONFiles = await fs.readdirSync(directoryPath);
  15. //listing all files using forEach
  16. maybeJSONFiles.forEach(file => {
  17. if (!file.endsWith('.json') || file === 'package.json') return;
  18. files.push(path.join(path.resolve(directoryPath), file));
  19. });
  20. return files;
  21. }
  22. type Generation = string;
  23. type Identifier = string;
  24. type Mapping = Record<Identifier, Generation>;
  25. async function collectDefinitions(files: string[]): Promise<Mapping> {
  26. const definitions: Mapping = {};
  27. const queue = [...files];
  28. while (queue.length > 0) {
  29. const file = queue.pop();
  30. if (!file) {
  31. throw new Error('Empty queue');
  32. }
  33. const contents = fs.readFileSync(file, 'utf-8');
  34. const content = JSON.parse(contents);
  35. if (typeof content?.[0]?.Identifier === 'undefined') {
  36. continue;
  37. }
  38. for (let i = 0; i < content.length; i++) {
  39. definitions[content[i].Identifier] = content[i].Generation;
  40. }
  41. }
  42. return definitions;
  43. }
  44. const HEADER = `
  45. // THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
  46. // generated using scripts/extract-ios-device-names.ts as part of build step.
  47. // the purpose of the script is to extract only the iOS information that Sentry cares about
  48. // and discard the rest of the JSON so we do not end up bloating bundle size.
  49. `;
  50. const template = (contents: string) => {
  51. return `
  52. ${HEADER}
  53. const iOSDeviceMapping: Record<string, string> = ${contents}
  54. export {iOSDeviceMapping}
  55. `;
  56. };
  57. const formatOutput = async (unformatted: string) => {
  58. const config = await prettier.resolveConfig(outputPath);
  59. if (config) {
  60. return prettier.format(unformatted, {...config, parser: 'babel'});
  61. }
  62. return unformatted;
  63. };
  64. export async function extractIOSDeviceNames() {
  65. const files = await getDefinitionFiles();
  66. const definitions = await collectDefinitions(files);
  67. const formatted = await formatOutput(
  68. template(JSON.stringify(definitions, undefined, 2))
  69. );
  70. // All exit code has to synchronous
  71. const cleanup = () => {
  72. if (fs.existsSync(tmpOutputPath)) {
  73. fs.unlinkSync(tmpOutputPath);
  74. }
  75. };
  76. process.on('exit', cleanup);
  77. process.on('SIGINT', () => {
  78. cleanup();
  79. process.exit(1);
  80. });
  81. // Write to tmp output path
  82. fs.writeFileSync(tmpOutputPath, formatted);
  83. // Rename the file (atomic)
  84. fs.renameSync(tmpOutputPath, outputPath);
  85. }