easol-canvas 1.3.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4b413ee9262a5f7b363a8f53950da655c1c85aaf71474a331b412c62d5ae8f62
4
- data.tar.gz: ecae8f840fffee09e161857beb61cb002d3006f63e00e7e52283342c228234a9
3
+ metadata.gz: 5446d70b87d779a13b4a5b3f132b91a29722d84167fcc2ac9b61a142e7b5a45c
4
+ data.tar.gz: ccc2f5bc197c2f7ec72969289989742f3400f69e2a2eb468c001fd994237f2bc
5
5
  SHA512:
6
- metadata.gz: 42fe4d0cdede7d029e2e4c6ced43c23defb19a109bf11df3a4933d9411d2c6c83173042f4f2fee148573042760e62645eeb44b2e3af53e28b9bc91588c23d0a1
7
- data.tar.gz: 492e9fbeb71dfc80b56874d83e441ec799ae7ab04dedd668dc3e47c0cdfaabb0c9c9312fdeff2b792039ca44fb127af1eb1d876072c12d4c468567c6e20b6d6a
6
+ metadata.gz: a1b2ab985beac4aef8812c35fcda2707c52fc204c26435d7bf9dd7b33441dc9666739e4a9319e64e1fab31fab8f46d73e7af79c63b14ae21a084f517c0e7f9ea
7
+ data.tar.gz: f57a9566ebb142092e574dc0889a636c673342e5a71e5ccc1f111951c4ac1fa78995dbbe090cd2de7d5c3cd073dbecd3999aca06889a3beb5419d72616547090
@@ -22,8 +22,9 @@ module Canvas
22
22
  def run
23
23
  custom_types = Canvas::FetchCustomTypes.call
24
24
  block_files.each do |filename|
25
- file = File.read(filename)
26
- front_matter = extract_front_matter(file)
25
+ front_matter = extract_front_matter(filename)
26
+ next unless front_matter
27
+
27
28
  validate_format(filename, front_matter) &&
28
29
  validate_schema(filename, front_matter, custom_types)
29
30
  end
@@ -37,7 +38,8 @@ module Canvas
37
38
 
38
39
  def validate_format(filename, front_matter)
39
40
  return true if front_matter.is_a?(Hash) &&
40
- front_matter.values.all? { |attr| attr.is_a?(Hash) }
41
+ (front_matter.key?("attributes") ? front_matter["attributes"] : front_matter).values.all? { |attr| attr.is_a?(Hash) }
42
+
41
43
 
42
44
  @offenses << Offense.new(
43
45
  message: "Invalid Block Schema: #{filename} - \nSchema is not in a valid format"
@@ -45,8 +47,7 @@ module Canvas
45
47
  false
46
48
  end
47
49
 
48
- def validate_schema(filename, front_matter, custom_types)
49
- schema = extract_schema(front_matter)
50
+ def validate_schema(filename, schema, custom_types)
50
51
  validator = Validator::BlockSchema.new(schema: schema, custom_types: custom_types)
51
52
  return if validator.validate
52
53
 
@@ -57,16 +58,18 @@ module Canvas
57
58
  end
58
59
  end
59
60
 
60
- def extract_front_matter(file)
61
+ def extract_front_matter(filename)
62
+ file = File.read(filename)
63
+
61
64
  extractor = Canvas::FrontMatterExtractor.new(file)
62
65
  front_matter = extractor.front_matter
63
66
  front_matter.nil? ? {} : YAML.safe_load(front_matter)
64
- end
67
+ rescue Psych::SyntaxError
68
+ @offenses << Offense.new(
69
+ message: "Invalid Block Schema: #{filename} - \nFront matter's YAML is not in a valid format"
70
+ )
65
71
 
66
- def extract_schema(front_matter)
67
- {
68
- "attributes" => Canvas::ExpandAttributes.call(front_matter)
69
- }
72
+ nil
70
73
  end
71
74
  end
72
75
  end
@@ -51,8 +51,7 @@ module Canvas
51
51
  front_matter["attributes"].values.all? { |attr| attr.is_a?(Hash) }
52
52
  end
53
53
 
54
- def validate_schema(front_matter)
55
- schema = extract_schema(front_matter)
54
+ def validate_schema(schema)
56
55
  validator = Validator::FooterSchema.new(
57
56
  schema: schema,
58
57
  custom_types: Canvas::FetchCustomTypes.call
@@ -71,11 +70,5 @@ module Canvas
71
70
  front_matter = extractor.front_matter
72
71
  front_matter.nil? ? {} : YAML.safe_load(front_matter)
73
72
  end
74
-
75
- def extract_schema(front_matter)
76
- front_matter.merge(
77
- "attributes" => Canvas::ExpandAttributes.call(front_matter["attributes"])
78
- )
79
- end
80
73
  end
81
74
  end
@@ -51,8 +51,7 @@ module Canvas
51
51
  front_matter["attributes"].values.all? { |attr| attr.is_a?(Hash) }
52
52
  end
53
53
 
54
- def validate_schema(front_matter)
55
- schema = extract_schema(front_matter)
54
+ def validate_schema(schema)
56
55
  validator = Validator::MenuSchema.new(
57
56
  schema: schema,
58
57
  custom_types: Canvas::FetchCustomTypes.call
@@ -71,11 +70,5 @@ module Canvas
71
70
  front_matter = extractor.front_matter
72
71
  front_matter.nil? ? {} : YAML.safe_load(front_matter)
73
72
  end
74
-
75
- def extract_schema(front_matter)
76
- front_matter.merge(
77
- "attributes" => Canvas::ExpandAttributes.call(front_matter["attributes"])
78
- )
79
- end
80
73
  end
81
74
  end
@@ -30,6 +30,7 @@ module Canvas
30
30
  # @return [Array<Hash>] array of hashes that represent each attribute
31
31
  def call(attributes_hash)
32
32
  return [] if attributes_hash.nil?
33
+ return attributes_hash if attributes_hash.is_a?(Array)
33
34
 
34
35
  attributes_hash.each_with_object([]) do |(name, attribute_hash), attrs|
35
36
  attrs << attribute_hash.merge("name" => name)
@@ -9,35 +9,46 @@ module Canvas
9
9
  # This class is used to validate a schema for a block.
10
10
  # Example of a valid block schema:
11
11
  # {
12
- # "attributes" => [
13
- # {
14
- # "name" => "my_title",
12
+ # "attributes" => {
13
+ # "my_title" => {
15
14
  # "type" => "string"
16
15
  # },
17
- # {
18
- # "name" => "my_color",
16
+ # "my_color" => {
19
17
  # "type" => "color",
20
18
  # "label" => "My color",
21
19
  # "hint" => "Select your favourite color"
22
20
  # }
21
+ # },
22
+ # "layout" => [
23
+ # {
24
+ # "type" => "tab",
25
+ # "label" => "Content",
26
+ # "elements" => [
27
+ # "my_title",
28
+ # "my_color"
29
+ # ]
30
+ # }
23
31
  # ]
24
32
  # }
25
33
  class BlockSchema
26
- PERMITTED_KEYS = %w[attributes].freeze
34
+ PERMITTED_KEYS = %w[attributes layout].freeze
27
35
 
28
36
  attr_reader :errors, :schema
29
37
 
30
38
  # @param schema [Hash] the schema to be validated
31
39
  # @param custom_types [Array<Hash>] a list of custom types
32
40
  def initialize(schema:, custom_types: [])
33
- @schema = schema
41
+ @schema = normalize_schema(schema)
34
42
  @custom_types = custom_types
35
43
  @errors = []
36
44
  end
37
45
 
38
46
  def validate
47
+ @errors = []
48
+
39
49
  if ensure_valid_format
40
50
  ensure_no_unrecognized_keys
51
+ ensure_layout_is_valid
41
52
  ensure_attributes_are_valid
42
53
  end
43
54
 
@@ -48,12 +59,22 @@ module Canvas
48
59
 
49
60
  def ensure_valid_format
50
61
  return true if schema.is_a?(Hash) &&
51
- (schema["attributes"].nil? || attributes_array_of_hashes?(schema))
62
+ (schema["attributes"].nil? || attributes_hash_of_hashes?(schema))
52
63
 
53
64
  @errors << "Schema is not in a valid format"
54
65
  false
55
66
  end
56
67
 
68
+ def ensure_layout_is_valid
69
+ return true unless schema["layout"]
70
+
71
+ layout_validator = LayoutSchema.new(schema: @schema)
72
+ return true if layout_validator.validate
73
+
74
+ @errors += layout_validator.errors
75
+ false
76
+ end
77
+
57
78
  def ensure_no_unrecognized_keys
58
79
  unrecognized_keys = schema.keys - PERMITTED_KEYS
59
80
  return true if unrecognized_keys.empty?
@@ -65,7 +86,8 @@ module Canvas
65
86
  def ensure_attributes_are_valid
66
87
  return true unless schema["attributes"]
67
88
 
68
- schema["attributes"].each do |attribute_schema|
89
+ attributes = Canvas::ExpandAttributes.call(schema["attributes"])
90
+ attributes.each do |attribute_schema|
69
91
  attr_validator = Validator::SchemaAttribute.new(
70
92
  attribute: attribute_schema,
71
93
  custom_types: @custom_types
@@ -77,9 +99,17 @@ module Canvas
77
99
  end
78
100
  end
79
101
 
80
- def attributes_array_of_hashes?(schema)
81
- schema["attributes"].is_a?(Array) &&
82
- schema["attributes"].all? { |attr| attr.is_a?(Hash) }
102
+ def attributes_hash_of_hashes?(schema)
103
+ schema["attributes"].is_a?(Hash) &&
104
+ schema["attributes"].values.all? { |attr| attr.is_a?(Hash) }
105
+ end
106
+
107
+ # To support older schemas that do not nest the attributes
108
+ # under the `attributes` key.
109
+ def normalize_schema(schema)
110
+ return schema if schema.key?("attributes")
111
+
112
+ { "attributes" => schema }
83
113
  end
84
114
  end
85
115
  end
@@ -11,19 +11,27 @@ module Canvas
11
11
  #
12
12
  # Example:
13
13
  # {
14
- # "max_item_levels": 2,
15
- # "supports_open_new_tab": "true",
16
- # "attributes": {
17
- # "fixed": {
18
- # "group": "design",
19
- # "label": "Fixed when scrolling",
20
- # "hint": "The menu will stay fixed to the top when scrolling down the page.",
21
- # "type": "boolean",
22
- # "default: "false"
14
+ # "max_item_levels" => 2,
15
+ # "supports_open_new_tab" => "true",
16
+ # "attributes" => {
17
+ # "text_color" => {
18
+ # "type" => "color"
19
+ # },
20
+ # "background_color" => {
21
+ # "type" => "color"
23
22
  # }
24
- # }
23
+ # },
24
+ # "layout" => [
25
+ # {
26
+ # "type" => "tab",
27
+ # "label" => "Content",
28
+ # "elements" => [
29
+ # "text_color",
30
+ # "background_color"
31
+ # ]
32
+ # }
33
+ # ]
25
34
  # }
26
- #
27
35
  class FooterSchema < MenuSchema; end
28
36
  end
29
37
  end
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "json-schema"
5
+
6
+ module Canvas
7
+ module Validator
8
+ # :documented:
9
+ # This class is used to validate a layout definition, part of block schema.
10
+ # Example of a valid layout definition:
11
+ # {
12
+ # "attributes" => {
13
+ # "title" => {
14
+ # "type" => "string"
15
+ # }
16
+ # ...
17
+ # },
18
+ # "layout" => [
19
+ # {
20
+ # "label" => "Design",
21
+ # "type" => "tab",
22
+ # "elements" => [
23
+ # "heading",
24
+ # {
25
+ # "type" => "accordion",
26
+ # "label" => "Logo",
27
+ # "elements" => [
28
+ # "description",
29
+ # { "type" => "attribute", "name" => "logo_alt" },
30
+ # "title"
31
+ # ]
32
+ # },
33
+ # {
34
+ # "type" => "accordion_toggle",
35
+ # "toggle_attribute" => "cta_enabled",
36
+ # "elements" => [
37
+ # "cta_text",
38
+ # "cta_target"
39
+ # ]
40
+ # }
41
+ # ]
42
+ # }
43
+ # ]
44
+ # }
45
+ class LayoutSchema
46
+ attr_reader :errors
47
+
48
+ def initialize(schema:)
49
+ @schema = schema
50
+ @errors = []
51
+ end
52
+
53
+ def validate
54
+ @errors = []
55
+
56
+ if ensure_valid_format
57
+ ensure_no_unrecognized_keys
58
+ ensure_no_duplicate_keys
59
+ ensure_accordion_toggles_are_valid
60
+ end
61
+
62
+ @errors.empty?
63
+ end
64
+
65
+ private
66
+
67
+ attr_reader :schema
68
+
69
+ def ensure_no_duplicate_keys
70
+ attributes = fetch_all_attribute_names
71
+ duplicates =
72
+ attributes
73
+ .group_by { |(key)| key }
74
+ .filter { |key, usage| usage.size > 1 }
75
+
76
+ unless duplicates.empty?
77
+ duplicates.each do |attribute, usage|
78
+ @errors << "Duplicated attribute key `#{attribute}` found. Location: #{usage.map { |(_, location)| location }.join(", ")}"
79
+ end
80
+ end
81
+ end
82
+
83
+ def ensure_no_unrecognized_keys
84
+ attributes = fetch_all_attribute_names
85
+ defined_attributes = expanded_attributes.map { |definition| normalize_attribute(definition["name"]) } || []
86
+
87
+ attributes.each do |attribute, location|
88
+ @errors << "Unrecognized attribute `#{attribute}`. Location: #{location}" unless defined_attributes.include?(attribute)
89
+ end
90
+ end
91
+
92
+ # @return [Array<Array(String, String)>] an array of all the attribute names that
93
+ # are mentioned in the layout schema, along with its path. The names are
94
+ # normalized, i.e. downcased.
95
+ def fetch_all_attribute_names
96
+ attributes = fetch_elements_of_type("attribute")
97
+ attributes.map do |(node, path)|
98
+ [
99
+ normalize_attribute(node.is_a?(Hash) ? node["name"] : node),
100
+ path
101
+ ]
102
+ end
103
+ end
104
+
105
+ # @param type [String] the element type to fetch
106
+ # @return [Array<Array(<Hash, String>, String)] an array of elements that match
107
+ # the given type. Each element is an array containing the node and its path.
108
+ def fetch_elements_of_type(type)
109
+ elements = []
110
+
111
+ fetch_element = ->(node, path) {
112
+ if type == "attribute" && node.is_a?(String)
113
+ elements << [node, path]
114
+ elsif node["type"] == type
115
+ elements << [node, path]
116
+ end
117
+
118
+ if node.is_a?(Hash) && node.key?("elements")
119
+ node["elements"].each_with_index do |element, i|
120
+ current_path = "#{path}/elements/#{i}"
121
+ fetch_element.call(element, current_path)
122
+ end
123
+ end
124
+ }
125
+
126
+ layout_schema.each_with_index do |tab, i|
127
+ current_path = "layout/#{i}"
128
+ fetch_element.call(tab, current_path)
129
+ end
130
+
131
+ elements
132
+ end
133
+
134
+ def ensure_valid_format
135
+ result = JSON::Validator.fully_validate(schema_definition, { "layout" => layout_schema }, strict: true, clear_cache: true)
136
+
137
+ return true if result.empty?
138
+
139
+ @errors += result
140
+ false
141
+ end
142
+
143
+ def ensure_accordion_toggles_are_valid
144
+ accordion_toggles = fetch_elements_of_type("accordion_toggle")
145
+ accordion_toggles.each do |accordion_toggle, location|
146
+ toggle_attribute = expanded_attributes.detect { |attr|
147
+ attr["name"] == accordion_toggle["toggle_attribute"]
148
+ }
149
+
150
+ if toggle_attribute.nil?
151
+ @errors << "The toggle_attribute in accordion_toggle is unrecognized. Location: #{location}"
152
+ elsif toggle_attribute["type"]&.downcase != "boolean"
153
+ @errors << "The toggle_attribute in accordion_toggle must be a boolean. Location: #{location}"
154
+ end
155
+ end
156
+ end
157
+
158
+ def layout_schema
159
+ schema["layout"] || []
160
+ end
161
+
162
+ def schema_definition
163
+ File.read(
164
+ File.join(File.dirname(__FILE__), "../../../", "schema_definitions", "layout.json")
165
+ )
166
+ end
167
+
168
+ def normalize_attribute(name)
169
+ name.strip.downcase
170
+ end
171
+
172
+ def expanded_attributes
173
+ return [] if schema["attributes"].nil?
174
+
175
+ @_expanded_attributes ||= Canvas::ExpandAttributes.call(schema["attributes"])
176
+ end
177
+ end
178
+ end
179
+ end
@@ -7,21 +7,33 @@ module Canvas
7
7
  #
8
8
  # Example:
9
9
  # {
10
- # "max_item_levels": 2,
11
- # "supports_open_new_tab": "true",
12
- # "attributes": {
13
- # "fixed": {
14
- # "group": "design",
15
- # "label": "Fixed when scrolling",
16
- # "hint": "The menu will stay fixed to the top when scrolling down the page.",
17
- # "type": "boolean",
18
- # "default: "false"
10
+ # "max_item_levels" => 2,
11
+ # "supports_open_new_tab" => "true",
12
+ # "attributes" => {
13
+ # "fixed" => {
14
+ # "group" => "design",
15
+ # "label" => "Fixed when scrolling",
16
+ # "hint" => "The menu will stay fixed to the top when scrolling down the page.",
17
+ # "type" => "boolean",
18
+ # "default" => "false"
19
+ # },
20
+ # "background_color" => {
21
+ # "type" => "color"
19
22
  # }
20
- # }
23
+ # },
24
+ # "layout" => [
25
+ # {
26
+ # "type" => "tab",
27
+ # "label" => "Content",
28
+ # "elements" => [
29
+ # "fixed",
30
+ # "background_color"
31
+ # ]
32
+ # }
33
+ # ]
21
34
  # }
22
- #
23
35
  class MenuSchema
24
- PERMITTED_KEYS = %w[max_item_levels supports_open_new_tab attributes].freeze
36
+ PERMITTED_KEYS = %w[max_item_levels supports_open_new_tab attributes layout].freeze
25
37
  ADDITIONAL_RESERVED_NAMES = %w[items type].freeze
26
38
 
27
39
  attr_reader :schema, :errors
@@ -38,6 +50,7 @@ module Canvas
38
50
  if ensure_valid_format
39
51
  ensure_no_unrecognized_keys
40
52
  ensure_max_item_levels_is_valid
53
+ ensure_layout_is_valid
41
54
  ensure_attributes_are_valid
42
55
  end
43
56
 
@@ -48,7 +61,7 @@ module Canvas
48
61
 
49
62
  def ensure_valid_format
50
63
  return true if schema.is_a?(Hash) &&
51
- (schema["attributes"].nil? || attributes_array_of_hashes?(schema))
64
+ (schema["attributes"].nil? || attributes_hash_of_hashes?(schema))
52
65
 
53
66
  @errors << "Schema is not in a valid format"
54
67
  false
@@ -70,10 +83,21 @@ module Canvas
70
83
  false
71
84
  end
72
85
 
86
+ def ensure_layout_is_valid
87
+ return true unless schema["layout"]
88
+
89
+ layout_validator = LayoutSchema.new(schema: @schema)
90
+ return true if layout_validator.validate
91
+
92
+ @errors += layout_validator.errors
93
+ false
94
+ end
95
+
73
96
  def ensure_attributes_are_valid
74
97
  return true unless schema["attributes"]
75
98
 
76
- schema["attributes"].each do |attribute_schema|
99
+ attributes = Canvas::ExpandAttributes.call(schema["attributes"])
100
+ attributes.each do |attribute_schema|
77
101
  attr_validator = Validator::SchemaAttribute.new(
78
102
  attribute: attribute_schema,
79
103
  custom_types: @custom_types,
@@ -86,9 +110,9 @@ module Canvas
86
110
  end
87
111
  end
88
112
 
89
- def attributes_array_of_hashes?(schema)
90
- schema["attributes"].is_a?(Array) &&
91
- schema["attributes"].all? { |attr| attr.is_a?(Hash) }
113
+ def attributes_hash_of_hashes?(schema)
114
+ schema["attributes"].is_a?(Hash) &&
115
+ schema["attributes"].values.all? { |attr| attr.is_a?(Hash) }
92
116
  end
93
117
  end
94
118
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Canvas
4
- VERSION = "1.3.0"
4
+ VERSION = "2.0.0"
5
5
  end
@@ -0,0 +1,87 @@
1
+ {
2
+ "type": "object",
3
+ "properties": {
4
+ "layout": {
5
+ "type": "array",
6
+ "items": { "$ref": "#/$defs/tab" }
7
+ }
8
+ },
9
+ "$defs": {
10
+ "tab": {
11
+ "type": "object",
12
+ "required": ["type", "label"],
13
+ "properties": {
14
+ "type": {
15
+ "type": "string",
16
+ "const": "tab"
17
+ },
18
+ "label": {
19
+ "type": "string"
20
+ },
21
+ "elements": {
22
+ "type": "array",
23
+ "minItems": 1,
24
+ "items": {
25
+ "oneOf": [
26
+ { "type": "string" },
27
+ { "$ref": "#/$defs/accordion" },
28
+ { "$ref": "#/$defs/accordion_toggle" },
29
+ { "$ref": "#/$defs/attribute" }
30
+ ]
31
+ }
32
+ }
33
+ }
34
+ },
35
+ "accordion": {
36
+ "type": "object",
37
+ "required": ["label", "type"],
38
+ "properties": {
39
+ "type": {
40
+ "type": "string",
41
+ "const": "accordion"
42
+ },
43
+ "label": {
44
+ "type": "string"
45
+ },
46
+ "elements": {
47
+ "type": "array",
48
+ "items": {
49
+ "oneOf": [{ "type": "string" }, { "$ref": "#/$defs/attribute" }]
50
+ }
51
+ }
52
+ }
53
+ },
54
+ "accordion_toggle": {
55
+ "type": "object",
56
+ "required": ["type", "toggle_attribute", "elements"],
57
+ "properties": {
58
+ "type": {
59
+ "type": "string",
60
+ "const": "accordion_toggle"
61
+ },
62
+ "toggle_attribute": {
63
+ "type": "string"
64
+ },
65
+ "elements": {
66
+ "type": "array",
67
+ "items": {
68
+ "oneOf": [{ "type": "string" }, { "$ref": "#/$defs/attribute" }]
69
+ }
70
+ }
71
+ }
72
+ },
73
+ "attribute": {
74
+ "type": "object",
75
+ "required": ["name", "type"],
76
+ "properties": {
77
+ "type": {
78
+ "type": "string",
79
+ "const": "attribute"
80
+ },
81
+ "name": {
82
+ "type": "string"
83
+ }
84
+ }
85
+ }
86
+ }
87
+ }
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: easol-canvas
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kyle Byrne
8
8
  - Ian Mooney
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-07-06 00:00:00.000000000 Z
12
+ date: 2022-07-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor
@@ -81,6 +81,20 @@ dependencies:
81
81
  - - "~>"
82
82
  - !ruby/object:Gem::Version
83
83
  version: '2.4'
84
+ - !ruby/object:Gem::Dependency
85
+ name: json-schema
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '3'
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '3'
84
98
  description: |
85
99
  Canvas is a command line tool to help with building themes for Easol.
86
100
  It provides tooling to check theme directories for errors and to make sure
@@ -117,6 +131,7 @@ files:
117
131
  - lib/canvas/validators/footer_schema.rb
118
132
  - lib/canvas/validators/html.rb
119
133
  - lib/canvas/validators/json.rb
134
+ - lib/canvas/validators/layout_schema.rb
120
135
  - lib/canvas/validators/liquid.rb
121
136
  - lib/canvas/validators/menu_schema.rb
122
137
  - lib/canvas/validators/sass.rb
@@ -135,11 +150,12 @@ files:
135
150
  - lib/canvas/validators/schema_attributes/variant.rb
136
151
  - lib/canvas/version.rb
137
152
  - lib/easol/canvas.rb
153
+ - schema_definitions/layout.json
138
154
  homepage: https://rubygems.org/gems/easol-canvas
139
155
  licenses:
140
156
  - MIT
141
157
  metadata: {}
142
- post_install_message:
158
+ post_install_message:
143
159
  rdoc_options: []
144
160
  require_paths:
145
161
  - lib
@@ -154,8 +170,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
170
  - !ruby/object:Gem::Version
155
171
  version: '0'
156
172
  requirements: []
157
- rubygems_version: 3.3.7
158
- signing_key:
173
+ rubygems_version: 3.1.6
174
+ signing_key:
159
175
  specification_version: 4
160
176
  summary: CLI to help with building themes for Easol
161
177
  test_files: []