blob: 9c9e5f57731a9a8d5ff8a3ff1ad6429ba7ac4e02 [file] [log] [blame]
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/token.dart';
// A camel case string here is defined as:
// * An arbitrary number of optional leading `_`s or `$`s,
// * followed by an upper-case letter, `$` or `?`,
// * followed by any number of letters, digits, `?` or `$`s.
//
// This ensures that the text contains a `$`, `?` or upper-case letter
// before any lower-case letter or digit, and no letters or `?`s before an
// `_`.
final _camelCasePattern = RegExp(r'^_*(?:\$+_+)*[$?A-Z][$?a-zA-Z\d]*$');
// An identifier here is defined as:
// * A sequence of `_`, `$`, letters or digits,
// * where no `$` comes after a digit.
final _identifier = RegExp(r'^[_$a-z]+(\d[_a-z\d]*)?$', caseSensitive: false);
// A lower camel-case here is defined as:
// * Any number of optional leading underscores,
// * a lower case letter, `$` or `?` followed by a "word-tail"
// (a sequence of lower-case letters, digits, `$` or `?`),
// * followed by any number of either
// * an upper case letter followed by a word tail, or
// * an underscore and then a digit followed by a word tail.
// * and potentially ended by a single optional underscore.
final _lowerCamelCase = RegExp(
r'^_*[?$a-z][a-z\d?$]*(?:(?:[A-Z]|_\d)[a-z\d?$]*)*_?$',
);
@Deprecated('Prefer: ascii_utils.isValidFileName')
final _lowerCaseUnderScoreWithDots = RegExp(
r'^_?[_a-z\d]*(?:\.[a-z][_a-z\d]*)*$',
);
// A lower-case underscored (snake-case) with leading underscores is defined as
// * An optional leading sequence of any number of underscores,
// * followed by a sequence of lower-case letters, digits and underscores,
// * with no two adjacent underscores,
// * and not ending in an underscore.
final _lowerCaseUnderScoreWithLeadingUnderscores = RegExp(
r'^_*[a-z](?:_?[a-z\d])*$',
);
final Set<String> _reservedWords = {
for (var entry in Keyword.keywords.entries)
if (entry.value.isReservedWord) entry.key,
};
// A library prefix here is defined as:
// * An optional leading `?`,
// * then any number of underscores, `_`,
// * then a lower-case letter,
// * followed by any number of lower-case letters, digits and underscores.
final _validLibraryPrefix = RegExp(r'^\$?_*[a-z][_a-z\d]*$');
/// Whether this [string] is formatted in `CamelCase`.
bool isCamelCase(String string) => _isCamelCase(string);
/// Whether this [fileName] is a Dart file.
bool isDartFileName(String fileName) => fileName.endsWith('.dart');
/// Whether [id] is `lowerCamelCase`.
bool isLowerCamelCase(String id) =>
id.length == 1 && isUpperCase(id.codeUnitAt(0)) ||
id == '_' ||
_lowerCamelCase.hasMatch(id);
/// Whether this [id] is `lower_camel_case_with_underscores_or.dots`.
bool isLowerCaseUnderScoreWithDots(String id) =>
// ignore: deprecated_member_use_from_same_package
_lowerCaseUnderScoreWithDots.hasMatch(id);
/// Whether the given code unit [c] is upper case.
bool isUpperCase(int c) => c >= 0x40 && c <= 0x5A;
/// Whether this [libraryPrefix] is valid.
bool isValidLibraryPrefix(String libraryPrefix) =>
_validLibraryPrefix.hasMatch(libraryPrefix);
/// Whether this [id] is a valid package name.
bool isValidPackageName(String id) =>
_lowerCaseUnderScoreWithLeadingUnderscores.hasMatch(id) &&
_isIdentifier(id) &&
!_isReservedWord(id);
bool _isCamelCase(String name) => _camelCasePattern.hasMatch(name);
/// Whether this [name] is a legal Dart identifier.
bool _isIdentifier(String name) => _identifier.hasMatch(name);
/// Whether the given word is a Dart reserved word.
bool _isReservedWord(String word) => _reservedWords.contains(word);