extract-ios-device-names.ts 2.9 KB

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