easol-canvas 1.3.0 → 1.4.1

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: 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