_validate.scss 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. //
  2. // Copyright 2021 Google LLC
  3. // SPDX-License-Identifier: Apache-2.0
  4. //
  5. @use 'sass:list';
  6. @use 'sass:map';
  7. @use 'sass:meta';
  8. @use './string-ext';
  9. /// Validates a theme's tokens and throws an error if incorrect tokens are
  10. /// present or any tokens are missing.
  11. ///
  12. /// Use this in internal `theme-styles()` mixins to validate library-provided
  13. /// `$theme` maps and ensure that all tokens are correct and present.
  14. ///
  15. /// @example - scss
  16. /// @mixin theme-styles($theme) {
  17. /// $theme: theme.validate-theme-styles($light-theme, $theme);
  18. /// $theme: theme.create-theme-vars($theme, checkbox);
  19. /// }
  20. ///
  21. /// @throw If any tokens are invalid or missing.
  22. /// @param {Map|List} $reference-theme - A reference theme Map whose token keys
  23. /// will be used to validate the user-provided theme (or list of tokens).
  24. /// @param {Map} $theme - The theme Map to validate.
  25. /// @return {Map} The validated theme Map.
  26. @function theme-styles($reference-theme, $theme, $require-all: true) {
  27. $valid-tokens: $reference-theme;
  28. @if meta.type-of($reference-theme) == 'map' {
  29. $valid-tokens: map.keys($reference-theme);
  30. }
  31. $theme: _validate-theme-tokens(
  32. $valid-tokens,
  33. $theme,
  34. $require-all: $require-all
  35. );
  36. @return $theme;
  37. }
  38. /// Validates a theme's tokens and values and throws an error if incorrect
  39. /// tokens are present or invalid values are provided.
  40. ///
  41. /// Use this in `theme()` mixins to validate user-provided `$theme` maps before
  42. /// providing the value to `theme.create-theme-vars()`.
  43. ///
  44. /// @example - scss
  45. /// @mixin theme($theme) {
  46. /// $theme: validate.theme($light-theme, $theme);
  47. /// $theme: theme.create-theme-vars($theme, checkbox);
  48. /// }
  49. ///
  50. /// @throw If any tokens or values are invalid.
  51. /// @param {Map|List} $reference-theme - A reference theme Map whose token keys
  52. /// will be used to validate the user-provided theme (or list of tokens).
  53. /// @param {Map} $theme - User-provided theme Map to validate.
  54. /// @return {Map} The validated user-provided theme Map.
  55. @function theme($reference-theme, $theme) {
  56. $valid-tokens: $reference-theme;
  57. @if meta.type-of($reference-theme) == 'map' {
  58. $valid-tokens: map.keys($reference-theme);
  59. }
  60. $theme: _validate-theme-tokens($valid-tokens, $theme, $require-all: false);
  61. @return $theme;
  62. }
  63. /// Validates input for a `theme` mixin and throws an error if incorrect tokens
  64. /// are present or optionally missing if `$require-all` is true.
  65. ///
  66. /// @throw If any tokens are invalid or optionally missing.
  67. /// @param {List} $valid-tokens - A List of token keys to validate the theme.
  68. /// @param {Map} $theme - The theme Map to validate.
  69. /// @param {Bool} $require-all [false] - If true, throw an error if the theme
  70. /// is missing tokens from the list.
  71. /// @return {Map} The validated theme Map.
  72. @function _validate-theme-tokens($valid-tokens, $theme, $require-all: false) {
  73. $missing-tokens: ();
  74. $unsupported-tokens: ();
  75. @each $token, $value in $theme {
  76. @if list.index($valid-tokens, $token) == null {
  77. $unsupported-tokens: list.append(
  78. $unsupported-tokens,
  79. $token,
  80. $separator: comma
  81. );
  82. }
  83. }
  84. @if $require-all {
  85. // TODO(b/203778922): Remove when type composite tokens are removed
  86. $ignore-suffix: (
  87. // Ignore composite font tokens
  88. '-type'
  89. );
  90. @each $token in $valid-tokens {
  91. $missing: map.get($theme, $token) == null;
  92. @if $missing {
  93. @each $suffix in $ignore-suffix {
  94. @if string-ext.has-suffix($token, $suffix) {
  95. $missing: false;
  96. }
  97. }
  98. }
  99. @if $missing {
  100. $missing-tokens: list.append(
  101. $missing-tokens,
  102. $token,
  103. $separator: comma
  104. );
  105. }
  106. }
  107. }
  108. @if list.length($unsupported-tokens) > 0 {
  109. @error 'The following tokens are invalid: #{$unsupported-tokens}.';
  110. }
  111. @if list.length($missing-tokens) > 0 {
  112. @error 'The following required tokens are missing: #{$missing-tokens}.';
  113. }
  114. @return $theme;
  115. }