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 +4 -4
- data/lib/canvas/checks/valid_block_schemas_check.rb +3 -9
- data/lib/canvas/services/expand_attributes.rb +1 -0
- data/lib/canvas/validators/block_schema.rb +28 -2
- data/lib/canvas/validators/layout_schema.rb +123 -0
- data/lib/canvas/version.rb +1 -1
- data/schema_definitions/block_layout.json +67 -0
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5cc9522b87ab434f7121dfd557aa987b820c9934486da6c96e8c7706ac4f92b4
|
4
|
+
data.tar.gz: e922ef25a0d8a916a82a7b9c4d8b4faf342088f6da65077518d72b68bf64eeab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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,
|
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
|
data/lib/canvas/version.rb
CHANGED
@@ -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.
|
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-
|
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.
|
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
|