base_generator.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. # Copyright 2019 The Chromium Authors. All rights reserved.
  2. # Use of this source code is governed by a BSD-style license that can be
  3. # found in the LICENSE file.
  4. import os
  5. import sys
  6. import collections
  7. import re
  8. import textwrap
  9. from style_variable_generator import path_overrides
  10. from style_variable_generator.color import Color
  11. from style_variable_generator.opacity import Opacity
  12. from style_variable_generator.model import Model, Modes, VariableType
  13. _FILE_PATH = os.path.dirname(os.path.realpath(__file__))
  14. _JSON5_PATH = os.path.join(_FILE_PATH, os.pardir, os.pardir, 'third_party',
  15. 'pyjson5', 'src')
  16. sys.path.insert(1, _JSON5_PATH)
  17. import json5
  18. _JINJA2_PATH = os.path.join(_FILE_PATH, os.pardir, os.pardir, 'third_party')
  19. sys.path.insert(1, _JINJA2_PATH)
  20. import jinja2
  21. class BaseGenerator:
  22. '''A generic style variable generator.
  23. Subclasses should provide format-specific generation templates, filters and
  24. globals to render their output.
  25. '''
  26. @staticmethod
  27. def GetName():
  28. return None
  29. def __init__(self):
  30. self.out_file_path = None
  31. self.model = Model()
  32. # A map of input filepaths to their context object.
  33. self.in_file_to_context = dict()
  34. # If specified, only generates the given mode.
  35. self.generate_single_mode = None
  36. # If true, resolves all blend() colors to the RGBA values at
  37. # compile time.
  38. self.resolve_blended_colors = True
  39. # A dictionary of options used to alter generator function. See
  40. # ./README.md for each generators list of options.
  41. self.generator_options = {}
  42. def GetInputFiles(self):
  43. return sorted(self.in_file_to_context.keys())
  44. def AddJSONFilesToModel(self, paths):
  45. '''Adds one or more JSON files to the model.
  46. '''
  47. for path in paths:
  48. try:
  49. with open(path, 'r') as f:
  50. self.AddJSONToModel(f.read(), path)
  51. except ValueError as err:
  52. raise ValueError(f'Could not add {path}') from err
  53. self.model.PostProcess(
  54. resolve_blended_colors=self.resolve_blended_colors)
  55. def AddJSONToModel(self, json_string, in_file=None):
  56. '''Adds a |json_string| with variable definitions to the model.
  57. See *test.json5 files for a defacto format reference.
  58. |in_file| is used to populate a file-to-context map.
  59. '''
  60. # TODO(calamity): Add allow_duplicate_keys=False once pyjson5 is
  61. # rolled.
  62. data = json5.loads(json_string,
  63. object_pairs_hook=collections.OrderedDict)
  64. context = data.get('options', {})
  65. context['token_namespace'] = data.get('token_namespace', '')
  66. self.in_file_to_context[in_file] = context
  67. # Add variables to the model.
  68. for name, value in data.get('colors', {}).items():
  69. self.model.Add(VariableType.COLOR, name, value, context)
  70. for name, value in data.get('opacities', {}).items():
  71. self.model.Add(VariableType.OPACITY, name, value, context)
  72. typography = data.get('typography')
  73. if typography:
  74. for name, value in typography['font_families'].items():
  75. self.model.Add(VariableType.FONT_FAMILY, name, value, context)
  76. for name, value_obj in typography['typefaces'].items():
  77. self.model.Add(VariableType.TYPEFACE, name, value_obj, context)
  78. for group_name, value_obj in data.get('untyped_css', {}).items():
  79. for var_name, value in value_obj.items():
  80. self.model.Add(VariableType.UNTYPED_CSS, var_name, value,
  81. context)
  82. def ApplyTemplate(self, style_generator, path_to_template, params):
  83. loader_root_dir = path_overrides.GetFileSystemLoaderRootDirectory()
  84. jinja_env = jinja2.Environment(
  85. loader=jinja2.FileSystemLoader(loader_root_dir),
  86. keep_trailing_newline=True)
  87. jinja_env.globals.update(style_generator.GetGlobals())
  88. jinja_env.filters.update(style_generator.GetFilters())
  89. template = jinja_env.get_template(
  90. path_overrides.GetPathToTemplate(path_to_template))
  91. return template.render(params)