1# Copyright 2018-present 650 Industries. All rights reserved.
2
3module Expo
4  class ReactImportPatcher
5
6    public def initialize(installer, options)
7      @root = installer.sandbox.root
8      @module_dirs = get_module_dirs(installer)
9      @options = options
10    end
11
12    public def run!
13      args = [
14        'node',
15        '--no-warnings',
16        '--eval',
17        'require(require.resolve(\'expo-modules-autolinking\', { paths: [\'' + __dir__ + '\'] }))(process.argv.slice(1))',
18        'patch-react-imports',
19        '--pods-root',
20        File.expand_path(@root),
21      ]
22
23      if @options[:dry_run]
24        args.append('--dry-run')
25      end
26
27      @module_dirs.each do |dir|
28        args.append(File.expand_path(dir))
29      end
30      Pod::UI.message "Executing ReactImportsPatcher node command: #{Shellwords.join(args)}"
31
32      time_begin = Process.clock_gettime(Process::CLOCK_MONOTONIC)
33      system(*args)
34      elapsed_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) - time_begin
35      Pod::UI.info "expo_patch_react_imports! took #{elapsed_time.round(4)} seconds to transform files."
36    end
37
38    private def get_module_dirs(installer)
39      unless installer.pods_project
40        Pod::UI.message '`pods_project` not found. This is expected when `:incremental_installation` is enabled in your project\'s Podfile.'
41        return []
42      end
43
44      result = []
45      installer.pods_project.development_pods.children.each do |pod|
46        if pod.is_a?(Xcodeproj::Project::Object::PBXFileReference) && pod.path.end_with?('.xcodeproj')
47          # Support generate_multiple_pod_projects or use_frameworks!
48          project = Xcodeproj::Project.open(File.join(installer.sandbox.root, pod.path))
49          groups = project.groups.select { |group| !(['Dependencies', 'Frameworks', 'Products'].include? group.name) }
50          groups.each do |group|
51            result.append(group.real_path.to_s)
52          end
53        else
54          result.append(pod.real_path.to_s)
55        end
56      end
57
58      result
59        .select { |dir| dir.include? '/node_modules/' }
60        .reject do |dir|
61          # Exclude known dirs unnecessary to patch and reduce processing time
62          # Since we are using real (absolute) pathnames we need to assert that we are inside of the node_modules
63          # directory to not collide with other directories in the user's filesystem.
64          # We reject the react-native package and packages starting with expo-
65          dir.match(%r{^.*/node_modules/(react-native(/.*)?|expo-.*)$})
66        end
67    end
68
69  end # class ReactImportPatcher
70end # module Expo
71