# All files / lib/analyzers mobile-analyzer.js

100% Statements 34/34
93.75% Branches 15/16
100% Functions 2/2
100% Lines 33/33

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79

    8x

    8x
    8x
    3x
    3x
    3x

    3x
    2x

    3x
    1x

    8x
    8x
    1x
    1x
    1x
    1x

    8x

    8x
    26x
    3x
    3x
    3x
    3x

    8x

    8x
    27x
    2x
    2x
    2x

    8x
    8x
    8x

    8x

     import fs from 'fs-extra';
    import path from 'path';

    export async function analyzeMobile(projectPath) {
      const detected = {
        frameworks: [],
        platforms: [],
        buildTools: [],
        configFiles: []
      };

      // Check package.json for React Native/Expo
      const pkgPath = path.join(projectPath, 'package.json');
      if (await fs.pathExists(pkgPath)) {
        try {
          const pkg = await fs.readJson(pkgPath);
          const deps = { ...pkg.dependencies, ...pkg.devDependencies };

          if (deps['react-native'] || Object.keys(deps).some(k => k.startsWith('@react-native/'))) {
            detected.frameworks.push('react-native');
          }
          if (deps.expo) {
            detected.buildTools.push('expo');
          }
        } catch (e) {
          // Ignore parse errors
        }
      }

      // Check Flutter: pubspec.yaml with sdk: flutter
      const pubspecPath = path.join(projectPath, 'pubspec.yaml');
      if (await fs.pathExists(pubspecPath)) {
        try {
          const content = await fs.readFile(pubspecPath, 'utf8');
          Eif (/sdk:\s*flutter/.test(content)) {
            detected.frameworks.push('flutter');
          }
        } catch (e) {}
      }

      // iOS detection
      const iosIndicators = [
        path.join(projectPath, 'ios'),
        path.join(projectPath, '.xcodeproj'),
        path.join(projectPath, 'Podfile'),
        path.join(projectPath, 'Podfile.lock')
      ];
      for (const indicator of iosIndicators) {
        if (await fs.pathExists(indicator)) {
          detected.frameworks.push('ios');
          detected.platforms.push('ios');
          detected.buildTools.push('xcode');
          break;
        }
      }

      // Android detection
      const androidIndicators = [
        path.join(projectPath, 'android'),
        path.join(projectPath, 'build.gradle'),
        path.join(projectPath, 'app/build.gradle'),
        path.join(projectPath, 'AndroidManifest.xml')
      ];
      for (const indicator of androidIndicators) {
        if (await fs.pathExists(indicator)) {
          detected.frameworks.push('android');
          detected.platforms.push('android');
          break;
        }
      }

      // Deduplicate
      detected.frameworks = [...new Set(detected.frameworks)];
      detected.platforms = [...new Set(detected.platforms)];
      detected.buildTools = [...new Set(detected.buildTools)];

      return detected;
    }