1#!/usr/bin/env node 2import axios from 'axios'; 3import chalk from 'chalk'; 4import { Command } from 'commander'; 5import fs from 'fs-extra'; 6import { compile } from 'json-schema-to-typescript'; 7import path from 'path'; 8import semver from 'semver'; 9 10let version: string = ''; 11 12const packageJSON = require('../package.json'); 13 14const program = new Command(packageJSON.name) 15 .version(packageJSON.version) 16 .arguments('[version]') 17 .usage(`${chalk.green('[version]')} [options]`) 18 .description('Generate TypeScript types from the Expo config JSON schema.') 19 .option('-p, --path <schema-path>', 'Path to a local JSON schema to use.') 20 .action((inputVersion: string, options: any) => { 21 version = inputVersion; 22 }) 23 .allowUnknownOption() 24 .parse(process.argv); 25 26async function fetchSchemaAsync(version: string): Promise<Record<string, any>> { 27 const url = `http://exp.host/--/api/v2/project/configuration/schema/${version}`; 28 29 const { 30 data: { data }, 31 } = await axios.get(url); 32 33 return data.schema; 34} 35 36(async () => { 37 let schema = {}; 38 if (program.path && typeof program.path === 'string') { 39 const filePath = path.resolve(program.path.trim()); 40 console.log(`Using local file: "${filePath}"`); 41 try { 42 schema = (await fs.readJSON(filePath)).schema; 43 } catch (error) { 44 console.warn('Failed to read the local JSON schema:'); 45 console.error(error); 46 process.exit(1); 47 } 48 if (!schema) { 49 console.error( 50 `The local file "${filePath}" doesn't contain a valid JSON schema with a top-level \`schema\` object` 51 ); 52 process.exit(1); 53 } 54 } else { 55 if (typeof version === 'string') { 56 version = version.trim(); 57 } 58 59 if (!version) { 60 // @ts-ignore 61 version = semver.parse(packageJSON.version).major; 62 console.log('Using package version: ' + version); 63 } 64 let parsedVersion = version; 65 if (parsedVersion !== 'unversioned') { 66 parsedVersion += '.0.0'; 67 } else { 68 parsedVersion = parsedVersion.toUpperCase(); 69 } 70 71 schema = await fetchSchemaAsync(parsedVersion); 72 } 73 74 const ts = await compile(schema as any, 'ExpoConfig', { 75 bannerComment: `/* tslint:disable */\n/**\n* The standard Expo config object defined in \`app.config.js\` files.\n*/`, 76 unknownAny: false, 77 }); 78 const filepath = `src/ExpoConfig.ts`; 79 fs.ensureDirSync(path.dirname(filepath)); 80 await fs.writeFile(filepath, ts, 'utf8'); 81})(); 82