1import spawnAsync from '@expo/spawn-async';
2import fs from 'fs-extra';
3import path from 'path';
4
5import { transformFileAsync } from '../../Transforms';
6
7export async function updateVersionedReactNativeAsync(
8  reactNativeRoot: string,
9  versionedReactNativeRoot: string
10): Promise<void> {
11  // Clone whole directories
12  const copyDirs = ['ReactAndroid', 'ReactCommon'];
13  await Promise.all(
14    copyDirs.map((subdir) => fs.remove(path.join(versionedReactNativeRoot, subdir)))
15  );
16  await Promise.all(
17    copyDirs.map((subdir) =>
18      fs.copy(path.join(reactNativeRoot, subdir), path.join(versionedReactNativeRoot, subdir))
19    )
20  );
21
22  // Run codegen
23  const codegenOutputRoot = path.join(versionedReactNativeRoot, 'codegen');
24  await fs.remove(codegenOutputRoot);
25  await runReactNativeCodegenAndroidAsync(reactNativeRoot, codegenOutputRoot);
26
27  // Patch ReactAndroid/build.gradle for codegen
28  const buildGradlePath = path.join(versionedReactNativeRoot, 'ReactAndroid', 'build.gradle');
29  await transformFileAsync(buildGradlePath, [
30    // Update codegen folder to our customized folder
31    {
32      find: /"REACT_GENERATED_SRC_DIR=.+?",/,
33      replaceWith: `"REACT_GENERATED_SRC_DIR=${versionedReactNativeRoot}",`,
34    },
35    // Add generated java to sourceSets
36    {
37      find: /(\bsrcDirs = \["src\/main\/java",.+)(])/,
38      replaceWith: `$1, "${codegenOutputRoot}/java"$2`,
39    },
40    // Disable codegen plugin
41    {
42      find: /(\bid\("com\.facebook\.react\.codegen"\)$)/m,
43      replaceWith: '// $1',
44    },
45    {
46      find: /(^react {[^]+?\n\})/m,
47      replaceWith: '/* $1 */',
48    },
49    {
50      find: /(\bdependsOn\("generateCodegenArtifactsFromSchema"\))/,
51      replaceWith: '// $1',
52    },
53  ]);
54}
55
56async function runReactNativeCodegenAndroidAsync(
57  reactNativeRoot: string,
58  codegenOutputRoot: string
59) {
60  await fs.ensureDir(codegenOutputRoot);
61
62  // generate schema.json from js & flow types
63  const genSchemaScript = path.join(
64    reactNativeRoot,
65    'packages',
66    'react-native-codegen',
67    'lib',
68    'cli',
69    'combine',
70    'combine-js-to-schema-cli.js'
71  );
72  const schemaOutputPath = path.join(codegenOutputRoot, 'schema.json');
73  const jsSourceRoot = path.join(reactNativeRoot, 'Libraries');
74  await spawnAsync('yarn', ['node', genSchemaScript, schemaOutputPath, jsSourceRoot]);
75
76  // generate code from schema.json
77  const genCodeScript = path.join(reactNativeRoot, 'scripts', 'generate-specs-cli.js');
78  await spawnAsync('yarn', [
79    'node',
80    genCodeScript,
81    'android',
82    schemaOutputPath,
83    codegenOutputRoot,
84    'ReactAndroidSpec',
85    'com.facebook.fbreact.specs',
86  ]);
87}
88