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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
|
# Copyright 2017 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# pylint: disable=import-error,print-statement
import copy
import re
SPECIAL_TOKENS = [
# This list should be sorted by length.
'WebCodecs',
'WebSocket',
'String16',
'Float32',
'Float64',
'Base64',
'IFrame',
'Latin1',
'MathML',
'PlugIn',
'SQLite',
'Uint16',
'Uint32',
'WebGL2',
'webgl2',
'WebGPU',
'ASCII',
'CSSOM',
'CType',
'DList',
'Int16',
'Int32',
'MPath',
'OList',
'TSpan',
'UList',
'UTF16',
'Uint8',
'WebGL',
'XPath',
'ETC1',
'etc1',
'HTML',
'Int8',
'S3TC',
's3tc',
'SPv2',
'UTF8',
'sRGB',
'URLs',
'API',
'CSS',
'DNS',
'DOM',
'EXT',
'RTC',
'SVG',
'XSS',
'2D',
'AX',
'FE',
'JS',
'V0',
'V8',
'v8',
'XR',
]
_SPECIAL_TOKENS_WITH_NUMBERS = [
token for token in SPECIAL_TOKENS if re.search(r'[0-9]', token)
]
# Applying _TOKEN_PATTERNS repeatedly should capture any sequence of a-z, A-Z,
# 0-9.
_TOKEN_PATTERNS = [
# 'Foo' 'foo'
'[A-Z]?[a-z]+',
# The following pattern captures only 'FOO' in 'FOOElement'.
'[A-Z]+(?![a-z])',
# '2D' '3D', but not '2Dimension'
'[0-9][Dd](?![a-z])',
'[0-9]+',
]
_TOKEN_RE = re.compile(r'(' + '|'.join(SPECIAL_TOKENS + _TOKEN_PATTERNS) +
r')')
def tokenize_name(name):
"""Tokenize the specified name.
A token consists of A-Z, a-z, and 0-9 characters. Other characters work as
token delimiters, and the resultant list won't contain such characters.
Capital letters also work as delimiters. E.g. 'FooBar-baz' is tokenized to
['Foo', 'Bar', 'baz']. See _TOKEN_PATTERNS for more details.
This function detects special cases that are not easily discernible without
additional knowledge, such as recognizing that in SVGSVGElement, the first
two SVGs are separate tokens, but WebGL is one token.
Returns:
A list of token strings.
"""
# In case |name| is written in lowerCamelCase, we try to match special
# tokens that contains numbers ignoring cases only at the first step.
tokens = []
match = re.search(r'^(' + '|'.join(_SPECIAL_TOKENS_WITH_NUMBERS) + r')',
name, re.IGNORECASE)
if match:
tokens.append(match.group(0))
name = name[match.end(0):]
return tokens + _TOKEN_RE.findall(name)
class NameStyleConverter(object):
"""Converts names from camelCase to various other styles.
"""
def __init__(self, name):
self.tokens = tokenize_name(name)
self._original = name
@property
def original(self):
return self._original
def __str__(self):
return self._original
# Make this class workable with sort().
def __lt__(self, other):
return self.original < other.original
# Make this class workable with groupby().
def __eq__(self, other):
return self.original == other.original
# If __eq__() is defined then a custom __hash__() needs to be defined.
def __hash__(self):
return hash(self.original)
def to_snake_case(self):
"""Snake case is the file and variable name style per Google C++ Style
Guide:
https://google.github.io/styleguide/cppguide.html#Variable_Names
Also known as the hacker case.
https://en.wikipedia.org/wiki/Snake_case
"""
return '_'.join([token.lower() for token in self.tokens])
def to_upper_camel_case(self):
"""Upper-camel case is the class and function name style per
Google C++ Style Guide:
https://google.github.io/styleguide/cppguide.html#Function_Names
Also known as the PascalCase.
https://en.wikipedia.org/wiki/Camel_case.
"""
tokens = self.tokens
# If the first token is one of SPECIAL_TOKENS, we should replace the
# token with the matched special token.
# e.g. ['css', 'External', 'Scanner', 'Preload'] => 'CSSExternalScannerPreload'
if tokens and tokens[0].lower() == tokens[0]:
for special in SPECIAL_TOKENS:
if special.lower() == tokens[0]:
tokens = copy.deepcopy(tokens)
tokens[0] = special
break
return ''.join([token[0].upper() + token[1:] for token in tokens])
def to_lower_camel_case(self):
"""Lower camel case is the name style for attribute names and operation
names in web platform APIs.
e.g. 'addEventListener', 'documentURI', 'fftSize'
https://en.wikipedia.org/wiki/Camel_case.
"""
if not self.tokens:
return ''
return self.tokens[0].lower() + ''.join(
[token[0].upper() + token[1:] for token in self.tokens[1:]])
def to_macro_case(self):
"""Macro case is the macro name style per Google C++ Style Guide:
https://google.github.io/styleguide/cppguide.html#Macro_Names
"""
return '_'.join([token.upper() for token in self.tokens])
def to_all_cases(self):
return {
'snake_case': self.to_snake_case(),
'upper_camel_case': self.to_upper_camel_case(),
'macro_case': self.to_macro_case(),
}
# Use the following high level naming functions which describe the semantics
# of the name, rather than a particular style.
def to_class_name(self, prefix=None, suffix=None):
"""Represents this name as a class name in Chromium C++ style.
i.e. UpperCamelCase.
"""
camel_prefix = prefix[0].upper() + prefix[1:].lower() if prefix else ''
camel_suffix = suffix[0].upper() + suffix[1:].lower() if suffix else ''
return camel_prefix + self.to_upper_camel_case() + camel_suffix
def to_class_data_member(self, prefix=None, suffix=None):
"""Represents this name as a data member name in Chromium C++ style.
i.e. snake_case_with_trailing_underscore_.
"""
lower_prefix = prefix.lower() + '_' if prefix else ''
lower_suffix = suffix.lower() + '_' if suffix else ''
return lower_prefix + self.to_snake_case() + '_' + lower_suffix
def to_function_name(self, prefix=None, suffix=None):
"""Represents this name as a function name in Blink C++ style.
i.e. UpperCamelCase
Note that this function should not be used for IDL operation names and
C++ functions implementing IDL operations and attributes.
"""
camel_prefix = prefix[0].upper() + prefix[1:].lower() if prefix else ''
camel_suffix = ''
if type(suffix) is list:
for item in suffix:
camel_suffix += item[0].upper() + item[1:].lower()
elif suffix:
camel_suffix = suffix[0].upper() + suffix[1:].lower()
return camel_prefix + self.to_upper_camel_case() + camel_suffix
def to_enum_value(self):
"""Represents this name as an enum value in Blink C++ style.
i.e. kUpperCamelCase
"""
return 'k' + self.to_upper_camel_case()
def to_header_guard(self):
"""Represents this name as a header guard style in Chromium C++ style.
i.e. THIRD_PARTY_BLINK_RENDERER_MODULES_MODULES_EXPORT_H_
"""
return re.sub(r'[-/.]', '_', self.to_macro_case()) + '_'
|