def usage(apis, directory, context_size=2, ignore_dirs=None): """Gets information about the usage of Chrome Apps APIs in an app directory. Args: apis: List of API names. directory: Path to app directory. context_size: Number of lines either side of each API usage to consider part of the context for that usage. Default is 2. ignore_dirs: Set of absolute directory paths to ignore. Optional. Returns: Dictionary mapping API names to dictionaries. These dictionaries then map member names to (filepath, linenum, context, context_linenum) tuples. - linenum is the line number of the API usage. - context is a string containing the lines of code surrounding references to the API usage. - context_linenum is the line number that the context starts on. """ if ignore_dirs is None: ignore_dirs = set() # Maps API names to dictionaries that map API members to contexts usage_data = {api: collections.defaultdict(list) for api in apis} api_regexes = { api: re.compile(r'chrome\.{}((?:\.\w+)+)'.format(api)) for api in apis } for js_path in walk.all_paths(directory, extension='js', ignore_dirs=ignore_dirs): with open(js_path, 'rU') as js_file: lines = [surrogateescape.decode(line) for line in js_file] for line_num, line in enumerate(lines): for api, regex in api_regexes.items(): match = regex.search(line) if match: context_linenum = max(0, line_num - context_size) member = match.group(1)[ 1:] # Slice to remove the leading dot. context = lines[context_linenum:line_num + context_size + 1] rel_path = os.path.relpath(js_path, directory) member_usage = (rel_path, line_num, ''.join(context), context_linenum) usage_data[api][member].append(member_usage) return usage_data
def usage(apis, directory, context_size=2, ignore_dirs=None): """Gets information about the usage of Chrome Apps APIs in an app directory. Args: apis: List of API names. directory: Path to app directory. context_size: Number of lines either side of each API usage to consider part of the context for that usage. Default is 2. ignore_dirs: Set of absolute directory paths to ignore. Optional. Returns: Dictionary mapping API names to dictionaries. These dictionaries then map member names to (filepath, linenum, context, context_linenum) tuples. - linenum is the line number of the API usage. - context is a string containing the lines of code surrounding references to the API usage. - context_linenum is the line number that the context starts on. """ if ignore_dirs is None: ignore_dirs = set() # Maps API names to dictionaries that map API members to contexts usage_data = {api: collections.defaultdict(list) for api in apis} api_regexes = {api: re.compile(r'chrome\.{}((?:\.\w+)+)'.format(api)) for api in apis} for js_path in walk.all_paths( directory, extension='js', ignore_dirs=ignore_dirs): with open(js_path, 'rU') as js_file: lines = [surrogateescape.decode(line) for line in js_file] for line_num, line in enumerate(lines): for api, regex in api_regexes.items(): match = regex.search(line) if match: context_linenum = max(0, line_num - context_size) member = match.group(1)[1:] # Slice to remove the leading dot. context = lines[context_linenum:line_num + context_size + 1] rel_path = os.path.relpath(js_path, directory) member_usage = (rel_path, line_num, ''.join(context), context_linenum) usage_data[api][member].append(member_usage) return usage_data
def app_apis(directory): """Returns a set of Chrome APIs used in a given app directory. Args: directory: App directory to search for Chrome APIs. Returns: A sorted list of Chrome API names. """ # This will be done really naively by searching for 'chrome.*'. # Note that this fails for cases like 'var a = chrome; a.tts;'. # For each js file in the directory, add all of the Chrome APIs being used to # a set of Chrome API names. apis = set() for js_path in walk.all_paths(directory, extension='js'): with open(js_path, 'rU') as js_file: js = surrogateescape.decode(js_file.read()) for api_match in CHROME_API_REGEX.finditer(js): apis.add(api_match.group(1)) return sorted(apis)