This repository has been archived by the owner on Jul 27, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 96
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 6f48828
Showing
22 changed files
with
756 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/.bundle/ | ||
/.yardoc | ||
/_yardoc/ | ||
/coverage/ | ||
/doc/ | ||
/pkg/ | ||
/spec/reports/ | ||
/tmp/ | ||
|
||
*.gem | ||
Gemfile.lock | ||
|
||
.rubocop-https---shopify-github-io-ruby-style-guide-rubocop-yml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
inherit_from: | ||
- 'https://shopify.github.io/ruby-style-guide/rubocop.yml' | ||
|
||
Metrics/MethodLength: | ||
Enabled: false | ||
|
||
Layout/LineLength: | ||
Enabled: false | ||
|
||
Lint/MissingSuper: | ||
Enabled: false | ||
|
||
Style/FrozenStringLiteralComment: | ||
Enabled: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
source "https://rubygems.org" | ||
|
||
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } | ||
|
||
# Specify your gem's dependencies in theme-check.gemspec | ||
gemspec | ||
|
||
gem 'bundler' | ||
gem 'rake' | ||
gem 'minitest' | ||
gem 'rubocop', require: false | ||
|
||
gem 'liquid', github: 'Shopify/liquid', branch: 'master' | ||
gem 'liquid-c', github: 'Shopify/liquid-c', branch: 'master' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
require "rake/testtask" | ||
require 'rubocop/rake_task' | ||
|
||
Rake::TestTask.new(:test) do |t| | ||
t.libs << "test" | ||
t.libs << "lib" | ||
t.test_files = FileList["test/**/*_test.rb"] | ||
end | ||
|
||
RuboCop::RakeTask.new | ||
|
||
task default: [:rubocop, :test] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#!/usr/bin/env ruby | ||
|
||
require "theme_check" | ||
|
||
path = ARGV[0] || abort("usage: theme-check theme/root/path") | ||
puts ThemeCheck.analyze(path) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
require "liquid/c" | ||
|
||
require_relative "theme_check/analyzer" | ||
require_relative "theme_check/check" | ||
require_relative "theme_check/checks" | ||
require_relative "theme_check/node" | ||
require_relative "theme_check/offense" | ||
require_relative "theme_check/tags" | ||
require_relative "theme_check/theme" | ||
require_relative "theme_check/visitor" | ||
|
||
Dir[__dir__ + "/theme_check/checks/*.rb"].each { |file| require file } | ||
|
||
module ThemeCheck | ||
def self.analyze(theme_root) | ||
analyzer = Analyzer.new(Theme.new(theme_root)) | ||
analyzer.analyze_theme | ||
analyzer.offenses | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
module ThemeCheck | ||
class Analyzer | ||
attr_reader :offenses | ||
|
||
def initialize(theme, check_classes = Check.all) | ||
@theme = theme | ||
@offenses = [] | ||
@checks = Checks.new | ||
check_classes.each do |check_class| | ||
check = check_class.new | ||
check.theme = @theme | ||
check.offenses = @offenses | ||
@checks << check | ||
end | ||
@visitor = Visitor.new(@checks) | ||
end | ||
|
||
def analyze_theme | ||
@theme.all_files_paths.each { |template| analyze_template(template) } | ||
@checks.call(:on_end) | ||
end | ||
|
||
def analyze_template(template_path) | ||
template_path = Pathname(template_path) | ||
template = Liquid::Template.parse( | ||
template_path.read, | ||
line_numbers: true, | ||
disable_liquid_c_nodes: true | ||
) | ||
relative_template_path = template_path.relative_path_from(@theme.root) | ||
@visitor.visit_template(template, path: relative_template_path) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
module ThemeCheck | ||
class Check | ||
attr_accessor :theme | ||
attr_accessor :offenses | ||
|
||
SEVERITIES = [ | ||
:error, | ||
:suggestion, | ||
:style, | ||
] | ||
|
||
class << self | ||
def all | ||
@all ||= [] | ||
end | ||
|
||
def inherited(klass) | ||
all << klass | ||
end | ||
|
||
def severity(severity = nil) | ||
if severity | ||
unless SEVERITIES.include?(severity) | ||
raise ArgumentError, "unknown severity. Use: #{SEVERITIES.join(', ')}" | ||
end | ||
@severity = severity | ||
end | ||
@severity | ||
end | ||
|
||
def doc(doc = nil) | ||
@doc = doc if doc | ||
@doc | ||
end | ||
end | ||
|
||
def severity | ||
self.class.severity | ||
end | ||
|
||
def doc | ||
self.class.doc | ||
end | ||
|
||
def ignore! | ||
@ignored = true | ||
end | ||
|
||
def unignore! | ||
@ignored = false | ||
end | ||
|
||
def ignored? | ||
defined?(@ignored) && @ignored | ||
end | ||
|
||
def add_offense(message, node: nil, template: node&.template) | ||
offenses << Offense.new(self, template, node, message) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
module ThemeCheck | ||
class Checks < Array | ||
def call(method, *args) | ||
each do |check| | ||
if check.respond_to?(method) && !check.ignored? | ||
check.send(method, *args) | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
module ThemeCheck | ||
# Recommends using {% liquid ... %} if 3 or more consecutive {% ... %} are found. | ||
class LiquidTag < Check | ||
severity :suggestion | ||
doc "https://shopify.dev/docs/themes/liquid/reference/tags/theme-tags#liquid" | ||
|
||
MIN_CONSECUTIVE_STATEMENTS = 4 | ||
|
||
def initialize | ||
@first_statement = nil | ||
@consecutive_statements = 0 | ||
end | ||
|
||
def on_tag(node) | ||
unless node.comment? | ||
increment_consecutive_statements(node) | ||
end | ||
end | ||
|
||
def on_string(node) | ||
# Only reset the counter on outputted strings, and ignore empty line-breaks | ||
if node.parent.block? && !node.value.strip.empty? | ||
reset_consecutive_statements | ||
end | ||
end | ||
|
||
def after_document(_node) | ||
reset_consecutive_statements | ||
end | ||
|
||
def increment_consecutive_statements(node) | ||
@first_statement ||= node | ||
@consecutive_statements += 1 | ||
end | ||
|
||
def reset_consecutive_statements | ||
if @consecutive_statements >= MIN_CONSECUTIVE_STATEMENTS | ||
add_offense("Use {% liquid ... %} to write multiple tags", node: @first_statement) | ||
end | ||
@first_statement = nil | ||
@consecutive_statements = 0 | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
require "set" | ||
|
||
module ThemeCheck | ||
class UnusedSnippets < Check | ||
severity :suggestion | ||
|
||
def initialize | ||
@used_templates = Set.new | ||
end | ||
|
||
def on_include(node) | ||
if node.value.template_name_expr.is_a?(String) | ||
@used_templates << "snippets/#{node.value.template_name_expr}.liquid" | ||
else | ||
# Can't reliably track unused snippets if an expression is used, ignore this check | ||
@used_templates.clear | ||
ignore! | ||
end | ||
end | ||
alias_method :on_render, :on_include | ||
|
||
def on_end | ||
(theme.snippets - @used_templates.to_a).each do |template| | ||
add_offense("This template is not used", template: template) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
require 'active_support/core_ext/string/inflections' | ||
|
||
module ThemeCheck | ||
class Node | ||
attr_reader :value, :parent, :template | ||
|
||
def initialize(value, parent, template) | ||
raise ArgumentError, "Expected a Liquid AST Node" if value.is_a?(Node) | ||
@value = value | ||
@parent = parent | ||
@template = template | ||
end | ||
|
||
def children | ||
@children ||= begin | ||
nodes = | ||
if defined?(@value.class::ParseTreeVisitor) | ||
@value.class::ParseTreeVisitor.new(@value, {}).children | ||
elsif @value.respond_to?(:nodelist) | ||
Array(@value.nodelist) | ||
else | ||
[] | ||
end | ||
nodes.map { |node| Node.new(node, self, @template) } | ||
end | ||
end | ||
|
||
def literal? | ||
@value.is_a?(String) || @value.is_a?(Integer) | ||
end | ||
|
||
def tag? | ||
@value.is_a?(Liquid::Tag) | ||
end | ||
|
||
def comment? | ||
@value.is_a?(Liquid::Comment) | ||
end | ||
|
||
def document? | ||
@value.is_a?(Liquid::Document) | ||
end | ||
alias_method :root?, :document? | ||
|
||
def block_tag? | ||
@value.is_a?(Liquid::Block) | ||
end | ||
|
||
def block? | ||
block_tag? || block_body? || document? | ||
end | ||
|
||
def block_body? | ||
@value.is_a?(Liquid::BlockBody) | ||
end | ||
|
||
def line_number | ||
@value.line_number if @value.respond_to?(:line_number) | ||
end | ||
|
||
def type_name | ||
@type_name ||= @value.class.name.demodulize.underscore.to_sym | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
module ThemeCheck | ||
class Offense < Struct.new(:check, :template, :node, :message) | ||
def line_number | ||
node&.line_number | ||
end | ||
|
||
def severity | ||
check.severity | ||
end | ||
|
||
def doc | ||
check.doc | ||
end | ||
|
||
def to_s | ||
out = +'' | ||
out << "#{message} at #{template}" | ||
out << ":#{line_number}" if line_number | ||
out | ||
end | ||
end | ||
end |
Oops, something went wrong.