easol-canvas 1.3.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4b413ee9262a5f7b363a8f53950da655c1c85aaf71474a331b412c62d5ae8f62
4
- data.tar.gz: ecae8f840fffee09e161857beb61cb002d3006f63e00e7e52283342c228234a9
3
+ metadata.gz: 5cc9522b87ab434f7121dfd557aa987b820c9934486da6c96e8c7706ac4f92b4
4
+ data.tar.gz: e922ef25a0d8a916a82a7b9c4d8b4faf342088f6da65077518d72b68bf64eeab
5
5
  SHA512:
6
- metadata.gz: 42fe4d0cdede7d029e2e4c6ced43c23defb19a109bf11df3a4933d9411d2c6c83173042f4f2fee148573042760e62645eeb44b2e3af53e28b9bc91588c23d0a1
7
- data.tar.gz: 492e9fbeb71dfc80b56874d83e441ec799ae7ab04dedd668dc3e47c0cdfaabb0c9c9312fdeff2b792039ca44fb127af1eb1d876072c12d4c468567c6e20b6d6a
6
+ metadata.gz: c33da855f7ad39a4dad8172fc0942c9c60d4af81acf6c677bddb9c55dcacd9759392fa9c24e65910d76228a760bad31c244b865e8f83e52623ffdf26282f99b6
7
+ data.tar.gz: e4d2f3ebae85a1ed14716a1f5514bd3211ae130b973475bbcaf3b52c946cb25db90cdcfbd75143db9984600e3604071d153eb1766e79388e172a2307e09abcfb
@@ -37,7 +37,8 @@ module Canvas
37
37
 
38
38
  def validate_format(filename, front_matter)
39
39
  return true if front_matter.is_a?(Hash) &&
40
- front_matter.values.all? { |attr| attr.is_a?(Hash) }
40
+ (front_matter.key?("attributes") ? front_matter["attributes"] : front_matter).values.all? { |attr| attr.is_a?(Hash) }
41
+
41
42
 
42
43
  @offenses << Offense.new(
43
44
  message: "Invalid Block Schema: #{filename} - \nSchema is not in a valid format"
@@ -45,8 +46,7 @@ module Canvas
45
46
  false
46
47
  end
47
48
 
48
- def validate_schema(filename, front_matter, custom_types)
49
- schema = extract_schema(front_matter)
49
+ def validate_schema(filename, schema, custom_types)
50
50
  validator = Validator::BlockSchema.new(schema: schema, custom_types: custom_types)
51
51
  return if validator.validate
52
52
 
@@ -62,11 +62,5 @@ module Canvas
62
62
  front_matter = extractor.front_matter
63
63
  front_matter.nil? ? {} : YAML.safe_load(front_matter)
64
64
  end
65
-
66
- def extract_schema(front_matter)
67
- {
68
- "attributes" => Canvas::ExpandAttributes.call(front_matter)
69
- }
70
- end
71
65
  end
72
66
  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)
@@ -23,21 +23,24 @@ module Canvas
23
23
  # ]
24
24
  # }
25
25
  class BlockSchema
26
- PERMITTED_KEYS = %w[attributes].freeze
26
+ PERMITTED_KEYS = %w[attributes layout].freeze
27
27
 
28
28
  attr_reader :errors, :schema
29
29
 
30
30
  # @param schema [Hash] the schema to be validated
31
31
  # @param custom_types [Array<Hash>] a list of custom types
32
32
  def initialize(schema:, custom_types: [])
33
- @schema = schema
33
+ @schema = normalize_schema(schema)
34
34
  @custom_types = custom_types
35
35
  @errors = []
36
36
  end
37
37
 
38
38
  def validate
39
+ @errors = []
40
+
39
41
  if ensure_valid_format
40
42
  ensure_no_unrecognized_keys
43
+ ensure_layout_is_valid
41
44
  ensure_attributes_are_valid
42
45
  end
43
46
 
@@ -54,6 +57,16 @@ module Canvas
54
57
  false
55
58
  end
56
59
 
60
+ def ensure_layout_is_valid
61
+ return true unless schema["layout"]
62
+
63
+ layout_validator = LayoutSchema.new(schema: @schema)
64
+ return true if layout_validator.validate
65
+
66
+ @errors += layout_validator.errors
67
+ false
68
+ end
69
+
57
70
  def ensure_no_unrecognized_keys
58
71
  unrecognized_keys = schema.keys - PERMITTED_KEYS
59
72
  return true if unrecognized_keys.empty?
@@ -81,6 +94,19 @@ module Canvas
81
94
  schema["attributes"].is_a?(Array) &&
82
95
  schema["attributes"].all? { |attr| attr.is_a?(Hash) }
83
96
  end
97
+
98
+ def normalize_schema(schema)
99
+ if schema.key?("attributes")
100
+ {
101
+ **schema,
102
+ "attributes" => Canvas::ExpandAttributes.call(schema["attributes"])
103
+ }
104
+ else
105
+ {
106
+ "attributes" => Canvas::ExpandAttributes.call(schema)
107
+ }
108
+ end
109
+ end
84
110
  end
85
111
  end
86
112
  end
@@ -0,0 +1,123 @@
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
+ # "layout" => [
13
+ # {
14
+ # "label" => "Design",
15
+ # "type" => "tab",
16
+ # "elements" => [
17
+ # "heading",
18
+ # {
19
+ # "type" => "accordion",
20
+ # "label" => "Logo",
21
+ # "elements" => [
22
+ # "description",
23
+ # { "type" => "attribute", "name" => "logo_alt" },
24
+ # "title"
25
+ # ]
26
+ # }
27
+ # ]
28
+ # }]
29
+ # }
30
+ class LayoutSchema
31
+ attr_reader :errors
32
+
33
+ def initialize(schema:)
34
+ @schema = schema
35
+ @errors = []
36
+ end
37
+
38
+ def validate
39
+ @errors = []
40
+
41
+ if ensure_valid_format
42
+ ensure_no_unrecognized_keys
43
+ ensure_no_duplicate_keys
44
+ end
45
+
46
+ @errors.empty?
47
+ end
48
+
49
+ private
50
+
51
+ def ensure_no_duplicate_keys
52
+ attributes = gather_attributes_from_layout_schema
53
+ duplicates =
54
+ attributes
55
+ .group_by { |(key)| key }
56
+ .filter { |key, usage| usage.size > 1 }
57
+
58
+ unless duplicates.empty?
59
+ duplicates.each do |attribute, usage|
60
+ @errors << "Duplicated attribute key `#{attribute}` found. Location: #{usage.map { |(_, location)| location }.join(", ")}"
61
+ end
62
+ end
63
+ end
64
+
65
+ def ensure_no_unrecognized_keys
66
+ attributes = gather_attributes_from_layout_schema
67
+ defined_attributes = @schema["attributes"]&.map { |definition| normalize_attribute(definition["name"]) } || []
68
+
69
+ attributes.each do |attribute, location|
70
+ @errors << "Unrecognized attribute `#{attribute}`. Location: #{location}" unless defined_attributes.include?(attribute)
71
+ end
72
+ end
73
+
74
+ def gather_attributes_from_layout_schema
75
+ attribute_keys = []
76
+
77
+ fetch_attribute_type = ->(node, path) {
78
+ if node.is_a?(Hash) && node.key?("elements")
79
+ node["elements"].each_with_index do |element, i|
80
+ current_path = "#{path}/elements/#{i}"
81
+ fetch_attribute_type.call(element, current_path)
82
+ end
83
+ else
84
+ attribute_keys << [
85
+ normalize_attribute(node.is_a?(Hash) ? node["name"] : node),
86
+ path
87
+ ]
88
+ end
89
+ }
90
+
91
+ layout_schema.each_with_index do |tab, i|
92
+ current_path = "layout/#{i}"
93
+ fetch_attribute_type.call(tab, current_path)
94
+ end
95
+
96
+ attribute_keys
97
+ end
98
+
99
+ def ensure_valid_format
100
+ result = JSON::Validator.fully_validate(schema_definition, { "layout" => layout_schema }, strict: true, clear_cache: true)
101
+
102
+ return true if result.empty?
103
+
104
+ @errors += result
105
+ false
106
+ end
107
+
108
+ def layout_schema
109
+ @schema["layout"] || []
110
+ end
111
+
112
+ def schema_definition
113
+ File.read(
114
+ File.join(File.dirname(__FILE__), "../../../", "schema_definitions", "block_layout.json")
115
+ )
116
+ end
117
+
118
+ def normalize_attribute(name)
119
+ name.strip.downcase
120
+ end
121
+ end
122
+ end
123
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Canvas
4
- VERSION = "1.3.0"
4
+ VERSION = "1.4.1"
5
5
  end
@@ -0,0 +1,67 @@
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/component" },
28
+ { "$ref": "#/$defs/attribute" }
29
+ ]
30
+ }
31
+ }
32
+ }
33
+ },
34
+ "component": {
35
+ "type": "object",
36
+ "required": ["label", "type"],
37
+ "properties": {
38
+ "type": {
39
+ "type": "string",
40
+ "enum": ["accordion"]
41
+ },
42
+ "label": {
43
+ "type": "string"
44
+ },
45
+ "elements": {
46
+ "type": "array",
47
+ "items": {
48
+ "oneOf": [{ "type": "string" }, { "$ref": "#/$defs/attribute" }]
49
+ }
50
+ }
51
+ }
52
+ },
53
+ "attribute": {
54
+ "type": "object",
55
+ "required": ["name", "type"],
56
+ "properties": {
57
+ "type": {
58
+ "type": "string",
59
+ "const": "attribute"
60
+ },
61
+ "name": {
62
+ "type": "string"
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
metadata CHANGED
@@ -1,7 +1,7 @@
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: 1.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kyle Byrne
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-07-06 00:00:00.000000000 Z
12
+ date: 2022-07-15 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,6 +150,7 @@ 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/block_layout.json
138
154
  homepage: https://rubygems.org/gems/easol-canvas
139
155
  licenses:
140
156
  - MIT
@@ -154,7 +170,7 @@ 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
173
+ rubygems_version: 3.2.33
158
174
  signing_key:
159
175
  specification_version: 4
160
176
  summary: CLI to help with building themes for Easol