easol-canvas 0.1.0
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 +7 -0
- data/bin/canvas +5 -0
- data/bin/rspec +29 -0
- data/lib/canvas/check.rb +19 -0
- data/lib/canvas/checks/required_files_check.rb +22 -0
- data/lib/canvas/checks/valid_html_check.rb +22 -0
- data/lib/canvas/checks/valid_liquid_check.rb +40 -0
- data/lib/canvas/checks.rb +19 -0
- data/lib/canvas/cli.rb +12 -0
- data/lib/canvas/lint.rb +44 -0
- data/lib/canvas/offense.rb +9 -0
- data/lib/canvas/services/front_matter_extractor.rb +39 -0
- data/lib/canvas/validators/html.rb +52 -0
- data/lib/canvas/validators/liquid.rb +43 -0
- data/lib/canvas/version.rb +3 -0
- data/lib/canvas.rb +17 -0
- metadata +117 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3adb680aaee894634145000781ac9b4fbc7d4429f165bd70482c04f3fbdb7c6b
|
4
|
+
data.tar.gz: b787e246b9be34acebcb80454504632a4b56e48dbd3e7c79755e33bf2272398a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7d6db23a8b543fbace909d12fae0c4293ea040dccc11180d12f0265afb0b89f405b8d35fb5d957ac8f4a1c4de0e084c6bc82ebfe79bd809669634678863a9220
|
7
|
+
data.tar.gz: 92323781eab651622fc54fe94f43305075ebcdfb9046c056152d62cc4645d77b03f65a2bf569739ad8d74e22366fc814a19d8bbce41a16a8aed9ab02e00d6ddb
|
data/bin/canvas
ADDED
data/bin/rspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rspec' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rspec-core", "rspec")
|
data/lib/canvas/check.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module Canvas
|
2
|
+
class RequiredFilesCheck < Check
|
3
|
+
REQUIRED_FILES = [
|
4
|
+
"templates/product/index.{html,liquid}",
|
5
|
+
"templates/blog_overview/index.{html,liquid}",
|
6
|
+
"templates/blog_post/index.{html,liquid}",
|
7
|
+
"partials/footer/index.{html,liquid}",
|
8
|
+
"partials/menu/index.{html,liquid}",
|
9
|
+
"assets/index.css"
|
10
|
+
].freeze
|
11
|
+
|
12
|
+
def run
|
13
|
+
REQUIRED_FILES.each do |filename|
|
14
|
+
next unless Dir.glob(filename).empty?
|
15
|
+
|
16
|
+
@offenses << Offense.new(
|
17
|
+
message: "Missing file: #{filename}"
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Canvas
|
2
|
+
class ValidHtmlCheck < Check
|
3
|
+
def run
|
4
|
+
html_files.each do |filename|
|
5
|
+
file = File.read(filename)
|
6
|
+
validator = Validator::Html.new(file)
|
7
|
+
|
8
|
+
next if validator.validate
|
9
|
+
|
10
|
+
validator.errors.map(&:message).each do |message|
|
11
|
+
@offenses << Offense.new(
|
12
|
+
message: "Invalid HTML: #{filename} - \n#{message}"
|
13
|
+
)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def html_files
|
19
|
+
Dir.glob("**/*.{html,liquid}")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Canvas
|
2
|
+
class ValidLiquidCheck < Check
|
3
|
+
def run
|
4
|
+
register_tags!
|
5
|
+
|
6
|
+
liquid_files.each do |filename|
|
7
|
+
file = File.read(filename)
|
8
|
+
validator = Validator::Liquid.new(file)
|
9
|
+
|
10
|
+
next if validator.validate
|
11
|
+
|
12
|
+
validator.errors.map(&:message).each do |message|
|
13
|
+
@offenses << Offense.new(
|
14
|
+
message: "Invalid Liquid: #{filename} - \n#{message}"
|
15
|
+
)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def liquid_files
|
23
|
+
Dir.glob("**/*.{html,liquid}")
|
24
|
+
end
|
25
|
+
|
26
|
+
def register_tag(name, klass)
|
27
|
+
::Liquid::Template.register_tag(name, klass)
|
28
|
+
end
|
29
|
+
|
30
|
+
# These are the tags that we define in the Rails app. If we add a new custom tag
|
31
|
+
# in the Rails app, we'll need to register it here.
|
32
|
+
def register_tags!
|
33
|
+
register_tag("form", ::Liquid::Block)
|
34
|
+
register_tag("product_search", ::Liquid::Block)
|
35
|
+
register_tag("easol_badge", ::Liquid::Tag)
|
36
|
+
register_tag("accommodation_availability", ::Liquid::Block)
|
37
|
+
register_tag("cache", ::Liquid::Block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Canvas
|
2
|
+
class Checks
|
3
|
+
class << self
|
4
|
+
def registered
|
5
|
+
@checks ||= []
|
6
|
+
end
|
7
|
+
|
8
|
+
def register(klass)
|
9
|
+
@checks ||= []
|
10
|
+
return if @checks.include?(klass)
|
11
|
+
@checks << klass
|
12
|
+
end
|
13
|
+
|
14
|
+
def deregister_all!
|
15
|
+
@checks = []
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/canvas/cli.rb
ADDED
data/lib/canvas/lint.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'cli/ui'
|
2
|
+
|
3
|
+
module Canvas
|
4
|
+
class Lint
|
5
|
+
def run
|
6
|
+
output_context = CLI::UI::SpinGroup.new(auto_debrief: false)
|
7
|
+
|
8
|
+
@checks = Checks.registered.map(&:new)
|
9
|
+
|
10
|
+
@checks.each do |check|
|
11
|
+
run_check(check, output_context)
|
12
|
+
end
|
13
|
+
|
14
|
+
output_context.wait
|
15
|
+
|
16
|
+
if @checks.any?(&:failed?)
|
17
|
+
puts debrief_message
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def run_check(check, output_context)
|
24
|
+
output_context.add(check.class.name) do
|
25
|
+
check.run
|
26
|
+
raise if check.offenses.any?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def debrief_message
|
31
|
+
CLI::UI::Frame.open('Failures', color: :red) do
|
32
|
+
failed_checks = @checks.filter(&:failed?)
|
33
|
+
failed_checks.map do |check|
|
34
|
+
CLI::UI::Frame.open(check.class.name, color: :red) do
|
35
|
+
output = check.offenses.map do |offense|
|
36
|
+
CLI::UI.fmt "{{x}} #{offense.message}"
|
37
|
+
end
|
38
|
+
puts output.join("\n")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Canvas
|
3
|
+
# :documented:
|
4
|
+
# This service can be used to extract front matter from a liquid string.
|
5
|
+
class FrontMatterExtractor
|
6
|
+
attr_accessor :front_matter, :html
|
7
|
+
|
8
|
+
def initialize(full_markup)
|
9
|
+
@front_matter = extract_front_matter(full_markup)
|
10
|
+
@html = extract_html(full_markup)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
# @return [String] the front matter, with the rest of the HTML stripped out
|
16
|
+
def extract_front_matter(full_markup)
|
17
|
+
return if full_markup.nil?
|
18
|
+
|
19
|
+
front_matter, body = scan(full_markup)
|
20
|
+
front_matter unless [nil, ""].include?(body)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [String] the HTML, with the front matter stripped out
|
24
|
+
def extract_html(full_markup)
|
25
|
+
return if full_markup.nil?
|
26
|
+
|
27
|
+
liquid_markup_stripped = full_markup.gsub("\n\n", "\n")
|
28
|
+
_, body = scan(liquid_markup_stripped)
|
29
|
+
body || full_markup
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [Array<String>] an array consisting of two items: the front matter
|
33
|
+
# and the HTML content.
|
34
|
+
def scan(markup)
|
35
|
+
markup = markup.gsub(/\t/, " ")
|
36
|
+
[*markup.match(/(?:---\s+(.*?)\s+---\s+)(.*\s?)$/m)&.captures]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
require "liquid"
|
3
|
+
|
4
|
+
module Canvas
|
5
|
+
module Validator
|
6
|
+
class Html
|
7
|
+
LIQUID_TAG = /#{Liquid::TagStart}.*?#{Liquid::TagEnd}/om
|
8
|
+
LIQUID_VARIABLE = /#{Liquid::VariableStart}.*?#{Liquid::VariableEnd}/om
|
9
|
+
LIQUID_TAG_OR_VARIABLE = /#{LIQUID_TAG}|#{LIQUID_VARIABLE}/om
|
10
|
+
|
11
|
+
attr_reader :errors
|
12
|
+
|
13
|
+
def initialize(file)
|
14
|
+
@file = file
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate
|
18
|
+
doc = Nokogiri::HTML5.fragment(extracted_html, max_errors: 1)
|
19
|
+
@errors = doc.errors
|
20
|
+
doc.errors.empty?
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def extracted_html
|
26
|
+
html = strip_out_front_matter(@file)
|
27
|
+
strip_out_liquid(html)
|
28
|
+
end
|
29
|
+
|
30
|
+
# We want to strip out the liquid tags and replace them with the
|
31
|
+
# same number of empty space characters, so that the linter
|
32
|
+
# reports the correct character number.
|
33
|
+
def strip_out_liquid(html)
|
34
|
+
html.gsub(LIQUID_TAG_OR_VARIABLE) { |tag| " " * tag.size }
|
35
|
+
end
|
36
|
+
|
37
|
+
# We want to strip out the front matter and replace it
|
38
|
+
# with empty new lines, so that linter output reports the
|
39
|
+
# correct line numbers
|
40
|
+
def strip_out_front_matter(html)
|
41
|
+
extractor = Canvas::FrontMatterExtractor.new(html)
|
42
|
+
|
43
|
+
if extractor.front_matter
|
44
|
+
num_lines = extractor.front_matter.lines.size - 1
|
45
|
+
html.sub(extractor.front_matter, "\n" * num_lines)
|
46
|
+
else
|
47
|
+
html
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
require "liquid"
|
3
|
+
|
4
|
+
module Canvas
|
5
|
+
module Validator
|
6
|
+
class Liquid
|
7
|
+
attr_reader :errors
|
8
|
+
|
9
|
+
def initialize(file)
|
10
|
+
@file = file
|
11
|
+
end
|
12
|
+
|
13
|
+
def validate
|
14
|
+
liquid = strip_out_front_matter(@file)
|
15
|
+
::Liquid::Template.parse(
|
16
|
+
liquid,
|
17
|
+
line_numbers: true,
|
18
|
+
error_mode: :warn
|
19
|
+
)
|
20
|
+
true
|
21
|
+
rescue ::Liquid::SyntaxError => e
|
22
|
+
@errors = [e]
|
23
|
+
false
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# We want to strip out the front matter and replace it
|
29
|
+
# with empty new lines, so that linter output reports the
|
30
|
+
# correct line numbers
|
31
|
+
def strip_out_front_matter(html)
|
32
|
+
extractor = Canvas::FrontMatterExtractor.new(html)
|
33
|
+
|
34
|
+
if extractor.front_matter
|
35
|
+
num_lines = extractor.front_matter.lines.size - 1
|
36
|
+
html.sub(extractor.front_matter, "\n" * num_lines)
|
37
|
+
else
|
38
|
+
html
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/canvas.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative "canvas/version"
|
2
|
+
require_relative "canvas/cli"
|
3
|
+
require_relative "canvas/lint"
|
4
|
+
require_relative "canvas/validators/html"
|
5
|
+
require_relative "canvas/validators/liquid"
|
6
|
+
require_relative "canvas/check"
|
7
|
+
require_relative "canvas/offense"
|
8
|
+
require_relative "canvas/checks"
|
9
|
+
|
10
|
+
Dir[__dir__ + "/canvas/{checks,services}/*.rb"].each { |file| require file }
|
11
|
+
|
12
|
+
Canvas::Checks.register(Canvas::RequiredFilesCheck)
|
13
|
+
Canvas::Checks.register(Canvas::ValidHtmlCheck)
|
14
|
+
Canvas::Checks.register(Canvas::ValidLiquidCheck)
|
15
|
+
|
16
|
+
module Canvas
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: easol-canvas
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kyle Byrne
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-05-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: nokogiri
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: cli-ui
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: liquid
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: |
|
70
|
+
Canvas is a command line tool to help with building themes for Easol.
|
71
|
+
It provides tooling to check theme directories for errors and to make sure
|
72
|
+
they confirm with the Easol theme spec.
|
73
|
+
email: kyle@easol.com
|
74
|
+
executables:
|
75
|
+
- canvas
|
76
|
+
extensions: []
|
77
|
+
extra_rdoc_files: []
|
78
|
+
files:
|
79
|
+
- bin/canvas
|
80
|
+
- bin/rspec
|
81
|
+
- lib/canvas.rb
|
82
|
+
- lib/canvas/check.rb
|
83
|
+
- lib/canvas/checks.rb
|
84
|
+
- lib/canvas/checks/required_files_check.rb
|
85
|
+
- lib/canvas/checks/valid_html_check.rb
|
86
|
+
- lib/canvas/checks/valid_liquid_check.rb
|
87
|
+
- lib/canvas/cli.rb
|
88
|
+
- lib/canvas/lint.rb
|
89
|
+
- lib/canvas/offense.rb
|
90
|
+
- lib/canvas/services/front_matter_extractor.rb
|
91
|
+
- lib/canvas/validators/html.rb
|
92
|
+
- lib/canvas/validators/liquid.rb
|
93
|
+
- lib/canvas/version.rb
|
94
|
+
homepage:
|
95
|
+
licenses:
|
96
|
+
- MIT
|
97
|
+
metadata: {}
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options: []
|
100
|
+
require_paths:
|
101
|
+
- lib
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
requirements: []
|
113
|
+
rubygems_version: 3.1.6
|
114
|
+
signing_key:
|
115
|
+
specification_version: 4
|
116
|
+
summary: CLI to help with building themes for Easol
|
117
|
+
test_files: []
|