<commit_before>import 'package:quiver/collection.dart';

import '../core/change_detection/change_detection.dart'
    show ChangeDetectionStrategy;
import '../core/metadata/lifecycle_hooks.dart' show LifecycleHooks;
import '../core/metadata/view.dart';
import '../core/metadata/visibility.dart';
import '../facade/exceptions.dart' show BaseException;
import 'analyzed_class.dart';
import 'compiler_utils.dart';
import 'output/output_ast.dart' as o;
import 'selector.dart' show CssSelector;

// group 1: 'property' from '[property]'
// group 2: 'event' from '(event)'
var HOST_REG_EXP = new RegExp(r'^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))$');

abstract class CompileMetadataWithIdentifier<T> {
  CompileIdentifierMetadata<T> get identifier;
}

abstract class CompileMetadataWithType<T>
    extends CompileMetadataWithIdentifier<T> {
  CompileTypeMetadata get type;
}

class CompileIdentifierMetadata<T> implements CompileMetadataWithIdentifier<T> {
  // TODO(het): remove this once we switch to codegen. The transformer version
  // includes prefixes that aren't supposed to be emitted because it can't tell
  // if a prefix is a class name or a qualified import name.
  final bool emitPrefix;
  final List<o.OutputType> genericTypes;
  final String prefix;

  final String name;
  final String moduleUrl;
  final T value;

  /// If this identifier refers to a class declaration, this is non-null.
  final AnalyzedClass analyzedClass;

  CompileIdentifierMetadata(
      {this.name,
      this.moduleUrl,
      this.prefix,
      this.emitPrefix: false,
      this.genericTypes: const [],
      this.value,
      this.analyzedClass});

  @override
  CompileIdentifierMetadata<T> get identifier => this;
}

class CompileDiDependencyMetadata {
  final bool isAttribute;
  final bool isSelf;
  final bool isHost;
  final bool isSkipSelf;
  final bool isOptional;
  final bool isValue;
  CompileTokenMetadata token;
  dynamic value;
  CompileDiDependencyMetadata(
      {this.isAttribute: false,
      this.isSelf: false,
      this.isHost: false,
      this.isSkipSelf: false,
      this.isOptional: false,
      this.isValue: false,
      this.token,
      this.value});
}

class CompileProviderMetadata {
  final CompileTokenMetadata token;
  final CompileTypeMetadata useClass;
  dynamic useValue;
  final CompileTokenMetadata useExisting;
  final CompileFactoryMetadata useFactory;
  final List<CompileDiDependencyMetadata> deps;

  final bool multi;

  // TODO(matanl): Refactor to avoid two fields for multi-providers.
  final CompileTypeMetadata typeArgument;

  /// Restricts where the provider is injectable.
  final Visibility visibility;

  CompileProviderMetadata({
    this.token,
    this.useClass,
    this.useValue,
    this.useExisting,
    this.useFactory,
    this.deps,
    this.visibility: Visibility.all,
    this.multi: false,
    this.typeArgument,
  });

  @override
  // ignore: hash_and_equals
  bool operator ==(other) {
    if (other is! CompileProviderMetadata) return false;
    return token == other.token &&
        useClass == other.useClass &&
        useValue == other.useValue &&
        useExisting == other.useExisting &&
        useFactory == other.useFactory &&
        listsEqual(deps, other.deps) &&
        multi == other.multi;
  }

  @override
  String toString() => '{\n'
      'token:$token,\n'
      'useClass:$useClass,\n'
      'useValue:$useValue,\n'
      'useExisting:$useExisting,\n'
      'useFactory:$useFactory,\n'
      'deps:$deps,\n'
      'multi:$multi,\n'
      '}';
}

class CompileFactoryMetadata implements CompileIdentifierMetadata<Function> {
  @override
  String name;

  @override
  String prefix;

  @override
  bool emitPrefix;

  @override
  String moduleUrl;

  @override
  Function value;

  @override
  List<o.OutputType> get genericTypes => const [];

  List<CompileDiDependencyMetadata> diDeps;

  CompileFactoryMetadata(
      {this.name,
      this.moduleUrl,
      this.prefix,
      this.emitPrefix: false,
      this.diDeps: const [],
      this.value});

  @override
  CompileIdentifierMetadata<Function> get identifier => this;

  @override
  AnalyzedClass get analyzedClass => null;
}

class CompileTokenMetadata implements CompileMetadataWithIdentifier {
  dynamic value;
  @override
  CompileIdentifierMetadata identifier;
  bool identifierIsInstance;

  CompileTokenMetadata(
      {this.value, this.identifier, this.identifierIsInstance: false});

  // Used to determine unique-ness of CompileTokenMetadata.
  //
  // Because this code originated from the shared TypeScript source, a unique
  // String is emitted and compared, and not something more Dart-y like
  // equality. Should be refactored.
  dynamic get assetCacheKey {
    if (identifier != null) {
      return identifier.moduleUrl != null &&
              Uri.parse(identifier.moduleUrl).scheme != null
          ? ''
              '${identifier.name}|'
              '${identifier.moduleUrl}|'
              '$identifierIsInstance|'
              '$value|'
              '${identifier.genericTypes.map(_typeAssetKey).join(',')}'
          : null;
    } else {
      return value;
    }
  }

  static String _typeAssetKey(o.OutputType t) {
    if (t is o.ExternalType) {
      final generics = t.value.genericTypes != null
          ? t.value.genericTypes.map(_typeAssetKey).join(',')
          : '[]';
      return 'ExternalType {${t.value.moduleUrl}:${t.value.name}:$generics}';
    }
    return '{notExternalType}';
  }

  bool equalsTo(CompileTokenMetadata token2) {
    var ak = assetCacheKey;
    return (ak != null && ak == token2.assetCacheKey);
  }

  String get name {
    return value != null ? sanitizeIdentifier(value) : identifier?.name;
  }

  @override
  // ignore: hash_and_equals
  bool operator ==(other) {
    if (other is CompileTokenMetadata) {
      return value == other.value &&
          identifier == other.identifier &&
          identifierIsInstance == other.identifierIsInstance;
    }
    return false;
  }

  @override
  String toString() => '{\n'
      'value:$value,\n'
      'identifier:$identifier,\n'
      'identifierIsInstance:$identifierIsInstance,\n'
      '}';
}

class CompileTokenMap<V> {
  final _valueMap = new Map<dynamic, V>();
  final List<V> _values = [];
  final List<CompileTokenMetadata> _tokens = [];

  void add(CompileTokenMetadata token, V value) {
    var existing = get(token);
    if (existing != null) {
      throw new BaseException(
          'Add failed. Token already exists. Token: ${token.name}');
    }
    _tokens.add(token);
    _values.add(value);
    var ak = token.assetCacheKey;
    if (ak != null) {
      _valueMap[ak] = value;
    }
  }

  V get(CompileTokenMetadata token) {
    var ak = token.assetCacheKey;
    return ak != null ? _valueMap[ak] : null;
  }

  bool containsKey(CompileTokenMetadata token) => get(token) != null;

  List<CompileTokenMetadata> get keys => _tokens;

  List<V> get values => _values;

  int get size => _values.length;
}

/// Metadata regarding compilation of a type.
class CompileTypeMetadata
    implements CompileIdentifierMetadata<Type>, CompileMetadataWithType<Type> {
  @override
  String name;

  @override
  String prefix;

  @override
  final bool emitPrefix = false;

  @override
  String moduleUrl;

  bool isHost;

  @override
  Type value;

  List<CompileDiDependencyMetadata> diDeps;

  @override
  final List<o.OutputType> genericTypes;

  CompileTypeMetadata(
      {this.name,
      this.moduleUrl,
      this.prefix,
      this.isHost: false,
      this.value,
      this.genericTypes: const [],
      this.diDeps: const []});

  @override
  CompileIdentifierMetadata<Type> get identifier => this;

  @override
  CompileTypeMetadata get type => this;

  @override
  AnalyzedClass get analyzedClass => null;

  @override
  // ignore: hash_and_equals
  bool operator ==(other) {
    if (other is! CompileTypeMetadata) return false;
    return name == other.name &&
        prefix == other.prefix &&
        emitPrefix == other.emitPrefix &&
        moduleUrl == other.moduleUrl &&
        isHost == other.isHost &&
        value == other.value &&
        listsEqual(diDeps, other.diDeps);
  }

  @override
  String toString() => '{\n'
      'name:$name,\n'
      'prefix:$prefix,\n'
      'emitPrefix:$emitPrefix,\n'
      'moduleUrl:$moduleUrl,\n'
      'isHost:$isHost,\n'
      'value:$value,\n'
      'diDeps:$diDeps,\n'
      'genericTypes:$genericTypes\n'
      '}';
}

/// Provides metadata for Query, ViewQuery, ViewChildren,
/// ContentChild and ContentChildren decorators.
class CompileQueryMetadata {
  /// List of types or tokens to match.
  final List<CompileTokenMetadata> selectors;

  /// Whether nested elements should be queried.
  final bool descendants;<commit_msg>cleanup(Compiler): Make compile_metadata strong-mode clean<commit_after>import 'package:quiver/collection.dart';

import '../core/change_detection/change_detection.dart'
    show ChangeDetectionStrategy;
import '../core/metadata/lifecycle_hooks.dart' show LifecycleHooks;
import '../core/metadata/view.dart';
import '../core/metadata/visibility.dart';
import '../facade/exceptions.dart' show BaseException;
import 'analyzed_class.dart';
import 'compiler_utils.dart';
import 'output/output_ast.dart' as o;
import 'selector.dart' show CssSelector;

// group 1: 'property' from '[property]'
// group 2: 'event' from '(event)'
var HOST_REG_EXP = new RegExp(r'^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))$');

abstract class CompileMetadataWithIdentifier<T> {
  CompileIdentifierMetadata<T> get identifier;
}

abstract class CompileMetadataWithType<T>
    extends CompileMetadataWithIdentifier<T> {
  CompileTypeMetadata get type;
}

class CompileIdentifierMetadata<T> implements CompileMetadataWithIdentifier<T> {
  // TODO(het): remove this once we switch to codegen. The transformer version
  // includes prefixes that aren't supposed to be emitted because it can't tell
  // if a prefix is a class name or a qualified import name.
  final bool emitPrefix;
  final List<o.OutputType> genericTypes;
  final String prefix;

  final String name;
  final String moduleUrl;
  final T value;

  /// If this identifier refers to a class declaration, this is non-null.
  final AnalyzedClass analyzedClass;

  CompileIdentifierMetadata(
      {this.name,
      this.moduleUrl,
      this.prefix,
      this.emitPrefix: false,
      this.genericTypes: const [],
      this.value,
      this.analyzedClass});

  @override
  CompileIdentifierMetadata<T> get identifier => this;
}

class CompileDiDependencyMetadata {
  final bool isAttribute;
  final bool isSelf;
  final bool isHost;
  final bool isSkipSelf;
  final bool isOptional;
  final bool isValue;
  CompileTokenMetadata token;
  dynamic value;
  CompileDiDependencyMetadata(
      {this.isAttribute: false,
      this.isSelf: false,
      this.isHost: false,
      this.isSkipSelf: false,
      this.isOptional: false,
      this.isValue: false,
      this.token,
      this.value});
}

class CompileProviderMetadata {
  final CompileTokenMetadata token;
  final CompileTypeMetadata useClass;
  dynamic useValue;
  final CompileTokenMetadata useExisting;
  final CompileFactoryMetadata useFactory;
  final List<CompileDiDependencyMetadata> deps;

  final bool multi;

  // TODO(matanl): Refactor to avoid two fields for multi-providers.
  final CompileTypeMetadata typeArgument;

  /// Restricts where the provider is injectable.
  final Visibility visibility;

  CompileProviderMetadata({
    this.token,
    this.useClass,
    this.useValue,
    this.useExisting,
    this.useFactory,
    this.deps,
    this.visibility: Visibility.all,
    this.multi: false,
    this.typeArgument,
  });

  @override
  // ignore: hash_and_equals
  bool operator ==(other) {
    if (other is! CompileProviderMetadata) return false;
    CompileProviderMetadata _other = other;
    return token == _other.token &&
        useClass == _other.useClass &&
        useValue == _other.useValue &&
        useExisting == _other.useExisting &&
        useFactory == _other.useFactory &&
        listsEqual(deps, _other.deps) &&
        multi == _other.multi;
  }

  @override
  String toString() => '{\n'
      'token:$token,\n'
      'useClass:$useClass,\n'
      'useValue:$useValue,\n'
      'useExisting:$useExisting,\n'
      'useFactory:$useFactory,\n'
      'deps:$deps,\n'
      'multi:$multi,\n'
      '}';
}

class CompileFactoryMetadata implements CompileIdentifierMetadata<Function> {
  @override
  String name;

  @override
  String prefix;

  @override
  bool emitPrefix;

  @override
  String moduleUrl;

  @override
  Function value;

  @override
  List<o.OutputType> get genericTypes => const [];

  List<CompileDiDependencyMetadata> diDeps;

  CompileFactoryMetadata(
      {this.name,
      this.moduleUrl,
      this.prefix,
      this.emitPrefix: false,
      this.diDeps: const [],
      this.value});

  @override
  CompileIdentifierMetadata<Function> get identifier => this;

  @override
  AnalyzedClass get analyzedClass => null;
}

class CompileTokenMetadata implements CompileMetadataWithIdentifier {
  dynamic value;
  @override
  CompileIdentifierMetadata identifier;
  bool identifierIsInstance;

  CompileTokenMetadata(
      {this.value, this.identifier, this.identifierIsInstance: false});

  // Used to determine unique-ness of CompileTokenMetadata.
  //
  // Because this code originated from the shared TypeScript source, a unique
  // String is emitted and compared, and not something more Dart-y like
  // equality. Should be refactored.
  dynamic get assetCacheKey {
    if (identifier != null) {
      return identifier.moduleUrl != null &&
              Uri.parse(identifier.moduleUrl).scheme != null
          ? ''
              '${identifier.name}|'
              '${identifier.moduleUrl}|'
              '$identifierIsInstance|'
              '$value|'
              '${identifier.genericTypes.map(_typeAssetKey).join(',')}'
          : null;
    } else {
      return value;
    }
  }

  static String _typeAssetKey(o.OutputType t) {
    if (t is o.ExternalType) {
      final generics = t.value.genericTypes != null
          ? t.value.genericTypes.map(_typeAssetKey).join(',')
          : '[]';
      return 'ExternalType {${t.value.moduleUrl}:${t.value.name}:$generics}';
    }
    return '{notExternalType}';
  }

  bool equalsTo(CompileTokenMetadata token2) {
    var ak = assetCacheKey;
    return (ak != null && ak == token2.assetCacheKey);
  }

  String get name {
    return value != null ? sanitizeIdentifier(value) : identifier?.name;
  }

  @override
  // ignore: hash_and_equals
  bool operator ==(other) {
    if (other is CompileTokenMetadata) {
      return value == other.value &&
          identifier == other.identifier &&
          identifierIsInstance == other.identifierIsInstance;
    }
    return false;
  }

  @override
  String toString() => '{\n'
      'value:$value,\n'
      'identifier:$identifier,\n'
      'identifierIsInstance:$identifierIsInstance,\n'
      '}';
}

class CompileTokenMap<V> {
  final _valueMap = new Map<dynamic, V>();
  final List<V> _values = [];
  final List<CompileTokenMetadata> _tokens = [];

  void add(CompileTokenMetadata token, V value) {
    var existing = get(token);
    if (existing != null) {
      throw new BaseException(
          'Add failed. Token already exists. Token: ${token.name}');
    }
    _tokens.add(token);
    _values.add(value);
    var ak = token.assetCacheKey;
    if (ak != null) {
      _valueMap[ak] = value;
    }
  }

  V get(CompileTokenMetadata token) {
    var ak = token.assetCacheKey;
    return ak != null ? _valueMap[ak] : null;
  }

  bool containsKey(CompileTokenMetadata token) => get(token) != null;

  List<CompileTokenMetadata> get keys => _tokens;

  List<V> get values => _values;

  int get size => _values.length;
}

/// Metadata regarding compilation of a type.
class CompileTypeMetadata
    implements CompileIdentifierMetadata<Type>, CompileMetadataWithType<Type> {
  @override
  String name;

  @override
  String prefix;

  @override
  final bool emitPrefix = false;

  @override
  String moduleUrl;

  bool isHost;

  @override
  Type value;

  List<CompileDiDependencyMetadata> diDeps;

  @override
  final List<o.OutputType> genericTypes;

  CompileTypeMetadata(
      {this.name,
      this.moduleUrl,
      this.prefix,
      this.isHost: false,
      this.value,
      this.genericTypes: const [],
      this.diDeps: const []});

  @override
  CompileIdentifierMetadata<Type> get identifier => this;

  @override
  CompileTypeMetadata get type => this;

  @override
  AnalyzedClass get analyzedClass => null;

  @override
  // ignore: hash_and_equals
  bool operator ==(other) {
    if (other is! CompileTypeMetadata) return false;
    CompileTypeMetadata _other = other;
    return name == _other.name &&
        prefix == _other.prefix &&
        emitPrefix == _other.emitPrefix &&
        moduleUrl == _other.moduleUrl &&
        isHost == _other.isHost &&
        value == _other.value &&
        listsEqual(diDeps, _other.diDeps);
  }

  @override
  String toString() => '{\n'
      'name:$name,\n'
      'prefix:$prefix,\n'
      'emitPrefix:$emitPrefix,\n'
      'moduleUrl:$moduleUrl,\n'
      'isHost:$isHost,\n'
      'value:$value,\n'
      'diDeps:$diDeps,\n'
      'genericTypes:$genericTypes\n'
      '}';
}

/// Provides metadata for Query, ViewQuery, ViewChildren,
/// ContentChild and ContentChildren decorators.
class CompileQueryMetadata {
  /// List of types or tokens to match.
  final List<CompileTokenMetadata> selectors;

  /// Whether nested elements should be queried.
  final bool descendants;
{'fraction_non_alphanumeric': 0.11461577665779489, 'fraction_numerical': 0.00045302678520867546, 'mean_word_length': 3.2027605901951453, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 81, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6262757', 'n_tokens_mistral': 5386, 'n_tokens_neox': 5176, 'n_words': 1319}