Path: blob/trunk/javascript/private/closure_make_deps.py
8666 views
# Licensed to the Software Freedom Conservancy (SFC) under one1# or more contributor license agreements. See the NOTICE file2# distributed with this work for additional information3# regarding copyright ownership. The SFC licenses this file4# to you under the Apache License, Version 2.0 (the5# "License"); you may not use this file except in compliance6# with the License. You may obtain a copy of the License at7#8# http://www.apache.org/licenses/LICENSE-2.09#10# Unless required by applicable law or agreed to in writing,11# software distributed under the License is distributed on an12# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY13# KIND, either express or implied. See the License for the14# specific language governing permissions and limitations15# under the License.1617"""Generate a Closure deps.js file by scanning JS sources for goog.provide/require/module calls.1819Replaces the Node.js closure-make-deps wrapper to avoid npm symlink issues on Windows.2021Usage: closure_make_deps.py <files_list> <output> <closure_path>22files_list - path to a file containing one JS source path per line23output - path to write the generated deps.js24closure_path - directory containing Closure Library's base.js (for computing relative paths)25"""2627import os28import re29import sys3031PROVIDE_RE = re.compile(r"goog\.provide\(\s*['\"]([^'\"]+)['\"]\s*\)")32MODULE_RE = re.compile(r"goog\.module\(\s*['\"]([^'\"]+)['\"]\s*\)")33REQUIRE_RE = re.compile(r"goog\.require\(\s*['\"]([^'\"]+)['\"]\s*\)")343536def strip_comments(content):37"""Remove JS comments so regexes don't match goog.require() in documentation."""38content = re.sub(r"/\*.*?\*/", "", content, flags=re.DOTALL)39content = re.sub(r"//[^\n]*", "", content)40return content414243def parse_js_file(path):44"""Extract goog.provide, goog.module, and goog.require namespaces from a JS file."""45with open(path, encoding="utf-8") as f:46content = f.read()4748cleaned = strip_comments(content)4950provides = sorted(PROVIDE_RE.findall(cleaned))51modules = sorted(MODULE_RE.findall(cleaned))52requires = sorted(REQUIRE_RE.findall(cleaned))5354is_module = len(modules) > 055all_provides = sorted(set(provides + modules))5657return all_provides, requires, is_module585960def main():61if len(sys.argv) < 4:62print(63"Usage: closure_make_deps.py <files_list> <output> <closure_path>",64file=sys.stderr,65)66sys.exit(1)6768files_list_path = sys.argv[1]69output_path = sys.argv[2]70closure_path = sys.argv[3]7172with open(files_list_path, encoding="utf-8") as f:73files = [line.strip() for line in f if line.strip()]7475lines = []76for filepath in files:77provides, requires, is_module = parse_js_file(filepath)7879rel_path = os.path.relpath(filepath, closure_path)80# deps.js is consumed in the browser, so always use forward slashes81rel_path = rel_path.replace(os.sep, "/")8283provides_str = ", ".join(f"'{p}'" for p in provides)84requires_str = ", ".join(f"'{r}'" for r in requires)8586if is_module:87line = f"goog.addDependency('{rel_path}', [{provides_str}], [{requires_str}], {{'module': 'goog'}});"88else:89line = f"goog.addDependency('{rel_path}', [{provides_str}], [{requires_str}]);"9091lines.append((rel_path, line))9293# Sort by relative path for deterministic output94lines.sort(key=lambda x: x[0])9596with open(output_path, "w", encoding="utf-8") as f:97for _, line in lines:98f.write(line + "\n")99100101if __name__ == "__main__":102main()103104105