/* eslint-env node */ import {existsSync, unlinkSync} from 'node:fs'; import fs from 'node:fs/promises'; import path from 'node:path'; // joining path of directory const tmpOutputPath = path.join( __dirname, '../static/app/constants/ios-device-list.tmp.tsx' ); const outputPath = path.join(__dirname, '../static/app/constants/ios-device-list.tsx'); const directoryPath = path.join(__dirname, '../node_modules/ios-device-list/'); type Generation = string; type Identifier = string; type Mapping = Record; async function getDefinitionFiles(): Promise { const files: string[] = []; const maybeJSONFiles = await fs.readdir(directoryPath); // listing all files using forEach for (const file of maybeJSONFiles) { if (!file.endsWith('.json') || file === 'package.json') { continue; } files.push(path.join(path.resolve(directoryPath), file)); } return files; } async function collectDefinitions(files: string[]): Promise { const definitions: Mapping = {}; const queue = [...files]; while (queue.length > 0) { const file = queue.pop(); if (!file) { throw new Error('Empty queue'); } const contents = await fs.readFile(file, 'utf8'); const content = JSON.parse(contents); if (typeof content?.[0]?.Identifier === 'undefined') { continue; } for (let i = 0; i < content.length; i++) { if (content[i].Identifier) { definitions[content[i].Identifier] = content[i].Generation; } } } return definitions; } const HEADER = ` // THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. // generated using scripts/extract-ios-device-names.ts as part of build step. // the purpose of the script is to extract only the iOS information that Sentry cares about // and discard the rest of the JSON so we do not end up bloating bundle size. `; // The formatting issues will be picked up by the CI and can quickly be fixed by // running `yarn fix` command that triggers the linter and formatter. const template = (contents: string) => { return ` ${HEADER} const iOSDeviceMapping: Record = ${contents} export {iOSDeviceMapping} `; }; async function run() { const files = await getDefinitionFiles(); const definitions = await collectDefinitions(files); const formatted = template(JSON.stringify(definitions, undefined, 2)); // All exit code has to synchronous function cleanup() { if (existsSync(tmpOutputPath)) { unlinkSync(tmpOutputPath); } } process.once('exit', cleanup); process.once('SIGINT', () => { cleanup(); process.exit(1); }); // Write to tmp output path await fs.writeFile(tmpOutputPath, formatted); // Rename the file (atomic) await fs.rename(tmpOutputPath, outputPath); } run() // eslint-disable-next-line no-console .catch(error => console.error(`Failed to run extract-ios-device-names`, error));