Index: third_party/closure_compiler/processor.py |
diff --git a/third_party/closure_compiler/processor.py b/third_party/closure_compiler/processor.py |
index 682dce4ee08dc17aaa0989c9f5b277eee7f1f23d..be6b79772009e39f8ef4ce8a27df990047632739 100644 |
--- a/third_party/closure_compiler/processor.py |
+++ b/third_party/closure_compiler/processor.py |
@@ -2,38 +2,83 @@ |
# Use of this source code is governed by a BSD-style license that can be |
# found in the LICENSE file. |
+"""Process Chrome resources (HTML/CSS/JS) to handle <include> and <if> tags.""" |
+ |
from collections import defaultdict |
import re |
import os |
class LineNumber(object): |
- def __init__(self, file, line_number): |
- self.file = file |
+ """A simple wrapper to hold line information (e.g. file.js:32). |
+ |
+ Args: |
+ source_file: A file path. |
+ line_number: The line in |file|. |
+ """ |
+ def __init__(self, source_file, line_number): |
+ self.file = source_file |
self.line_number = int(line_number) |
class FileCache(object): |
+ """An in-memory cache to speed up reading the same files over and over. |
+ |
+ Usage: |
+ FileCache.read(path_to_file) |
+ """ |
+ |
_cache = defaultdict(str) |
- def _read(self, file): |
- file = os.path.abspath(file) |
- self._cache[file] = self._cache[file] or open(file, "r").read() |
- return self._cache[file] |
+ @classmethod |
+ def read(self, source_file): |
+ """Read a file and return it as a string. |
+ |
+ Args: |
+ source_file: a file to read and return the contents of. |
- @staticmethod |
- def read(file): |
- return FileCache()._read(file) |
+ Returns: |
+ |file| as a string. |
+ """ |
+ abs_file = os.path.abspath(source_file) |
+ self._cache[abs_file] = self._cache[abs_file] or open(abs_file, "r").read() |
+ return self._cache[abs_file] |
class Processor(object): |
+ """Processes resource files, inlining the contents of <include> tags, removing |
+ <if> tags, and retaining original line info. |
+ |
+ For example |
+ |
+ 1: /* blah.js */ |
+ 2: <if expr="is_win"> |
+ 3: <include src="win.js"> |
+ 4: </if> |
+ |
+ would be turned into: |
+ |
+ 1: /* blah.js */ |
+ 2: |
+ 3: /* win.js */ |
+ 4: alert('Ew; Windows.'); |
+ 5: |
+ |
+ Args: |
+ source_file: A file to process. |
+ |
+ Attributes: |
+ contents: Expanded contents after inlining <include>s and stripping <if>s. |
+ included_files: A list of files that were inlined via <include>. |
+ """ |
+ |
_IF_TAGS_REG = "</?if[^>]*?>" |
_INCLUDE_REG = "<include[^>]+src=['\"]([^>]*)['\"]>" |
- def __init__(self, file): |
+ def __init__(self, source_file): |
self._included_files = set() |
self._index = 0 |
- self._lines = self._get_file(file) |
+ self._lines = self._get_file(source_file) |
while self._index < len(self._lines): |
current_line = self._lines[self._index] |
@@ -50,18 +95,25 @@ class Processor(object): |
self.contents = "\n".join(l[2] for l in self._lines) |
# Returns a list of tuples in the format: (file, line number, line contents). |
- def _get_file(self, file): |
- lines = FileCache.read(file).splitlines() |
- return [(file, lnum + 1, line) for lnum, line in enumerate(lines)] |
+ def _get_file(self, source_file): |
+ lines = FileCache.read(source_file).splitlines() |
+ return [(source_file, lnum + 1, line) for lnum, line in enumerate(lines)] |
- def _include_file(self, file): |
- self._included_files.add(file) |
- f = self._get_file(file) |
+ def _include_file(self, source_file): |
+ self._included_files.add(source_file) |
+ f = self._get_file(source_file) |
self._lines = self._lines[:self._index] + f + self._lines[self._index + 1:] |
def get_file_from_line(self, line_number): |
+ """Get the original file and line number for an expanded file's line number. |
+ |
+ Args: |
+ line_number: A processed file's line number. |
+ """ |
line_number = int(line_number) - 1 |
return LineNumber(self._lines[line_number][0], self._lines[line_number][1]) |
+ @property |
def included_files(self): |
+ """A list of files that were inlined via <include>.""" |
return self._included_files |