checkTinyrackProject function

Future<TinyrackCheckResult> checkTinyrackProject([
  1. TinyrackCheckOptions options = const TinyrackCheckOptions()
])

Implementation

Future<TinyrackCheckResult> checkTinyrackProject([
  TinyrackCheckOptions options = const TinyrackCheckOptions(),
]) async {
  final requestedRoot = Directory(options.root).absolute;
  if (!requestedRoot.existsSync()) {
    throw FileSystemException(
      'Project root does not exist',
      requestedRoot.path,
    );
  }
  final root = Directory(requestedRoot.resolveSymbolicLinksSync());
  final files = _sourceFiles(root, _config(root, options.configPath)).toList()
    ..sort((left, right) => left.path.compareTo(right.path));
  final contexts = AnalysisContextCollection(
    includedPaths: <String>[root.path],
    sdkPath: _dartSdkPath(),
  );
  final violations = <TinyrackCheckViolation>[];
  final configuredThemes = <String>{};
  try {
    for (final file in files) {
      final source = file.readAsStringSync();
      final path = _pathKey(file.path.substring(root.path.length + 1));
      final resolved = await contexts
          .contextFor(file.path)
          .currentSession
          .getResolvedUnit(file.path);
      if (resolved is! ResolvedUnitResult) {
        throw FormatException('Could not resolve $path.');
      }
      final errors = resolved.diagnostics.where(
        (diagnostic) =>
            diagnostic.diagnosticCode.type == DiagnosticType.SYNTACTIC_ERROR,
      );
      if (errors.isNotEmpty) {
        final first = errors.first;
        final location = resolved.lineInfo.getLocation(first.offset);
        throw FormatException(
          '$path:${location.lineNumber}:${location.columnNumber} '
          '${first.message}',
        );
      }
      final variableVisitor = _VariableVisitor();
      resolved.unit.accept(variableVisitor);
      final visitor = _CheckVisitor(
        lineInfo: resolved.lineInfo,
        path: path,
        source: source,
        variables: variableVisitor.variables,
      );
      resolved.unit.accept(visitor);
      configuredThemes.addAll(visitor.configuredThemes);
      violations.addAll(visitor.violations);
    }
  } finally {
    await contexts.dispose();
  }
  for (final theme in const <String>['light', 'dark']) {
    if (files.isEmpty || configuredThemes.contains(theme)) continue;
    violations.add(
      TinyrackCheckViolation(
        column: 1,
        line: 1,
        message: 'The application does not configure TinyrackTheme.$theme().',
        path: '.',
        replacement: 'Configure both Tinyrack light and dark themes.',
        ruleId: 'setup/require-tinyrack-theme',
      ),
    );
  }
  violations.sort(
    (left, right) =>
        '${left.path}:${left.line}:${left.column}:${left.ruleId}'.compareTo(
          '${right.path}:${right.line}:${right.column}:${right.ruleId}',
        ),
  );
  return TinyrackCheckResult(
    checkedFiles: files.length,
    violations: violations,
  );
}